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