1 /******************************************************************************/
2 /*                                                                            */
3 /*   Copyright (c) International Business Machines  Corp., 2006               */
4 /*                                                                            */
5 /*   This program is free software;  you can redistribute it and/or modify    */
6 /*   it under the terms of the GNU General Public License as published by     */
7 /*   the Free Software Foundation; either version 2 of the License, or        */
8 /*   (at your option) any later version.                                      */
9 /*                                                                            */
10 /*   This program is distributed in the hope that it will be useful,          */
11 /*   but WITHOUT ANY WARRANTY;  without even the implied warranty of          */
12 /*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See                */
13 /*   the GNU General Public License for more details.                         */
14 /*                                                                            */
15 /*   You should have received a copy of the GNU General Public License        */
16 /*   along with this program;  if not, write to the Free Software             */
17 /*   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA  */
18 /*                                                                            */
19 /******************************************************************************/
20 
21 /*
22  * File:
23  *	ns-icmpv6_sender.c
24  *
25  * Description:
26  *	This is ICMPv6 message (Echo request / MLDv2 query) sender.
27  *	This utility is also able to set illegal information in the IP header
28  *
29  * Author:
30  *	Mitsuru Chinen <mitch@jp.ibm.com>
31  *
32  * History:
33  *	Mar 15 2006 - Created (Mitsuru Chinen)
34  *---------------------------------------------------------------------------*/
35 
36 /*
37  * Header Files
38  */
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <errno.h>
43 #include <netdb.h>
44 #include <signal.h>
45 #include <time.h>
46 #include <unistd.h>
47 #include <sys/ioctl.h>
48 #include <sys/socket.h>
49 #include <arpa/inet.h>
50 #include <net/ethernet.h>
51 #include <netinet/in.h>
52 
53 #include "ns-mcast.h"
54 #include "ns-traffic.h"
55 
56 /*
57  * Structure Definitions
58  */
59 struct icmp6_info {
60 	struct ip6_datagram pkt;
61 	struct sockaddr_ll saddr_ll;
62 	struct sockaddr_ll daddr_ll;
63 	struct in6_addr saddr;
64 	struct in6_addr daddr;
65 	unsigned short int pkt_size;
66 	unsigned short int data_size;
67 	double timeout;
68 	struct timespec interval;
69 
70 	u_int16_t fake_flag;
71 };
72 
73 /*
74  * Gloval variables
75  */
76 char *program_name;		/* program name */
77 struct sigaction handler;	/* Behavior for a signal */
78 int catch_sighup;		/* When catch the SIGHUP, set to non-zero */
79 struct in6_addr in6addr_allnodes = IN6ADDR_ALLNODES_MULTICAST_INIT;
80 
81 /*
82  * Function: usage()
83  *
84  * Descripton:
85  *  Print the usage of this program. Then, terminate this program with
86  *  the specified exit value.
87  *
88  * Argument:
89  *  exit_value:	exit value
90  *
91  * Return value:
92  *  This function does not return.
93  */
usage(char * program_name,int exit_value)94 void usage(char *program_name, int exit_value)
95 {
96 	FILE *stream = stdout;	/* stream where the usage is output */
97 
98 	if (exit_value == EXIT_FAILURE)
99 		stream = stderr;
100 
101 	fprintf(stream, "%s [OPTION]\n"
102 		"\t-I if_name\tInterface name of the source host\n"
103 		"\t-S ip_addr\tIPv6 address of the source host\n"
104 		"\t-M mac_addr\tMAC address of the destination host\n"
105 		"\t-D ip_addr\tIPv6 address of the destination host\n"
106 		"\t-t value\ttimeout [sec]\n"
107 		"\t-w value\tinterval [nanosec]\n"
108 		"\t-o\t\tsend only one ICMPv6 message\n"
109 		"\t-b\t\twork in the background\n"
110 		"\t-d\t\tdisplay debug informations\n"
111 		"\t-h\t\tdisplay this usage\n"
112 		"\n"
113 		"\t[options for echo request]\n"
114 		"\t  -s packetsize\tsize of data (exclude header)\n"
115 		"\n"
116 		"\t[options for fake]\n"
117 		"\t  -i\t\tbreak IPv6 destination address\n"
118 		"\t  -L\t\tbreak payload length\n"
119 		"\t  -n\t\tbreak next header\n"
120 		"\t  -v\t\tbreak IP version\n"
121 		"\n"
122 		"\t[options for MLDv2 query]\n"
123 		"\t  -m\t\tsend MLDv2 query\n"
124 		"\t  -a addrs\tcomma separated array of Source Addresses\n"
125 		"\t  -r value\tMax Resp Code\n", program_name);
126 	exit(exit_value);
127 }
128 
129 /*
130  * Function: set_signal_flag()
131  *
132  * Description:
133  *  This function sets global variables according to signal
134  *
135  * Argument:
136  *  type: type of signal
137  *
138  * Return value:
139  *  None
140  */
set_signal_flag(int type)141 void set_signal_flag(int type)
142 {
143 	if (debug)
144 		fprintf(stderr, "Catch signal. type is %d\n", type);
145 
146 	switch (type) {
147 	case SIGHUP:
148 		catch_sighup = 1;
149 		handler.sa_handler = SIG_IGN;
150 		if (sigaction(type, &handler, NULL) < 0)
151 			fatal_error("sigaction()");
152 		break;
153 
154 	default:
155 		fprintf(stderr, "Unexpected signal (%d) is caught\n", type);
156 		exit(EXIT_FAILURE);
157 	}
158 }
159 
160 /*
161  * Function: specify_hw_addr()
162  *
163  * Description:
164  *  This function specifies the hardware address from the interface name
165  *
166  * Argument:
167  *   lladdr_p:	pointer to the sockaddr_ll structure
168  *    ifname:	interface name where icmpv6 messages go out
169  *
170  * Return value:
171  *  None
172  *
173  */
specify_hw_addr(struct sockaddr_ll * lladdr_p,const char * ifname)174 void specify_hw_addr(struct sockaddr_ll *lladdr_p, const char *ifname)
175 {
176 	int sock_fd;		/* Socket for ioctl() */
177 	struct ifreq ifinfo;	/* Interface information */
178 
179 	if ((sock_fd = socket(AF_PACKET, SOCK_DGRAM, 0)) < 0)
180 		fatal_error("socket()");
181 
182 	lladdr_p->sll_family = AF_PACKET;	/* Always AF_PACKET */
183 	lladdr_p->sll_protocol = htons(ETH_P_IPV6);	/* IPv6 */
184 	lladdr_p->sll_hatype = ARPHRD_ETHER;	/* Header type */
185 	lladdr_p->sll_pkttype = PACKET_HOST;	/* Packet type */
186 	lladdr_p->sll_halen = ETH_ALEN;	/* Length of address */
187 
188 	/* Get the MAC address of the interface at source host */
189 	get_ifinfo(&ifinfo, sock_fd, ifname, SIOCGIFHWADDR);
190 	memcpy(lladdr_p->sll_addr, ifinfo.ifr_hwaddr.sa_data, ETH_ALEN);
191 
192 	/* Get the interface index */
193 	lladdr_p->sll_ifindex = if_nametoindex(ifname);
194 	close(sock_fd);
195 }
196 
197 /*
198  * Function: calc_hd_mcastaddr
199  *
200  * Description:
201  *  This function calculate multicast hardware address from IPv6
202  *  multicast address
203  *
204  * Argument:
205  *   lladdr_p:	pointer to the sockaddr_ll structure
206  *    addr_p:	pointer to the in6_addr structure
207  *
208  * Return value:
209  *  None
210  */
calc_hd_mcastaddr(struct sockaddr_ll * lladdr_p,struct in6_addr * addr_p)211 void calc_hd_mcastaddr(struct sockaddr_ll *lladdr_p, struct in6_addr *addr_p)
212 {
213 	lladdr_p->sll_family = AF_PACKET;	/* Always AF_PACKET */
214 	lladdr_p->sll_protocol = htons(ETH_P_IPV6);	/* IPv6 */
215 	lladdr_p->sll_ifindex = 0;	/* Unspecified here */
216 	lladdr_p->sll_hatype = ARPHRD_ETHER;	/* Header type */
217 	lladdr_p->sll_pkttype = PACKET_MULTICAST;	/* Packet type */
218 	lladdr_p->sll_halen = ETH_ALEN;	/* Length of address */
219 
220 	lladdr_p->sll_addr[0] = 0x33;
221 	lladdr_p->sll_addr[1] = 0x33;
222 	memcpy(&lladdr_p->sll_addr[2], &addr_p->s6_addr[12], ETH_ALEN - 2);
223 }
224 
225 /*
226  * Function: create_mld_query()
227  *
228  * Description:
229  *  This function create a mldv2 query information.
230  *
231  * Argument:
232  *  info_p:	pointer to data of icmp structure
233  *   mrc:	Max Resp Code
234  *   saddrs:	comma separated array of the source addresses
235  *
236  * Return value:
237  *  0: Success
238  *  1: Fail
239  */
create_mld_query(struct icmp6_info * info_p,uint16_t mrc,char * saddrs)240 int create_mld_query(struct icmp6_info *info_p, uint16_t mrc, char *saddrs)
241 {
242 	struct ip6_datagram pkt;	/* ICMPv6 packet */
243 	struct hbh_router_alert *alart_p;	/* pointer to router alart */
244 	struct my_mldv2_query *query_p;	/* pointer to my_mldv2_query */
245 	struct pseudo_ip6_datagram pseudo;	/* ICMPv6 pseudo packet for checksum */
246 	uint16_t numsrc;	/* number of source address */
247 	unsigned short int ip6_psize;	/* size of IPv6 payload */
248 	unsigned short int query_size;	/* size of my_mldv2_query */
249 	struct in6_addr ip6;
250 	uint32_t idx;
251 	char *sp, *ep;
252 
253 	memset(&pkt, '\0', sizeof(struct ip6_datagram));
254 	alart_p = (struct hbh_router_alert *)&(pkt.payload);
255 	query_p =
256 	    (struct my_mldv2_query *)((unsigned char *)alart_p +
257 				      sizeof(struct hbh_router_alert));
258 
259 	/* calculate the number of source address */
260 	if (saddrs == NULL) {
261 		numsrc = 0;
262 	} else {
263 		numsrc = 1;
264 		for (sp = saddrs; *sp != '\0'; sp++)
265 			if (*sp == ',')
266 				numsrc++;
267 	}
268 	if (debug)
269 		fprintf(stderr, "number of source address is %u\n", numsrc);
270 
271 	query_size = MY_MLDV2_QUERY_SIZE(numsrc);
272 	ip6_psize = sizeof(struct hbh_router_alert) + query_size;
273 
274 	/* IPv6 Header */
275 	pkt.hdr.ip6_vfc = 6 << 4;
276 	pkt.hdr.ip6_flow |= 0;
277 	pkt.hdr.ip6_plen = htons(ip6_psize);
278 	pkt.hdr.ip6_nxt = IPPROTO_HOPOPTS;
279 	pkt.hdr.ip6_hlim = 1;
280 	pkt.hdr.ip6_src = info_p->saddr;
281 	pkt.hdr.ip6_dst = info_p->daddr;
282 
283 	/* Router Alert Option */
284 	alart_p->nxthdr = IPPROTO_ICMPV6;
285 	alart_p->hbh_len = 0;
286 	alart_p->alart_type = 0x05;	/* router alert */
287 	alart_p->alart_len = 0x02;	/* data len */
288 	alart_p->alart_data = htons(0x0000);	/* MLD */
289 	alart_p->padn_type = 0x01;	/* PadN option */
290 	alart_p->padn_len = 0x00;	/* 2 Octets */
291 
292 	/* MLDv2 query */
293 	query_p->type = MLD_LISTENER_QUERY;
294 	query_p->code = 0;
295 	query_p->cksum = 0;	/* Calculate later */
296 	query_p->maxdelay = htons(mrc);
297 	query_p->resv = 0;
298 	query_p->suppress = 0;
299 	query_p->qrv = 0;
300 	query_p->qqic = 0;
301 	query_p->nsrcs = htons(numsrc);
302 
303 	/* define the multicast address */
304 	if (memcmp(&info_p->daddr, &in6addr_allnodes, sizeof(struct in6_addr))
305 	    == 0)
306 		query_p->addr = in6addr_any;
307 	else
308 		query_p->addr = info_p->daddr;
309 
310 	/* substitute source addresses */
311 	sp = saddrs;
312 	for (idx = 0; idx < numsrc; idx++) {
313 		ep = strchr(sp, ',');
314 		if (ep != NULL)
315 			*ep = '\0';
316 		if (debug)
317 			fprintf(stderr, "source address[%u]: %s\n", idx, sp);
318 
319 		if (inet_pton(AF_INET6, sp, &ip6) <= 0) {
320 			fprintf(stderr,
321 				"source address list is something wrong\n");
322 			return 1;
323 		}
324 		query_p->srcs[idx] = ip6;
325 		sp = ep + 1;
326 	}
327 
328 	/* ICMPv6 Pseudo packet */
329 	pseudo.hdr.p_ip6_src = pkt.hdr.ip6_src;
330 	pseudo.hdr.p_ip6_dst = pkt.hdr.ip6_dst;
331 	pseudo.hdr.p_ip6_plen = htons(query_size);
332 	pseudo.hdr.p_ip6_zero1 = 0;
333 	pseudo.hdr.p_ip6_zero2 = 0;
334 	pseudo.hdr.p_ip6_nxt = IPPROTO_ICMPV6;
335 	memcpy(pseudo.payload, query_p, query_size);
336 
337 	/* Calcualte checksums */
338 	query_p->cksum = calc_checksum((u_int16_t *) (&pseudo),
339 				       sizeof(struct pseudo_ip6_hdr) +
340 				       query_size);
341 
342 	/* Store the clean packet data */
343 	info_p->pkt = pkt;
344 	info_p->pkt_size = sizeof(struct ip6_hdr) + ip6_psize;
345 
346 	return 0;
347 }
348 
349 /*
350  * Function: create_echo_request()
351  *
352  * Description:
353  *  This function creates icmpv6 echo request
354  *
355  * Argument:
356  *  info_p: pointer to data of icmp structure
357  *
358  * Return value:
359  *  None
360  */
create_echo_request(struct icmp6_info * info_p)361 void create_echo_request(struct icmp6_info *info_p)
362 {
363 	struct ip6_datagram pkt;	/* ICMPv6 packet */
364 	struct icmp6_segment *echoreq_p;	/* Echo request header and payload */
365 	struct pseudo_ip6_datagram pseudo;	/* ICMPv6 pseudo packet for checksum */
366 	unsigned short int ip6_psize;	/* payload size */
367 
368 	ip6_psize = sizeof(struct icmp6_hdr)	/* ICMP header */
369 	    +info_p->data_size;	/* ICMP payload */
370 	memset(&pkt, '\0', sizeof(struct ip6_datagram));
371 	echoreq_p = (struct icmp6_segment *)&(pkt.payload);
372 
373 	/* IPv6 Header */
374 	pkt.hdr.ip6_vfc = 6 << 4;
375 	pkt.hdr.ip6_flow |= 0;
376 	pkt.hdr.ip6_plen = htons(ip6_psize);
377 	pkt.hdr.ip6_nxt = IPPROTO_ICMPV6;
378 	pkt.hdr.ip6_hlim = IPV6_DEFAULT_HOPLIMIT;
379 	pkt.hdr.ip6_src = info_p->saddr;
380 	pkt.hdr.ip6_dst = info_p->daddr;
381 
382 	/* Echo Request Header */
383 	echoreq_p->hdr.icmp6_type = ICMP6_ECHO_REQUEST;
384 	echoreq_p->hdr.icmp6_code = 0;
385 	echoreq_p->hdr.icmp6_cksum = 0;	/* Calculate later */
386 	echoreq_p->hdr.icmp6_id = htons(ICMP_ECHO_ID);
387 	echoreq_p->hdr.icmp6_seq = htons(1);
388 
389 	/* Echo Request Payload */
390 	fill_payload(echoreq_p->data, info_p->data_size);
391 
392 	/* ICMPv6 Pseudo packet */
393 	pseudo.hdr.p_ip6_src = pkt.hdr.ip6_src;
394 	pseudo.hdr.p_ip6_dst = pkt.hdr.ip6_dst;
395 	pseudo.hdr.p_ip6_plen = htons(ip6_psize);
396 	pseudo.hdr.p_ip6_zero1 = 0;
397 	pseudo.hdr.p_ip6_zero2 = 0;
398 	pseudo.hdr.p_ip6_nxt = IPPROTO_ICMPV6;
399 	memcpy(pseudo.payload, echoreq_p, ip6_psize);
400 
401 	/* Calcualte checksums */
402 	echoreq_p->hdr.icmp6_cksum = calc_checksum((u_int16_t *) (&pseudo),
403 						   sizeof(struct pseudo_ip6_hdr)
404 						   + ip6_psize);
405 
406 	/* Store the clean packet data */
407 	info_p->pkt = pkt;
408 	info_p->pkt_size = sizeof(struct ip6_hdr) + ip6_psize;
409 }
410 
411 /*
412  * Function: parse_options()
413  *
414  * Description:
415  *  This function parse the options
416  *
417  * Argument:
418  *   argc:  the number of argument
419  *   argv:  arguments
420  *  info_p: pointer to data of icmp data to modify
421  *   bg_p:  pointer to the flag of working in backgrond
422  *
423  * Return value:
424  *  None
425  */
parse_options(int argc,char * argv[],struct icmp6_info * info_p,int * bg_p)426 void parse_options(int argc, char *argv[], struct icmp6_info *info_p, int *bg_p)
427 {
428 	int optc;		/* option */
429 	unsigned long opt_ul;	/* option value in unsigned long */
430 	double opt_d;		/* option value in double */
431 	struct in6_addr opt_addr;	/* option value in struct in_addr */
432 	struct sockaddr_ll opt_addr_ll;	/* option value in struct sockaddr_ll */
433 	char *ifname;		/* interface name where datagrams go out */
434 	int is_mld_query;	/* set to non-zero if sending MLDv2 query */
435 	char *mld_saddrs;	/* comma separated array of source addresses */
436 	uint16_t max_resp;	/* Max Resp Code */
437 	int is_specified_daddr_ll = 0;
438 	int is_specified_saddr = 0;
439 	int is_specified_daddr = 0;
440 
441 	ifname = NULL;
442 	is_mld_query = 0;
443 	mld_saddrs = NULL;
444 	max_resp = MY_MLD_MAX_HOST_REPORT_DELAY;
445 
446 	while ((optc =
447 		getopt(argc, argv, "I:S:M:D:t:w:obdhs:iLnvma:r:")) != EOF) {
448 		switch (optc) {
449 		case 'I':
450 			if (if_nametoindex(optarg) == 0) {
451 				fprintf(stderr,
452 					"specified interface is incorrect\n");
453 				usage(program_name, EXIT_FAILURE);
454 			}
455 			ifname = strdup(optarg);
456 			if (ifname == NULL)
457 				fatal_error("strdup() failed.");
458 			break;
459 
460 		case 'S':
461 			if (inet_pton(AF_INET6, optarg, &opt_addr) <= 0) {
462 				fprintf(stderr, "Source address is wrong\n");
463 				usage(program_name, EXIT_FAILURE);
464 			}
465 			info_p->saddr = opt_addr;
466 			is_specified_saddr = 1;
467 			break;
468 
469 		case 'M':
470 			if (eth_pton(AF_INET6, optarg, &opt_addr_ll)) {
471 				fprintf(stderr,
472 					"Destination MAC address is wrong\n");
473 				usage(program_name, EXIT_FAILURE);
474 			}
475 			info_p->daddr_ll = opt_addr_ll;
476 			is_specified_daddr_ll = 1;
477 			break;
478 
479 		case 'D':
480 			if (inet_pton(AF_INET6, optarg, &opt_addr) <= 0) {
481 				fprintf(stderr,
482 					"Destination address is wrong\n");
483 				usage(program_name, EXIT_FAILURE);
484 			}
485 			info_p->daddr = opt_addr;
486 			is_specified_daddr = 1;
487 			break;
488 
489 		case 't':
490 			opt_d = strtod(optarg, NULL);
491 			if (opt_d < 0.0) {
492 				fprintf(stderr,
493 					"Timeout should be positive value\n");
494 				usage(program_name, EXIT_FAILURE);
495 			}
496 			info_p->timeout = opt_d;
497 			break;
498 
499 		case 'w':
500 			if (strtotimespec(optarg, &info_p->interval)) {
501 				fprintf(stderr,
502 					"Interval is something wrong\n");
503 				usage(program_name, EXIT_FAILURE);
504 			}
505 			break;
506 
507 		case 'o':
508 			info_p->timeout = -1.0;
509 			break;
510 
511 		case 'b':
512 			*bg_p = 1;
513 			break;
514 
515 		case 'd':
516 			debug = 1;
517 			break;
518 
519 		case 'h':
520 			usage(program_name, EXIT_SUCCESS);
521 			break;
522 
523 			/* Options for echo request */
524 		case 's':
525 			opt_ul = strtoul(optarg, NULL, 0);
526 			if (opt_ul > ICMPV6_DATA_MAXSIZE) {
527 				fprintf(stderr,
528 					"Data size sholud be less than %d\n",
529 					ICMPV6_DATA_MAXSIZE + 1);
530 				usage(program_name, EXIT_FAILURE);
531 			}
532 			info_p->data_size = opt_ul;
533 			break;
534 
535 			/* Options for fake */
536 		case 'i':
537 			info_p->fake_flag |= FAKE_DADDR;
538 			break;
539 
540 		case 'L':
541 			info_p->fake_flag |= FAKE_PLEN;
542 			break;
543 
544 		case 'n':
545 			info_p->fake_flag |= FAKE_NXT;
546 			break;
547 
548 		case 'v':
549 			info_p->fake_flag |= FAKE_VERSION;
550 			break;
551 
552 			/* Options for MLDv2 query */
553 		case 'm':
554 			is_mld_query = 1;
555 			break;
556 
557 		case 'a':
558 			mld_saddrs = strdup(optarg);
559 			if (mld_saddrs == NULL)
560 				fatal_error("strdup()");
561 			break;
562 
563 		case 'r':
564 			opt_ul = strtoul(optarg, NULL, 0);
565 			if (opt_ul > 0xFFFF) {
566 				fprintf(stderr,
567 					"Max Resp Code should be less than 65536\n");
568 				usage(program_name, EXIT_FAILURE);
569 			}
570 			max_resp = opt_ul;
571 			break;
572 
573 		default:
574 			usage(program_name, EXIT_FAILURE);
575 		}
576 	}
577 
578 	if (ifname == NULL) {
579 		fprintf(stderr, "Outgoing interface is not specified\n");
580 		usage(program_name, EXIT_FAILURE);
581 	}
582 	specify_hw_addr(&info_p->saddr_ll, ifname);
583 
584 	if (!is_specified_saddr) {
585 		fprintf(stderr, "Source IP address is not specified\n");
586 		usage(program_name, EXIT_FAILURE);
587 	}
588 
589 	if (is_mld_query) {	/* MLDv2 query */
590 		if (info_p->fake_flag) {
591 			fprintf(stderr,
592 				"It is not permitted to break MLDv2 query\n");
593 			usage(program_name, EXIT_FAILURE);
594 		}
595 
596 		if (!is_specified_daddr)
597 			info_p->daddr = in6addr_allnodes;
598 
599 		calc_hd_mcastaddr(&info_p->daddr_ll, &info_p->daddr);
600 		if (create_mld_query(info_p, max_resp, mld_saddrs))
601 			exit(EXIT_FAILURE);
602 	} else {		/* echo request */
603 		if (info_p->fake_flag)
604 			srand(getpid());
605 
606 		if (!is_specified_daddr_ll) {
607 			fprintf(stderr,
608 				"Destination MAC address is not specified\n");
609 			usage(program_name, EXIT_FAILURE);
610 		}
611 
612 		if (!is_specified_daddr) {
613 			fprintf(stderr,
614 				"Destination IP address is not specified\n");
615 			usage(program_name, EXIT_FAILURE);
616 		}
617 
618 		create_echo_request(info_p);
619 	}
620 	info_p->daddr_ll.sll_ifindex = if_nametoindex(ifname);
621 }
622 
623 /*
624  * Function: thrust_fakes()
625  *
626  * Description:
627  *  This function thrust fake information to the icmp packet
628  *
629  * Argument:
630  *     pkt   : Payload of the Ethernet frame (Namely, IPv6 packet)
631  *  fake_flag: Flag which represents what information would be faked
632  *
633  * Return value:
634  *  None
635  */
thrust_fakes(struct ip6_datagram * pkt,u_int16_t fake_flag)636 void thrust_fakes(struct ip6_datagram *pkt, u_int16_t fake_flag)
637 {
638 	int rand_val;
639 	size_t bitsize;
640 	u_int32_t seed;
641 
642 	if (debug)
643 		fprintf(stderr, "fake_flag = %2x\n", fake_flag);
644 
645 	if (fake_flag & FAKE_VERSION) {	/* version */
646 		bitsize = 4;
647 		seed = bit_change_seed(bitsize, 1);
648 		pkt->hdr.ip6_vfc ^= (seed << 4);
649 	}
650 
651 	if (fake_flag & FAKE_PLEN) {	/* total length */
652 		bitsize = sizeof(pkt->hdr.ip6_plen) * 8;
653 		seed = bit_change_seed(bitsize, bitsize / 8);
654 		pkt->hdr.ip6_plen ^= seed;
655 	}
656 
657 	if (fake_flag & FAKE_NXT) {	/* next header */
658 		rand_val = rand() / ((RAND_MAX + 1U) / 5);
659 		switch (rand_val) {
660 		case 1:
661 		case 2:
662 			if (debug)
663 				fprintf(stderr, "Bit reverse\n");
664 			bitsize = sizeof(pkt->hdr.ip6_nxt) * 8;
665 			seed = bit_change_seed(bitsize, 0);
666 			pkt->hdr.ip6_nxt ^= seed;
667 			break;
668 
669 		case 3:
670 		case 4:
671 			if (debug)
672 				fprintf(stderr, "Unknown Protocol\n");
673 			if (rand_val) {
674 				int number;
675 				int counter;
676 				for (counter = 0; counter <= 0xff; counter++) {
677 					number =
678 					    rand() / ((RAND_MAX + 1U) / 0x100);
679 					if (getprotobynumber(number) == NULL) {
680 						pkt->hdr.ip6_nxt = number;
681 						break;
682 					}
683 				}
684 			}
685 			break;
686 
687 		default:
688 			if (debug)
689 				fprintf(stderr, "Do nothing\n");
690 			break;
691 		}
692 	}
693 
694 	if (fake_flag & FAKE_DADDR) {	/* destination address */
695 		rand_val = rand() / ((RAND_MAX + 1U) / 4);
696 		bitsize = sizeof(pkt->hdr.ip6_dst.s6_addr32[rand_val]) * 8;
697 		seed = bit_change_seed(bitsize, bitsize / 8);
698 		pkt->hdr.ip6_dst.s6_addr32[rand_val] ^= seed;
699 	}
700 }
701 
702 /*
703  * Function: send_packet()
704  *
705  * Description:
706  *  This function sends icmpv6 packet
707  *
708  * Argument:
709  *  info_p: pointer to data of icmp structure
710  *
711  * Return value:
712  *  None
713  */
send_packets(struct icmp6_info * info_p)714 void send_packets(struct icmp6_info *info_p)
715 {
716 	int sock_fd;
717 	int retval;
718 	struct ip6_datagram pkt;
719 	double start_time;
720 
721 	/* Open a socket */
722 	sock_fd = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_IPV6));
723 	if (sock_fd < 0)
724 		fatal_error("socket()");
725 
726 	/* Bind the socket to the physical address */
727 	retval = bind(sock_fd, (struct sockaddr *)&(info_p->saddr_ll),
728 		      sizeof(struct sockaddr_ll));
729 	if (retval < 0)
730 		fatal_error("bind()");
731 
732 	/* Set singal hander for SIGHUP */
733 	handler.sa_handler = set_signal_flag;
734 	handler.sa_flags = 0;
735 	if (sigfillset(&handler.sa_mask) < 0)
736 		fatal_error("sigfillset()");
737 	if (sigaction(SIGHUP, &handler, NULL) < 0)
738 		fatal_error("sigfillset()");
739 
740 	/*
741 	 * loop for sending packets
742 	 */
743 	pkt = info_p->pkt;
744 	start_time = time(NULL);
745 
746 	for (;;) {
747 		if (info_p->fake_flag) {
748 			pkt = info_p->pkt;
749 			thrust_fakes(&pkt, info_p->fake_flag);
750 		}
751 
752 		retval = sendto(sock_fd, &pkt, info_p->pkt_size, 0,
753 				(struct sockaddr *)&(info_p->daddr_ll),
754 				sizeof(struct sockaddr_ll));
755 		if (retval < 0)
756 			fatal_error("sendto()");
757 
758 		/* Check timeout:
759 		   If timeout value is negative only send one datagram */
760 		if (info_p->timeout)
761 			if (info_p->timeout < difftime(time(NULL), start_time))
762 				break;
763 
764 		/* Wait in specified interval */
765 		nanosleep(&info_p->interval, NULL);
766 
767 		if (catch_sighup)	/* catch SIGHUP */
768 			break;
769 	}
770 
771 	/* Close the socket */
772 	close(sock_fd);
773 }
774 
775 /*
776  *
777  *  Function: main()
778  *
779  */
main(int argc,char * argv[])780 int main(int argc, char *argv[])
781 {
782 	struct icmp6_info icmp6_data;
783 	int background = 0;
784 
785 	debug = 0;
786 	program_name = strdup(argv[0]);
787 
788 	memset(&icmp6_data, '\0', sizeof(struct icmp6_info));
789 	parse_options(argc, argv, &icmp6_data, &background);
790 
791 	if (background)		/* Work in the background */
792 		if (daemon(0, 0) < 0)
793 			fatal_error("daemon()");
794 
795 	send_packets(&icmp6_data);
796 
797 	exit(EXIT_SUCCESS);
798 }
799