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