Branch data Line data Source code
1 : : /**
2 : : * \file client/spa_comm.c
3 : : *
4 : : * \brief Network-related functions for the fwknop client
5 : : */
6 : :
7 : : /* Fwknop is developed primarily by the people listed in the file 'AUTHORS'.
8 : : * Copyright (C) 2009-2015 fwknop developers and contributors. For a full
9 : : * list of contributors, see the file 'CREDITS'.
10 : : *
11 : : * License (GNU General Public License):
12 : : *
13 : : * This program is free software; you can redistribute it and/or
14 : : * modify it under the terms of the GNU General Public License
15 : : * as published by the Free Software Foundation; either version 2
16 : : * of the License, or (at your option) any later version.
17 : : *
18 : : * This program is distributed in the hope that it will be useful,
19 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 : : * GNU General Public License for more details.
22 : : *
23 : : * You should have received a copy of the GNU General Public License
24 : : * along with this program; if not, write to the Free Software
25 : : * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
26 : : * USA
27 : : *
28 : : *****************************************************************************
29 : : */
30 : : #include "spa_comm.h"
31 : : #include "utils.h"
32 : :
33 : : static void
34 : 2155 : dump_transmit_options(const fko_cli_options_t *options)
35 : : {
36 : 2155 : char proto_str[PROTOCOL_BUFSIZE] = {0}; /* Protocol string */
37 : :
38 : 2155 : proto_inttostr(options->spa_proto, proto_str, sizeof(proto_str));
39 : :
40 : 2155 : log_msg(LOG_VERBOSITY_INFO, "Generating SPA packet:");
41 : 2155 : log_msg(LOG_VERBOSITY_INFO, " protocol: %s", proto_str);
42 : :
43 [ + + ]: 2155 : if (options->spa_src_port)
44 : 15 : log_msg(LOG_VERBOSITY_INFO, " source port: %d", options->spa_src_port);
45 : : else
46 : 2140 : log_msg(LOG_VERBOSITY_INFO, " source port: <OS assigned>");
47 : :
48 : 2155 : log_msg(LOG_VERBOSITY_INFO, " destination port: %d", options->spa_dst_port);
49 : 2155 : log_msg(LOG_VERBOSITY_INFO, " IP/host: %s", options->spa_server_str);
50 : :
51 : 2155 : return;
52 : : }
53 : :
54 : : /* Function to generate a header checksum.
55 : : */
56 : : static unsigned short
57 : 9 : chksum(unsigned short *buf, int nbytes)
58 : : {
59 : : unsigned int sum;
60 : : unsigned short oddbyte;
61 : :
62 : 9 : sum = 0;
63 [ + + ]: 885 : while (nbytes > 1)
64 : : {
65 : 876 : sum += *buf++;
66 : 876 : nbytes -= 2;
67 : : }
68 : :
69 [ + + ]: 9 : if (nbytes == 1)
70 : : {
71 : 7 : oddbyte = 0;
72 : 7 : *((unsigned short *) &oddbyte) = *(unsigned short *) buf;
73 : 7 : sum += oddbyte;
74 : : }
75 : :
76 : 9 : sum = (sum >> 16) + (sum & 0xffff);
77 : 9 : sum += (sum >> 16);
78 : :
79 : 9 : return (unsigned short) ~sum;
80 : : }
81 : :
82 : : /* Send the SPA data via UDP packet.
83 : : */
84 : : static int
85 : 2138 : send_spa_packet_tcp_or_udp(const char *spa_data, const int sd_len,
86 : : const fko_cli_options_t *options)
87 : : {
88 : 2138 : int sock=-1, sock_success=0, res=0, error;
89 : 2138 : struct addrinfo *result=NULL, *rp, hints;
90 : 2138 : char port_str[MAX_PORT_STR_LEN+1] = {0};
91 : :
92 [ + + ]: 2138 : if (options->test)
93 : : {
94 : 100 : log_msg(LOG_VERBOSITY_NORMAL,
95 : : "test mode enabled, SPA packet not actually sent.");
96 : 100 : return res;
97 : : }
98 : :
99 : : memset(&hints, 0, sizeof(struct addrinfo));
100 : :
101 : 2038 : hints.ai_family = AF_INET; /* Allow IPv4 only */
102 : :
103 [ + + ]: 2038 : if (options->spa_proto == FKO_PROTO_UDP)
104 : : {
105 : : /* Send the SPA data packet via an single UDP packet - this is the
106 : : * most common usage.
107 : : */
108 : 2027 : hints.ai_socktype = SOCK_DGRAM;
109 : 2027 : hints.ai_protocol = IPPROTO_UDP;
110 : : }
111 : : else
112 : : {
113 : : /* Send the SPA data packet via an established TCP connection.
114 : : */
115 : 11 : hints.ai_socktype = SOCK_STREAM;
116 : 11 : hints.ai_protocol = IPPROTO_TCP;
117 : : }
118 : :
119 : 2038 : snprintf(port_str, MAX_PORT_STR_LEN+1, "%d", options->spa_dst_port);
120 : :
121 : : #if AFL_FUZZING
122 : : /* Make sure to never send SPA packets under AFL fuzzing cycles
123 : : */
124 : : log_msg(LOG_VERBOSITY_NORMAL,
125 : : "AFL fuzzing enabled, SPA packet not actually sent.");
126 : : return res;
127 : : #endif
128 : :
129 : 2038 : error = getaddrinfo(options->spa_server_str, port_str, &hints, &result);
130 : :
131 [ + + ]: 2038 : if (error != 0)
132 : : {
133 : 8 : log_msg(LOG_VERBOSITY_ERROR, "error in getaddrinfo: %s", gai_strerror(error));
134 : 8 : return -1;
135 : : }
136 : :
137 [ + + ]: 2039 : for (rp = result; rp != NULL; rp = rp->ai_next) {
138 : : /* Apply --server-resolve-ipv4 criteria
139 : : */
140 [ - + ]: 2030 : if(options->spa_server_resolve_ipv4)
141 : : {
142 [ # # ]: 0 : if(rp->ai_family != AF_INET)
143 : : {
144 : 0 : log_msg(LOG_VERBOSITY_DEBUG, "Non-IPv4 resolution");
145 : 0 : continue;
146 : : }
147 : : }
148 : :
149 : 2030 : sock = socket(rp->ai_family, rp->ai_socktype,
150 : : rp->ai_protocol);
151 [ - + ]: 2030 : if (sock < 0)
152 : 0 : continue;
153 : :
154 [ + + ]: 2030 : if ((error = (connect(sock, rp->ai_addr, rp->ai_addrlen) != -1)))
155 : : {
156 : : sock_success = 1;
157 : : break; /* made it */
158 : : }
159 : : else /* close the open socket if there was a connect error */
160 : : {
161 : : #ifdef WIN32
162 : : closesocket(sock);
163 : : #else
164 : 9 : close(sock);
165 : : #endif
166 : : }
167 : : }
168 [ + - ]: 2030 : if(result != NULL)
169 : 2030 : freeaddrinfo(result);
170 : :
171 [ + + ]: 2030 : if (! sock_success) {
172 : 9 : log_msg(LOG_VERBOSITY_ERROR,
173 : : "send_spa_packet_tcp_or_udp: Could not create socket: ",
174 : 9 : strerror(errno));
175 : 9 : return -1;
176 : : }
177 : :
178 : 2021 : res = send(sock, spa_data, sd_len, 0);
179 : :
180 [ - + ]: 2021 : if(res < 0)
181 : : {
182 : 0 : log_msg(LOG_VERBOSITY_ERROR, "send_spa_packet_tcp_or_udp: write error: ", strerror(errno));
183 : : }
184 [ - + ]: 2021 : else if(res != sd_len)
185 : : {
186 : 0 : log_msg(LOG_VERBOSITY_WARNING,
187 : : "[#] Warning: bytes sent (%i) not spa data length (%i).",
188 : : res, sd_len
189 : : );
190 : : }
191 : :
192 : : #ifdef WIN32
193 : : closesocket(sock);
194 : : #else
195 : 2021 : close(sock);
196 : : #endif
197 : :
198 : 2021 : return(res);
199 : : }
200 : :
201 : : /* Send the SPA data via raw TCP packet.
202 : : */
203 : : static int
204 : 3 : send_spa_packet_tcp_raw(const char *spa_data, const int sd_len,
205 : : const struct sockaddr_in *saddr, const struct sockaddr_in *daddr,
206 : : const fko_cli_options_t *options)
207 : : {
208 : : #ifdef WIN32
209 : : log_msg(LOG_VERBOSITY_ERROR,
210 : : "send_spa_packet_tcp_raw: raw packets are not yet supported.");
211 : : return(-1);
212 : : #else
213 : 3 : int sock, res = 0;
214 : 3 : char pkt_data[2048] = {0}; /* Should be enough for our purposes */
215 : :
216 : 3 : struct iphdr *iph = (struct iphdr *) pkt_data;
217 : 3 : struct tcphdr *tcph = (struct tcphdr *) (pkt_data + sizeof (struct iphdr));
218 : :
219 : 3 : int hdrlen = sizeof(struct iphdr) + sizeof(struct tcphdr);
220 : :
221 : : /* Values for setsockopt.
222 : : */
223 : 3 : int one = 1;
224 : 3 : const int *so_val = &one;
225 : :
226 [ + + ]: 3 : if (options->test)
227 : : {
228 : 2 : log_msg(LOG_VERBOSITY_NORMAL,
229 : : "test mode enabled, SPA packet not actually sent.");
230 : : return res;
231 : : }
232 : :
233 : 1 : sock = socket (PF_INET, SOCK_RAW, IPPROTO_RAW);
234 [ - + ]: 1 : if (sock < 0)
235 : : {
236 : 0 : log_msg(LOG_VERBOSITY_ERROR, "send_spa_packet_tcp_raw: create socket: ", strerror(errno));
237 : : return(sock);
238 : : }
239 : :
240 : : /* Put the spa data in place.
241 : : */
242 : 1 : memcpy((pkt_data + hdrlen), spa_data, sd_len);
243 : :
244 : : /* Construct our own header by filling in the ip/tcp header values,
245 : : * starting with the IP header values.
246 : : */
247 : 1 : iph->ihl = 5;
248 : 1 : iph->version = 4;
249 : 1 : iph->tos = 0;
250 : : /* Total size is header plus payload */
251 : 1 : iph->tot_len = hdrlen + sd_len;
252 : : /* The value here does not matter */
253 : 1 : iph->id = random() & 0xffff;
254 : 1 : iph->frag_off = 0;
255 : 1 : iph->ttl = RAW_SPA_TTL;
256 : 1 : iph->protocol = IPPROTO_TCP;
257 : 1 : iph->check = 0;
258 : 1 : iph->saddr = saddr->sin_addr.s_addr;
259 : 1 : iph->daddr = daddr->sin_addr.s_addr;
260 : :
261 : : /* Now the TCP header values.
262 : : */
263 : 1 : tcph->source = saddr->sin_port;
264 : 1 : tcph->dest = daddr->sin_port;
265 : 1 : tcph->seq = htonl(1);
266 : 1 : tcph->ack_seq = 0;
267 : 1 : tcph->doff = 5;
268 : 1 : tcph->res1 = 0;
269 : : /* TCP flags */
270 : 1 : tcph->fin = 0;
271 : 1 : tcph->syn = 1;
272 : 1 : tcph->rst = 0;
273 : 1 : tcph->psh = 0;
274 : 1 : tcph->ack = 0;
275 : 1 : tcph->urg = 0;
276 : :
277 : 1 : tcph->res2 = 0;
278 : 1 : tcph->window = htons(32767);
279 : 1 : tcph->check = 0;
280 : 1 : tcph->urg_ptr = 0;
281 : :
282 : : /* Now we can compute our checksum.
283 : : */
284 : 1 : iph->check = chksum((unsigned short *)pkt_data, iph->tot_len);
285 : :
286 : : /* Make sure the kernel knows the header is included in the data so it
287 : : * doesn't try to insert its own header into the packet.
288 : : */
289 [ - + ]: 1 : if (setsockopt (sock, IPPROTO_IP, IP_HDRINCL, so_val, sizeof(one)) < 0)
290 : 0 : log_msg(LOG_VERBOSITY_ERROR, "send_spa_packet_tcp_raw: setsockopt HDRINCL: ", strerror(errno));
291 : :
292 : 1 : res = sendto (sock, pkt_data, iph->tot_len, 0,
293 : : (struct sockaddr *)daddr, sizeof(*daddr));
294 : :
295 [ - + ]: 1 : if(res < 0)
296 : : {
297 : 0 : log_msg(LOG_VERBOSITY_ERROR, "send_spa_packet_tcp_raw: sendto error: ", strerror(errno));
298 : : }
299 [ - + ]: 1 : else if(res != sd_len + hdrlen) /* account for the header ?*/
300 : : {
301 : 0 : log_msg(LOG_VERBOSITY_WARNING,
302 : : "[#] Warning: bytes sent (%i) not spa data length (%i).",
303 : : res, sd_len
304 : : );
305 : : }
306 : :
307 : 1 : close(sock);
308 : :
309 : : return(res);
310 : :
311 : : #endif /* !WIN32 */
312 : : }
313 : :
314 : : /* Send the SPA data via raw UDP packet.
315 : : */
316 : : static int
317 : 5 : send_spa_packet_udp_raw(const char *spa_data, const int sd_len,
318 : : const struct sockaddr_in *saddr, const struct sockaddr_in *daddr,
319 : : const fko_cli_options_t *options)
320 : : {
321 : : #ifdef WIN32
322 : : log_msg(LOG_VERBOSITY_ERROR,
323 : : "send_spa_packet_udp_raw: raw packets are not yet supported.");
324 : : return(-1);
325 : : #else
326 : 5 : int sock, res = 0;
327 : 5 : char pkt_data[2048] = {0}; /* Should be enough for our purposes */
328 : :
329 : 5 : struct iphdr *iph = (struct iphdr *) pkt_data;
330 : 5 : struct udphdr *udph = (struct udphdr *) (pkt_data + sizeof (struct iphdr));
331 : :
332 : 5 : int hdrlen = sizeof(struct iphdr) + sizeof(struct udphdr);
333 : :
334 : : /* Values for setsockopt.
335 : : */
336 : 5 : int one = 1;
337 : 5 : const int *so_val = &one;
338 : :
339 [ + + ]: 5 : if (options->test)
340 : : {
341 : 1 : log_msg(LOG_VERBOSITY_NORMAL,
342 : : "test mode enabled, SPA packet not actually sent.");
343 : : return res;
344 : : }
345 : :
346 : 4 : sock = socket (PF_INET, SOCK_RAW, IPPROTO_RAW);
347 [ - + ]: 4 : if (sock < 0)
348 : : {
349 : 0 : log_msg(LOG_VERBOSITY_ERROR, "send_spa_packet_udp_raw: create socket: ", strerror(errno));
350 : : return(sock);
351 : : }
352 : :
353 : : /* Put the spa data in place.
354 : : */
355 : 4 : memcpy((pkt_data + hdrlen), spa_data, sd_len);
356 : :
357 : : /* Construct our own header by filling in the ip/udp header values,
358 : : * starting with the IP header values.
359 : : */
360 : 4 : iph->ihl = 5;
361 : 4 : iph->version = 4;
362 : 4 : iph->tos = 0;
363 : : /* Total size is header plus payload */
364 : 4 : iph->tot_len = hdrlen + sd_len;
365 : : /* The value here does not matter */
366 : 4 : iph->id = random() & 0xffff;
367 : 4 : iph->frag_off = 0;
368 : 4 : iph->ttl = RAW_SPA_TTL;
369 : 4 : iph->protocol = IPPROTO_UDP;
370 : 4 : iph->check = 0;
371 : 4 : iph->saddr = saddr->sin_addr.s_addr;
372 : 4 : iph->daddr = daddr->sin_addr.s_addr;
373 : :
374 : : /* Now the UDP header values.
375 : : */
376 : 4 : udph->source = saddr->sin_port;
377 : 4 : udph->dest = daddr->sin_port;
378 : 4 : udph->check = 0;
379 [ - + ]: 4 : udph->len = htons(sd_len + sizeof(struct udphdr));
380 : :
381 : : /* Now we can compute our checksum.
382 : : */
383 : 4 : iph->check = chksum((unsigned short *)pkt_data, iph->tot_len);
384 : :
385 : : /* Make sure the kernel knows the header is included in the data so it
386 : : * doesn't try to insert its own header into the packet.
387 : : */
388 [ - + ]: 4 : if (setsockopt (sock, IPPROTO_IP, IP_HDRINCL, so_val, sizeof(one)) < 0)
389 : 0 : log_msg(LOG_VERBOSITY_ERROR, "send_spa_packet_udp_raw: setsockopt HDRINCL: ", strerror(errno));
390 : :
391 : 4 : res = sendto (sock, pkt_data, iph->tot_len, 0,
392 : : (struct sockaddr *)daddr, sizeof(*daddr));
393 : :
394 [ - + ]: 4 : if(res < 0)
395 : : {
396 : 0 : log_msg(LOG_VERBOSITY_ERROR, "send_spa_packet_udp_raw: sendto error: ", strerror(errno));
397 : : }
398 [ - + ]: 4 : else if(res != sd_len + hdrlen) /* account for the header ?*/
399 : : {
400 : 0 : log_msg(LOG_VERBOSITY_WARNING,
401 : : "[#] Warning: bytes sent (%i) not spa data length (%i).",
402 : : res, sd_len
403 : : );
404 : : }
405 : :
406 : 4 : close(sock);
407 : :
408 : : return(res);
409 : :
410 : : #endif /* !WIN32 */
411 : : }
412 : :
413 : : /* Send the SPA data via ICMP packet.
414 : : */
415 : : static int
416 : 4 : send_spa_packet_icmp(const char *spa_data, const int sd_len,
417 : : const struct sockaddr_in *saddr, const struct sockaddr_in *daddr,
418 : : const fko_cli_options_t *options)
419 : : {
420 : : #ifdef WIN32
421 : : log_msg(LOG_VERBOSITY_ERROR, "send_spa_packet_icmp: raw packets are not yet supported.");
422 : : return(-1);
423 : : #else
424 : 4 : int res = 0, sock;
425 : 4 : char pkt_data[2048] = {0};
426 : :
427 : 4 : struct iphdr *iph = (struct iphdr *) pkt_data;
428 : 4 : struct icmphdr *icmph = (struct icmphdr *) (pkt_data + sizeof (struct iphdr));
429 : :
430 : 4 : int hdrlen = sizeof(struct iphdr) + sizeof(struct icmphdr);
431 : :
432 : : /* Values for setsockopt.
433 : : */
434 : 4 : int one = 1;
435 : 4 : const int *so_val = &one;
436 : :
437 [ + + ]: 4 : if (options->test)
438 : : {
439 : 2 : log_msg(LOG_VERBOSITY_NORMAL,
440 : : "test mode enabled, SPA packet not actually sent.");
441 : : return res;
442 : : }
443 : :
444 : 2 : sock = socket (PF_INET, SOCK_RAW, IPPROTO_RAW);
445 : :
446 [ - + ]: 2 : if (sock < 0)
447 : : {
448 : 0 : log_msg(LOG_VERBOSITY_ERROR, "send_spa_packet_icmp: create socket: ", strerror(errno));
449 : : return(sock);
450 : : }
451 : :
452 : : /* Put the spa data in place.
453 : : */
454 : 2 : memcpy((pkt_data + hdrlen), spa_data, sd_len);
455 : :
456 : : /* Construct our own header by filling in the ip/icmp header values,
457 : : * starting with the IP header values.
458 : : */
459 : 2 : iph->ihl = 5;
460 : 2 : iph->version = 4;
461 : 2 : iph->tos = 0;
462 : : /* Total size is header plus payload */
463 : 2 : iph->tot_len = hdrlen + sd_len;
464 : : /* The value here does not matter */
465 : 2 : iph->id = random() & 0xffff;
466 : 2 : iph->frag_off = 0;
467 : 2 : iph->ttl = RAW_SPA_TTL;
468 : 2 : iph->protocol = IPPROTO_ICMP;
469 : 2 : iph->check = 0;
470 : 2 : iph->saddr = saddr->sin_addr.s_addr;
471 : 2 : iph->daddr = daddr->sin_addr.s_addr;
472 : :
473 : : /* Now the ICMP header values.
474 : : */
475 : 2 : icmph->type = options->spa_icmp_type;
476 : 2 : icmph->code = options->spa_icmp_code;
477 : 2 : icmph->checksum = 0;
478 : :
479 [ + + ]: 2 : if(icmph->type == ICMP_ECHO && icmph->code == 0)
480 : : {
481 [ - + ]: 1 : icmph->un.echo.id = htons(random() & 0xffff);
482 : 1 : icmph->un.echo.sequence = htons(1);
483 : : }
484 : :
485 : : /* Now we can compute our checksum.
486 : : */
487 : 2 : iph->check = chksum((unsigned short *)pkt_data, iph->tot_len);
488 : 2 : icmph->checksum = chksum((unsigned short *)icmph, sizeof(struct icmphdr) + sd_len);
489 : :
490 : : /* Make sure the kernel knows the header is included in the data so it
491 : : * doesn't try to insert its own header into the packet.
492 : : */
493 [ - + ]: 2 : if (setsockopt (sock, IPPROTO_IP, IP_HDRINCL, so_val, sizeof(one)) < 0)
494 : 0 : log_msg(LOG_VERBOSITY_ERROR, "send_spa_packet_icmp: setsockopt HDRINCL: ", strerror(errno));
495 : :
496 : 2 : res = sendto (sock, pkt_data, iph->tot_len, 0,
497 : : (struct sockaddr *)daddr, sizeof(*daddr));
498 : :
499 [ - + ]: 2 : if(res < 0)
500 : : {
501 : 0 : log_msg(LOG_VERBOSITY_ERROR, "send_spa_packet_icmp: sendto error: ", strerror(errno));
502 : : }
503 [ - + ]: 2 : else if(res != sd_len + hdrlen) /* account for icmp header */
504 : : {
505 : 0 : log_msg(LOG_VERBOSITY_WARNING, "[#] Warning: bytes sent (%i) not spa data length (%i).",
506 : : res, sd_len);
507 : : }
508 : :
509 : 2 : close(sock);
510 : :
511 : : return(res);
512 : :
513 : : #endif /* !WIN32 */
514 : : }
515 : :
516 : : /* Send the SPA data packet via an HTTP request
517 : : */
518 : : static int
519 : 5 : send_spa_packet_http(const char *spa_data, const int sd_len,
520 : : fko_cli_options_t *options)
521 : : {
522 : 5 : char http_buf[HTTP_MAX_REQUEST_LEN] = {0}, *spa_data_copy = NULL;
523 : 5 : char *ndx = options->http_proxy;
524 : 5 : int i, proxy_port = 0, is_err;
525 : :
526 : 5 : spa_data_copy = malloc(sd_len+1);
527 [ - + ]: 5 : if (spa_data_copy == NULL)
528 : : {
529 : 0 : log_msg(LOG_VERBOSITY_ERROR, "[*] Fatal, could not allocate memory.");
530 : 0 : return -1;
531 : : }
532 : 5 : memcpy(spa_data_copy, spa_data, sd_len+1);
533 : :
534 : : /* Change "+" to "-", and "/" to "_" for HTTP requests (the server
535 : : * side will translate these back before decrypting)
536 : : */
537 [ + + ]: 853 : for (i=0; i < sd_len; i++) {
538 [ + + ]: 848 : if (spa_data_copy[i] == '+') {
539 : 17 : spa_data_copy[i] = '-';
540 : : }
541 [ + + ]: 831 : else if (spa_data_copy[i] == '/') {
542 : 11 : spa_data_copy[i] = '_';
543 : : }
544 : : }
545 : :
546 [ + + ]: 5 : if(options->http_proxy[0] == 0x0)
547 : : {
548 : : snprintf(http_buf, HTTP_MAX_REQUEST_LEN,
549 : : "GET /%s HTTP/1.0\r\nUser-Agent: %s\r\nAccept: */*\r\n"
550 : : "Host: %s\r\nConnection: close\r\n\r\n",
551 : : spa_data_copy,
552 : 2 : options->http_user_agent,
553 : 2 : options->spa_server_str /* hostname or IP */
554 : : );
555 : : }
556 : : else /* we are sending the SPA packet through an HTTP proxy */
557 : : {
558 : : /* Extract the hostname if it was specified as a URL. Actually,
559 : : * we just move the start of the hostname to the beginning of the
560 : : * original string.
561 : : */
562 [ + - ]: 3 : if(strncasecmp(ndx, "http://", 7) == 0)
563 : 3 : memmove(ndx, ndx+7, strlen(ndx)+1);
564 : :
565 : : /* If there is a colon assume the proxy hostame or IP is on the left
566 : : * and the proxy port is on the right. So we make the : a \0 and
567 : : * extract the port value.
568 : : */
569 : 3 : ndx = strchr(options->http_proxy, ':');
570 [ + - ]: 3 : if(ndx)
571 : : {
572 : 3 : *ndx = '\0';
573 : 3 : proxy_port = strtol_wrapper(ndx+1, 1, MAX_PORT, NO_EXIT_UPON_ERR, &is_err);
574 [ + + ]: 3 : if(is_err != FKO_SUCCESS)
575 : : {
576 : 1 : log_msg(LOG_VERBOSITY_ERROR,
577 : : "[-] proxy port value is invalid, must be in [%d-%d]",
578 : : 1, MAX_PORT);
579 : 1 : free(spa_data_copy);
580 : 1 : return -1;
581 : : }
582 : : }
583 : :
584 : : /* If we have a valid port value, use it.
585 : : */
586 [ + - ]: 2 : if(proxy_port)
587 : 2 : options->spa_dst_port = proxy_port;
588 : :
589 : : snprintf(http_buf, HTTP_MAX_REQUEST_LEN,
590 : : "GET http://%s/%s HTTP/1.0\r\nUser-Agent: %s\r\nAccept: */*\r\n"
591 : : "Host: %s\r\nConnection: close\r\n\r\n",
592 : 2 : options->spa_server_str,
593 : : spa_data_copy,
594 : 2 : options->http_user_agent,
595 : : options->http_proxy /* hostname or IP */
596 : : );
597 : 2 : strlcpy(options->spa_server_str, options->http_proxy,
598 : : sizeof(options->spa_server_str));
599 : : }
600 : 4 : free(spa_data_copy);
601 : :
602 [ + - ]: 4 : if (options->test)
603 : : {
604 : 4 : log_msg(LOG_VERBOSITY_INFO, "%s", http_buf);
605 : :
606 : 4 : log_msg(LOG_VERBOSITY_NORMAL,
607 : : "Test mode enabled, SPA packet not actually sent.");
608 : 4 : return 0;
609 : : }
610 : :
611 : : /* In AFL fuzzing mode, the following function will not send
612 : : * the SPA packet.
613 : : */
614 : 0 : return send_spa_packet_tcp_or_udp(http_buf, strlen(http_buf), options);
615 : : }
616 : :
617 : : /* Function used to send the SPA data.
618 : : */
619 : : int
620 : 2155 : send_spa_packet(fko_ctx_t ctx, fko_cli_options_t *options)
621 : : {
622 : : int res, sd_len;
623 : : char *spa_data;
624 : : struct sockaddr_in saddr, daddr;
625 : 2155 : char ip_str[INET_ADDRSTRLEN] = {0}; /* String used to contain the ip address of an hostname */
626 : : struct addrinfo hints; /* Structure used to set hints to resolve hostname */
627 : : #ifdef WIN32
628 : : WSADATA wsa_data;
629 : : #endif
630 : :
631 : : /* Initialize the hint buffer */
632 : : memset(&hints, 0 , sizeof(hints));
633 : :
634 : : /* Get our spa data here.
635 : : */
636 : 2155 : res = fko_get_spa_data(ctx, &spa_data);
637 : :
638 [ - + ]: 2155 : if(res != FKO_SUCCESS)
639 : : {
640 : 0 : log_msg(LOG_VERBOSITY_ERROR,
641 : : "send_spa_packet: Error #%i from fko_get_spa_data: %s",
642 : : res, fko_errstr(res)
643 : : );
644 : 0 : return(-1);
645 : : }
646 : :
647 : 2155 : sd_len = strlen(spa_data);
648 : :
649 : : #ifdef WIN32
650 : : /* Winsock needs to be initialized...
651 : : */
652 : : res = WSAStartup( MAKEWORD(1,1), &wsa_data );
653 : : if( res != 0 )
654 : : {
655 : : log_msg(LOG_VERBOSITY_ERROR, "Winsock initialization error %d", res );
656 : : return(-1);
657 : : }
658 : : #endif
659 : :
660 : 2155 : errno = 0;
661 : :
662 : 2155 : dump_transmit_options(options);
663 : :
664 [ + + ]: 2155 : if (options->spa_proto == FKO_PROTO_TCP || options->spa_proto == FKO_PROTO_UDP)
665 : : {
666 : 2138 : res = send_spa_packet_tcp_or_udp(spa_data, sd_len, options);
667 : : }
668 [ + + ]: 17 : else if (options->spa_proto == FKO_PROTO_HTTP)
669 : : {
670 : 5 : res = send_spa_packet_http(spa_data, sd_len, options);
671 : : }
672 [ + + ]: 12 : else if (options->spa_proto == FKO_PROTO_TCP_RAW
673 : 12 : || options->spa_proto == FKO_PROTO_UDP_RAW
674 [ + - ]: 4 : || options->spa_proto == FKO_PROTO_ICMP)
675 : : {
676 : : memset(&saddr, 0, sizeof(saddr));
677 : : memset(&daddr, 0, sizeof(daddr));
678 : :
679 : 12 : saddr.sin_family = AF_INET;
680 : 12 : daddr.sin_family = AF_INET;
681 : :
682 : : /* Set source address and port
683 : : */
684 [ + - ]: 12 : if (options->spa_src_port)
685 [ - + ]: 12 : saddr.sin_port = htons(options->spa_src_port);
686 : : else
687 : : saddr.sin_port = INADDR_ANY;
688 : :
689 [ + + ]: 12 : if (options->spoof_ip_src_str[0] != 0x00) {
690 : 8 : saddr.sin_addr.s_addr = inet_addr(options->spoof_ip_src_str);
691 : : } else
692 : : saddr.sin_addr.s_addr = INADDR_ANY; /* default */
693 : :
694 [ - + ]: 12 : if (saddr.sin_addr.s_addr == -1)
695 : : {
696 : 0 : log_msg(LOG_VERBOSITY_ERROR, "Could not set source IP.");
697 : 0 : return -1;
698 : : }
699 : :
700 : : /* Set destination port
701 : : */
702 [ - + ]: 12 : daddr.sin_port = htons(options->spa_dst_port);
703 : :
704 : : /* Set destination address. We use the default protocol to resolve
705 : : * the ip address */
706 : 12 : hints.ai_family = AF_INET;
707 : :
708 : : #if AFL_FUZZING
709 : : /* Make sure to never send SPA packets under AFL fuzzing cycles
710 : : */
711 : : log_msg(LOG_VERBOSITY_NORMAL,
712 : : "AFL fuzzing enabled, SPA packet not actually sent.");
713 : : return res;
714 : : #endif
715 : :
716 [ - + ]: 12 : if (resolve_dst_addr(options->spa_server_str,
717 : : &hints, ip_str, sizeof(ip_str), options) != 0)
718 : : {
719 : 0 : log_msg(LOG_VERBOSITY_ERROR, "[*] Unable to resolve %s as an ip address",
720 : : options->spa_server_str);
721 : 0 : return -1;
722 : : }
723 : : else;
724 : :
725 : 12 : daddr.sin_addr.s_addr = inet_addr(ip_str);
726 : :
727 [ + + ]: 12 : if (options->spa_proto == FKO_PROTO_TCP_RAW)
728 : : {
729 : 3 : res = send_spa_packet_tcp_raw(spa_data, sd_len, &saddr, &daddr, options);
730 : : }
731 [ + + ]: 9 : else if (options->spa_proto == FKO_PROTO_UDP_RAW)
732 : : {
733 : 5 : res = send_spa_packet_udp_raw(spa_data, sd_len, &saddr, &daddr, options);
734 : : }
735 : : else
736 : : {
737 : 4 : res = send_spa_packet_icmp(spa_data, sd_len, &saddr, &daddr, options);
738 : : }
739 : : }
740 : : else
741 : : {
742 : : /* --DSS XXX: What to we really want to do here? */
743 : 0 : log_msg(LOG_VERBOSITY_ERROR, "%i is not a valid or supported protocol.",
744 : : options->spa_proto);
745 : 0 : res = -1;
746 : : }
747 : :
748 : 2155 : return res;
749 : : }
750 : :
751 : : /* Function to write SPA packet data to the filesystem
752 : : */
753 : 4 : int write_spa_packet_data(fko_ctx_t ctx, const fko_cli_options_t *options)
754 : : {
755 : : FILE *fp;
756 : : char *spa_data;
757 : : int res;
758 : :
759 : 4 : res = fko_get_spa_data(ctx, &spa_data);
760 : :
761 [ - + ]: 4 : if(res != FKO_SUCCESS)
762 : : {
763 : 0 : log_msg(LOG_VERBOSITY_ERROR,
764 : : "write_spa_packet_data: Error #%i from fko_get_spa_data: %s",
765 : : res, fko_errstr(res)
766 : : );
767 : :
768 : 0 : return(-1);
769 : : }
770 : :
771 [ + + ]: 4 : if (options->save_packet_file_append)
772 : : {
773 : 1 : fp = fopen(options->save_packet_file, "a");
774 : : }
775 : : else
776 : : {
777 : 3 : unlink(options->save_packet_file);
778 : 3 : fp = fopen(options->save_packet_file, "w");
779 : : }
780 : :
781 [ - + ]: 4 : if(fp == NULL)
782 : : {
783 : 0 : log_msg(LOG_VERBOSITY_ERROR, "write_spa_packet_data: ", strerror(errno));
784 : 0 : return(-1);
785 : : }
786 : :
787 [ + - ]: 4 : fprintf(fp, "%s\n",
788 : 4 : (spa_data == NULL) ? "<NULL>" : spa_data);
789 : :
790 : 4 : fclose(fp);
791 : :
792 : 4 : return(0);
793 : : }
794 : :
795 : : /***EOF***/
|