2 *****************************************************************************
6 * Author: Damien S. Stuart (dstuart@dstuart.org)
7 * Michael Rash (mbr@cipherdyne.org)
9 * Purpose: Network-related functions for the fwknop client
11 * Copyright 2009-2010 Damien Stuart (dstuart@dstuart.org)
13 * License (GNU Public License):
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
30 *****************************************************************************
36 print_proto(const int proto)
42 case FKO_PROTO_TCP_RAW:
59 dump_transmit_options(const fko_cli_options_t *options)
61 printf("Generating SPA packet:\n protocol: ");
62 print_proto(options->spa_proto),
63 printf("\n port: %d\n", options->spa_dst_port);
64 printf(" IP/host: %s\n", options->spa_server_str);
68 /* Function to generate a header checksum.
71 chksum(unsigned short *buf, int nbytes)
74 unsigned short oddbyte;
86 *((unsigned short *) &oddbyte) = *(unsigned short *) buf;
90 sum = (sum >> 16) + (sum & 0xffff);
93 return (unsigned short) ~sum;
97 static int is_ip(char *str)
102 for (i=0; i < strlen(str); i++) {
103 if (str[i] != '.' && ! isdigit(str[i])) {
113 /* Send the SPA data via UDP packet.
116 send_spa_packet_tcp_or_udp(const char *spa_data, const int sd_len,
117 const fko_cli_options_t *options)
119 int sock, res=0, error;
120 struct addrinfo *result, *rp, hints;
121 char port_str[MAX_PORT_STR_LEN];
126 "test mode enabled, SPA packet not actually sent.\n");
130 memset(&hints, 0, sizeof(struct addrinfo));
132 hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
134 if (options->spa_proto == FKO_PROTO_UDP)
136 /* Send the SPA data packet via an single UDP packet - this is the
139 hints.ai_socktype = SOCK_DGRAM;
140 hints.ai_protocol = IPPROTO_UDP;
144 /* Send the SPA data packet via an established TCP connection.
146 hints.ai_socktype = SOCK_STREAM;
147 hints.ai_protocol = IPPROTO_TCP;
150 snprintf(port_str, MAX_PORT_STR_LEN, "%d", options->spa_dst_port);
152 error = getaddrinfo(options->spa_server_str, port_str, &hints, &result);
156 fprintf(stderr, "error in getaddrinfo: %s\n", gai_strerror(error));
160 for (rp = result; rp != NULL; rp = rp->ai_next) {
161 sock = socket(rp->ai_family, rp->ai_socktype,
166 if ((error = (connect(sock, rp->ai_addr, rp->ai_addrlen) != -1)))
177 perror("send_spa_packet_tcp_or_udp: Could not create socket: ");
181 freeaddrinfo(result);
183 res = send(sock, spa_data, sd_len, 0);
187 perror("send_spa_packet_tcp_or_udp: write error: ");
189 else if(res != sd_len)
192 "[#] Warning: bytes sent (%i) not spa data length (%i).\n",
206 /* Send the SPA data via raw TCP packet.
209 send_spa_packet_tcp_raw(const char *spa_data, const int sd_len,
210 const struct sockaddr_in *saddr, const struct sockaddr_in *daddr,
211 const fko_cli_options_t *options)
215 "send_spa_packet_tcp_raw: raw packets are not yet supported.\n");
219 char pkt_data[2048] = {0}; /* Should be enough for our purposes */
221 struct iphdr *iph = (struct iphdr *) pkt_data;
222 struct tcphdr *tcph = (struct tcphdr *) (pkt_data + sizeof (struct iphdr));
224 int hdrlen = sizeof(struct iphdr) + sizeof(struct tcphdr);
226 /* Values for setsockopt.
229 const int *so_val = &one;
234 "test mode enabled, SPA packet not actually sent.\n");
238 sock = socket (PF_INET, SOCK_RAW, IPPROTO_RAW);
241 perror("send_spa_packet_tcp_raw: create socket: ");
245 /* Put the spa data in place.
247 memcpy((pkt_data + hdrlen), spa_data, sd_len);
249 /* Construct our own header by filling in the ip/tcp header values,
250 * starting with the IP header values.
255 /* Total size is header plus payload */
256 iph->tot_len = hdrlen + sd_len;
257 /* The value here does not matter */
258 iph->id = random() & 0xffff;
261 iph->protocol = IPPROTO_TCP;
263 iph->saddr = saddr->sin_addr.s_addr;
264 iph->daddr = daddr->sin_addr.s_addr;
266 /* Now the TCP header values.
268 tcph->source = saddr->sin_port;
269 tcph->dest = daddr->sin_port;
270 tcph->seq = htonl(1);
283 tcph->window = htons(32767);
287 /* No we can compute our checksum.
289 iph->check = chksum((unsigned short *)pkt_data, iph->tot_len);
291 /* Make sure the kernel knows the header is included in the data so it
292 * doesn't try to insert its own header into the packet.
294 if (setsockopt (sock, IPPROTO_IP, IP_HDRINCL, so_val, sizeof(one)) < 0)
295 perror("send_spa_packet_tcp_raw: setsockopt HDRINCL: ");
297 res = sendto (sock, pkt_data, iph->tot_len, 0,
298 (struct sockaddr *)daddr, sizeof(*daddr));
302 perror("send_spa_packet_tcp_raw: sendto error: ");
304 else if(res != sd_len + hdrlen) /* account for the header ?*/
307 "[#] Warning: bytes sent (%i) not spa data length (%i).\n",
319 /* Send the SPA data via ICMP packet.
322 send_spa_packet_icmp(const char *spa_data, const int sd_len,
323 const struct sockaddr_in *saddr, const struct sockaddr_in *daddr,
324 const fko_cli_options_t *options)
327 fprintf(stderr, "send_spa_packet_icmp: raw packets are not yet supported.\n");
331 char pkt_data[2048] = {0};
333 struct iphdr *iph = (struct iphdr *) pkt_data;
334 struct icmphdr *icmph = (struct icmphdr *) (pkt_data + sizeof (struct iphdr));
336 int hdrlen = sizeof(struct iphdr) + sizeof(struct icmphdr);
338 /* Values for setsockopt.
341 const int *so_val = &one;
346 "test mode enabled, SPA packet not actually sent.\n");
350 sock = socket (PF_INET, SOCK_RAW, IPPROTO_RAW);
354 perror("send_spa_packet_icmp: create socket: ");
358 /* Put the spa data in place.
360 memcpy((pkt_data + hdrlen), spa_data, sd_len);
362 /* Construct our own header by filling in the ip/icmp header values,
363 * starting with the IP header values.
368 /* Total size is header plus payload */
369 iph->tot_len = hdrlen + sd_len;
370 /* The value here does not matter */
371 iph->id = random() & 0xffff;
374 iph->protocol = IPPROTO_ICMP;
376 iph->saddr = saddr->sin_addr.s_addr;
377 iph->daddr = daddr->sin_addr.s_addr;
379 /* Now the ICMP header values.
381 icmph->type = ICMP_ECHOREPLY; /* Make it an echo reply */
385 /* No we can compute our checksum.
387 iph->check = chksum((unsigned short *)pkt_data, iph->tot_len);
388 icmph->checksum = chksum((unsigned short *)icmph, sizeof(struct icmphdr) + sd_len);
390 /* Make sure the kernel knows the header is included in the data so it
391 * doesn't try to insert its own header into the packet.
393 if (setsockopt (sock, IPPROTO_IP, IP_HDRINCL, so_val, sizeof(one)) < 0)
394 perror("send_spa_packet_icmp: setsockopt HDRINCL: ");
396 res = sendto (sock, pkt_data, iph->tot_len, 0,
397 (struct sockaddr *)daddr, sizeof(*daddr));
401 perror("send_spa_packet_icmp: sendto error: ");
403 else if(res != sd_len + hdrlen) /* account for icmp header */
405 fprintf(stderr, "[#] Warning: bytes sent (%i) not spa data length (%i).\n",
416 /* Send the SPA data packet via an HTTP request
419 send_spa_packet_http(const char *spa_data, const int sd_len,
420 fko_cli_options_t *options)
422 char http_buf[HTTP_MAX_REQUEST_LEN], *spa_data_copy = NULL;
423 char *ndx = options->http_proxy;
424 int i, proxy_port = 0;
426 spa_data_copy = malloc(sd_len+1);
427 if (spa_data_copy == NULL)
431 memcpy(spa_data_copy, spa_data, sd_len+1);
433 /* Change "+" to "-", and "/" to "_" for HTTP requests (the server
434 * side will translate these back before decrypting)
436 for (i=0; i < sd_len; i++) {
437 if (spa_data_copy[i] == '+') {
438 spa_data_copy[i] = '-';
440 else if (spa_data_copy[i] == '/') {
441 spa_data_copy[i] = '_';
445 if(options->http_proxy[0] == 0x0)
447 snprintf(http_buf, HTTP_MAX_REQUEST_LEN,
448 "GET /%s HTTP/1.0\r\nUser-Agent: %s\r\nAccept: */*\r\n"
449 "Host: %s\r\nConnection: close\r\n\r\n",
451 options->http_user_agent,
452 options->spa_server_str /* hostname or IP */
455 else /* we are sending the SPA packet through an HTTP proxy */
457 /* Extract the hostname if it was specified as a URL. Actually,
458 * we just move the start of the hostname to the begining of the
461 if(strncasecmp(ndx, "http://", 7) == 0)
462 memmove(ndx, ndx+7, strlen(ndx)+1);
464 /* If there is a colon assume the proxy hostame or IP is on the left
465 * and the proxy port is on the right. So we make the : a \0 and
466 * extract the port value.
468 ndx = strchr(options->http_proxy, ':');
472 proxy_port = atoi(ndx+1);
475 /* If we have a valid port value, use it.
478 options->spa_dst_port = proxy_port;
480 snprintf(http_buf, HTTP_MAX_REQUEST_LEN,
481 "GET http://%s/%s HTTP/1.0\r\nUser-Agent: %s\r\nAccept: */*\r\n"
482 "Host: %s\r\nConnection: close\r\n\r\n",
483 options->spa_server_str,
485 options->http_user_agent,
486 options->http_proxy /* hostname or IP */
488 strlcpy(options->spa_server_str, options->http_proxy, MAX_SERVER_STR_LEN);
494 if (options->verbose)
495 fprintf(stderr, "%s\n", http_buf);
498 "Test mode enabled, SPA packet not actually sent.\n");
502 return send_spa_packet_tcp_or_udp(http_buf, strlen(http_buf), options);
505 /* Function used to send the SPA data.
508 send_spa_packet(fko_ctx_t ctx, fko_cli_options_t *options)
513 struct sockaddr_in saddr, daddr;
519 /* Get our spa data here.
521 res = fko_get_spa_data(ctx, &spa_data);
523 if(res != FKO_SUCCESS)
526 "send_spa_packet: Error #%i from fko_get_spa_data: %s\n",
532 sd_len = strlen(spa_data);
535 /* Winsock needs to be initialized...
537 res = WSAStartup( MAKEWORD(1,1), &wsa_data );
540 fprintf(stderr, "Winsock initialization error %d\n", res );
547 if (options->verbose)
548 dump_transmit_options(options);
550 if (options->spa_proto == FKO_PROTO_TCP || options->spa_proto == FKO_PROTO_UDP)
552 res = send_spa_packet_tcp_or_udp(spa_data, sd_len, options);
554 else if (options->spa_proto == FKO_PROTO_HTTP)
556 res = send_spa_packet_http(spa_data, sd_len, options);
558 else if (options->spa_proto == FKO_PROTO_TCP_RAW
559 || options->spa_proto == FKO_PROTO_ICMP)
561 memset(&saddr, 0, sizeof(saddr));
562 memset(&daddr, 0, sizeof(daddr));
564 saddr.sin_family = AF_INET;
565 daddr.sin_family = AF_INET;
567 /* Set source address and port
569 if (options->spa_src_port)
570 saddr.sin_port = htons(options->spa_src_port);
572 saddr.sin_port = INADDR_ANY; /* default */
574 if (options->spoof_ip_src_str[0] != 0x00) {
575 saddr.sin_addr.s_addr = inet_addr(options->spoof_ip_src_str);
577 saddr.sin_addr.s_addr = INADDR_ANY; /* default */
579 if (saddr.sin_addr.s_addr == -1)
581 fprintf(stderr, "Could not set source IP.\n");
585 /* Set destination address and port
587 daddr.sin_port = htons(options->spa_dst_port);
588 daddr.sin_addr.s_addr = inet_addr(options->spa_server_str);
590 if (daddr.sin_addr.s_addr == -1)
592 fprintf(stderr, "Could not set destination IP.\n");
596 if (options->spa_proto == FKO_PROTO_TCP_RAW)
598 res = send_spa_packet_tcp_raw(spa_data, sd_len, &saddr, &daddr, options);
602 res = send_spa_packet_icmp(spa_data, sd_len, &saddr, &daddr, options);
607 /* --DSS XXX: What to we really want to do here? */
608 fprintf(stderr, "%i is not a valid or supported protocol.\n",
616 /* Function to write SPA packet data to the filesystem
618 int write_spa_packet_data(fko_ctx_t ctx, const fko_cli_options_t *options)
624 res = fko_get_spa_data(ctx, &spa_data);
626 if(res != FKO_SUCCESS)
629 "write_spa_packet_data: Error #%i from fko_get_spa_data: %s\n",
636 if (options->save_packet_file_append)
638 fp = fopen(options->save_packet_file, "a");
642 unlink(options->save_packet_file);
643 fp = fopen(options->save_packet_file, "w");
648 perror("write_spa_packet_data: ");
653 (spa_data == NULL) ? "<NULL>" : spa_data);