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