1 /*
2  * flow6: A security assessment tool that determines the Flow Label
3  *        generation policy of a target node
4  *
5  * Copyright (C) 2011-2015 Fernando Gont <fgont@si6networks.com>
6  *
7  * Programmed by Fernando Gont for SI6 Networks (www.si6networks.com)
8  *
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warrsi6networks.allanty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  *
22  *
23  * Build with: make flow6
24  *
25  * It requires that the libpcap library be installed on your system.
26  *
27  * Please send any bug reports to Fernando Gont <fgont@si6networks.com>
28  */
29 
30 #include <sys/types.h>
31 #include <sys/param.h>
32 #include <sys/select.h>
33 #include <sys/socket.h>
34 
35 #include <netinet/in.h>
36 #include <arpa/inet.h>
37 #include <netinet/ip6.h>
38 #include <netinet/icmp6.h>
39 #include <netinet/tcp.h>
40 #include <netinet/udp.h>
41 #include <net/if.h>
42 #include <netdb.h>
43 
44 #include <stdlib.h>
45 #include <stdio.h>
46 #include <errno.h>
47 #include <time.h>
48 #include <getopt.h>
49 #include <unistd.h>
50 #include <signal.h>
51 #include <string.h>
52 #include <pcap.h>
53 
54 #include "flow6.h"
55 #include "ipv6toolkit.h"
56 #include "libipv6.h"
57 
58 
59 /* Function prototypes */
60 void				print_attack_info(void);
61 void				usage(void);
62 void				print_help(void);
63 int					send_fid_probe(void);
64 int					predict_flow_id(uint32_t *, unsigned int, uint32_t *, unsigned int);
65 
66 
67 /* Used for router discovery */
68 struct iface_data	idata;
69 struct in6_addr		randprefix;
70 unsigned char		randpreflen;
71 
72 /* Data structures for packets read from the wire */
73 struct pcap_pkthdr	*pkthdr;
74 const u_char		*pktdata;
75 unsigned char		*pkt_end, *pkt_ptr;
76 struct ether_header	*pkt_ether;
77 struct ip6_hdr		*pkt_ipv6;
78 struct tcp_hdr		*pkt_tcp;
79 struct udp_hdr		*pkt_udp;
80 struct icmp6_hdr	*pkt_icmp6;
81 struct nd_neighbor_solicit *pkt_ns;
82 struct in6_addr		*pkt_ipv6addr;
83 unsigned int		pktbytes;
84 
85 
86 bpf_u_int32			my_netmask;
87 bpf_u_int32			my_ip;
88 struct bpf_program	pcap_filter;
89 char 				dev[64];
90 unsigned char		buffer[65556], buffrh[MIN_IPV6_HLEN + MIN_TCP_HLEN];
91 unsigned char		*v6buffer, *ptr, *startofprefixes;
92 char				*pref;
93 char 				iface[IFACE_LENGTH];
94 
95 struct ip6_hdr		*ipv6;
96 struct icmp6_hdr	*icmp6;
97 
98 struct ether_header	*ethernet;
99 struct nd_opt_tlla	*tllaopt;
100 struct ether_addr	linkaddr[MAX_TLLA_OPTION];
101 unsigned int		nlinkaddr=0, linkaddrs;
102 
103 char				*lasts, *rpref;
104 char				*charptr;
105 
106 size_t				nw;
107 unsigned long		ul_res, ul_val;
108 unsigned int		i, j, startrand;
109 unsigned int		skip;
110 unsigned int		frags, nfrags, nsleep;
111 unsigned char		srcpreflen;
112 
113 uint16_t			mask, ip6length;
114 uint8_t			hoplimit;
115 
116 char 				plinkaddr[ETHER_ADDR_PLEN];
117 char 				psrcaddr[INET6_ADDRSTRLEN], pdstaddr[INET6_ADDRSTRLEN], pv6addr[INET6_ADDRSTRLEN];
118 unsigned char 		localaddr_f=0;
119 unsigned char		srcprefix_f=0, hoplimit_f=0, flowidp_f=0, dstport_f=0, protocol_f=0;
120 
121 /* Support for Extension Headers */
122 unsigned int		dstopthdrs, dstoptuhdrs, hbhopthdrs;
123 char				hbhopthdr_f=0, dstoptuhdr_f=0, dstopthdr_f=0;
124 unsigned char		*dstopthdr[MAX_DST_OPT_HDR], *dstoptuhdr[MAX_DST_OPT_U_HDR];
125 unsigned char		*hbhopthdr[MAX_HBH_OPT_HDR];
126 unsigned int		dstopthdrlen[MAX_DST_OPT_HDR], dstoptuhdrlen[MAX_DST_OPT_U_HDR];
127 unsigned int		hbhopthdrlen[MAX_HBH_OPT_HDR], m, pad;
128 
129 struct ip6_frag		*fh;
130 struct ip6_hdr		*fipv6;
131 unsigned char		fragh_f=0;
132 
133 unsigned char		*fragpart, *ptrend, *ptrhdr, *ptrhdrend;
134 unsigned int		hdrlen, ndstopthdr=0, nhbhopthdr=0, ndstoptuhdr=0;
135 unsigned int		nfrags, fragsize;
136 unsigned char		*prev_nh, *startoffragment;
137 
138 
139 /* For the sampling of Flow Label values */
140 uint16_t			baseport, lastport, dstport, tcpwin, addr_sig, addr_key;
141 uint32_t			tcpseq;
142 uint8_t			protocol;
143 
144 
main(int argc,char ** argv)145 int main(int argc, char **argv){
146 	extern char			*optarg;
147 	fd_set				sset, rset;
148 	struct timeval		timeout;
149 	int					r, sel;
150 	time_t				curtime, start, lastfrag1=0;
151 	struct target_ipv6	targetipv6;
152 
153 	/* Arrays for storing the Flow ID samples */
154 	uint32_t			test1[NSAMPLES], test2[NSAMPLES];
155 	unsigned int		ntest1=0, ntest2=0;
156 	unsigned char		testtype;
157 
158 	static struct option longopts[] = {
159 		{"interface", required_argument, 0, 'i'},
160 		{"src-address", required_argument, 0, 's'},
161 		{"dst-address", required_argument, 0, 'd'},
162 		{"hop-limit", required_argument, 0, 'A'},
163 		{"link-src-addr", required_argument, 0, 'S'},
164 		{"link-dst-addr", required_argument, 0, 'D'},
165 		{"protocol", required_argument, 0, 'P'},
166 		{"dst-port", no_argument, 0, 'p'},
167 		{"flow-label-policy", no_argument, 0, 'W'},
168 		{"verbose", no_argument, 0, 'v'},
169 		{"help", no_argument, 0, 'h'},
170 		{0, 0, 0,  0 }
171 	};
172 
173 	char shortopts[]= "i:s:d:A:S:D:P:p:Wvh";
174 
175 	char option;
176 
177 	if(argc<=1){
178 		usage();
179 		exit(EXIT_FAILURE);
180 	}
181 
182 
183 	srandom(time(NULL));
184 	hoplimit=64+random()%180;
185 
186 	if(init_iface_data(&idata) == FAILURE){
187 		puts("Error initializing internal data structure");
188 		exit(EXIT_FAILURE);
189 	}
190 
191 	while((r=getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) {
192 		option= r;
193 
194 		switch(option) {
195 
196 			case 'i':  /* Interface */
197 				strncpy(idata.iface, optarg, IFACE_LENGTH-1);
198 				idata.iface[IFACE_LENGTH-1]=0;
199 				idata.ifindex= if_nametoindex(idata.iface);
200 				idata.iface_f=TRUE;
201 				break;
202 
203 			case 's':	/* IPv6 Source Address */
204 				if((charptr = strtok_r(optarg, "/", &lasts)) == NULL){
205 					puts("Error in Source Address");
206 					exit(EXIT_FAILURE);
207 				}
208 
209 				if ( inet_pton(AF_INET6, charptr, &(idata.srcaddr)) <= 0){
210 					puts("inet_pton(): Source Address not valid");
211 					exit(EXIT_FAILURE);
212 				}
213 
214 				idata.srcaddr_f = 1;
215 
216 				if((charptr = strtok_r(NULL, " ", &lasts)) != NULL){
217 					srcpreflen = atoi(charptr);
218 
219 					if(srcpreflen>128){
220 						puts("Prefix length error in IPv6 Source Address");
221 						exit(EXIT_FAILURE);
222 					}
223 
224 					sanitize_ipv6_prefix(&(idata.srcaddr), srcpreflen);
225 					srcprefix_f=1;
226 				}
227 
228 				break;
229 
230 			case 'd':	/* IPv6 Destination Address */
231 				strncpy( targetipv6.name, optarg, NI_MAXHOST);
232 				targetipv6.name[NI_MAXHOST-1]= 0;
233 				targetipv6.flags= AI_CANONNAME;
234 
235 				if( (r=get_ipv6_target(&targetipv6)) != 0){
236 
237 					if(r < 0){
238 						printf("Unknown Destination: %s\n", gai_strerror(targetipv6.res));
239 					}
240 					else{
241 						puts("Unknown Destination: No IPv6 address found for specified destination");
242 					}
243 
244 					exit(1);
245 				}
246 
247 				idata.dstaddr= targetipv6.ip6;
248 				idata.dstaddr_f = 1;
249 				break;
250 
251 			case 'A':	/* Hop Limit */
252 				hoplimit= atoi(optarg);
253 				hoplimit_f=1;
254 				break;
255 
256 			case 'S':	/* Source Ethernet address */
257 				if(ether_pton(optarg, &(idata.hsrcaddr), sizeof(idata.hsrcaddr)) == 0){
258 					puts("Error in Source link-layer address.");
259 					exit(EXIT_FAILURE);
260 				}
261 
262 				idata.hsrcaddr_f = 1;
263 				break;
264 
265 			case 'D':	/* Destination Ethernet Address */
266 				if(ether_pton(optarg, &(idata.hdstaddr), sizeof(idata.hdstaddr)) == 0){
267 					puts("Error in Source link-layer address.");
268 					exit(EXIT_FAILURE);
269 				}
270 
271 				idata.hdstaddr_f = 1;
272 				break;
273 
274 			case 'P':	/* Protocol */
275 				if(strncmp(optarg, "tcp", MAX_STRING_SIZE) == 0 || \
276 					strncmp(optarg, "TCP", MAX_STRING_SIZE) == 0){
277 					protocol= IPPROTO_TCP;
278 				}
279 				else if(strncmp(optarg, "udp", MAX_STRING_SIZE) == 0 || \
280 					strncmp(optarg, "UDP", MAX_STRING_SIZE) == 0){
281 					protocol= IPPROTO_UDP;
282 				}
283 				else{
284 					puts("Unknown protocol type (valid types: 'tcp', 'udp')");
285 					exit(EXIT_FAILURE);
286 				}
287 
288 				protocol_f= 1;
289 				break;
290 
291 			case 'p':	/* Destination port */
292 				dstport= atoi(optarg);
293 				dstport_f=1;
294 				break;
295 
296 			case 'W':	/* Assess the Flow Label generation policy of the target */
297 				flowidp_f= 1;
298 				break;
299 
300 			case 'v':	/* Be verbose */
301 				idata.verbose_f++;
302 				break;
303 
304 			case 'h':	/* Help */
305 				print_help();
306 
307 				exit(EXIT_FAILURE);
308 				break;
309 
310 			default:
311 				usage();
312 				exit(EXIT_FAILURE);
313 				break;
314 
315 		} /* switch */
316 	} /* while(getopt) */
317 
318 	if(geteuid()) {
319 		puts("flow6 needs root privileges to run.");
320 		exit(EXIT_FAILURE);
321 	}
322 
323 	if(!idata.iface_f){
324 		if(idata.dstaddr_f && IN6_IS_ADDR_LINKLOCAL(&(idata.dstaddr))){
325 			puts("Must specify a network interface for link-local destinations");
326 			exit(EXIT_FAILURE);
327 		}
328 	}
329 
330 	if(load_dst_and_pcap(&idata, LOAD_SRC_NXT_HOP) == FAILURE){
331 		puts("Error while learning Souce Address and Next Hop");
332 		exit(EXIT_FAILURE);
333 	}
334 
335 	release_privileges();
336 
337 	if( !fragh_f && dstoptuhdr_f){
338 		puts("Dst. Options Header (Unfragmentable Part) set, but Fragmentation not specified");
339 		exit(EXIT_FAILURE);
340 	}
341 
342 	if(idata.verbose_f){
343 		print_attack_info();
344 	}
345 
346 	if(!idata.dstaddr_f){
347 		puts("Error: Nothing to send! (Destination Address left unspecified)");
348 		exit(EXIT_FAILURE);
349 	}
350 
351 	/* Assess the Flow ID generation policy */
352 	if(flowidp_f){
353 		if(dstport_f && !protocol_f){
354 			puts("Error: Must specify a protocol if the port number is specified");
355 			exit(EXIT_FAILURE);
356 		}
357 
358 		if(!protocol_f){
359 			protocol= IPPROTO_TCP;
360 			dstport= 80;
361 		}
362 		else if(!dstport_f){
363 			if(protocol == IPPROTO_TCP)
364 				dstport= 80;
365 			else
366 				dstport= 53;
367 		}
368 
369 		puts("Identifying the 'Flow ID' generation policy of the target node....");
370 
371 		if(protocol == IPPROTO_TCP){
372 			tcpwin= ((uint16_t) random() + 1500) & (uint16_t)0x7f00;
373 			tcpseq= random();
374 			baseport= 50000+ random()%10000;
375 			lastport= baseport;
376 		}
377 
378 		/*
379 		   Set filter for receiving Neighbor Solicitations, and TCP segments
380 		 */
381 		if(pcap_compile(idata.pfd, &pcap_filter, PCAP_NSTCP_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1){
382 			printf("pcap_compile(): %s", pcap_geterr(idata.pfd));
383 			exit(EXIT_FAILURE);
384 		}
385 
386 		if(pcap_setfilter(idata.pfd, &pcap_filter) == -1){
387 			printf("pcap_setfilter(): %s", pcap_geterr(idata.pfd));
388 			exit(EXIT_FAILURE);
389 		}
390 
391 		pcap_freecode(&pcap_filter);
392 
393 		FD_ZERO(&sset);
394 		FD_SET(idata.fd, &sset);
395 		start= time(NULL);
396 		lastfrag1=0;
397 		ntest1=0;
398 		ntest2=0;
399 		testtype= FIXED_ORIGIN;
400 
401 		if(srcprefix_f){
402 			randprefix= idata.srcaddr;
403 			randpreflen=srcpreflen;
404 		}
405 		else{
406 			randprefix= idata.srcaddr;
407 			randpreflen=64;
408 			sanitize_ipv6_prefix(&randprefix, randpreflen);
409 		}
410 
411 		while(1){
412 			curtime=time(NULL);
413 
414 			if( testtype==FIXED_ORIGIN && ((curtime - start) >= ID_ASSESS_TIMEOUT || ntest1 >= NSAMPLES)){
415 				testtype= MULTI_ORIGIN;
416 				addr_sig= random();
417 				addr_key= random();
418 				start= curtime;
419 				continue;
420 			}
421 			else if( testtype==MULTI_ORIGIN && ((curtime - start) >= ID_ASSESS_TIMEOUT || ntest2 >= NSAMPLES)){
422 				break;
423 			}
424 
425 			if((curtime - lastfrag1) >= 1){
426 				if(testtype == FIXED_ORIGIN){
427 					for(i=0; i<NSAMPLES; i++){
428 						if(send_fid_probe() == -1){
429 							puts("Error while sending packet");
430 							exit(EXIT_FAILURE);
431 						}
432 
433 						lastport++;
434 					}
435 				}
436 				else{
437 					for(i=0; i<NSAMPLES; i++){
438 						randomize_ipv6_addr(&(idata.srcaddr), &randprefix, randpreflen);
439 
440 						/*
441 						 * Two words of the Source IPv6 Address are specially encoded such that we only respond
442 						 * to Neighbor Solicitations that target those addresses, and accept ICMPv6 Echo Replies
443 						 * only if they are destined to those addresses
444 						 */
445 						idata.srcaddr.s6_addr32[2]= htonl((ntohl(idata.srcaddr.s6_addr32[2]) & 0xffff0000) | addr_sig);
446 						idata.srcaddr.s6_addr32[3]= htonl((ntohl(idata.srcaddr.s6_addr32[3]) & 0xffff0000) | \
447 						                            ((uint16_t)(ntohl(idata.srcaddr.s6_addr32[3])>>16) ^ addr_key));
448 
449 						if(send_neighbor_solicit(&idata, &(idata.dstaddr)) == -1){
450 							puts("Error while sending Neighbor Solicitation");
451 							exit(EXIT_FAILURE);
452 						}
453 
454 						if(send_fid_probe() == -1){
455 							puts("Error while sending packet");
456 							exit(EXIT_FAILURE);
457 						}
458 
459 						lastport++;
460 					}
461 				}
462 
463 				lastfrag1=curtime;
464 				continue;
465 			}
466 
467 			rset= sset;
468 
469 #if !defined(sun) && !defined(__sun)
470 			timeout.tv_usec=0;
471 			timeout.tv_sec= 1;
472 #else
473 			timeout.tv_usec=10000;
474 			timeout.tv_sec= 0;
475 #endif
476 
477 			if((sel=select(idata.fd+1, &rset, NULL, NULL, &timeout)) == -1){
478 				if(errno == EINTR){
479 					continue;
480 				}
481 				else{
482 					puts("Error in select()");
483 					exit(EXIT_FAILURE);
484 				}
485 			}
486 
487 #if defined(sun) || defined(__sun)
488 			if(TRUE){
489 #else
490 			if(sel && FD_ISSET(idata.fd, &rset)){
491 #endif
492 				/* Read a packet (Echo Reply, or Neighbor Solicitation) */
493 				if((r=pcap_next_ex(idata.pfd, &pkthdr, &pktdata)) == -1){
494 					printf("pcap_next_ex(): %s", pcap_geterr(idata.pfd));
495 					exit(EXIT_FAILURE);
496 				}
497 				else if(r == 1 && pktdata != NULL){
498 					pkt_ether = (struct ether_header *) pktdata;
499 					pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_ether + idata.linkhsize);
500 					pkt_icmp6 = (struct icmp6_hdr *) ((char *) pkt_ipv6 + sizeof(struct ip6_hdr));
501 					pkt_end = (unsigned char *) pktdata + pkthdr->caplen;
502 
503 					if( (pkt_end -  pktdata) < (idata.linkhsize + MIN_IPV6_HLEN))
504 						continue;
505 
506 					if(pkt_ipv6->ip6_nxt == IPPROTO_ICMPV6 && pkt_icmp6->icmp6_type == ND_NEIGHBOR_SOLICIT){
507 						pkt_ns= (struct nd_neighbor_solicit *) pkt_icmp6;
508 
509 						if( (pkt_end - (unsigned char *) pkt_ns) < sizeof(struct nd_neighbor_solicit))
510 							continue;
511 						/*
512 							If the addresses that we're using are not actually configured on the local system
513 							(i.e., they are "spoofed", we must check whether it is a Neighbor Solicitation for
514 							one of our addresses, and respond with a Neighbor Advertisement. Otherwise, the kernel
515 							will take care of that.
516 						 */
517 						if(testtype==FIXED_ORIGIN){
518 							if(!localaddr_f && is_eq_in6_addr(&(pkt_ns->nd_ns_target), &(idata.srcaddr))){
519 								if(send_neighbor_advert(&idata, idata.pfd, pktdata) == -1){
520 									puts("Error sending Neighbor Advertisement");
521 									exit(EXIT_FAILURE);
522 								}
523 							}
524 						}
525 						else if(idata.type == DLT_EN10MB && !(idata.flags & IFACE_LOOPBACK)){
526 							if( (ntohl(pkt_ns->nd_ns_target.s6_addr32[2]) & 0x0000ffff) != addr_sig || \
527 								(ntohl(pkt_ns->nd_ns_target.s6_addr32[3]) & 0x0000ffff) != ( (ntohl(pkt_ns->nd_ns_target.s6_addr32[3])>>16) ^ addr_key)){
528 								continue;
529 							}
530 
531 							if(send_neighbor_advert(&idata, idata.pfd, pktdata) == -1){
532 								puts("Error sending Neighbor Advertisement");
533 								exit(EXIT_FAILURE);
534 							}
535 						}
536 					}
537 					else if(pkt_ipv6->ip6_nxt == protocol){
538 
539 						/* Perform TCP-specific validation checks */
540 						if(protocol == IPPROTO_TCP){
541 							if( (pkt_end - (unsigned char *) pkt_ipv6) < \
542 									(sizeof(struct ip6_hdr) + sizeof(struct tcp_hdr)))
543 								continue;
544 
545 							pkt_tcp= (struct tcp_hdr *) ((unsigned char *)pkt_ipv6 + sizeof(struct ip6_hdr));
546 
547 							/*
548 							 * The TCP Destination Port must correspond to one of the ports that we have used as
549 							 * TCP Source Port
550 							 */
551 							if(ntohs(pkt_tcp->th_dport) < baseport || ntohs(pkt_tcp->th_dport) > lastport)
552 								continue;
553 
554 							/* The Source Port must be that to which we're sending our TCP segments */
555 							if(ntohs(pkt_tcp->th_sport) != dstport)
556 								continue;
557 
558 							/* The TCP Acknowledgement Number must ack our SYN */
559 							if(ntohl(pkt_tcp->th_ack) != tcpseq+1)
560 								continue;
561 
562 							/* We sample Flow ID's only on SYN/ACKs */
563 							if( (pkt_tcp->th_flags & ~TH_SYN) == 0 || (pkt_tcp->th_flags & TH_ACK) == 0)
564 								continue;
565 
566 							/* The TCP checksum must be valid */
567 							if(in_chksum(pkt_ipv6, pkt_tcp, pkt_end-((unsigned char *)pkt_tcp), IPPROTO_TCP) != 0)
568 								continue;
569 						}
570 						/* Perform UDP-specific validation checks */
571 						else if(protocol == IPPROTO_UDP){
572 							if( (pkt_end - (unsigned char *) pkt_ipv6) < \
573 									(sizeof(struct ip6_hdr) + sizeof(struct udp_hdr)))
574 								continue;
575 
576 							pkt_udp= (struct udp_hdr *) ((unsigned char *)pkt_ipv6 + sizeof(struct ip6_hdr));
577 
578 							/*
579 							 * The UDP Destination Port must correspond to one of the ports that we have used as
580 							 * the UDP Source Port
581 							 */
582 							if(ntohs(pkt_udp->uh_dport) < baseport || ntohs(pkt_udp->uh_dport) > lastport)
583 								continue;
584 
585 							/* The Source Port must be that to which we're sending our UDP datagrams */
586 							if(ntohs(pkt_udp->uh_sport) != dstport)
587 								continue;
588 
589 							/* The UDP checksum must be valid */
590 							if(in_chksum(pkt_ipv6, pkt_udp, pkt_end-((unsigned char *)pkt_udp), IPPROTO_UDP) != 0)
591 								continue;
592 						}
593 
594 						if(testtype==FIXED_ORIGIN){
595 							if(!is_eq_in6_addr(&(pkt_ipv6->ip6_dst), &(idata.srcaddr))){
596 								continue;
597 							}
598 
599 							if(ntest1 >= NSAMPLES)
600 								continue;
601 
602 							test1[ntest1]= ntohl(pkt_ipv6->ip6_flow) & 0x000fffff;
603 							ntest1++;
604 						}
605 						else{
606 							if( (ntohl(pkt_ipv6->ip6_dst.s6_addr32[2]) & 0x0000ffff) != addr_sig || \
607 								(ntohl(pkt_ipv6->ip6_dst.s6_addr32[3]) & 0x0000ffff) !=  ( (ntohl(pkt_ipv6->ip6_dst.s6_addr32[3])>>16) ^ addr_key)){
608 								continue;
609 							}
610 
611 							if(ntest2 >= NSAMPLES)
612 								continue;
613 
614 							test2[ntest2]= ntohl(pkt_ipv6->ip6_flow) & 0x000fffff;
615 							ntest2++;
616 						}
617 					}
618 				}
619 			}
620 		}
621 
622 		if(idata.verbose_f > 1){
623 			printf("Sampled %u Flow Labels from single-origin probes\n", ntest1);
624 
625 			for(i=0; i<ntest1; i++)
626 				printf("#%02u: %05x\n", (i+1), test1[i]);
627 
628 			printf("\nSampled %u Flow Labels from multi-origin probes\n", ntest2);
629 
630 			for(i=0; i<ntest2; i++)
631 				printf("#%02u: %05x\n", (i+1), test2[i]);
632 
633 			puts("");
634 		}
635 
636 		if(ntest1 < 10 || ntest2 < 10){
637 			puts("Error: Didn't receive enough response packets");
638 			exit(EXIT_FAILURE);
639 		}
640 
641 		if(predict_flow_id(test1, ntest1, test2, ntest2) == -1){
642 			puts("Error in predict_flow_id()");
643 			exit(EXIT_FAILURE);
644 		}
645 
646 		exit(EXIT_SUCCESS);
647 	}
648 
649 	exit(EXIT_SUCCESS);
650 }
651 
652 
653 /*
654  * Function: send_fid_probe()
655  *
656  * Send a TCP segment or UDP datagram used for sampling the Flow Label
657  * values sent by the target
658  */
659 int send_fid_probe(void){
660 	struct ether_header	*ethernet;
661 	struct dlt_null		*dlt_null;
662 	struct ip6_hdr		*ipv6;
663 	struct tcp_hdr		*tcp;
664 	struct udp_hdr		*udp;
665 	unsigned char		*ptr;
666 
667 	ethernet= (struct ether_header *) buffer;
668 	dlt_null= (struct dlt_null *) buffer;
669 	v6buffer = buffer + idata.linkhsize;
670 	ipv6 = (struct ip6_hdr *) v6buffer;
671 
672 	if(idata.type == DLT_EN10MB){
673 		ethernet->ether_type = htons(ETHERTYPE_IPV6);
674 
675 		if( !(idata.flags & IFACE_LOOPBACK)){
676 			ethernet->src = idata.hsrcaddr;
677 			ethernet->dst = idata.hdstaddr;
678 		}
679 	}
680 	else if(idata.type == DLT_NULL){
681 		dlt_null->family= PF_INET6;
682 	}
683 #if defined (__OpenBSD__)
684 	else if(idata->type == DLT_LOOP){
685 		dlt_null->family= htonl(PF_INET6);
686 	}
687 #endif
688 
689 	ipv6->ip6_flow=0;
690 	ipv6->ip6_vfc= 0x60;
691 	ipv6->ip6_hlim= hoplimit;
692 	ipv6->ip6_src= idata.srcaddr;
693 	ipv6->ip6_dst= idata.dstaddr;
694 	ipv6->ip6_nxt= protocol;
695 
696 	if(protocol == IPPROTO_TCP){
697 		tcp= (struct tcp_hdr *) ( (unsigned char *) ipv6 + sizeof(struct ip6_hdr));
698 		ptr= (unsigned char *) tcp + sizeof(struct tcp_hdr);
699 		memset(tcp, 0, sizeof(struct tcp_hdr));
700 		tcp->th_sport= htons(lastport);
701 		tcp->th_dport= htons(dstport);
702 		tcp->th_seq = htonl(tcpseq);
703 		tcp->th_ack= htonl(0);
704 		tcp->th_flags= TH_SYN;;
705 		tcp->th_urp= htons(0);
706 		tcp->th_win= htons(tcpwin);
707 		tcp->th_off= sizeof(struct tcp_hdr) >> 2;
708 		ipv6->ip6_plen= htons(ptr - (unsigned char *) tcp);
709 		tcp->th_sum = in_chksum(ipv6, tcp, (ptr - (unsigned char *) tcp), IPPROTO_TCP);
710 	}
711 	else{
712 		udp= (struct udp_hdr *) ( (unsigned char *) ipv6 + sizeof(struct ip6_hdr));
713 		ptr= (unsigned char *) udp + sizeof(struct udp_hdr);
714 		memset(udp, 0, sizeof(struct udp_hdr));
715 		udp->uh_sport= htons(lastport);
716 		udp->uh_dport= htons(dstport);
717 		ipv6->ip6_plen= htons(ptr - (unsigned char *) udp);
718 		udp->uh_sum = in_chksum(ipv6, udp, (ptr - (unsigned char *) udp), IPPROTO_TCP);
719 	}
720 
721 	if((nw=pcap_inject(idata.pfd, buffer, ptr - buffer)) == -1){
722 		if(idata.verbose_f)
723 			printf("pcap_inject(): %s\n", pcap_geterr(idata.pfd));
724 
725 		return(-1);
726 	}
727 
728 	if(nw != (ptr- buffer)){
729 		if(idata.verbose_f)
730 			printf("pcap_inject(): only wrote %lu bytes (rather than %lu bytes)\n", (LUI) nw, (LUI) (ptr-buffer));
731 
732 		return(-1);
733 	}
734 
735 	return(0);
736 }
737 
738 
739 /*
740  * Function: usage()
741  *
742  * Prints the syntax of the flow6 tool
743  */
744 void usage(void){
745 	puts("usage: flow6 -d DST_ADDR [-i INTERFACE] [-S LINK_SRC_ADDR] [-D LINK-DST-ADDR]\n"
746 	     "       [-s SRC_ADDR[/LEN]] [-A HOP_LIMIT] [-P PROTOCOL] [-p PORT]\n"
747 	     "       [-W] [-v] [-h]");
748 }
749 
750 
751 /*
752  * Function: print_help()
753  *
754  * Prints help information for the flow6 tool
755  */
756 void print_help(void){
757 	puts(SI6_TOOLKIT);
758 	puts("flow6: Security assessment tool for the IPv6 Flow Label field\n");
759 	usage();
760 
761 	puts("\nOPTIONS:\n"
762 	"  --interface, -i           Network interface\n"
763 	"  --link-src-address, -S    Link-layer Destination Address\n"
764 	"  --link-dst-address, -D    Link-layer Source Address\n"
765 	"  --src-address, -s         IPv6 Source Address\n"
766 	"  --dst-address, -d         IPv6 Destination Address\n"
767 	"  --hop-limit, -A           IPv6 Hop Limit\n"
768 	"  --protocol, -P            IPv6 Payload protocol (valid: TCP, UDP)\n"
769 	"  --dst-port, -p            Transport Protocol Destination Port\n"
770 	"  --flow-label-policy, -W   Assess the Flow Label generation policy\n"
771 	"  --help, -h                Print help for the flow6 tool\n"
772 	"  --verbose, -v             Be verbose\n"
773 	"\n"
774 	"Programmed by Fernando Gont on behalf of SI6 Networks <http://www.si6networks.com>\n"
775 	"Please send any bug reports to <fgont@si6networks.com>\n"
776 	);
777 }
778 
779 
780 
781 
782 /*
783  * Function: print_attack_info()
784  *
785  * Prints attack details (when the verbose ("-v") option is specified).
786  */
787 
788 void print_attack_info(void){
789 	if(ether_ntop(&(idata.hsrcaddr), plinkaddr, sizeof(plinkaddr)) == 0){
790 		puts("ether_ntop(): Error converting address");
791 		exit(EXIT_FAILURE);
792 	}
793 
794 	printf("Ethernet Source Address: %s%s\n", plinkaddr, (!idata.hsrcaddr_f)?" (automatically selected)":"");
795 
796 	/*
797 	   Ethernet Destination Address only used if a IPv6 Destination Address or an
798 	   Ethernet Destination Address were specified.
799 	 */
800 	if(ether_ntop(&(idata.hdstaddr), plinkaddr, sizeof(plinkaddr)) == 0){
801 		puts("ether_ntop(): Error converting address");
802 		exit(EXIT_FAILURE);
803 	}
804 
805 	printf("Ethernet Destination Address: %s%s\n", plinkaddr, (!idata.hdstaddr_f)?" (automatically selected)":"");
806 
807 	if(inet_ntop(AF_INET6, &(idata.srcaddr), psrcaddr, sizeof(psrcaddr)) == NULL){
808 		puts("inet_ntop(): Error converting IPv6 Source Address to presentation format");
809 		exit(EXIT_FAILURE);
810 	}
811 
812 	if(idata.dstaddr_f){
813 		printf("IPv6 Source Address: %s%s\n", psrcaddr, ((!idata.srcaddr_f)?" (automatically selected)":""));
814 	}
815 
816 	if(inet_ntop(AF_INET6, &(idata.dstaddr), pdstaddr, sizeof(pdstaddr)) == NULL){
817 		puts("inet_ntop(): Error converting IPv6 Destination Address to presentation format");
818 		exit(EXIT_FAILURE);
819 	}
820 
821 	printf("IPv6 Destination Address: %s\n", pdstaddr);
822 
823 	printf("IPv6 Hop Limit: %u%s\n", hoplimit, (hoplimit_f)?"":" (randomized)");
824 
825 	printf("Protocol: %s\tDestination Port: %u\n", (protocol==IPPROTO_TCP)?"TCP":"UDP", dstport);
826 }
827 
828 
829 
830 /*
831  * Function: predict_flow_id()
832  *
833  * Identifies and prints the Flow Label generation policy
834 */
835 int predict_flow_id(uint32_t *s1, unsigned int n1, uint32_t *s2, unsigned int n2){
836 	uint32_t		diff1_avg, diff2_avg;
837 	double			diff1_sdev, diff2_sdev;
838 
839 	if(inc_sdev(s1, n1, &diff1_avg, &diff1_sdev) == -1){
840 		if(idata.verbose_f)
841 			puts("Error while allocating memory in inc_sdev()");
842 
843 		return(-1);
844 	}
845 
846 	if(inc_sdev(s2, n2, &diff2_avg, &diff2_sdev) == -1){
847 		if(idata.verbose_f)
848 			puts("Error while allocating memory in inc_sdev()");
849 
850 		return(-1);
851 	}
852 
853 	if(diff1_sdev == 0 && diff1_avg == 0){
854 		if(diff2_sdev == 0 && diff2_avg == 0){
855 			printf("Flow Label policy: Global (predictable) constant labels, set to %05lu\n", (LUI) s1[0]);
856 		}
857 		else{
858 			printf("Flow Label policy: Per-destination constant labels with increments of %lu (sdev: %f)\n", \
859 					(LUI) diff2_avg, diff2_sdev);
860 		}
861 	}
862 
863 	else if(diff1_sdev <= 100){
864 		if(diff2_sdev <= 100){
865 			printf("Flow Label policy: Global (predictable) labels with increments of %lu (sdev: %f)\n", \
866 					(LUI) diff1_avg, diff1_sdev);
867 		}
868 		else{
869 			printf("Flow Label policy: Per-destination labels with increments of %lu (sdev: %f)\n", \
870 					(LUI) diff1_avg, diff1_sdev);
871 			printf("                   Global policy: Avg. inc.: %lu, sdev: %f\n", (LUI) diff2_avg, diff2_sdev);
872 		}
873 	}
874 	else{
875 		puts("Flow Label policy: Randomized labels");
876 		printf("    Per-destination: Avg. inc.: %lu, sdev: %f\n"
877 		       "    Global:          Avg. inc.: %lu, sdev: %f\n", \
878 				(LUI) diff1_avg, diff1_sdev, (LUI) diff2_avg, diff2_sdev);
879 	}
880 
881 	return(0);
882 }
883 
884 
885