1 /*
2 * ipv6mon v1.0: An IPv6 Address Monitoring Tool
3 *
4 * Copyright (C) 2011-2012 Fernando Gont
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 *
20 * Build with: gcc ipv6mon.c -Wall -lpcap -o ipv6mon
21 *
22 * This program has been tested to compile and run on: FreeBSD 9.0,
23 * NetBSD 5.1, OpenBSD 4.9, and Linux 2.6.38-10. It requires that the
24 * libpcap library be installed on your system.
25 *
26 * Please send any bug reports to Fernando Gont <fgont@si6networks.com>
27 */
28
29 #include <errno.h>
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <time.h>
33 #include <getopt.h>
34 #include <unistd.h>
35 #include <signal.h>
36 #include <string.h>
37 #include <pcap.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <fcntl.h>
41 #include <sys/param.h>
42 #include <setjmp.h>
43 #include <netinet/in.h>
44 #include <arpa/inet.h>
45 #include <netinet/ip6.h>
46 #include <netinet/icmp6.h>
47 #include <sys/socket.h>
48 #include <sys/select.h>
49 #include <sys/time.h>
50 #include <sys/resource.h>
51 #include <pwd.h>
52 #include <grp.h>
53 #include <sys/param.h>
54 #include <net/if.h>
55 #include <ifaddrs.h>
56 #ifdef __linux__
57 #include <netpacket/packet.h>
58 #elif defined (__FreeBSD__) || defined(__NetBSD__) || defined (__OpenBSD__) || defined(__APPLE__)
59 #include <net/if_dl.h>
60 #endif
61 #include <syslog.h>
62 #include "ipv6mon.h"
63
64 /* Function prototypes */
65 int init_iface_data(struct iface_data *);
66 int init_host_list(struct host_list *);
67 int insert_pad_opt(unsigned char *ptrhdr, const unsigned char *, unsigned int);
68 void usage(void);
69 void print_help(void);
70 int ether_pton(const char *, struct ether_addr *, unsigned int);
71 int ether_ntop(const struct ether_addr *, char *, size_t);
72 u_int16_t in_chksum(void *, void *, size_t);
73 unsigned int match_ipv6(struct in6_addr *, u_int8_t *, unsigned int, struct in6_addr *);
74 unsigned int match_ether(struct ether_addr *, unsigned int, struct ether_addr *);
75 void sanitize_ipv6_prefix(struct in6_addr *, u_int8_t);
76 void randomize_ipv6_addr(struct in6_addr *, struct in6_addr *, u_int8_t);
77 void randomize_ether_addr(struct ether_addr *);
78 void ether_to_ipv6_linklocal(struct ether_addr *etheraddr, struct in6_addr *ipv6addr);
79 void generate_slaac_address(struct in6_addr *, struct ether_addr *, struct in6_addr *);
80 int is_eq_in6_addr(struct in6_addr *, struct in6_addr *);
81 struct in6_addr solicited_node(const struct in6_addr *);
82 struct ether_addr ether_multicast(const struct in6_addr *);
83 int match_ipv6_to_prefixes(struct in6_addr *, struct in6_addr *, unsigned char *, unsigned int);
84 int process_router_advert(struct iface_data *, struct pcap_pkthdr *, const u_char *);
85 int validate_host_entries(pcap_t *, struct iface_data *, struct host_list *, struct host_list *);
86 int create_candidate_andress(struct iface_data *, struct host_list *, struct host_entry *);
87 void free_host_entries(struct host_list *);
88 int send_multicast_probe(pcap_t *, struct iface_data *, struct host_list *, unsigned char);
89 int probe_node_nd(const char *, struct ether_addr *, struct in6_addr *, struct in6_addr *,\
90 struct ether_addr *);
91 struct host_entry *is_ip6_in_list(struct host_list *, struct in6_addr *);
92 int is_ip6_in_prefix_list(struct in6_addr *, struct prefix_list *);
93 int is_ip6_in_address_list(struct prefix_list *, struct in6_addr *);
94 struct prefix_entry *lookup_ip6_in_address_list(struct prefix_list *, struct in6_addr *);
95 int send_neighbor_advert(struct iface_data *, pcap_t *, const u_char *);
96 int send_router_solicit(pcap_t *, struct iface_data *);
97 int process_icmp6_response(struct iface_data *, struct host_list *, unsigned char , \
98 struct pcap_pkthdr *, const u_char *, unsigned char *);
99 int valid_icmp6_response(struct iface_data *, struct host_list *, struct pcap_pkthdr *, const u_char *);
100 int process_host_entries(pcap_t *, struct iface_data *, struct host_list *);
101 int get_if_addrs(struct iface_data *);
102 int check_local_addresses(struct iface_data *);
103 int send_host_probe(pcap_t *, struct iface_data *, unsigned char, struct host_entry *);
104 int gcollection_host_entries(struct iface_data *, struct host_list *);
105 struct host_entry *add_host_entry(struct host_list *, struct in6_addr *, struct ether_addr *);
106 int log_hentry(struct iface_data *, struct host_entry *, time_t *, unsigned char);
107 u_int16_t key(struct host_list *, struct in6_addr *);
108 struct in6_addr *src_addr_sel(struct iface_data *, struct in6_addr *);
109 int keyval(char *, unsigned int, char **, char **);
110 int process_config_file(const char *);
111 int make_daemon(void);
112 int already_running(void);
113 int log_start(struct iface_data *);
114 int log_stop(struct iface_data *);
115 void sigterm(int);
116
117 /* Host list */
118 struct host_list hlist;
119
120 /* Used for router discovery */
121 struct iface_data idata;
122 struct prefix_entry *prefix_ols[MAX_PREFIXES_ONLINK], *prefix_acs[MAX_PREFIXES_AUTO];
123 struct prefix_entry *prefix_local[MAX_LOCAL_ADDRESSES];
124
125 /* Variables used for learning the default router */
126 struct ether_addr router_ether, rs_ether;
127 struct in6_addr router_ipv6, rs_ipv6;
128
129 /* Data structures for packets read from the wire */
130 pcap_t *sfd;
131 struct pcap_pkthdr *pkthdr;
132 const u_char *pktdata;
133 unsigned char *pkt_end;
134 struct ether_header *pkt_ether;
135 struct ip6_hdr *pkt_ipv6;
136 struct in6_addr *pkt_ipv6addr;
137 unsigned int pktbytes;
138
139 struct bpf_program pcap_filter;
140 char dev[64], errbuf[PCAP_ERRBUF_SIZE];
141 unsigned char buffer[BUFFER_SIZE], buffrh[MIN_IPV6_HLEN + MIN_TCP_HLEN];
142 unsigned char wbuffer[BUFFER_SIZE];
143 unsigned char *v6buffer, *ptr, *startofprefixes;
144 char *pref;
145 char iface[IFACE_LENGTH];
146
147 struct ip6_hdr *ipv6;
148 struct icmp6_hdr *icmp6;
149
150 struct ether_header *ethernet;
151 struct ether_addr hsrcaddr, hdstaddr;
152
153 struct in6_addr srcaddr, dstaddr;
154
155 char *lasts, *rpref;
156 char *charptr;
157
158 size_t nw;
159 unsigned long ul_res, ul_val;
160 unsigned int i, j, startrand;
161 unsigned int skip;
162 unsigned char srcpreflen;
163
164 u_int16_t mask;
165 u_int8_t hoplimit;
166
167 char plinkaddr[ETHER_ADDR_PLEN];
168 char psrcaddr[INET6_ADDRSTRLEN], pdstaddr[INET6_ADDRSTRLEN], pv6addr[INET6_ADDRSTRLEN];
169 unsigned char verbose_f=0, iface_f=0, hsrcaddr_f=0, probe_echo_f=0, probe_unrec_f=0, probe_f=0;
170 unsigned char *prev_nh;
171
172 /* Configuration variables */
173 char *logfile, *lockfile, *unprivuser, *unprivgroup, *probestr, *configfile;
174 unsigned int timestampf, maxaddrentries, maxcandentries, addrtimeout, candaddrtimeout, maxunprobedint;
175 unsigned int unicastprobeint, mcechoprobeint, mcunrecprobeint;
176
177 unsigned char logfile_f=0, lockfile_f=0, unprivuser_f=0, unprivgroup_f=0, probetype_f=0, timestampf_f=0;
178 unsigned char maxaddrentries_f=0, maxcandentries_f=0, addrtimeout_f=0, candaddrtimeout_f=0;
179 unsigned char maxunprobedint_f=0, unicastprobeint_f=0, mcechoprobeint_f=0, mcunrecprobeint_f=0;
180 unsigned char configfile_f=0, showconfig_f=0, shutdown_f=0;
181
182 /* For the log file */
183 FILE *fplog;
184
185 /* Used to store the all-nodes onlink address */
186 struct in6_addr all_nodes_onlink;
187
188 /* For I/O multiplexing */
189 fd_set rset, wset, eset;
190
191 /* Current time */
192 time_t curtime;
193
main(int argc,char ** argv)194 int main(int argc, char **argv){
195 extern char *optarg;
196 extern int optind;
197 struct passwd *pwdptr;
198 struct group *grpptr;
199 fd_set sset;
200 int sel;
201 struct timeval timeout;
202 int result;
203 struct sigaction sa;
204 unsigned char error_f=0;
205 struct host_entry *hptr;
206 struct ether_header *pkt_ether;
207 struct ip6_hdr *pkt_ipv6;
208 struct icmp6_hdr *pkt_icmp6;
209 struct nd_neighbor_solicit *pkt_ns;
210 unsigned char *pkt_end;
211
212 static struct option longopts[] = {
213 {"config-file", required_argument, 0, 'c'},
214 {"show-config", no_argument, 0, 'q'},
215 {"verbose", no_argument, 0, 'v'},
216 {"help", no_argument, 0, 'h'}
217 };
218
219 char shortopts[]= "c:qvh";
220
221 char option;
222
223 hoplimit=255;
224
225 while((option=getopt_long(argc, argv, shortopts, longopts, NULL)) != -1){
226 switch(option) {
227 case 'c': /* Configuration file */
228 if( (configfile= malloc(strlen(optarg)+1)) == NULL){
229 error_f=1;
230 break;
231 }
232
233 strncpy(configfile, optarg, strlen(optarg)+1);
234 configfile_f=1;
235 break;
236
237 case 'q':
238 showconfig_f=1;
239 break;
240
241 case 'v': /* Be verbose */
242 verbose_f++;
243 break;
244
245 case 'h': /* Help */
246 print_help();
247 exit(1);
248 break;
249
250 default:
251 usage();
252 exit(1);
253 break;
254
255 } /* switch */
256 } /* while(getopt) */
257
258 if(!showconfig_f)
259 openlog("ipv6mon", LOG_CONS, LOG_DAEMON);
260
261 if(error_f){
262 if(showconfig_f)
263 puts("Error while allocating memory to store configuration file pathname");
264 else
265 syslog(LOG_ERR, "Error while allocating memory to store configuration file pathname");
266
267 exit(1);
268 }
269
270 if(geteuid()) {
271 if(showconfig_f)
272 puts("ipv6mon needs superuser privileges to run");
273 else
274 syslog(LOG_ERR, "ipv6mon needs superuser privileges to run");
275
276 exit(1);
277 }
278
279 if(!configfile_f){
280 configfile=IPV6MON_CONF;
281 }
282
283 if(process_config_file(configfile) == -1)
284 exit(1);
285
286 if(init_iface_data(&idata) != 0){
287 if(showconfig_f)
288 puts("Error initializing internal idata structure");
289 else
290 syslog(LOG_ERR, "Error initializing internal idata structure");
291
292 exit(1);
293 }
294
295 if(init_host_list(&hlist) !=0){
296 if(showconfig_f)
297 puts("Error initializing internal host_list structure");
298 else
299 syslog(LOG_ERR, "Error initializing internal host_list structure");
300
301 exit(1);
302 }
303
304 if(!iface_f){
305 if(showconfig_f)
306 puts("Must specify the network interface with the 'NetworkInterface' variable");
307 else
308 syslog(LOG_ERR, "Network Interface card not specified");
309
310 exit(1);
311 }
312
313 if(showconfig_f){
314 if(probe_echo_f){
315 if(probe_unrec_f)
316 probestr="all";
317 else
318 probestr="echo";
319 }
320 else
321 probestr="unrec";
322
323 printf("NetworkInterface: %s\n", idata.iface);
324 printf("AddressLogFile: %s\n", logfile);
325 printf("LockFile: %s\n", lockfile);
326 printf("UnprivilegedUser: %s\n", unprivuser);
327 printf("UnprivilegedGroup: %s\n", unprivgroup);
328 printf("TimestampFormat: %s\n", (timestampf==TIMESTAMP_DATE)?"date":"epoch");
329 printf("MaxAddressEntries: %u\n", maxaddrentries);
330 printf("MaxCandidateEntries: %u\n", maxcandentries);
331 printf("AddressTimeout: %u\n", addrtimeout);
332 printf("CandidateAddressTimeout: %u\n", candaddrtimeout);
333 printf("MaxUnprobedInterval: %u\n", maxunprobedint);
334 printf("UnicastProbeInterval: %u\n", unicastprobeint);
335 printf("McastEchoProbeInterval: %u\n", mcechoprobeint);
336 printf("McastUnrecProbeInterval: %u\n", mcunrecprobeint);
337 printf("ProbeType: %s\n", probestr);
338 exit(0);
339 }
340
341 /*
342 We close the file descriptor for syslog. make_daemon() will close all open descriptors, and open
343 a new one for syslog()
344 */
345 closelog();
346
347 if(make_daemon() == -1){
348 syslog(LOG_ERR, "Failed when trying to become daemon");
349 exit(1);
350 }
351
352 if( (result=already_running()) == 1){
353 syslog(LOG_ERR, "Another instance of ipv6mon is already running");
354 exit(5);
355 }
356 else if(result == -1){
357 syslog(LOG_ERR, "Error in already running():");
358 exit(1);
359 }
360
361 /* Log file should be rw for the owner, readable by the group, with no access to others */
362 umask(S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH);
363
364 if( (fplog=fopen(logfile, "a")) == NULL){
365 syslog(LOG_ERR, "Error opening logfile (%m)");
366 exit(1);
367 }
368
369 if( (sfd= pcap_open_live(idata.iface, PCAP_SNAP_LEN, PCAP_PROMISC, PCAP_TIMEOUT, errbuf)) == NULL){
370 syslog(LOG_ERR, "Opening pcap device: %s", errbuf);
371 return(-1);
372 }
373
374 if( pcap_datalink(sfd) != DLT_EN10MB){
375 syslog(LOG_ERR, "Interface '%s' is not of supported interface types", iface);
376 return(-1);
377 }
378
379 /*
380 We to setuid() to UnprivilegedUser, and setgid to UnprivilegedGroup, thus releasing superuser
381 privileges.
382 */
383 if((grpptr=getgrnam(unprivgroup)) != NULL){
384 if(!grpptr->gr_gid){
385 syslog(LOG_ERR, "Group %s has incorrect privileges", unprivuser);
386 exit(1);
387 }
388
389 if(setgid(grpptr->gr_gid) == -1){
390 syslog(LOG_ERR, "Error while releasing superuser privileges (changing to group '%s')", unprivgroup);
391 exit(1);
392 }
393 }
394 else{
395 syslog(LOG_ERR, "Error while releasing superuser privileges (group '%s' does not exist)", unprivgroup);
396 exit(1);
397 }
398
399
400 if((pwdptr=getpwnam(unprivuser))){
401 if(!pwdptr->pw_uid || !pwdptr->pw_gid){
402 syslog(LOG_ERR, "User %s has incorrect privileges", unprivuser);
403 exit(1);
404 }
405
406 if(setuid(pwdptr->pw_uid) == -1){
407 syslog(LOG_ERR, "Error while releasing superuser privileges (changing to user '%s')", unprivuser);
408 exit(1);
409 }
410 }
411 else{
412 syslog(LOG_ERR, "Error while releasing superuser privileges (user '%s' does not exist)", unprivuser);
413 exit(1);
414 }
415
416
417 if(pcap_compile(sfd, &pcap_filter, PCAP_IPV6MON_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1){
418 syslog(LOG_ERR, "pcap_compile(): %s", pcap_geterr(sfd));
419 exit(1);
420 }
421
422 if(pcap_setfilter(sfd, &pcap_filter) == -1){
423 syslog(LOG_ERR, "pcap_setfilter(): %s", pcap_geterr(sfd));
424 exit(1);
425 }
426
427 pcap_freecode(&pcap_filter);
428
429 srand(time(NULL));
430
431 hlist.mc_unrec_probe_f= probe_unrec_f;
432 hlist.mc_echo_probe_f= probe_echo_f;
433
434 if(get_if_addrs(&idata) == -1){
435 syslog(LOG_ERR, "Error in get_if_addrs()");
436 exit(1);
437 }
438
439 if(!idata.ether_flag){
440 randomize_ether_addr(&idata.ether);
441 idata.ether_flag=1;
442 }
443
444 if(!idata.ip6_local_flag){
445 ether_to_ipv6_linklocal(&idata.ether, &idata.ip6_local);
446 idata.ip6_local_flag=1;
447 }
448
449 if ( inet_pton(AF_INET6, ALL_NODES_MULTICAST_ADDR, &all_nodes_onlink) <= 0){
450 syslog(LOG_ERR, "Error when converting all-nodes online multicast to binary format");
451 exit(1);
452 }
453
454 idata.mtu= ETH_DATA_LEN;
455
456 idata.ip6_global_conftime= time(NULL);
457 idata.ip6_global_lastcheck= time(NULL);
458
459 if( (idata.fd= pcap_fileno(sfd)) == -1){
460 syslog(LOG_ERR, "Error obtaining descriptor number for pcap_t");
461 exit(1);
462 }
463
464 FD_ZERO(&sset);
465 FD_SET(idata.fd, &sset);
466
467 /* Catch SIGTERM so that we can do a clean shutdown */
468 sa.sa_handler = sigterm;
469 sigemptyset(&sa.sa_mask);
470 sa.sa_flags = 0;
471
472 if(sigaction(SIGTERM, &sa, NULL) < 0){
473 if(verbose_f)
474 syslog(LOG_ERR, "Error while setting handler for SIGTERM");
475
476 exit(1);
477 }
478
479 /* Write the initialization notice to the log file */
480 if(log_start(&idata) == -1){
481 syslog(LOG_ERR, "Error while writing to log file");
482 exit(1);
483 }
484
485 while(1){
486 rset= sset;
487 wset= sset;
488 eset= sset;
489
490 timeout.tv_usec=0;
491 timeout.tv_sec= SELECT_TIMEOUT;
492
493 if(shutdown_f){
494 if(log_stop(&idata) == -1){
495 syslog(LOG_ERR, "Error while stopping the ipv6mon daemon");
496 exit(1);
497 }
498
499 exit(0);
500 }
501
502 /*
503 Check for readability and exceptions. We only check for writeability if there is pending data
504 to send (the pcap descriptor will usually be writeable!).
505 */
506 if((sel=select(idata.fd+1, &rset, (idata.pending_write_f?&wset:NULL), &eset, &timeout)) == -1){
507 if(errno == EINTR){
508 continue;
509 }
510 else{
511 syslog(LOG_ERR, "Error in select() loop (%m)");
512
513 if(log_stop(&idata) == -1){
514 syslog(LOG_ERR, "Error while stopping the ipv6mon daemon");
515 }
516
517 exit(1);
518 }
519 }
520
521 curtime = time(NULL);
522
523 if(sel == 0 && (curtime-hlist.lastgcollection) > MAX_GARB_COLLECT_INT && \
524 (curtime-hlist.lastprocessed) > MAX_GARB_COLLECT_INT){
525 if(gcollection_host_entries(&idata, &hlist) == -1){
526 syslog(LOG_ERR, "Error while doing garbage collection");
527
528 if(log_stop(&idata) == -1){
529 syslog(LOG_ERR, "Error while stopping the ipv6mon daemon");
530 }
531
532 exit(1);
533 }
534
535 hlist.lastgcollection=curtime;
536 }
537
538 /*
539 If we didn't check for writeability in the previous call to select(), we must do it now. Otherwise, we might
540 block when trying to send a packet.
541 */
542 if(!idata.pending_write_f){
543 wset= sset;
544
545 timeout.tv_usec=0;
546 timeout.tv_sec= 0;
547
548 if( (sel=select(idata.fd+1, NULL, &wset, NULL, &timeout)) == -1){
549 if(errno == EINTR){
550 continue;
551 }
552 else{
553 syslog(LOG_ERR, "Error in select() loop (%m)");
554
555 if(log_stop(&idata) == -1){
556 syslog(LOG_ERR, "Error while stopping the ipv6mon daemon");
557 }
558
559 exit(1);
560 }
561 }
562 }
563
564 if( (idata.ip6_global_flag == VALID_MAPPING) && \
565 (curtime - idata.ip6_global_lastcheck) >= LOCAL_ADDRESS_TIMEOUT){
566
567 if(check_local_addresses(&idata) == -1){
568 syslog(LOG_ERR, "Error in check_local_addresses()");
569 exit(1);
570 }
571 }
572
573 /* If we had not configured any global address, retry now */
574 if( (idata.ip6_global_flag != VALID_MAPPING) && ((curtime - idata.ip6_global_conftime) >= RETRY_CONFIG)){
575 if(get_if_addrs(&idata) == -1){
576 syslog(LOG_ERR, "Error in get_if_addrs()");
577 exit(1);
578 }
579
580 idata.ip6_global_conftime= curtime;
581 }
582
583 if(FD_ISSET(idata.fd, &wset)){
584 curtime = time(NULL);
585
586 if(idata.pending_write_f){
587 /* There was something to send from a previous iteration, but there was no space left in the
588 send buffer
589 */
590
591 if((nw=pcap_inject(sfd, idata.pending_write_data, idata.pending_write_size)) < 0){
592 syslog(LOG_ERR, "Error injecting packet in main loop: pcap_inject(): %s", \
593 pcap_geterr(sfd));
594
595 if(log_stop(&idata) == -1){
596 syslog(LOG_ERR, "Error while stopping the ipv6mon daemon");
597 }
598
599 exit(1);
600 }
601
602 if(nw != idata.pending_write_size){
603 if(verbose_f)
604 syslog(LOG_ERR, "pcap_inject(): only wrote %lu bytes "
605 "(rather than %lu bytes)\n", (LUI) nw, \
606 (LUI) (idata.pending_write_size));
607
608 idata.write_errors++;
609
610 if(idata.write_errors > 10){
611 syslog(LOG_ERR, "Too many write errors");
612
613 if(log_stop(&idata) == -1){
614 syslog(LOG_ERR, "Error while stopping the ipv6mon daemon");
615 }
616
617 exit(1);
618 }
619 }
620
621 idata.pending_write_f=0;
622 idata.write_errors=0;
623 }
624
625 else if( (( (idata.ip6_global.nprefix - idata.ip6_global_nconfig) && \
626 ((curtime - idata.ip6_global_lastcheck) >= CHECK_CONFIG_INTERVAL)) ||
627 ((curtime - idata.ip6_global_conftime) < RA_ACCEPT_WINDOW)) && \
628 ((curtime - idata.last_rs) >= RS_SEND_INTERVAL)){
629
630 idata.last_rs=curtime;
631
632 if(send_router_solicit(sfd, &idata) == -1){
633 syslog(LOG_ERR, "Error sending Router Solicitation message");
634
635 if(log_stop(&idata) == -1){
636 syslog(LOG_ERR, "Error while stopping the ipv6mon daemon");
637 }
638
639 exit(1);
640 }
641 }
642
643 else if( hlist.mc_echo_probe_f && ((curtime - hlist.mc_echo_last) >= mcechoprobeint)){
644 hlist.mc_echo_last= curtime;
645
646 if(send_multicast_probe(sfd, &idata, &hlist, PROBE_ICMP6_ECHO) != 0){
647 syslog(LOG_ERR, "Error when sending multicast probe");
648
649 if(log_stop(&idata) == -1){
650 syslog(LOG_ERR, "Error while stopping the ipv6mon daemon");
651 }
652
653 exit(1);
654 }
655
656 }
657 else if( hlist.mc_unrec_probe_f && ((curtime - hlist.mc_unrec_last) >= mcunrecprobeint)){
658 hlist.mc_unrec_last= curtime;
659
660 if(send_multicast_probe(sfd, &idata, &hlist, PROBE_UNREC_OPT) != 0){
661 syslog(LOG_ERR, "Error when sending multicast probe");
662
663 if(log_stop(&idata) == -1){
664 syslog(LOG_ERR, "Error while stopping the ipv6mon daemon");
665 }
666
667 exit(1);
668 }
669 }
670 else if( (curtime - hlist.lastprocessed) > MAX_PROC_ENTRIES_INT){
671 if(process_host_entries(sfd, &idata, &hlist) != 0){
672 syslog(LOG_ERR, "Error while processing host entries");
673
674 if(log_stop(&idata) == -1){
675 syslog(LOG_ERR, "Error while stopping the ipv6mon daemon");
676 }
677
678 exit(1);
679 }
680 }
681 }
682
683 if(FD_ISSET(idata.fd, &rset)){
684 error_f=0;
685
686 do{
687 if((result=pcap_next_ex(sfd, &pkthdr, &pktdata)) == -1){
688 error_f=1;
689 break;
690 }
691 }while(result==0);
692
693 if(error_f){
694 syslog(LOG_ERR, "Error while reading packet in main loop: pcap_next_ex(): %s", pcap_geterr(sfd));
695
696 if(log_stop(&idata) == -1){
697 syslog(LOG_ERR, "Error while stopping the ipv6mon daemon");
698 }
699
700 exit(1);
701 }
702
703 pkt_ether = (struct ether_header *) pktdata;
704 pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_ether + ETHER_HDR_LEN);
705 pkt_icmp6 = (struct icmp6_hdr *) ((char *) pkt_ipv6 + sizeof(struct ip6_hdr));
706 pkt_ns= (struct nd_neighbor_solicit *) pkt_icmp6;
707 pkt_end = (unsigned char *) pktdata + pkthdr->caplen;
708
709 if( (pkt_end - pktdata) < (ETHER_HDR_LEN + MIN_IPV6_HLEN))
710 continue;
711
712 if(pkt_ipv6->ip6_nxt == IPPROTO_ICMPV6){
713 if(pkt_icmp6->icmp6_type == ND_NEIGHBOR_SOLICIT){
714 if( (pkt_end - (unsigned char *) pkt_ns) < sizeof(struct nd_neighbor_solicit))
715 continue;
716
717 /*
718 If the addresses that we're using are not actually configured on the local system
719 (i.e., they are "spoofed", we must check whether it is a Neighbor Solicitation for
720 one of our addresses, and respond with a Neighbor Advertisement. Otherwise, the kernel
721 will take care of that.
722 */
723 if(is_ip6_in_address_list(&(idata.ip6_global), &(pkt_ns->nd_ns_target)) || \
724 is_eq_in6_addr(&(pkt_ns->nd_ns_target), &(idata.ip6_local))){
725 if(send_neighbor_advert(&idata, sfd, pktdata) == -1){
726 syslog(LOG_ERR, "Error sending Neighbor Advertisement message");
727
728 if(log_stop(&idata) == -1){
729 syslog(LOG_ERR, "Error while stopping the ipv6mon daemon");
730 }
731
732 exit(1);
733 }
734 }
735 else{
736 /*
737 Check whether it is a Duplicate Address Detection (DAD) packet, and if so, add the ND
738 Target Address as a "candidate" address
739 */
740
741 /* The Source Address of the DAD packets must be the Unspecified address (::) */
742 if(!IN6_IS_ADDR_UNSPECIFIED(&(pkt_ipv6->ip6_src))){
743 continue;
744 }
745
746 /* DAD packets are destined to multicast addresses (solicited-node) */
747 if(!IN6_IS_ADDR_MULTICAST(&(pkt_ipv6->ip6_dst))){
748 continue;
749 }
750
751 /*
752 We do some sanity checks on the ND Target Address: It must not be any of the following:
753 a multicast address, the unspecified address, the loopback address, or any of our own
754 addresses
755 */
756 if(IN6_IS_ADDR_MULTICAST(&(pkt_ns->nd_ns_target)) || \
757 IN6_IS_ADDR_UNSPECIFIED(&(pkt_ns->nd_ns_target)) || \
758 IN6_IS_ADDR_LOOPBACK(&(pkt_ns->nd_ns_target)) || \
759 is_ip6_in_address_list(&(idata.ip6_global), &(pkt_ns->nd_ns_target)) || \
760 is_eq_in6_addr(&(pkt_ns->nd_ns_target), &(idata.ip6_local))){
761 continue;
762 }
763
764 if(hlist.ncandidates >= hlist.maxcandidates){
765 syslog(LOG_INFO, "Couldn't add candidate address: Reached limit (%u)"
766 " of candidate addresses", hlist.maxcandidates);
767 continue;
768 }
769
770 if( (hptr=add_host_entry(&hlist, &(pkt_ns->nd_ns_target), &(pkt_ether->src))) == NULL){
771 syslog(LOG_INFO, "Error while adding new host entry");
772 continue;
773 }
774
775 hptr->flag= INVALID_MAPPING;
776 hlist.ncandidates++;
777 }
778 }
779 else if( (pkt_icmp6->icmp6_type == ICMP6_ECHO_REPLY) || (pkt_icmp6->icmp6_type == ICMP6_PARAM_PROB)){
780 if( (pkt_end - (unsigned char *) pkt_icmp6) < sizeof(struct icmp6_hdr))
781 continue;
782
783 /*
784 Do a preliminar validation check on the ICMPv6 packet (packet size, Source Address,
785 and Destination Address).
786 */
787 if(valid_icmp6_response(&idata, &hlist, pkthdr, pktdata)){
788 hptr=is_ip6_in_list(&hlist, &(pkt_ipv6->ip6_src));
789 curtime= time(NULL);
790
791 if( hptr != NULL){
792 hptr->nprobes= 0;
793 hptr->lseen= curtime;
794
795 if(hptr->flag != VALID_MAPPING){
796 hptr->flag= VALID_MAPPING;
797 hptr->fseen= curtime;
798
799 if(hlist.ncandidates){
800 (hlist.ncandidates)--;
801 }
802 else{
803 syslog(LOG_ERR, "Candidates number is trashed!");
804
805 if(log_stop(&idata) == -1){
806 syslog(LOG_ERR, "Error while stopping the ipv6mon daemon");
807 }
808
809 exit(1);
810 }
811
812 if( log_hentry(&idata, hptr, &(hptr->fseen), ADD_ENTRY) != 0){
813 syslog(LOG_ERR, "Error while logging new entry");
814
815 if(log_stop(&idata) == -1){
816 syslog(LOG_ERR, "Error while stopping the ipv6mon daemon");
817 }
818
819 exit(1);
820 }
821 }
822 }
823 else{
824 if( (hptr=add_host_entry(&hlist, &(pkt_ipv6->ip6_src), &(pkt_ether->src))) == NULL){
825 syslog(LOG_INFO, "Error while adding new host entry");
826 continue;
827 }
828
829 if( log_hentry(&idata, hptr, &(hptr->fseen), ADD_ENTRY) != 0){
830 syslog(LOG_ERR, "Error while logging new entry");
831
832 if(log_stop(&idata) == -1){
833 syslog(LOG_ERR, "Error while stopping the ipv6mon daemon");
834 }
835
836 exit(1);
837 }
838
839 if( (result=create_candidate_andress(&idata, &hlist, hptr)) == -1){
840 syslog(LOG_ERR, "Error while adding candidate addresses");
841 continue;
842 }
843 else if(result==0){
844 syslog(LOG_INFO, "Could not add candidate address: Reached limit of "
845 "%u candidate addresses", hlist.maxcandidates);
846 continue;
847 }
848 }
849 }
850 }
851 else if(pkt_icmp6->icmp6_type == ND_ROUTER_ADVERT){
852 if(process_router_advert(&idata, pkthdr, pktdata) == -1){
853 syslog(LOG_ERR, "Error while processing Router Advertisement"); /* XXX */
854 continue;
855 }
856 }
857 }
858 }
859
860 if(FD_ISSET(idata.fd, &eset)){
861 syslog(LOG_ERR, "Found exception on pcap_t");
862 continue;
863 }
864 }
865
866 exit(0);
867 }
868
869
870
871 /*
872 * Function: usage()
873 *
874 * Prints the syntax of the na-attack tool
875 */
usage(void)876 void usage(void){
877 puts("usage: ipv6mon [-c CONFIG_FILE] [-q] [-v] [-h]");
878 }
879
880
881 /*
882 * Function: print_help()
883 *
884 * Prints help information for the na-attack tool
885 */
print_help(void)886 void print_help(void){
887 puts( "ipv6mon version 0.2\nAn IPv6 Address Monitoring tool\n");
888 usage();
889
890 puts("\nOPTIONS:\n"
891 " --config-file, -c Configuration file pathname (defaults to '"
892 IPV6MON_CONF "')\n"
893 " --show-config, -q Shows configuration values and quits\n"
894 " --help, -h Print help for the scan6 tool\n"
895 " --verbose, -v Be verbose\n"
896 "\n"
897 " Programmed by Fernando Gont on behalf of CPNI (http://www.cpni.gov.uk)\n"
898 " Please send any bug reports to <fgont@si6networks.com>\n"
899 );
900 }
901
902
903 /*
904 * Function: in_chksum()
905 *
906 * Calculate the 16-bit ICMPv6 checksum
907 */
908
in_chksum(void * ptr_ipv6,void * ptr_icmpv6,size_t len)909 u_int16_t in_chksum(void *ptr_ipv6, void *ptr_icmpv6, size_t len){
910 struct ipv6pseudohdr pseudohdr;
911 struct ip6_hdr *v6packet;
912 size_t nleft;
913 unsigned int sum= 0;
914 u_int16_t *w;
915 u_int16_t answer= 0;
916
917 v6packet=ptr_ipv6;
918
919 bzero(&pseudohdr, sizeof(struct ipv6pseudohdr));
920 pseudohdr.srcaddr= v6packet->ip6_src;
921 pseudohdr.dstaddr= v6packet->ip6_dst;
922 pseudohdr.len = htons(len);
923 pseudohdr.nh = IPPROTO_ICMPV6;
924
925 nleft=40;
926 w= (u_int16_t *) &pseudohdr;
927
928 while(nleft > 1){
929 sum += *w++;
930 nleft -= 2;
931 }
932
933 nleft= len;
934 w= (u_int16_t *) ptr_icmpv6;
935
936 while(nleft > 1){
937 sum += *w++;
938 nleft -= 2;
939 }
940
941 if(nleft == 1){
942 *(unsigned char *) (&answer) = *(unsigned char *) w;
943 sum += answer;
944 }
945
946 sum = (sum >> 16) + (sum & 0xffff);
947 sum += (sum >> 16);
948 answer = ~sum;
949 return(answer);
950 }
951
952
953
954 /*
955 * Function: ether_pton()
956 *
957 * Convert a string (printable Ethernet Address) into binary format
958 */
959
ether_pton(const char * ascii,struct ether_addr * etheraddr,unsigned int s)960 int ether_pton(const char *ascii, struct ether_addr *etheraddr, unsigned int s){
961 unsigned int i, a[6];
962
963 if(s < ETHER_ADDR_LEN)
964 return 0;
965
966 if(ascii){
967 if( sscanf(ascii,"%x:%x:%x:%x:%x:%x", &a[0], &a[1], &a[2], &a[3], &a[4], &a[5]) == 6){
968 for(i=0;i<6;i++)
969 etheraddr->a[i]= a[i];
970
971 return 1;
972 }
973 }
974
975 return 0;
976 }
977
978
979
980 /*
981 * Function: ether_ntop()
982 *
983 * Convert binary Ethernet Address into printable foramt (an ASCII string)
984 */
985
ether_ntop(const struct ether_addr * ether,char * ascii,size_t s)986 int ether_ntop(const struct ether_addr *ether, char *ascii, size_t s){
987 unsigned int r;
988
989 if(s < ETHER_ADDR_PLEN)
990 return 0;
991
992 r=snprintf(ascii, s, "%02x:%02x:%02x:%02x:%02x:%02x", ether->a[0], ether->a[1], ether->a[2], ether->a[3], \
993 ether->a[4], ether->a[5]);
994
995 if(r != 17)
996 return 0;
997
998 return 1;
999 }
1000
1001
1002 /*
1003 * Function match_ipv6()
1004 *
1005 * Finds if an IPv6 address matches a prefix in a list of prefixes.
1006 */
1007
match_ipv6(struct in6_addr * prefixlist,u_int8_t * prefixlen,unsigned int nprefix,struct in6_addr * ipv6addr)1008 unsigned int match_ipv6(struct in6_addr *prefixlist, u_int8_t *prefixlen, unsigned int nprefix,
1009 struct in6_addr *ipv6addr){
1010
1011 unsigned int i;
1012 struct in6_addr dummyipv6;
1013
1014 for(i=0; i<nprefix; i++){
1015 dummyipv6 = *ipv6addr;
1016 sanitize_ipv6_prefix(&dummyipv6, prefixlen[i]);
1017
1018 for(j=0; j<4; j++)
1019 if(dummyipv6.s6_addr32[j] != prefixlist[i].s6_addr32[j])
1020 break;
1021
1022 if(j==4)
1023 return 1;
1024 }
1025
1026 return 0;
1027 }
1028
1029
1030 /*
1031 * match_ether()
1032 *
1033 * Finds if an Ethernet address matches any of the Ethernet addreses contained in an array.
1034 */
1035
match_ether(struct ether_addr * addrlist,unsigned int naddr,struct ether_addr * linkaddr)1036 unsigned int match_ether(struct ether_addr *addrlist, unsigned int naddr, \
1037 struct ether_addr *linkaddr){
1038
1039 unsigned int i, j;
1040
1041 for(i=0; i<naddr; i++){
1042 for(j=0; j<6; j++)
1043 if(linkaddr->a[j] != addrlist[i].a[j])
1044 break;
1045
1046 if(j==6)
1047 return 1;
1048 }
1049
1050 return 0;
1051 }
1052
1053
1054
1055 /*
1056 * sanitize_ipv6_prefix()
1057 *
1058 * Clears those bits in an IPv6 address that are not within a prefix length.
1059 */
1060
sanitize_ipv6_prefix(struct in6_addr * ipv6addr,u_int8_t prefixlen)1061 void sanitize_ipv6_prefix(struct in6_addr *ipv6addr, u_int8_t prefixlen){
1062 unsigned int skip, i;
1063 u_int16_t mask;
1064
1065 skip= (prefixlen+15)/16;
1066
1067 if(prefixlen%16){
1068 mask=0;
1069 for(i=0; i<(prefixlen%16); i++)
1070 mask= (mask>>1) | 0x8000;
1071
1072 ipv6addr->s6_addr16[skip-1]= ipv6addr->s6_addr16[skip-1] & htons(mask);
1073 }
1074
1075 for(i=skip;i<8;i++)
1076 ipv6addr->s6_addr16[i]=0;
1077 }
1078
1079
1080 /*
1081 * randomize_ipv6_addr()
1082 *
1083 * Select a random IPv6 from a given prefix.
1084 */
1085
randomize_ipv6_addr(struct in6_addr * ipv6addr,struct in6_addr * prefix,u_int8_t preflen)1086 void randomize_ipv6_addr(struct in6_addr *ipv6addr, struct in6_addr *prefix, u_int8_t preflen){
1087 u_int16_t mask;
1088 u_int8_t startrand;
1089 unsigned int i;
1090
1091 startrand= preflen/16;
1092
1093 for(i=0; i<startrand; i++)
1094 ipv6addr->s6_addr16[i]= 0;
1095
1096 for(i=startrand; i<8; i++)
1097 ipv6addr->s6_addr16[i]=random();
1098
1099 if(preflen%16){
1100 mask=0xffff;
1101
1102 for(i=0; i<(preflen%16); i++)
1103 mask= mask>>1;
1104
1105 ipv6addr->s6_addr16[startrand]= ipv6addr->s6_addr16[startrand] & htons(mask);
1106 }
1107
1108 for(i=0; i<=(preflen/16); i++)
1109 ipv6addr->s6_addr16[i]= ipv6addr->s6_addr16[i] | prefix->s6_addr16[i];
1110
1111 }
1112
1113
1114
1115 /*
1116 * randomize_ether_addr()
1117 *
1118 * Select a random Ethernet address.
1119 */
1120
randomize_ether_addr(struct ether_addr * ethaddr)1121 void randomize_ether_addr(struct ether_addr *ethaddr){
1122 for(i=0; i<6; i++)
1123 ethaddr->a[i]= random();
1124
1125 ethaddr->a[0]= (ethaddr->a[0] & 0xfc) | 0x02;
1126 }
1127
1128
1129 /*
1130 * Function: insert_pad_opt()
1131 *
1132 * Insert a padding option (Pad1 or PadN) into an IPv6 extension header
1133 */
1134
insert_pad_opt(unsigned char * ptrhdr,const unsigned char * ptrhdrend,unsigned int padn)1135 int insert_pad_opt(unsigned char *ptrhdr, const unsigned char *ptrhdrend, unsigned int padn){
1136 unsigned char *ptr;
1137
1138 if( (ptrhdrend - ptrhdr) < padn)
1139 return 0;
1140
1141 if(padn == 1){
1142 *ptrhdr= 0x00;
1143 return 1;
1144 }
1145 else{
1146 ptr=ptrhdr;
1147 *ptr= 0x01;
1148 ptr++;
1149 *ptr= padn-2;
1150 ptr+=2;
1151
1152 while(ptr < (ptrhdr+padn)){
1153 *ptr= 0x00;
1154 ptr++;
1155 }
1156 return 1;
1157 }
1158 }
1159
1160
1161
1162 /*
1163 * Function: solicited_node()
1164 *
1165 * Obtains the Solicited-node multicast address corresponding to an IPv6 address.
1166 */
1167
solicited_node(const struct in6_addr * ipv6addr)1168 struct in6_addr solicited_node(const struct in6_addr *ipv6addr){
1169 struct in6_addr solicited;
1170
1171 solicited.s6_addr16[0]= htons(0xff02);
1172 solicited.s6_addr16[1]= 0x0000;
1173 solicited.s6_addr16[2]= 0x0000;
1174 solicited.s6_addr16[3]= 0x0000;
1175 solicited.s6_addr16[4]= 0x0000;
1176 solicited.s6_addr16[5]= htons(0x0001);
1177 solicited.s6_addr16[6]= htons(0xff00) | ipv6addr->s6_addr16[6];
1178 solicited.s6_addr16[7]= ipv6addr->s6_addr16[7];
1179
1180 return solicited;
1181 }
1182
1183
1184 /*
1185 * Function: ether_multicast()
1186 *
1187 * Obtains the Ethernet multicast address corresponding to an IPv6 multicast address.
1188 */
1189
ether_multicast(const struct in6_addr * ipv6addr)1190 struct ether_addr ether_multicast(const struct in6_addr *ipv6addr){
1191 unsigned int i;
1192 struct ether_addr ether;
1193
1194 ether.a[0]=0x33;
1195 ether.a[1]=0x33;
1196
1197 for(i=2;i<6;i++)
1198 ether.a[i]= ipv6addr->s6_addr[i+10];
1199
1200 return ether;
1201 }
1202
1203
1204
1205 /*
1206 * Function: init_iface_data()
1207 *
1208 * Initializes the contents of "iface_data" structure
1209 */
1210
init_iface_data(struct iface_data * idata)1211 int init_iface_data(struct iface_data *idata){
1212 bzero(idata, sizeof(struct iface_data));
1213
1214 strncpy(idata->iface, iface, IFACE_LENGTH);
1215 idata->local_retrans = 0;
1216 idata->local_timeout = 1;
1217
1218 idata->ip6_global.prefix= prefix_local;
1219
1220 idata->ip6_global.nprefix=0;
1221 idata->ip6_global.maxprefix= MAX_LOCAL_ADDRESSES;
1222 idata->ip6_global_nconfig=0;
1223 idata->ip6_global_flag= INVALID_MAPPING;
1224
1225 idata->prefix_ol.prefix= prefix_ols;
1226 idata->prefix_ol.nprefix= 0;
1227 idata->prefix_ol.maxprefix= MAX_PREFIXES_ONLINK;
1228
1229 idata->prefix_ac.prefix= prefix_acs;
1230 idata->prefix_ac.nprefix= 0;
1231 idata->prefix_ac.maxprefix= MAX_PREFIXES_AUTO;
1232
1233 idata->pending_write_f= 0;
1234 idata->pending_write_data= NULL;
1235 idata->pending_write_size= 0;
1236
1237 idata->rset= &rset;
1238 idata->wset= &wset;
1239 idata->eset= &eset;
1240 idata->write_errors= 0;
1241 return 0;
1242 }
1243
1244
1245 /*
1246 * Function: process_router_advert()
1247 *
1248 * Process an incoming Router Advertisement message
1249 */
1250
process_router_advert(struct iface_data * idata,struct pcap_pkthdr * pkthdr,const u_char * pktdata)1251 int process_router_advert(struct iface_data *idata, struct pcap_pkthdr *pkthdr, const u_char *pktdata){
1252 struct ip6_hdr *pkt_ipv6;
1253 struct nd_router_advert *pkt_ra;
1254 unsigned char *pkt_end;
1255 unsigned char *p;
1256 struct nd_opt_prefix_info *pio;
1257 unsigned char error_f=0;
1258
1259 pkt_ether = (struct ether_header *) pktdata;
1260 pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_ether + ETHER_HDR_LEN);
1261 pkt_ra = (struct nd_router_advert *) ((char *) pkt_ipv6 + MIN_IPV6_HLEN);
1262 pkt_end = (unsigned char *) pktdata + pkthdr->caplen;
1263
1264
1265 /* The packet length is the minimum of what we capured, and what is specified in the
1266 IPv6 Total Lenght field
1267 */
1268 if( pkt_end > ((unsigned char *)pkt_ra + pkt_ipv6->ip6_plen) )
1269 pkt_end = (unsigned char *)pkt_ra + pkt_ipv6->ip6_plen;
1270
1271 /*
1272 Discard the packet if it is not of the minimum size to contain a Neighbor Advertisement
1273 message with a source link-layer address option
1274 */
1275 if( (pkt_end - (unsigned char *) pkt_ra) < (sizeof(struct nd_router_advert) + \
1276 sizeof(struct nd_opt_slla)))
1277 return 0;
1278
1279 /*
1280 Neighbor Discovery packets must have a Hop Limit of 255
1281 */
1282 if(pkt_ipv6->ip6_hlim != 255)
1283 return 0;
1284
1285 /*
1286 Check that the IPv6 Source Address of the Router Advertisement is an IPv6 link-local
1287 address.
1288 */
1289 if( (pkt_ipv6->ip6_src.s6_addr16[0] & htons(0xffc0)) != htons(0xfe80))
1290 return 0;
1291
1292 /*
1293 Check that that the Destination Address of the Router Advertisement is either the one
1294 that we used for sending the Router Solicitation message or a multicast address
1295 (typically the all-nodes)
1296 */
1297 if(!is_eq_in6_addr(&(pkt_ipv6->ip6_dst), &(idata->ip6_local)) && !IN6_IS_ADDR_MULTICAST(&(pkt_ipv6->ip6_dst)))
1298 return 0;
1299
1300 /* Check that the ICMPv6 checksum is correct. If the received checksum is valid,
1301 and we compute the checksum over the received packet (including the Checkdum field)
1302 the result is 0. Otherwise, the packet has been corrupted.
1303 */
1304 if(in_chksum(pkt_ipv6, pkt_ra, pkt_end- (unsigned char *)pkt_ra) != 0)
1305 return 0;
1306
1307 p= (unsigned char *) pkt_ra + sizeof(struct nd_router_advert);
1308
1309 if( (curtime - idata->ip6_global_conftime) < RA_ACCEPT_WINDOW){
1310 /* Process Router Advertisement options */
1311 while( (p+ *(p+1) * 8) <= pkt_end && *(p+1)!=0 && !error_f){
1312 switch(*p){
1313 case ND_OPT_SOURCE_LINKADDR:
1314 if( (*(p+1) * 8) != sizeof(struct nd_opt_tlla))
1315 break;
1316
1317 /* Save the link-layer address */
1318 idata->router_ether = *(struct ether_addr *) (p+2);
1319 idata->router_ip6= pkt_ipv6->ip6_src;
1320 break;
1321
1322 case ND_OPT_PREFIX_INFORMATION:
1323 if(*(p+1) != 4)
1324 break;
1325
1326 pio= (struct nd_opt_prefix_info *) p;
1327
1328 if((idata->prefix_ol.nprefix) < idata->prefix_ol.maxprefix){
1329 if( (pio->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK) && \
1330 (pio->nd_opt_pi_prefix_len <= 128) && !is_ip6_in_prefix_list(&(pio->nd_opt_pi_prefix), \
1331 &(idata->prefix_ol))){
1332
1333 if( (idata->prefix_ol.prefix[idata->prefix_ol.nprefix] = \
1334 malloc(sizeof(struct prefix_entry))) == NULL){
1335 if(verbose_f)
1336 syslog(LOG_ERR, "process_router_advert(): Error in malloc() while "
1337 "learning prefixes");
1338
1339 error_f=1;
1340 break;
1341 }
1342
1343 (idata->prefix_ol.prefix[idata->prefix_ol.nprefix])->ip6= pio->nd_opt_pi_prefix;
1344 (idata->prefix_ol.prefix[idata->prefix_ol.nprefix])->len= pio->nd_opt_pi_prefix_len;
1345 sanitize_ipv6_prefix(&((idata->prefix_ol.prefix[idata->prefix_ol.nprefix])->ip6), \
1346 (idata->prefix_ol.prefix[idata->prefix_ol.nprefix])->len);
1347 (idata->prefix_ol.nprefix)++;
1348 }
1349 }
1350
1351 if(idata->prefix_ac.nprefix < idata->prefix_ac.maxprefix){
1352 if( (pio->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO) && \
1353 (pio->nd_opt_pi_prefix_len == 64) && !is_ip6_in_prefix_list(&(pio->nd_opt_pi_prefix), \
1354 &(idata->prefix_ac))){
1355
1356 if((idata->prefix_ac.prefix[idata->prefix_ac.nprefix] = \
1357 malloc(sizeof(struct prefix_entry))) == NULL){
1358 if(verbose_f)
1359 syslog(LOG_ERR, "find_ipv6_router_full(): Error in malloc() while "
1360 "learning prefixes");
1361
1362 error_f=1;
1363 break;
1364 }
1365
1366 (idata->prefix_ac.prefix[idata->prefix_ac.nprefix])->ip6= \
1367 pio->nd_opt_pi_prefix;
1368 (idata->prefix_ac.prefix[idata->prefix_ac.nprefix])->len= \
1369 pio->nd_opt_pi_prefix_len;
1370
1371 sanitize_ipv6_prefix(&((idata->prefix_ac.prefix[idata->prefix_ac.nprefix])->ip6), \
1372 (idata->prefix_ac.prefix[idata->prefix_ac.nprefix])->len);
1373
1374 if((idata->ip6_global_flag != VALID_MAPPING) && \
1375 idata->ip6_global.nprefix < idata->ip6_global.maxprefix){
1376
1377 if( (idata->ip6_global.prefix[idata->ip6_global.nprefix] = \
1378 malloc(sizeof(struct prefix_entry))) == NULL){
1379 if(verbose_f)
1380 syslog(LOG_ERR, "find_ipv6_router_full(): Error in malloc() creating "
1381 "local SLAAC addresses");
1382
1383 error_f=1;
1384 break;
1385 }
1386
1387 generate_slaac_address(&(idata->prefix_ac.prefix[idata->prefix_ac.nprefix]->ip6), \
1388 &(idata->ether), &((idata->ip6_global.prefix[idata->ip6_global.nprefix])->ip6));
1389 (idata->ip6_global.prefix[idata->ip6_global.nprefix])->len = 64;
1390 (idata->ip6_global.nprefix)++;
1391 }
1392 (idata->prefix_ac.nprefix)++;
1393 }
1394 }
1395
1396 break;
1397
1398 default:
1399 break;
1400 }
1401
1402 p= p + *(p+1) * 8;
1403 } /* Processing options */
1404
1405
1406 /* If we added at least one global address, we set the corresponding flag to 1 */
1407 if(idata->ip6_global.nprefix)
1408 idata->ip6_global_flag=VALID_MAPPING;
1409 }
1410 /*
1411 If at least one of our addresses was added in response to an RA, we should check whether the corresponding
1412 autoconf prefix is still valid for the local network
1413 */
1414 else if((idata->ip6_global.nprefix - idata->ip6_global_nconfig) > 0){
1415 /* Process Router Advertisement options */
1416 while( (p+ *(p+1) * 8) <= pkt_end && *(p+1)!=0 && !error_f){
1417 switch(*p){
1418 case ND_OPT_PREFIX_INFORMATION:
1419 if(*(p+1) != 4)
1420 break;
1421
1422 pio= (struct nd_opt_prefix_info *) p;
1423
1424 if( (pio->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO) && (pio->nd_opt_pi_prefix_len == 64)){
1425
1426 for(i=idata->ip6_global_nconfig; i < idata->ip6_global.nprefix; i++){
1427 for(j=0; j < 4; j++)
1428 if(pio->nd_opt_pi_prefix.s6_addr16[j] != \
1429 (idata->ip6_global.prefix[i])->ip6.s6_addr16[j])
1430 break;
1431
1432 if(j == 4){
1433 (idata->ip6_global.prefix[i])->tstamp= curtime;
1434 break;
1435 }
1436 }
1437 }
1438
1439 break;
1440
1441 default:
1442 break;
1443 }
1444
1445 p= p + *(p+1) * 8;
1446 } /* Processing options */
1447 }
1448
1449 if(error_f)
1450 return(-1);
1451 else
1452 return 0;
1453 }
1454
1455
1456 /*
1457 * Function: is_eq_in6_addr()
1458 *
1459 * Compares two IPv6 addresses. Returns 1 if they are equal.
1460 */
1461
is_eq_in6_addr(struct in6_addr * ip1,struct in6_addr * ip2)1462 int is_eq_in6_addr(struct in6_addr *ip1, struct in6_addr *ip2){
1463 unsigned int i;
1464
1465 for(i=0; i<8; i++)
1466 if(ip1->s6_addr16[i] != ip2->s6_addr16[i])
1467 return 0;
1468
1469 return 1;
1470 }
1471
1472
1473 /*
1474 * Function: ether_to_ipv6_linklocal()
1475 *
1476 * Generates an IPv6 link-local address (with modified EUI-64 identifiers) based on
1477 * an Ethernet address.
1478 */
1479
ether_to_ipv6_linklocal(struct ether_addr * etheraddr,struct in6_addr * ipv6addr)1480 void ether_to_ipv6_linklocal(struct ether_addr *etheraddr, struct in6_addr *ipv6addr){
1481 ipv6addr->s6_addr16[0]= htons(0xfe80); /* Link-local unicast prefix */
1482
1483 for(i=1;i<4;i++)
1484 ipv6addr->s6_addr16[i]=0x0000;
1485
1486 ipv6addr->s6_addr16[4]= htons(((u_int16_t)(etheraddr->a[0] | 0x02) << 8) | etheraddr->a[1]);
1487 ipv6addr->s6_addr16[5]= htons( ((u_int16_t)etheraddr->a[2] << 8) | 0xff);
1488 ipv6addr->s6_addr16[6]= htons((u_int16_t) 0xfe00 | etheraddr->a[3]);
1489 ipv6addr->s6_addr16[7]= htons(((u_int16_t)etheraddr->a[4] << 8) | etheraddr->a[5]);
1490 }
1491
1492
1493 /*
1494 * Function: generate_slaac_address()
1495 *
1496 * Generates an IPv6 address (with modified EUI-64 identifiers) based on
1497 * a IPv6 prefix and an Ethernet address.
1498 */
1499
generate_slaac_address(struct in6_addr * prefix,struct ether_addr * etheraddr,struct in6_addr * ipv6addr)1500 void generate_slaac_address(struct in6_addr *prefix, struct ether_addr *etheraddr, struct in6_addr *ipv6addr){
1501 ipv6addr->s6_addr16[0]= htons(0xfe80); /* Link-local unicast prefix */
1502
1503 for(i=0;i<4;i++)
1504 ipv6addr->s6_addr16[i]= prefix->s6_addr16[i];
1505
1506 ipv6addr->s6_addr16[4]= htons(((u_int16_t) (etheraddr->a[0] | 0x02) << 8) | etheraddr->a[1]);
1507 ipv6addr->s6_addr16[5]= htons( ((u_int16_t)etheraddr->a[2] << 8) | 0xff);
1508 ipv6addr->s6_addr16[6]= htons((u_int16_t) 0xfe00 | etheraddr->a[3]);
1509 ipv6addr->s6_addr16[7]= htons(((u_int16_t)etheraddr->a[4] << 8) | etheraddr->a[5]);
1510 }
1511
1512
1513 /*
1514 * match_ipv6_to_prefixes()
1515 *
1516 * Finds out whether an IPv6 address matches any IPv6 prefix in an array
1517 */
1518
match_ipv6_to_prefixes(struct in6_addr * ipv6addr,struct in6_addr * prefixes,unsigned char * preflen,unsigned int nprefixes)1519 int match_ipv6_to_prefixes(struct in6_addr *ipv6addr, struct in6_addr *prefixes, unsigned char *preflen, \
1520 unsigned int nprefixes){
1521 unsigned int i, j, full16, rbits;
1522 u_int16_t mask;
1523
1524 for(i=0; i<nprefixes; i++){
1525 full16= preflen[i]/16;
1526 for(j=0; j<full16; j++){
1527 if(ipv6addr->s6_addr16[j] != prefixes[i].s6_addr16[j])
1528 break;
1529 }
1530
1531 if(j == full16){
1532 if((rbits= preflen[i]%16) == 0)
1533 return 1;
1534 else{
1535 mask= 0xffff;
1536 mask= mask<<rbits;
1537 if(prefixes[i].s6_addr16[full16] == (ipv6addr->s6_addr16[full16] & htons(mask)))
1538 return 1;
1539 }
1540 }
1541 }
1542
1543 return 0;
1544 }
1545
1546
1547
1548 /*
1549 * Function: free_host_entries()
1550 *
1551 * Releases memory allocated for holding IPv6 addresses and Ethernet addresses
1552 */
1553
free_host_entries(struct host_list * hlist)1554 void free_host_entries(struct host_list *hlist){
1555 unsigned int i;
1556
1557 for(i=0; i< hlist->nhosts; i++)
1558 free(hlist->host[i]);
1559
1560 hlist->nhosts=0; /* Set the number of entries to 0, to reflect the released memory */
1561 return;
1562 }
1563
1564
1565 /*
1566 * Function: create_candidate_address()
1567 *
1568 * Generates list of cadidate addresses based on a host_entry structure
1569 */
1570
create_candidate_andress(struct iface_data * idata,struct host_list * hlist,struct host_entry * hentry)1571 int create_candidate_andress(struct iface_data *idata, struct host_list *hlist, struct host_entry *hentry){
1572 unsigned int i, j;
1573 struct in6_addr caddr;
1574 struct host_entry *hptr;
1575
1576
1577 /*
1578 We create one candidate address with the Interface-ID of the IPv6 address,
1579 for each of our autoconf prefixes
1580 */
1581 for(i=0; (i < idata->prefix_ac.nprefix) && (hlist->nhosts < hlist->maxhosts); i++){
1582
1583 if(hlist->ncandidates >= hlist->maxcandidates){
1584 syslog(LOG_INFO, "Couldn't add candidate address: Reached limit (%u)"
1585 " of candidate addresses", hlist->maxcandidates);
1586 return 0;
1587 }
1588
1589 for(j=0; j<4; j++)
1590 caddr.s6_addr16[j] = (idata->prefix_ac.prefix[i])->ip6.s6_addr16[j];
1591
1592 for(j=4; j<8; j++)
1593 caddr.s6_addr16[j] = hentry->ip6.s6_addr16[j];
1594
1595 /* We discard the candidate address if it is already present in our list */
1596 if(is_ip6_in_list(hlist, &caddr) != NULL)
1597 continue;
1598
1599 if( (hptr= add_host_entry(hlist, &caddr, &(hentry->ether))) == NULL){
1600 return(-1);
1601 }
1602
1603 hptr->flag= INVALID_MAPPING;
1604 (hlist->ncandidates)++;
1605 }
1606
1607 /*
1608 If the newly-added address is not a link-local address, we create a candidate address with the
1609 link-local prefix (fe80::/64) and the Interface-ID of the newly-added address.
1610 */
1611 if( (hlist->nhosts < hlist->maxhosts) && (hentry->ip6.s6_addr16[0] != htons(0xfe80))){
1612
1613 if(hlist->ncandidates >= hlist->maxcandidates){
1614 syslog(LOG_INFO, "Couldn't add candidate address: Reached limit (%u)"
1615 " of candidate addresses", hlist->maxcandidates);
1616 return 0;
1617 }
1618
1619 for(j=0; j<4; j++)
1620 caddr.s6_addr16[j] = idata->ip6_local.s6_addr16[j];
1621
1622 for(j=4; j<8; j++)
1623 caddr.s6_addr16[j] = hentry->ip6.s6_addr16[j];
1624
1625 /* We discard the candidate address if it is already present in our list */
1626 if(is_ip6_in_list(hlist, &caddr) != NULL)
1627 return 0;
1628
1629 if( (hptr= add_host_entry(hlist, &caddr, &(hentry->ether))) == NULL){
1630 if(verbose_f)
1631 syslog(LOG_ERR, "create_candidate_andress(): Failed to add candidate entry");
1632
1633 return(-1);
1634 }
1635
1636 hptr->flag= INVALID_MAPPING;
1637 (hlist->ncandidates)++;
1638 }
1639
1640 return 0;
1641 }
1642
1643
1644
1645 /*
1646 * Function: src_addr_sel()
1647 *
1648 * Selects a Source Address for a given Destination Address
1649 */
1650
src_addr_sel(struct iface_data * idata,struct in6_addr * dst)1651 struct in6_addr *src_addr_sel(struct iface_data *idata, struct in6_addr *dst){
1652 u_int16_t mask16;
1653 unsigned int i, j, full16, rest16;
1654 /*
1655 If the destination address is a link-local address, we select our link-local
1656 address as the Source Address. If the dst address is a global unicast address
1657 we select our first matching address, or else our first global address.
1658 Worst case scenario, we don't have global address and must use our link-local
1659 address.
1660 */
1661
1662 if( (dst->s6_addr16[0] & htons(0xffc0)) == htons(0xfe80)){
1663 return( &(idata->ip6_local));
1664 }
1665 else if(idata->ip6_global_flag == VALID_MAPPING){
1666 for(i=0; i < idata->ip6_global.nprefix; i++){
1667 full16=(idata->ip6_global.prefix[i])->len / 16;
1668 rest16=(idata->ip6_global.prefix[i])->len % 16;
1669 mask16 = 0xffff;
1670
1671 for(j=0; j < full16; j++)
1672 if( dst->s6_addr16[j] != (idata->ip6_global.prefix[i])->ip6.s6_addr16[j])
1673 break;
1674
1675 if( (j == full16) && rest16){
1676 mask16 = mask16 << (16 - rest16);
1677
1678 if( (dst->s6_addr16[full16] & mask16) == ((idata->ip6_global.prefix[i])->ip6.s6_addr16[full16] \
1679 & mask16))
1680 return( &((idata->ip6_global.prefix[i])->ip6));
1681 }
1682 }
1683
1684 return( &((idata->ip6_global.prefix[0])->ip6));
1685 }
1686 else{
1687 return( &(idata->ip6_local));
1688 }
1689 }
1690
1691
1692 /*
1693 * Function: is_ip6_in_list()
1694 *
1695 * Checks whether an IPv6 address is present in a host list.
1696 */
1697
is_ip6_in_list(struct host_list * hlist,struct in6_addr * target)1698 struct host_entry *is_ip6_in_list(struct host_list *hlist, struct in6_addr *target){
1699 u_int16_t ckey;
1700 struct host_entry *chentry;
1701
1702 ckey= key(hlist, target);
1703
1704 for(chentry= hlist->host[ckey]; chentry != NULL; chentry=chentry->next)
1705 if( is_eq_in6_addr(target, &(chentry->ip6)) )
1706 return chentry;
1707
1708 return NULL;
1709 }
1710
1711
1712 /*
1713 * Function: is_ip6_in_prefix_list()
1714 *
1715 * Checks whether an IPv6 address is present in a prefix list.
1716 */
1717
is_ip6_in_prefix_list(struct in6_addr * target,struct prefix_list * plist)1718 int is_ip6_in_prefix_list(struct in6_addr *target, struct prefix_list *plist){
1719 unsigned int i, j, full16, rest16;
1720 u_int16_t mask16;
1721
1722 for(i=0; i < plist->nprefix; i++){
1723 full16=(plist->prefix[i])->len / 16;
1724 rest16=(plist->prefix[i])->len % 16;
1725 mask16 = 0xffff;
1726
1727 for(j=0; j < full16; j++)
1728 if(target->s6_addr16[j] != (plist->prefix[i])->ip6.s6_addr16[j])
1729 break;
1730
1731 if( (j == full16) && rest16){
1732 mask16 = mask16 << (16 - rest16);
1733
1734 if( (target->s6_addr16[full16] & mask16) == ((plist->prefix[i])->ip6.s6_addr16[full16] & mask16))
1735 return 1;
1736 }
1737 }
1738
1739 return 0;
1740 }
1741
1742 /*
1743 * Function: is_ip6_in_address_list()
1744 *
1745 * Checks whether an IPv6 address is present in an address list.
1746 */
1747
is_ip6_in_address_list(struct prefix_list * plist,struct in6_addr * target)1748 int is_ip6_in_address_list(struct prefix_list *plist, struct in6_addr *target){
1749 unsigned int i, j;
1750
1751 for(i=0; i < plist->nprefix; i++){
1752 for(j=0; j < 8; j++){
1753 if(target->s6_addr16[j] != (plist->prefix[i])->ip6.s6_addr16[j])
1754 break;
1755 }
1756
1757 if(j == 8)
1758 return 1;
1759 }
1760
1761 return 0;
1762 }
1763
1764
1765 /*
1766 * Function: lookup_ip6_in_address_list()
1767 *
1768 * Checks whether an IPv6 address is present in an address list, and returns a pointer to the corresponding entry.
1769 */
1770
lookup_ip6_in_address_list(struct prefix_list * plist,struct in6_addr * target)1771 struct prefix_entry *lookup_ip6_in_address_list(struct prefix_list *plist, struct in6_addr *target){
1772 unsigned int i, j;
1773
1774 for(i=0; i < plist->nprefix; i++){
1775 for(j=0; j < 8; j++){
1776 if(target->s6_addr16[j] != (plist->prefix[i])->ip6.s6_addr16[j])
1777 break;
1778 }
1779
1780 if(j == 8)
1781 return(plist->prefix[i]);
1782 }
1783
1784 return NULL;
1785 }
1786
1787
1788 /*
1789 * Function: send_neighbor_advertisement()
1790 *
1791 * Send a Neighbor advertisement in response to a Neighbor Solicitation message
1792 */
1793
send_neighbor_advert(struct iface_data * idata,pcap_t * pfd,const u_char * pktdata)1794 int send_neighbor_advert(struct iface_data *idata, pcap_t *pfd, const u_char *pktdata){
1795 struct ether_header *pkt_ether;
1796 struct ip6_hdr *pkt_ipv6;
1797 struct nd_neighbor_solicit *pkt_ns;
1798 unsigned char *ptr;
1799 unsigned char *v6buffer;
1800 struct ether_header *ethernet;
1801 struct ip6_hdr *ipv6;
1802 struct nd_neighbor_advert *na;
1803 struct nd_opt_tlla *tllaopt;
1804
1805
1806 ethernet= (struct ether_header *) wbuffer;
1807 v6buffer = (unsigned char *) ethernet + sizeof(struct ether_header);
1808 ipv6 = (struct ip6_hdr *) v6buffer;
1809 na= (struct nd_neighbor_advert *) ((char *) v6buffer + MIN_IPV6_HLEN);
1810 ptr = (unsigned char *) na;
1811
1812 pkt_ether = (struct ether_header *) pktdata;
1813 pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_ether + ETHER_HDR_LEN);
1814 pkt_ns = (struct nd_neighbor_solicit *) ((char *) pkt_ipv6 + MIN_IPV6_HLEN);
1815
1816 ethernet->ether_type = htons(0x86dd);
1817 ipv6->ip6_flow=0;
1818 ipv6->ip6_vfc= 0x60;
1819 ipv6->ip6_hlim= 255;
1820 ipv6->ip6_nxt= IPPROTO_ICMPV6;
1821
1822 if( (ptr+sizeof(struct nd_neighbor_advert)) > (v6buffer+idata->mtu)){
1823 if(verbose_f)
1824 syslog(LOG_ERR, "send_neighbor_advert(): Packet too large while constructing "
1825 "Neighbor Advertisement message");
1826
1827 return(-1);
1828 }
1829
1830 na->nd_na_type = ND_NEIGHBOR_ADVERT;
1831 na->nd_na_code = 0;
1832 ptr += sizeof(struct nd_neighbor_advert);
1833
1834 if( (ptr+sizeof(struct nd_opt_tlla)) <= (v6buffer+idata->mtu) ){
1835 tllaopt = (struct nd_opt_tlla *) ptr;
1836 tllaopt->type= ND_OPT_TARGET_LINKADDR;
1837 tllaopt->length= TLLA_OPT_LEN;
1838 bcopy(idata->ether.a, tllaopt->address, ETH_ALEN);
1839 ptr += sizeof(struct nd_opt_tlla);
1840 }
1841 else{
1842 if(verbose_f)
1843 syslog(LOG_ERR, "send_neighbor_advert(): Packet Too Large while inserting TLLA option in NA message");
1844
1845 return(-1);
1846 }
1847
1848 /* If the IPv6 Source Address of the incoming Neighbor Solicitation is the unspecified
1849 address (::), the Neighbor Advertisement must be directed to the IPv6 all-nodes
1850 multicast address (and the Ethernet Destination address should be 33:33:33:00:00:01).
1851 Otherwise, the Neighbor Advertisement is sent to the IPv6 Source Address (and
1852 Ethernet Source Address) of the incoming Neighbor Solicitation message
1853 */
1854 pkt_ipv6addr = &(pkt_ipv6->ip6_src);
1855
1856 if(IN6_IS_ADDR_UNSPECIFIED(pkt_ipv6addr)){
1857 na->nd_na_flags_reserved = 0;
1858
1859 if ( inet_pton(AF_INET6, ALL_NODES_MULTICAST_ADDR, &(ipv6->ip6_dst)) <= 0){
1860 if(verbose_f)
1861 syslog(LOG_ERR, "send_neighbor_advert(): Error converting all-nodes multicast address");
1862
1863 return(-1);
1864 }
1865
1866 if(ether_pton(ETHER_ALLNODES_LINK_ADDR, &(ethernet->dst), ETHER_ADDR_LEN) == 0){
1867 if(verbose_f)
1868 syslog(LOG_ERR, "send_neighbor_advert(): Error converting all-nodes link-local address");
1869
1870 return(-1);
1871 }
1872 }
1873 else{
1874 ipv6->ip6_dst = pkt_ipv6->ip6_src;
1875 ethernet->dst = pkt_ether->src;
1876
1877 /*
1878 Set the "Solicited" flag if NS was sent from an address other than the unspecified
1879 address (i.e., the response will be unicast).
1880 */
1881
1882 na->nd_na_flags_reserved = ND_NA_FLAG_OVERRIDE | ND_NA_FLAG_SOLICITED;
1883 }
1884
1885 ethernet->src = idata->ether;
1886
1887 /*
1888 If the Neighbor Solicitation message was directed to one of our unicast addresses, the IPv6 Source
1889 Address is set to that address. Otherwise, we set the IPv6 Source Address to our link-local address.
1890 */
1891
1892 pkt_ipv6addr = &(pkt_ipv6->ip6_dst);
1893
1894 if(IN6_IS_ADDR_MULTICAST(pkt_ipv6addr)){
1895 ipv6->ip6_src = idata->ip6_local;
1896 }
1897 else{
1898 if(is_eq_in6_addr(pkt_ipv6addr, &(idata->ip6_local))){
1899 ipv6->ip6_src = idata->ip6_local;
1900 }
1901 else if(idata->ip6_global_flag == VALID_MAPPING){
1902 for(i=0; i < idata->ip6_global.nprefix; i++){
1903 if(is_eq_in6_addr(pkt_ipv6addr, &((idata->ip6_global.prefix[i])->ip6))){
1904 ipv6->ip6_src = (idata->ip6_global.prefix[i])->ip6;
1905 break;
1906 }
1907 }
1908
1909 if(i == idata->ip6_global.nprefix)
1910 return 0;
1911 }
1912 else{
1913 return 0;
1914 }
1915 }
1916
1917 na->nd_na_target= pkt_ns->nd_ns_target;
1918
1919 na->nd_na_cksum = 0;
1920 na->nd_na_cksum = in_chksum(v6buffer, na, ptr-((unsigned char *)na));
1921
1922
1923 ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN);
1924
1925 if(FD_ISSET(idata->fd, idata->wset)){
1926 if((nw=pcap_inject(pfd, wbuffer, ptr - wbuffer)) == -1){
1927 if(verbose_f)
1928 syslog(LOG_ERR, "send_neighbor_advert(): pcap_inject(): %s", pcap_geterr(pfd));
1929
1930 return(-1);
1931 }
1932
1933 if(nw != (ptr-wbuffer)){
1934 if(verbose_f)
1935 syslog(LOG_ERR, "send_neighbor_advert(): pcap_inject(): only wrote %lu bytes "
1936 "(rather than %lu bytes)", (LUI) nw, (LUI) (ptr-wbuffer));
1937
1938 idata->pending_write_f= 1;
1939 idata->pending_write_data= wbuffer;
1940 idata->pending_write_size= ptr- wbuffer;
1941 (idata->write_errors)++;
1942 return(0);
1943 }
1944 }
1945 else{
1946 idata->pending_write_f= 1;
1947 idata->pending_write_data= wbuffer;
1948 idata->pending_write_size= ptr- wbuffer;
1949 }
1950
1951 return 0;
1952 }
1953
1954
1955
1956 /*
1957 * Function: send_router_solicit()
1958 *
1959 * Send a Router Solicitation message
1960 */
1961
send_router_solicit(pcap_t * pfd,struct iface_data * idata)1962 int send_router_solicit(pcap_t *pfd, struct iface_data *idata){
1963 unsigned char *ptr;
1964 unsigned int rs_max_packet_size;
1965 struct ether_header *ether;
1966 unsigned char *v6buffer;
1967 struct ip6_hdr *ipv6;
1968 struct nd_router_solicit *rs;
1969 struct nd_opt_slla *sllaopt;
1970
1971 rs_max_packet_size = idata->mtu;
1972 ether = (struct ether_header *) wbuffer;
1973 v6buffer = (unsigned char *) ether + sizeof(struct ether_header);
1974 ipv6 = (struct ip6_hdr *) v6buffer;
1975
1976 ipv6->ip6_flow=0;
1977 ipv6->ip6_vfc= 0x60;
1978 ipv6->ip6_hlim= 255;
1979 ipv6->ip6_src= idata->ip6_local;
1980
1981 if ( inet_pton(AF_INET6, ALL_ROUTERS_MULTICAST_ADDR, &(ipv6->ip6_dst)) <= 0){
1982 if(verbose_f)
1983 syslog(LOG_ERR, "find_ipv6_router_full(): Error converting All Routers "
1984 "address from presentation to network format");
1985
1986 return(-1);
1987 }
1988
1989 ether->src = idata->ether;
1990
1991 if(ether_pton(ETHER_ALLROUTERS_LINK_ADDR, &(ether->dst), sizeof(struct ether_addr)) == 0){
1992 if(verbose_f)
1993 syslog(LOG_ERR, "find_ipv6_router_full(): ether_pton(): Error converting all-nodes multicast address");
1994
1995 return(-1);
1996 }
1997
1998 ether->ether_type = htons(0x86dd);
1999
2000 prev_nh = (unsigned char *) &(ipv6->ip6_nxt);
2001 *prev_nh = IPPROTO_ICMPV6;
2002
2003 ptr = (unsigned char *) v6buffer + MIN_IPV6_HLEN;
2004
2005 if( (ptr+sizeof(struct nd_router_solicit)) > (v6buffer+rs_max_packet_size)){
2006 if(verbose_f)
2007 syslog(LOG_ERR, "find_ipv6_router_full(): Packet too large while inserting Router Solicitation header");
2008
2009 return(-1);
2010 }
2011
2012 rs= (struct nd_router_solicit *) (ptr);
2013
2014 rs->nd_rs_type = ND_ROUTER_SOLICIT;
2015 rs->nd_rs_code = 0;
2016 rs->nd_rs_reserved = 0;
2017
2018 ptr += sizeof(struct nd_router_solicit);
2019 sllaopt = (struct nd_opt_slla *) ptr;
2020
2021 if( (ptr+sizeof(struct nd_opt_slla)) > (v6buffer+rs_max_packet_size)){
2022 if(verbose_f)
2023 syslog(LOG_ERR, "find_ipv6_router_full(): RS message too large while processing source "
2024 "link-layer addresss opt.");
2025
2026 return(-1);
2027 }
2028
2029 sllaopt->type= ND_OPT_SOURCE_LINKADDR;
2030 sllaopt->length= SLLA_OPT_LEN;
2031 bcopy( &(idata->ether.a), sllaopt->address, ETH_ALEN);
2032 ptr += sizeof(struct nd_opt_slla);
2033
2034 ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN);
2035 rs->nd_rs_cksum = 0;
2036 rs->nd_rs_cksum = in_chksum(v6buffer, rs, ptr-((unsigned char *)rs));
2037
2038 if(FD_ISSET(idata->fd, idata->wset)){
2039 if((nw=pcap_inject(pfd, wbuffer, ptr - wbuffer)) == -1){
2040 if(verbose_f)
2041 syslog(LOG_ERR, "send_router_solicit(): pcap_inject(): %s", pcap_geterr(pfd));
2042
2043 idata->pending_write_f= 1;
2044 idata->pending_write_data= wbuffer;
2045 idata->pending_write_size= ptr- wbuffer;
2046 (idata->write_errors)++;
2047 return(0);
2048 }
2049
2050 if(nw != (ptr-wbuffer)){
2051 if(verbose_f)
2052 syslog(LOG_ERR, "send_router_solicit(): pcap_inject(): only wrote %lu bytes "
2053 "(rather than %lu bytes)", (LUI) nw, (LUI) (ptr-wbuffer));
2054
2055 idata->pending_write_f= 1;
2056 idata->pending_write_data= wbuffer;
2057 idata->pending_write_size= ptr- wbuffer;
2058 (idata->write_errors)++;
2059 return(0);
2060 }
2061 }
2062 else{
2063 idata->pending_write_f= 1;
2064 idata->pending_write_data= wbuffer;
2065 idata->pending_write_size= ptr- wbuffer;
2066 }
2067
2068 return 0;
2069 }
2070
2071
2072
2073
2074 /*
2075 * Function: valid_icmp6_response()
2076 *
2077 * Checks whether the response to an ICMPv6 probe is valid
2078 */
2079
valid_icmp6_response(struct iface_data * idata,struct host_list * hlist,struct pcap_pkthdr * pkthdr,const u_char * pktdata)2080 int valid_icmp6_response(struct iface_data *idata, struct host_list *hlist, struct pcap_pkthdr *pkthdr,\
2081 const u_char *pktdata){
2082
2083 struct ether_header *pkt_ether;
2084 struct ip6_hdr *pkt_ipv6;
2085 struct icmp6_hdr *pkt_icmp6, *pkt_icmp6_icmp6;
2086 unsigned char *pkt_end;
2087
2088 pkt_ether = (struct ether_header *) pktdata;
2089 pkt_ipv6 = (struct ip6_hdr *)((char *) pkt_ether + ETHER_HDR_LEN);
2090 pkt_icmp6 = (struct icmp6_hdr *) ((char *) pkt_ipv6 + MIN_IPV6_HLEN);
2091 pkt_icmp6_icmp6= (struct icmp6_hdr *) ((unsigned char *) pkt_icmp6 + sizeof(struct icmp6_hdr) +\
2092 sizeof(struct ip6_hdr) + MIN_DST_OPT_HLEN);
2093 pkt_end = (unsigned char *) pktdata + pkthdr->caplen;
2094
2095 switch(pkt_icmp6->icmp6_type){
2096 case ICMP6_ECHO_REPLY:
2097 /* The packet length is the minimum of what we capured, and what is specified in the
2098 IPv6 Total Lenght field
2099 */
2100 if( pkt_end > ((unsigned char *)pkt_icmp6 + pkt_ipv6->ip6_plen) )
2101 pkt_end = (unsigned char *)pkt_icmp6 + pkt_ipv6->ip6_plen;
2102
2103 /*
2104 Discard the packet if it is not of the minimum size to contain an ICMPv6
2105 header and the payload we included in the ICMPv6 Echo Request
2106 */
2107 if( (pkt_end - (unsigned char *) pkt_icmp6) < (sizeof(struct icmp6_hdr) + \
2108 ICMPV6_ECHO_PAYLOAD_SIZE) ){
2109 return 0;
2110 }
2111
2112 if(pkt_icmp6->icmp6_data16[0] != htons(getpid())){
2113 return 0;
2114 }
2115
2116 break;
2117
2118 case ICMP6_PARAM_PROB:
2119 /* The packet length is the minimum of what we capured, and what is specified in the
2120 IPv6 Total Lenght field
2121 */
2122 if( pkt_end > ((unsigned char *)pkt_icmp6 + pkt_ipv6->ip6_plen) )
2123 pkt_end = (unsigned char *)pkt_icmp6 + pkt_ipv6->ip6_plen;
2124
2125 /*
2126 Discard the packet if it is not of the minimum size to contain an ICMPv6
2127 header and the payload we included in the ICMPv6 Echo Request
2128 */
2129 if( (pkt_end - (unsigned char *) pkt_icmp6) < (sizeof(struct icmp6_hdr) + \
2130 + sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) + \
2131 ICMPV6_ECHO_PAYLOAD_SIZE) ){
2132 return 0;
2133 }
2134
2135 if( pkt_icmp6->icmp6_code != ICMP6_PARAMPROB_OPTION){
2136 return 0;
2137 }
2138
2139 if(pkt_icmp6_icmp6->icmp6_data16[0] != htons(getpid())){
2140 return 0;
2141 }
2142
2143 break;
2144
2145 default:
2146 return 0;
2147 break;
2148 }
2149
2150 /*
2151 Check that the Source Address of the Packet is "valid"
2152 */
2153 if(IN6_IS_ADDR_UNSPECIFIED(&(pkt_ipv6->ip6_src))){
2154 return 0;
2155 }
2156
2157 if(IN6_IS_ADDR_LOOPBACK(&(pkt_ipv6->ip6_src))){
2158 return 0;
2159 }
2160
2161 if(IN6_IS_ADDR_MULTICAST(&(pkt_ipv6->ip6_src))){
2162 return 0;
2163 }
2164
2165 /*
2166 Check that that the Destination Address of the incoming packet is one
2167 of our addresses.
2168 */
2169 if(!is_eq_in6_addr(&(idata->ip6_local), &(pkt_ipv6->ip6_dst)) && \
2170 !is_ip6_in_address_list(&(idata->ip6_global), &(pkt_ipv6->ip6_dst))){
2171 return 0;
2172 }
2173
2174 /* Check that the ICMPv6 checksum is correct */
2175 if(in_chksum(pkt_ipv6, pkt_icmp6, pkt_end-((unsigned char *)pkt_icmp6)) != 0){
2176 return 0;
2177 }
2178
2179 return 1;
2180 }
2181
2182
2183 /*
2184 * Function: get_if_addrs()
2185 *
2186 * Obtains Ethernet and IPv6 addresses of a network interface card
2187 */
2188
get_if_addrs(struct iface_data * idata)2189 int get_if_addrs(struct iface_data *idata){
2190 struct ifaddrs *ifptr, *ptr;
2191 struct sockaddr_in6 *sockin6ptr;
2192
2193 #ifdef __linux__
2194 struct sockaddr_ll *sockpptr;
2195 #elif defined (__FreeBSD__) || defined(__NetBSD__) || defined (__OpenBSD__) || defined(__APPLE__)
2196 struct sockaddr_dl *sockpptr;
2197 #endif
2198
2199 if(getifaddrs(&ifptr) != 0){
2200 if(verbose_f){
2201 syslog(LOG_ERR, "get_if_addrs(): Error while learning addresses of the %s interface", idata->iface);
2202 }
2203
2204 return(-1);
2205 }
2206
2207 for(ptr=ifptr; ptr != NULL; ptr= ptr->ifa_next){
2208 if(ptr->ifa_addr != NULL){
2209 #ifdef __linux__
2210 if( !(idata->ether_flag) && ((ptr->ifa_addr)->sa_family == AF_PACKET)){
2211 if(strncmp(idata->iface, ptr->ifa_name, IFACE_LENGTH-1) == 0){
2212 sockpptr = (struct sockaddr_ll *) (ptr->ifa_addr);
2213 if(sockpptr->sll_halen == 6){
2214 idata->ether = *((struct ether_addr *)sockpptr->sll_addr);
2215 idata->ether_flag=1;
2216 }
2217 }
2218 }
2219 #elif defined (__FreeBSD__) || defined(__NetBSD__) || defined (__OpenBSD__) || defined(__APPLE__)
2220 if( !(idata->ether_flag) && ((ptr->ifa_addr)->sa_family == AF_LINK)){
2221 if(strncmp(idata->iface, ptr->ifa_name, IFACE_LENGTH-1) == 0){
2222 sockpptr = (struct sockaddr_dl *) (ptr->ifa_addr);
2223 if(sockpptr->sdl_alen == 6){
2224 idata->ether= *((struct ether_addr *)(sockpptr->sdl_data + sockpptr->sdl_nlen));
2225 idata->ether_flag= 1;
2226 }
2227 }
2228 }
2229 #endif
2230 else if((ptr->ifa_addr)->sa_family == AF_INET6){
2231 sockin6ptr= (struct sockaddr_in6 *) (ptr->ifa_addr);
2232
2233 if(!(idata->ip6_local_flag) && (((sockin6ptr->sin6_addr).s6_addr16[0] & htons(0xffc0)) == htons(0xfe80))){
2234 if(strncmp(idata->iface, ptr->ifa_name, IFACE_LENGTH-1) == 0){
2235 idata->ip6_local = sockin6ptr->sin6_addr;
2236 #if defined (__FreeBSD__) || defined(__NetBSD__) || defined (__OpenBSD__) || defined(__APPLE__)
2237 /* BSDs store the interface index in s6_addr16[1], so we must clear it */
2238 idata->ip6_local.s6_addr16[1] =0;
2239 idata->ip6_local.s6_addr16[2] =0;
2240 idata->ip6_local.s6_addr16[3] =0;
2241 #endif
2242 idata->ip6_local_flag= 1;
2243 }
2244 }
2245 else if((((sockin6ptr->sin6_addr).s6_addr16[0] & htons(0xffc0)) != htons(0xfe80))){
2246 if(strncmp(idata->iface, ptr->ifa_name, IFACE_LENGTH-1) == 0){
2247 if(!is_ip6_in_prefix_list( &(sockin6ptr->sin6_addr), &(idata->ip6_global))){
2248 if(idata->ip6_global.nprefix < idata->ip6_global.maxprefix){
2249 if( (idata->ip6_global.prefix[idata->ip6_global.nprefix] = \
2250 malloc(sizeof(struct prefix_entry))) == NULL){
2251 if(verbose_f)
2252 syslog(LOG_ERR, "get_if_addrs(): Error while storing Source Address");
2253
2254 return(-1);
2255 }
2256
2257 (idata->ip6_global.prefix[idata->ip6_global.nprefix])->len = 64;
2258 (idata->ip6_global.prefix[idata->ip6_global.nprefix])->ip6 = sockin6ptr->sin6_addr;
2259 idata->ip6_global.nprefix++;
2260 idata->ip6_global_nconfig++;
2261 idata->ip6_global_flag= VALID_MAPPING;
2262 }
2263 }
2264 }
2265 }
2266 }
2267 }
2268 }
2269
2270 freeifaddrs(ifptr);
2271 return(0);
2272 }
2273
2274
2275 /*
2276 * Function: check_local_addresses()
2277 *
2278 * Check whether our local addresses are still valid, and if not, remove them
2279 */
2280
check_local_addresses(struct iface_data * idata)2281 int check_local_addresses(struct iface_data *idata){
2282 struct ifaddrs *ifptr, *ptr;
2283 struct sockaddr_in6 *sockin6ptr;
2284 struct prefix_entry *prefptr;
2285 time_t curtime;
2286 unsigned int i;
2287
2288 curtime= time(NULL);
2289
2290 /* If at least one of our addresses was a locally-configured address, check whether they are still valid */
2291 if(idata->ip6_global_nconfig){
2292 if(getifaddrs(&ifptr) != 0){
2293 if(verbose_f){
2294 syslog(LOG_ERR, "get_if_addrs(): Error while learning addresses of the %s interface", idata->iface);
2295 }
2296
2297 return(-1);
2298 }
2299
2300 for(ptr=ifptr; ptr != NULL; ptr= ptr->ifa_next){
2301 if(ptr->ifa_addr != NULL){
2302 if((ptr->ifa_addr)->sa_family == AF_INET6){
2303 sockin6ptr= (struct sockaddr_in6 *) (ptr->ifa_addr);
2304
2305 if((((sockin6ptr->sin6_addr).s6_addr16[0] & htons(0xffc0)) != htons(0xfe80))){
2306 if(strncmp(idata->iface, ptr->ifa_name, IFACE_LENGTH-1) == 0){
2307 if( (prefptr=lookup_ip6_in_address_list(&(idata->ip6_global), &(sockin6ptr->sin6_addr))) != NULL){
2308 prefptr->tstamp=curtime;
2309 }
2310 }
2311 }
2312 }
2313 }
2314 }
2315
2316 freeifaddrs(ifptr);
2317
2318 }
2319
2320 /*
2321 Addresses configured as a result of Router Advertisements should already have their timestamp updated
2322 (when an if a corresponding RA was received while probing
2323 */
2324
2325
2326 for(i=0; i<idata->ip6_global.nprefix; i++)
2327 if(( curtime - (idata->ip6_global.prefix[i])->tstamp) >= LOCAL_ADDRESS_TIMEOUT)
2328 break;
2329
2330 if(i < idata->ip6_global.nprefix){
2331 idata->ip6_global_flag=INVALID_MAPPING;
2332 idata->ip6_global_conftime=curtime;
2333 idata->last_rs=0;
2334
2335 /* Remove all of our global addresses */
2336 for(i=0; i < idata->ip6_global.nprefix; i++)
2337 free(idata->ip6_global.prefix[i]);
2338
2339 idata->ip6_global.nprefix=0;
2340 idata->ip6_global_nconfig=0;
2341
2342 /* Remove all autoconf prefixes (used for candidate addresses) */
2343 for(i=0; i < idata->prefix_ac.nprefix; i++)
2344 free(idata->prefix_ac.prefix[i]);
2345
2346 idata->prefix_ac.nprefix=0;
2347
2348 /* Remove all "on-link" prefixes (currently unused) */
2349 for(i=0; i < idata->prefix_ol.nprefix; i++)
2350 free(idata->prefix_ol.prefix[i]);
2351
2352 idata->prefix_ol.nprefix=0;
2353 return 0;
2354 }
2355 else{
2356 idata->ip6_global_lastcheck= curtime;
2357 return 1;
2358 }
2359 }
2360
2361
2362 /*
2363 * Function: init_host_list()
2364 *
2365 * Initilizes a host_list structure
2366 */
2367
init_host_list(struct host_list * hlist)2368 int init_host_list(struct host_list *hlist){
2369 time_t curtime;
2370
2371 curtime= time(NULL);
2372
2373 bzero(hlist, sizeof(struct host_list));
2374
2375 if( (hlist->host = malloc(MAX_LIST_ENTRIES * sizeof(struct host_entry *))) == NULL){
2376 if(verbose_f){
2377 syslog(LOG_ERR, "init_host_list(): Not enough memory while initializing host list");
2378 }
2379
2380 return(-1);
2381 }
2382
2383 for(i=0; i < MAX_LIST_ENTRIES; i++)
2384 hlist->host[i]= NULL;
2385
2386 hlist->nhosts= 0;
2387 hlist->maxhosts= maxaddrentries;
2388 hlist->ncandidates= 0;
2389 hlist->maxcandidates= maxcandentries;
2390 hlist->lastprocessed= curtime;
2391 hlist->lastgcollection= curtime;
2392
2393 hlist->key_l= rand();
2394 hlist->key_h= rand();
2395
2396 hlist->mc_unrec_probe_f=1;
2397 hlist->mc_unrec_state= SCAN_LOCAL;
2398 hlist->mc_unrec_naddr= 0;
2399 hlist->mc_unrec_seq= rand();
2400 hlist->mc_unrec_last= 0;
2401
2402 hlist->mc_echo_probe_f=1;
2403 hlist->mc_echo_state= SCAN_LOCAL;
2404 hlist->mc_echo_naddr= 0;
2405 hlist->mc_echo_seq= rand();
2406 hlist->mc_echo_last= curtime - mcechoprobeint / 2;
2407
2408 hlist->np_key= 0;
2409 hlist->np_hentry= NULL;
2410
2411 return(0);
2412 }
2413
2414
2415 /*
2416 * Function: key()
2417 *
2418 * Compute a key for accessing the hash-table of a host_list structure
2419 */
2420
key(struct host_list * hlist,struct in6_addr * ipv6)2421 u_int16_t key(struct host_list *hlist, struct in6_addr *ipv6){
2422 return( ((hlist->key_l ^ ipv6->s6_addr16[0] ^ ipv6->s6_addr16[7]) \
2423 ^ (hlist->key_h ^ ipv6->s6_addr16[1] ^ ipv6->s6_addr16[6])) % MAX_LIST_ENTRIES);
2424 }
2425
2426
2427 /*
2428 * Function: add_host_entry()
2429 *
2430 * Add a host_entry structure to the hash table
2431 */
2432
add_host_entry(struct host_list * hlist,struct in6_addr * ipv6,struct ether_addr * ether)2433 struct host_entry *add_host_entry(struct host_list *hlist, struct in6_addr *ipv6, struct ether_addr *ether){
2434 struct host_entry *hentry, *ptr;
2435 u_int16_t hkey;
2436
2437 hkey= key(hlist, ipv6);
2438
2439 if(hlist->nhosts >= hlist->maxhosts){
2440 if(verbose_f){
2441 syslog(LOG_INFO, "add_host_entry(): Reached maximum number of hosts");
2442 }
2443
2444 return(NULL);
2445 }
2446
2447 if( (hentry= malloc(sizeof(struct host_entry))) == NULL){
2448 if(verbose_f){
2449 syslog(LOG_ERR, "add_host_entry(): Not enough memory while adding host entry");
2450 }
2451
2452 return(NULL);
2453 }
2454
2455 bzero(hentry, sizeof(struct host_entry));
2456 hentry->ip6 = *ipv6;
2457 hentry->ether= *ether;
2458 hentry->flag= VALID_MAPPING;
2459 hentry->fseen= time(NULL);
2460 hentry->lseen= time(NULL);
2461 hentry->lprobed= 0;
2462 hentry->nprobes= 0;
2463 hentry->next= NULL;
2464 hentry->ffactor= rand()%MAX_FUDGE_FACTOR;
2465
2466 if(hlist->host[hkey] == NULL){
2467 /* First node in chain */
2468 hlist->host[hkey]= hentry;
2469 hentry->prev= NULL;
2470 }
2471 else{
2472 /* Find last node in list */
2473 for(ptr=hlist->host[hkey]; ptr->next != NULL; ptr= ptr->next);
2474
2475 hentry->prev= ptr;
2476 ptr->next= hentry;
2477 }
2478
2479 (hlist->nhosts)++;
2480
2481 return(hentry);
2482 }
2483
2484
2485 /*
2486 * Function: del_host_entry()
2487 *
2488 * Remove a host_entry structure from the hash table
2489 */
2490
del_host_entry(struct host_list * hlist,struct host_entry * hentry)2491 int del_host_entry(struct host_list *hlist, struct host_entry *hentry){
2492 u_int16_t hkey;
2493
2494 hkey= key(hlist, &(hentry->ip6));
2495
2496 /* If this was not the last node in the list, make our next node point to our previous node */
2497 if(hentry->next != NULL){
2498 (hentry->next)->prev = hentry->prev;
2499 }
2500
2501 /* If this is not the first node in the list, the previous node should point to our next node */
2502 if(hentry->prev != NULL){
2503 (hentry->prev)->next= hentry->next;
2504 }
2505 else{
2506 hlist->host[hkey]= hentry->next;
2507 }
2508
2509 /* If this was the next host_entry to process, the next node should be come the next entry to process */
2510 if(hlist->np_key == hkey && hlist->np_hentry == hentry){
2511 hlist->np_hentry= hentry->next;
2512 }
2513
2514 if(hentry->flag != VALID_MAPPING){
2515 if(hlist->ncandidates){
2516 (hlist->ncandidates)--;
2517 }
2518 else{
2519 if(verbose_f){
2520 syslog(LOG_ERR, "del_host_entry(): Host list is trashed!");
2521 return(-1);
2522 }
2523 }
2524 }
2525
2526 if(hlist->nhosts){
2527 (hlist->nhosts)--;
2528 }
2529 else{
2530 if(verbose_f){
2531 syslog(LOG_ERR, "del_host_entry(): Host list is trashed!");
2532 return(-1);
2533 }
2534 }
2535
2536 free(hentry);
2537 return(0);
2538 }
2539
2540
2541 /*
2542 * Function: process_host_entries()
2543 *
2544 * Compute a key for accessing the hash-table of a host_list structure
2545 */
2546
process_host_entries(pcap_t * pfd,struct iface_data * idata,struct host_list * hlist)2547 int process_host_entries(pcap_t *pfd, struct iface_data *idata, struct host_list *hlist){
2548 unsigned int nkeys=0, nhosts=0;
2549 struct host_entry *chentry, *saved_hentry;
2550 time_t curtime;
2551
2552 if(hlist->nhosts == 0)
2553 return 0;
2554
2555 curtime = time(NULL);
2556 chentry= hlist->np_hentry;
2557
2558 while(nkeys < MAX_LIST_ENTRIES && nhosts < hlist->nhosts){
2559 nkeys++;
2560
2561 while(chentry != NULL){
2562 nhosts++;
2563
2564 /* Check whether host should be eliminated from list */
2565 if( ((chentry->flag == VALID_MAPPING) && ((curtime - chentry->lseen) >= addrtimeout)) ||\
2566 ((chentry->flag == INVALID_MAPPING) && ((curtime - chentry->lseen) >= candaddrtimeout))){
2567
2568 /*
2569 We must save chentry->next, because it may be impossible to access if we
2570 del_host_entry() the current node
2571 */
2572 saved_hentry= chentry->next;
2573
2574 if( (chentry->flag == VALID_MAPPING) && log_hentry(idata, chentry, &curtime, DEL_ENTRY) != 0){
2575 if(verbose_f)
2576 syslog(LOG_ERR, "process_host_entries(): Error while logging new entry");
2577
2578 return(-1);
2579 }
2580
2581 if(del_host_entry(hlist, chentry) != 0){
2582 if(verbose_f)
2583 syslog(LOG_ERR, "process_host_entries(): Error while eliminating host entry");
2584
2585 return(-1);
2586 }
2587 else{
2588 chentry= saved_hentry;
2589 }
2590 }
2591
2592 /* Check whether the host should be probed */
2593 else if( (chentry->flag != VALID_MAPPING) || ((curtime - chentry->lseen) >= maxunprobedint)){
2594 if( (curtime - chentry->lprobed) >= (unicastprobeint + chentry->ffactor)){
2595 if(send_host_probe(pfd, idata, ((chentry->nprobes % 2)?PROBE_ICMP6_ECHO:PROBE_UNREC_OPT), chentry)\
2596 == -1){
2597 if(verbose_f)
2598 syslog(LOG_ERR, "process_host_entries(): Error while sending probe to host");
2599
2600 return(-1);
2601 }
2602 else{
2603 chentry->lprobed= curtime;
2604 (chentry->nprobes)++;
2605 hlist->np_hentry= chentry->next;
2606 return(0);
2607 }
2608 }
2609 else{
2610 chentry= chentry->next;
2611 }
2612 }
2613 }
2614
2615 (hlist->np_key)++;
2616
2617 if(hlist->np_key >= MAX_LIST_ENTRIES || nhosts == hlist->nhosts){
2618 hlist->np_key= 0;
2619 hlist->lastprocessed= curtime;
2620 }
2621
2622 hlist->np_hentry = hlist->host[hlist->np_key];
2623 }
2624
2625 return 0;
2626 }
2627
2628
2629 /*
2630 * Function: gcollection_host_entries()
2631 *
2632 * Remove old entries from host_list
2633 */
2634
gcollection_host_entries(struct iface_data * idata,struct host_list * hlist)2635 int gcollection_host_entries(struct iface_data *idata, struct host_list *hlist){
2636 unsigned int nkeys=0, nhosts;
2637 time_t curtime;
2638 struct host_entry *chentry;
2639
2640 if(hlist->nhosts == 0)
2641 return 0;
2642
2643 for(nkeys=0; (nkeys <= MAX_LIST_ENTRIES) && (nhosts < hlist->nhosts); nkeys++){
2644
2645 for(chentry= hlist->host[nkeys]; chentry != NULL; chentry= chentry->next){
2646 nhosts++;
2647 curtime = time(NULL);
2648
2649 /* Check whether host should be eliminated from list */
2650 if( ((chentry->flag == VALID_MAPPING) && ((curtime - chentry->lseen) >= addrtimeout)) ||\
2651 ((chentry->flag == INVALID_MAPPING) && ((curtime - chentry->lseen) >= candaddrtimeout))){
2652
2653 if( (chentry->flag == VALID_MAPPING) && log_hentry(idata, chentry, &curtime, DEL_ENTRY) != 0){
2654 if(verbose_f)
2655 syslog(LOG_ERR, "gcollection_host_entries(: Error while logging new entry");
2656
2657 return(-1);
2658 }
2659
2660 if(del_host_entry(hlist, chentry) != 0){
2661 if(verbose_f)
2662 syslog(LOG_ERR, "gcollection_host_entries(): Error while eliminating host entry");
2663
2664 return(-1);
2665 }
2666 }
2667 }
2668 }
2669
2670 return 0;
2671 }
2672
2673
2674
2675 /*
2676 * Function: send_host_probe()
2677 *
2678 * Sends a probe packet to a single IPv6 address
2679 */
2680
send_host_probe(pcap_t * pfd,struct iface_data * idata,unsigned char type,struct host_entry * host)2681 int send_host_probe(pcap_t *pfd, struct iface_data *idata, unsigned char type, struct host_entry *host){
2682 volatile unsigned char *ptr;
2683
2684 unsigned int icmp6_max_packet_size;
2685 struct ether_header *ether;
2686 unsigned char *v6buffer;
2687 struct ip6_hdr *ipv6;
2688 struct in6_addr targetaddr;
2689 struct ip6_dest *destopth;
2690 struct ip6_opt *opt;
2691 u_int32_t *uint32;
2692
2693 icmp6_max_packet_size = idata->mtu;
2694 ether = (struct ether_header *) wbuffer;
2695 v6buffer = (unsigned char *) ether + sizeof(struct ether_header);
2696 ipv6 = (struct ip6_hdr *) v6buffer;
2697
2698 targetaddr= host->ip6;
2699
2700 ipv6->ip6_flow=0;
2701 ipv6->ip6_vfc= 0x60;
2702 ipv6->ip6_hlim= 255;
2703 ipv6->ip6_dst= targetaddr;
2704 ipv6->ip6_src= *src_addr_sel(idata, &(host->ip6));
2705
2706 ether->src = idata->ether;
2707 ether->dst = host->ether;
2708 ether->ether_type = htons(0x86dd);
2709
2710 prev_nh = (unsigned char *) &(ipv6->ip6_nxt);
2711
2712 ptr = (unsigned char *) v6buffer + MIN_IPV6_HLEN;
2713
2714 switch(type){
2715 case PROBE_ICMP6_ECHO:
2716 *prev_nh = IPPROTO_ICMPV6;
2717
2718 if( (ptr+sizeof(struct icmp6_hdr)+ICMPV6_ECHO_PAYLOAD_SIZE) > (v6buffer+icmp6_max_packet_size)){
2719 if(verbose_f)
2720 syslog(LOG_ERR, "send_host_probe(): Packet too large while creating ICMPv6 Echo Request "
2721 "Probe packet");
2722
2723 return(-1);
2724 }
2725
2726 icmp6 = (struct icmp6_hdr *) ptr;
2727 icmp6->icmp6_type = ICMP6_ECHO_REQUEST;
2728 icmp6->icmp6_code = 0;
2729 icmp6->icmp6_cksum = rand();
2730 icmp6->icmp6_data16[0]= htons(getpid()); /* Identifier */
2731 icmp6->icmp6_data16[1]= htons(rand()); /* Sequence Number */
2732
2733 ptr = ptr+ sizeof(struct icmp6_hdr);
2734
2735 for(i=0; i<(ICMPV6_ECHO_PAYLOAD_SIZE>>2); i++){
2736 *(u_int32_t *)ptr = rand();
2737 ptr += sizeof(u_int32_t);
2738 }
2739 break;
2740
2741 case PROBE_UNREC_OPT:
2742 *prev_nh = IPPROTO_DSTOPTS;
2743
2744
2745 if( (ptr+sizeof(struct icmp6_hdr) + 8 + ICMPV6_ECHO_PAYLOAD_SIZE) > (v6buffer+icmp6_max_packet_size)){
2746 if(verbose_f)
2747 syslog(LOG_ERR, "send_host_probe(): Packet too large while creating Unrec. Opt. Probe Packet");
2748
2749 return(-1);
2750 }
2751
2752 destopth = (struct ip6_dest *) ptr;
2753 destopth->ip6d_len= 0;
2754 destopth->ip6d_nxt= IPPROTO_ICMPV6;
2755
2756 ptr= ptr + 2;
2757 opt= (struct ip6_opt *) ptr;
2758 opt->ip6o_type= 0x80;
2759 opt->ip6o_len= 4;
2760
2761 ptr= ptr + 2;
2762 uint32 = (u_int32_t *) ptr;
2763 *uint32 = rand();
2764
2765 ptr= ptr +4;
2766 icmp6 = (struct icmp6_hdr *) ptr;
2767 icmp6->icmp6_type = ICMP6_ECHO_REQUEST;
2768 icmp6->icmp6_code = 0;
2769 icmp6->icmp6_cksum = rand();
2770 icmp6->icmp6_data16[0]= htons(getpid()); /* Identifier */
2771 icmp6->icmp6_data16[1]= htons(rand()); /* Sequence Number */
2772
2773 ptr = ptr+ sizeof(struct icmp6_hdr);
2774
2775 for(i=0; i<(ICMPV6_ECHO_PAYLOAD_SIZE>>2); i++){
2776 *(u_int32_t *)ptr = rand();
2777 ptr += sizeof(u_int32_t);
2778 }
2779 break;
2780 }
2781
2782 ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN);
2783 icmp6->icmp6_cksum = 0;
2784 icmp6->icmp6_cksum = in_chksum(v6buffer, icmp6, ptr-((unsigned char *)icmp6));
2785
2786
2787 if((nw=pcap_inject(pfd, (unsigned char *) ether, ptr - (unsigned char *) ether)) == -1){
2788 if(verbose_f)
2789 syslog(LOG_ERR, "send_host_probe(): pcap_inject(): %s", pcap_geterr(pfd));
2790
2791 return(-1);
2792 }
2793
2794 if(nw != (ptr- (unsigned char *) ether)){
2795 if(verbose_f)
2796 syslog(LOG_ERR, "send_host_probe(): pcap_inject(): only wrote %lu bytes "
2797 "(rather than %lu bytes)", (LUI) nw, (LUI) (ptr- (unsigned char *) ether));
2798 return(-1);
2799 }
2800
2801 return 0;
2802 }
2803
2804
2805
2806 /*
2807 * Function: send_multicast_packet()
2808 *
2809 * Sends a probe packet to the "all nodes link-local" multicast address
2810 */
2811
send_multicast_packet(pcap_t * pfd,struct iface_data * idata,struct in6_addr * srcaddr,unsigned char type,struct in6_addr * target)2812 int send_multicast_packet(pcap_t *pfd, struct iface_data *idata, struct in6_addr *srcaddr, unsigned char type, \
2813 struct in6_addr *target){
2814 unsigned char *ptr;
2815 unsigned int icmp6_max_packet_size;
2816 struct ether_header *ether;
2817 unsigned char *v6buffer;
2818 struct ip6_hdr *ipv6;
2819 struct ip6_dest *destopth;
2820 struct ip6_opt *opt;
2821 u_int32_t *uint32;
2822
2823 icmp6_max_packet_size = idata->mtu;
2824 ether = (struct ether_header *) wbuffer;
2825 v6buffer = (unsigned char *) ether + sizeof(struct ether_header);
2826 ipv6 = (struct ip6_hdr *) v6buffer;
2827
2828 ipv6->ip6_flow=0;
2829 ipv6->ip6_vfc= 0x60;
2830 ipv6->ip6_hlim= 255;
2831
2832 ipv6->ip6_src= *srcaddr;
2833 ipv6->ip6_dst= *target;
2834
2835 ether->src = idata->ether;
2836 ether->dst = ether_multicast(&(ipv6->ip6_dst));
2837 ether->ether_type = htons(0x86dd);
2838
2839 prev_nh = (unsigned char *) &(ipv6->ip6_nxt);
2840
2841 ptr = (unsigned char *) v6buffer + MIN_IPV6_HLEN;
2842
2843 switch(type){
2844 case PROBE_ICMP6_ECHO:
2845 *prev_nh = IPPROTO_ICMPV6;
2846
2847 if( (ptr+sizeof(struct icmp6_hdr)+ICMPV6_ECHO_PAYLOAD_SIZE) > (v6buffer+icmp6_max_packet_size)){
2848 if(verbose_f)
2849 syslog(LOG_ERR, "send_multicast_packet(): Packet too large while creating ICMPv6 Echo "
2850 "Request Probe packet");
2851
2852 return(-1);
2853 }
2854
2855 icmp6 = (struct icmp6_hdr *) ptr;
2856 icmp6->icmp6_type = ICMP6_ECHO_REQUEST;
2857 icmp6->icmp6_code = 0;
2858 icmp6->icmp6_cksum = rand();
2859 icmp6->icmp6_data16[0]= htons(getpid()); /* Identifier */
2860 icmp6->icmp6_data16[1]= htons(rand()); /* Sequence Number */
2861
2862 ptr = ptr+ sizeof(struct icmp6_hdr);
2863
2864 for(i=0; i<(ICMPV6_ECHO_PAYLOAD_SIZE>>2); i++){
2865 *(u_int32_t *)ptr = rand();
2866 ptr += sizeof(u_int32_t);
2867 }
2868 break;
2869
2870 case PROBE_UNREC_OPT:
2871 *prev_nh = IPPROTO_DSTOPTS;
2872
2873 if( (ptr+sizeof(struct icmp6_hdr) + 8 + ICMPV6_ECHO_PAYLOAD_SIZE) > (v6buffer+icmp6_max_packet_size)){
2874 if(verbose_f)
2875 syslog(LOG_ERR, "send_multicast_packet(): Packet too large while creating Unrec. Opt. "
2876 "Probe Packet");
2877
2878 return(-1);
2879 }
2880
2881 destopth = (struct ip6_dest *) ptr;
2882 destopth->ip6d_len= 0;
2883 destopth->ip6d_nxt= IPPROTO_ICMPV6;
2884
2885 ptr= ptr + 2;
2886 opt= (struct ip6_opt *) ptr;
2887 opt->ip6o_type= 0x80;
2888 opt->ip6o_len= 4;
2889
2890 ptr= ptr + 2;
2891 uint32 = (u_int32_t *) ptr;
2892 *uint32 = rand();
2893
2894 ptr= ptr +4;
2895 icmp6 = (struct icmp6_hdr *) ptr;
2896 icmp6->icmp6_type = ICMP6_ECHO_REQUEST;
2897 icmp6->icmp6_code = 0;
2898 icmp6->icmp6_cksum = rand();
2899 icmp6->icmp6_data16[0]= htons(getpid()); /* Identifier */
2900 icmp6->icmp6_data16[1]= htons(rand()); /* Sequence Number */
2901
2902 ptr = ptr+ sizeof(struct icmp6_hdr);
2903
2904 for(i=0; i<(ICMPV6_ECHO_PAYLOAD_SIZE>>2); i++){
2905 *(u_int32_t *)ptr = rand();
2906 ptr += sizeof(u_int32_t);
2907 }
2908 break;
2909 }
2910
2911 ipv6->ip6_plen = htons((ptr - v6buffer) - MIN_IPV6_HLEN);
2912 icmp6->icmp6_cksum = 0;
2913 icmp6->icmp6_cksum = in_chksum(v6buffer, icmp6, ptr-((unsigned char *)icmp6));
2914
2915 if((nw=pcap_inject(pfd, (unsigned char *) ether, ptr - (unsigned char *) ether)) == -1){
2916 if(verbose_f)
2917 syslog(LOG_ERR, "send_multicast_packet(): pcap_inject(): %s", pcap_geterr(pfd));
2918
2919 return(-1);
2920 }
2921
2922 if(nw != (ptr- (unsigned char *) ether)){
2923 if(verbose_f)
2924 syslog(LOG_ERR, "send_multicast_packet(): pcap_inject(): only wrote %lu bytes "
2925 "(rather than %lu bytes)\n", (LUI) nw, (LUI) (ptr - (unsigned char *) ether));
2926
2927 return(-1);
2928 }
2929
2930 return 0;
2931 }
2932
2933
2934 /*
2935 * Function: send_multicast_probe()
2936 *
2937 * Sends a probe packet to the "all nodes link-local" multicast address
2938 */
2939
send_multicast_probe(pcap_t * pfd,struct iface_data * idata,struct host_list * hlist,unsigned char probetype)2940 int send_multicast_probe(pcap_t *pfd, struct iface_data *idata, struct host_list *hlist, unsigned char probetype){
2941 unsigned int *state;
2942 unsigned int *naddr;
2943
2944 if(probetype == PROBE_ICMP6_ECHO){
2945 state= &(hlist->mc_echo_state);
2946 naddr= &(hlist->mc_echo_naddr);
2947 }
2948 else{
2949 state= &(hlist->mc_unrec_state);
2950 naddr= &(hlist->mc_unrec_naddr);
2951 }
2952
2953
2954 if( (*state == SCAN_GLOBAL) && (*naddr < idata->ip6_global.nprefix)){
2955 if(send_multicast_packet(pfd, idata, &((idata->ip6_global.prefix[*naddr])->ip6), probetype, &all_nodes_onlink) != 0){
2956 if(verbose_f)
2957 syslog(LOG_ERR, "send_multicast_probe(): Error when sending multicast probe to all-nodes "
2958 "link-local (src: link-local)");
2959
2960 return(-1);
2961 }
2962
2963 (*naddr)++;
2964
2965 if(*naddr >= idata->ip6_global.nprefix)
2966 *state= SCAN_LOCAL;
2967 }
2968 else{
2969 if(send_multicast_packet(pfd, idata, &(idata->ip6_local), probetype, &all_nodes_onlink) != 0){
2970 if(verbose_f)
2971 syslog(LOG_ERR, "send_multicast_probe(): Error when sending multicast probe to all-nodes "
2972 "link-local (src: link-local)");
2973
2974 return(-1);
2975 }
2976
2977 *state= SCAN_GLOBAL;
2978 *naddr=0;
2979 }
2980
2981 return 0;
2982 }
2983
2984
2985 /*
2986 * Function: log_hentry()
2987 *
2988 * Log a change in the status of an address
2989 */
2990
log_hentry(struct iface_data * idata,struct host_entry * hptr,time_t * timestamp,unsigned char status)2991 int log_hentry(struct iface_data *idata, struct host_entry *hptr, time_t *timestamp, unsigned char status){
2992 char date[30];
2993
2994 if(inet_ntop(AF_INET6, &(hptr->ip6), pv6addr, sizeof(pv6addr))<=0){
2995 if(verbose_f)
2996 syslog(LOG_ERR, "log_hentry(): inet_ntop(): Error converting IPv6 address to presentation format");
2997
2998 return(-1);
2999 }
3000
3001 if(ether_ntop( &(hptr->ether), plinkaddr, sizeof(plinkaddr)) == 0){
3002 if(verbose_f)
3003 syslog(LOG_ERR, "log_hentry(): ether_ntop(): Error converting address");
3004
3005 return(-1);
3006 }
3007
3008 switch(status){
3009 case(ADD_ENTRY):
3010 if(timestampf == TIMESTAMP_DATE){
3011 ctime_r(timestamp, date);
3012 date[24]=0;
3013 if(fprintf(fplog, "%s %s ADD_ADDR %s (%s)\n", date, idata->iface, pv6addr, plinkaddr) < 0){
3014 syslog(LOG_ERR, "Error while writting 'ADD_ADDR' message to IPv6 address log file");
3015 return(-1);
3016 }
3017 }
3018 else{
3019 if(fprintf(fplog, "%lu %s ADD_ADDR %s (%s)\n", (LUI) *timestamp, idata->iface, pv6addr, plinkaddr) < 0){
3020 syslog(LOG_ERR, "Error while writting 'ADD_ADDR' message to IPv6 address log file");
3021 return(-1);
3022 }
3023 }
3024
3025 break;
3026
3027 case(DEL_ENTRY):
3028 if(timestampf == TIMESTAMP_DATE){
3029 ctime_r(timestamp, date);
3030 date[24]=0;
3031
3032 if(fprintf(fplog, "%s %s DEL_ADDR %s (%s)\n", date, idata->iface, pv6addr, plinkaddr) < 0){
3033 syslog(LOG_ERR, "Error while writting 'DEL_ADDR' message to IPv6 address log file");
3034 return(-1);
3035 }
3036 }
3037 else{
3038 if(fprintf(fplog, "%lu %s DEL_ADDR %s (%s)\n", (LUI) *timestamp, idata->iface, pv6addr, plinkaddr) < 0){
3039 syslog(LOG_ERR, "Error while writting 'DEL_ADDR' message to IPv6 address log file");
3040 return(-1);
3041 }
3042 }
3043
3044 break;
3045
3046 default:
3047 break;
3048 }
3049
3050 fflush(fplog);
3051 return(0);
3052 }
3053
3054
3055 /*
3056 * Function: process_config_file()
3057 *
3058 * Processes the ipv6mon configuration file
3059 */
3060
process_config_file(const char * path)3061 int process_config_file(const char *path){
3062 FILE *fp;
3063 char *key, *value;
3064 char line[MAX_LINE_SIZE];
3065 int r;
3066 unsigned int ln=1;
3067
3068 if( (fp=fopen(path, "r")) == NULL){
3069 if(verbose_f){
3070 if(showconfig_f)
3071 puts("process_config_file(): Error opening config file");
3072 else
3073 syslog(LOG_ERR, "process_config_file(): Error opening config file");
3074 }
3075
3076 return(-1);
3077 }
3078
3079 while(fgets(line, sizeof(line), fp) != NULL){
3080 r=keyval(line, strlen(line), &key, &value);
3081
3082 if(r == 1){
3083 if(strncmp(key, "NetworkInterface", MAX_VAR_NAME_LEN) == 0){
3084 strncpy(iface, value, IFACE_LENGTH-1);
3085 iface_f=1;
3086 }
3087 else if(strncmp(key, "AddressLogFile", MAX_VAR_NAME_LEN) == 0){
3088 if( (logfile= malloc(strlen(value)+1)) == NULL){
3089 if(verbose_f){
3090 if(showconfig_f)
3091 puts("process_config_file(): Error while allocating memory to store log file path");
3092 else
3093 syslog(LOG_ERR, "process_config_file(): Error while allocating memory to store log file path");
3094 }
3095
3096 fclose(fp);
3097 return(-1);
3098 }
3099
3100 strncpy(logfile, value, strlen(value)+1);
3101 logfile_f=1;
3102 }
3103 else if(strncmp(key, "LockFile", MAX_VAR_NAME_LEN) == 0){
3104 if( (lockfile= malloc(strlen(value)+1)) == NULL){
3105 if(verbose_f){
3106 if(showconfig_f)
3107 puts("process_config_file(): Error while allocating memory to store lock file path");
3108 else
3109 syslog(LOG_ERR, "process_config_file(): Error while allocating memory to store lock file path");
3110 }
3111
3112 fclose(fp);
3113 return(-1);
3114 }
3115
3116 strncpy(lockfile, value, strlen(value)+1);
3117 lockfile_f=1;
3118 }
3119 else if(strncmp(key, "UnprivilegedUser", MAX_VAR_NAME_LEN) == 0){
3120 if( (unprivuser= malloc(strlen(value)+1)) == NULL){
3121 if(verbose_f){
3122 if(showconfig_f)
3123 puts("process_config_file(): Error while allocating memory to store "
3124 "unprivileged username");
3125 else
3126 syslog(LOG_ERR, "process_config_file(): Error while allocating memory to store "
3127 "unprivileged username");
3128 }
3129
3130 fclose(fp);
3131 return(-1);
3132 }
3133
3134 strncpy(unprivuser, value, strlen(value)+1);
3135 unprivuser_f=1;
3136 }
3137 else if(strncmp(key, "UnprivilegedGroup", MAX_VAR_NAME_LEN) == 0){
3138 if( (unprivgroup= malloc(strlen(value)+1)) == NULL){
3139 if(verbose_f){
3140 if(showconfig_f)
3141 puts("process_config_file(): Error while allocating memory to store "
3142 "unprivileged group name");
3143 else
3144 syslog(LOG_ERR, "process_config_file(): Error while allocating memory to store "
3145 "unprivileged group name");
3146 }
3147
3148 fclose(fp);
3149 return(-1);
3150 }
3151
3152 strncpy(unprivgroup, value, strlen(value)+1);
3153 unprivgroup_f=1;
3154 }
3155 else if(strncmp(key, "MaxAddressEntries", MAX_VAR_NAME_LEN) == 0){
3156 maxaddrentries= (unsigned int) atoi(value);
3157 maxaddrentries_f=1;
3158 }
3159 else if(strncmp(key, "MaxCandidateEntries", MAX_VAR_NAME_LEN) == 0){
3160 maxcandentries= (unsigned int) atoi(value);
3161 maxcandentries_f=1;
3162 }
3163 else if(strncmp(key, "CandidateAddressTimeout", MAX_VAR_NAME_LEN) == 0){
3164 candaddrtimeout= (unsigned int) atoi(value);
3165 candaddrtimeout_f=1;
3166 }
3167 else if(strncmp(key, "AddressTimeout", MAX_VAR_NAME_LEN) == 0){
3168 addrtimeout= (unsigned int) atoi(value);
3169 addrtimeout_f=1;
3170 }
3171 else if(strncmp(key, "ProbeType", MAX_VAR_NAME_LEN) == 0){
3172 if(strncmp(value, "echo", strlen("echo")) == 0){
3173 probe_echo_f=1;
3174 probetype_f=1;
3175 }
3176 else if(strncmp(value, "unrec", strlen("unrec")) == 0){
3177 probe_unrec_f=1;
3178 probetype_f=1;
3179 }
3180 else if(strncmp(value, "all", strlen("all")) == 0){
3181 probe_echo_f=1;
3182 probe_unrec_f=1;
3183 probetype_f=1;
3184 }
3185 else{
3186 if(verbose_f){
3187 if(showconfig_f)
3188 puts("process_config_file(): Uknown ProbeType in configuration file");
3189 else
3190 syslog(LOG_ERR, "process_config_file(): Uknown ProbeType in configuration file");
3191 }
3192
3193 fclose(fp);
3194 return(-1);
3195 }
3196 }
3197 else if(strncmp(key, "UnicastProbeInterval", MAX_VAR_NAME_LEN) == 0){
3198 unicastprobeint= (unsigned int) atoi(value);
3199 unicastprobeint_f=1;
3200 }
3201 else if(strncmp(key, "MaxUnprobedInterval", MAX_VAR_NAME_LEN) == 0){
3202 maxunprobedint= (unsigned int) atoi(value);
3203 maxunprobedint_f=1;
3204 }
3205 else if(strncmp(key, "McastEchoProbeInterval", MAX_VAR_NAME_LEN) == 0){
3206 mcechoprobeint= (unsigned int) atoi(value);
3207 mcechoprobeint_f=1;
3208 }
3209 else if(strncmp(key, "McastUnrecProbeInterval", MAX_VAR_NAME_LEN) == 0){
3210 mcunrecprobeint= (unsigned int) atoi(value);
3211 mcunrecprobeint_f=1;
3212 }
3213 else if(strncmp(key, "TimestampFormat", MAX_VAR_NAME_LEN) == 0){
3214 if(strncmp(value, "date", strlen("date")) == 0){
3215 timestampf= TIMESTAMP_DATE;
3216 timestampf_f=1;
3217 }
3218 else if(strncmp(value, "epoch", strlen("epoch")) == 0){
3219 timestampf= TIMESTAMP_EPOCH;
3220 timestampf_f=1;
3221 }
3222 else{
3223 if(verbose_f){
3224 if(showconfig_f)
3225 puts("process_config_file(): Uknown TimestampFormat");
3226 else
3227 syslog(LOG_ERR, "process_config_file(): Uknown TimestampFormat");
3228 }
3229
3230 fclose(fp);
3231 return(-1);
3232 }
3233 }
3234
3235 }
3236 else if(r == -1){
3237 if(verbose_f){
3238 if(showconfig_f)
3239 printf("process_config_file(): Error in line %u of configuration file\n", ln);
3240 else
3241 syslog(LOG_ERR, "process_config_file(): Error in line %u of configuration file", ln);
3242 }
3243
3244 fclose(fp);
3245 return(-1);
3246 }
3247
3248 ln++;
3249 }
3250
3251 fclose(fp);
3252
3253 if(!logfile_f)
3254 logfile="/var/log/ipv6mon.log";
3255
3256 if(!lockfile_f)
3257 lockfile="/var/run/ipv6mon.pid";
3258
3259 if(!unprivuser_f)
3260 unprivuser="ipv6mon";
3261
3262 if(!unprivgroup_f)
3263 unprivgroup="ipv6mon";
3264
3265 if(!maxaddrentries_f)
3266 maxaddrentries= MAX_ADDR_ENTRIES;
3267
3268 if(!maxcandentries_f){
3269 maxcandentries= maxaddrentries/4;
3270
3271 if(maxcandentries < MIN_ADDR_ENTRIES)
3272 maxcandentries= MIN_ADDR_ENTRIES;
3273 }
3274
3275 if(!addrtimeout_f)
3276 addrtimeout= ADDR_TIMEOUT;
3277
3278 if(!candaddrtimeout_f){
3279 if(addrtimeout > CAND_ADDR_TIMEOUT)
3280 candaddrtimeout= CAND_ADDR_TIMEOUT;
3281 else
3282 candaddrtimeout= addrtimeout;
3283 }
3284
3285 if(!maxunprobedint_f)
3286 maxunprobedint= MAX_UNPROBED_INTERVAL;
3287
3288 if(!unicastprobeint_f)
3289 unicastprobeint= UNICAST_PROBE_INTERVAL;
3290
3291 if(!mcechoprobeint_f)
3292 mcechoprobeint= MC_ECHO_PROBE_INTERVAL;
3293
3294 if(!mcunrecprobeint_f)
3295 mcunrecprobeint= MC_UNREC_PROBE_INTERVAL;
3296
3297 if(!timestampf_f)
3298 timestampf= TIMESTAMP_DATE;
3299
3300 if(!probetype_f){
3301 probe_echo_f=1;
3302 probe_unrec_f=1;
3303 probetype_f=1;
3304 }
3305
3306 if(strncmp(unprivuser, "root", MAX_VAR_NAME_LEN) == 0){
3307 if(showconfig_f)
3308 puts("process_config_file(): UnprivilegedUser cannot be set to 'root'");
3309 else
3310 syslog(LOG_ERR, "process_config_file(): UnprivilegedUser cannot be set to 'root'");
3311
3312 return(-1);
3313 }
3314
3315 if(maxaddrentries <= MIN_ADDR_ENTRIES){
3316 if(showconfig_f)
3317 puts("process_config_file(): MaxAddressEntries too small");
3318 else
3319 syslog(LOG_ERR, "process_config_file(): MaxAddressEntries too small");
3320
3321 return(-1);
3322 }
3323
3324 if(maxcandentries >= maxaddrentries){
3325 if(showconfig_f)
3326 puts("process_config_file(): Incompatible MaxAddressEntries and MaxCandidateEntries values");
3327 else
3328 syslog(LOG_ERR, "process_config_file(): Incompatible MaxAddressEntries and MaxCandidateEntries values");
3329
3330 return(-1);
3331 }
3332
3333 if(maxunprobedint > addrtimeout){
3334 if(showconfig_f)
3335 puts("process_config_file(): Incompatible MaxUnprobedInterval and AddressTimeout values");
3336 else
3337 syslog(LOG_ERR, "process_config_file(): Incompatible MaxUnprobedInterval and AddressTimeout values");
3338
3339 return(-1);
3340 }
3341
3342 if(unicastprobeint < MIN_UNICAST_PROBE_INTERVAL){
3343 if(showconfig_f)
3344 puts("process_config_file(): UnicastProbeInterval value too small");
3345 else
3346 syslog(LOG_ERR, "process_config_file(): UnicastProbeInterval value too small");
3347
3348 return(-1);
3349 }
3350
3351 if(mcechoprobeint < MIN_MC_ECHO_PROBE_INTERVAL){
3352 if(showconfig_f)
3353 puts("process_config_file(): McastEchoProbeInterval value too small");
3354 else
3355 syslog(LOG_ERR, "process_config_file(): McastEchoProbeInterval value too small");
3356
3357 return(-1);
3358 }
3359
3360 if(mcunrecprobeint < MIN_MC_UNREC_PROBE_INTERVAL){
3361 if(showconfig_f)
3362 puts("process_config_file(): McastEchoProbeInterval value too small");
3363 else
3364 syslog(LOG_ERR, "process_config_file(): McastEchoProbeInterval value too small");
3365
3366 return(-1);
3367 }
3368
3369 return(0);
3370 }
3371
3372
3373 /*
3374 * Function: keyval()
3375 *
3376 * Obtains a (variable, value) pair from a line of text in "variable=value # comments" format
3377 */
3378
keyval(char * line,unsigned int len,char ** key,char ** val)3379 int keyval(char *line, unsigned int len, char **key, char **val){
3380 char *ptr;
3381 ptr= line;
3382
3383 /* Skip initial spaces (e.g. " variable=value") */
3384 while( (*ptr==' ' || *ptr=='\t') && ptr < (line+len))
3385 ptr++;
3386
3387 /* If we got to end of line or there is a comment or equal sign, there is no (variable, value) pair) */
3388 if(ptr==(line+len) || *ptr=='#' || *ptr=='=' || *ptr=='\r' || *ptr=='\n')
3389 return 0;
3390
3391 *key=ptr;
3392
3393 /* The variable name is everything till (and excluding) the first separator character (e.g., space or tab) */
3394 while( (*ptr!=' ' && *ptr!='\t' && *ptr!='\r' && *ptr!='\n' && *ptr!='#' && *ptr!='=') && ptr < (line+len))
3395 ptr++;
3396
3397 /*
3398 If the variable name is followed by a comment sign, or occupies the entire line, there's an error
3399 in the config file (i.e., there is no "variable=value" pair)
3400 */
3401 if(ptr==(line+len) || *ptr=='#' || *ptr=='\r' || *ptr=='\n')
3402 return -1;
3403
3404
3405 if(*ptr==' ' || *ptr=='\t'){
3406 /* The variable name is followed by spaces -- skip them, and find the "equal to" sign */
3407 *ptr=0; /* NULL-terminate the key */
3408 ptr++;
3409
3410 while(ptr<(line+len) && (*ptr==' ' || *ptr=='\t'))
3411 ptr++;
3412
3413 if(ptr==(line+len) || *ptr!='=')
3414 return -1;
3415
3416 ptr++;
3417 }else{
3418 /* The variable name is followed by the "equal to" sign */
3419 *ptr=0;
3420 ptr++;
3421 }
3422
3423 /*
3424 If the equal sign is followed by spaces, skip them
3425 */
3426 while( (*ptr==' ' || *ptr=='\t') && ptr<(line+len))
3427 ptr++;
3428
3429 /* We found the "value" in the "variable=value" pair */
3430 *val=ptr;
3431
3432 /* The value is everthing till (and excluding) the first separator character */
3433 while( (*ptr!='#' && *ptr!='\r' && *ptr!='\n' && *ptr!='\t' && *ptr!='=' && *ptr!=' ') && ptr < (line+len))
3434 ptr++;
3435
3436 /* If the value string was actually "empty", we return an error */
3437 if(ptr == *val)
3438 return(-1);
3439
3440 *ptr=0;
3441 return(1);
3442 }
3443
3444
3445 /*
3446 * Function: make_daemon()
3447 *
3448 * Makes the current program become a daemon
3449 */
3450
make_daemon(void)3451 int make_daemon(void){
3452 pid_t pid;
3453 int fd0, fd1, fd2;
3454 struct rlimit r1;
3455 struct sigaction sa;
3456
3457 /*
3458 Set the umask such that "group" and "others" can only (by default) read files
3459 (e.g. the lockfile)
3460 */
3461 umask(S_IWGRP | S_IXGRP | S_IWOTH | S_IXOTH);
3462
3463 if(getrlimit(RLIMIT_NOFILE, &r1) < 0){
3464 if(verbose_f)
3465 syslog(LOG_ERR, "make_daemon(): Cannot get file limit");
3466
3467 return(-1);
3468 }
3469
3470 if( (pid=fork()) < 0){
3471 if(verbose_f)
3472 syslog(LOG_ERR, "make_daemon(): Error while forking first process");
3473
3474 return(-1);
3475 }
3476 else if(pid != 0){
3477 exit(0);
3478 }
3479
3480 setsid();
3481
3482 sa.sa_handler = SIG_IGN;
3483 sigemptyset(&sa.sa_mask);
3484 sa.sa_flags = 0;
3485
3486 if(sigaction(SIGHUP, &sa, NULL) < 0){
3487 if(verbose_f)
3488 syslog(LOG_ERR, "make_daemon(): Error when setting handler for SIGHUP");
3489
3490 return(-1);
3491 }
3492
3493 if((pid=fork()) < 0){
3494 if(verbose_f)
3495 puts("make_daemon(): Error when forking second process");
3496
3497 return(-1);
3498 }
3499 else if(pid != 0){
3500 exit(0);
3501 }
3502
3503 if(chdir("/") < 0){
3504 if(verbose_f)
3505 syslog(LOG_ERR, "Error while changing current working directory");
3506
3507 return(-1);
3508 }
3509
3510 if(r1.rlim_max == RLIM_INFINITY)
3511 r1.rlim_max = 1024;
3512
3513 for(i=0; i < r1.rlim_max; i++)
3514 close(i);
3515
3516 fd0 = open("/dev/null", O_RDWR);
3517 fd1 = dup(0);
3518 fd2 = dup(0);
3519
3520 if(fd0 != 0 || fd1 != 1 || fd2 != 2){
3521 if(verbose_f)
3522 syslog(LOG_ERR, "Unexpected descriptors (%d, %d, %d) when opening to /dev/null", fd0, fd1, fd2);
3523
3524 return(-1);
3525 }
3526
3527 return 0;
3528 }
3529
3530
3531 /*
3532 * Function: already_running()
3533 *
3534 * Check whether another instance of the daemon is already running
3535 */
3536
already_running(void)3537 int already_running(void){
3538 struct flock fl;
3539 int fd;
3540 char buffer[100];
3541
3542 if( (fd=open(lockfile, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0){
3543 if(verbose_f)
3544 syslog(LOG_ERR, "already_running(): open(): %m");
3545
3546 return(-1);
3547 }
3548
3549 fl.l_type= F_WRLCK;
3550 fl.l_start= 0;
3551 fl.l_whence= SEEK_SET;
3552 fl.l_len= 0;
3553
3554 if(fcntl(fd, F_SETLK, &fl) == -1){
3555 if(errno==EACCES || errno==EAGAIN){
3556 close(fd);
3557 return 1;
3558 }
3559 else{
3560 close(fd);
3561 return(-1);
3562 }
3563 }
3564
3565 if(ftruncate(fd, 0) == -1){
3566 if(verbose_f)
3567 syslog(LOG_ERR, "already_running(): ftruncate(): %m");
3568
3569 close(fd);
3570 return(-1);
3571 }
3572
3573 if(snprintf(buffer, 100, "%lu", (LUI) getpid()) < 0){
3574 if(verbose_f)
3575 syslog(LOG_ERR, "already_running(): snprintf(): %m");
3576
3577 close(fd);
3578 return(-1);
3579 }
3580
3581 if(write(fd, buffer, strlen(buffer)+1) == -1){
3582 if(verbose_f)
3583 syslog(LOG_ERR, "already_running(): write(): %m");
3584
3585 close(fd);
3586 return(-1);
3587 }
3588
3589 return 0;
3590 }
3591
3592
3593 /*
3594 * Function: log_start()
3595 *
3596 * Records to the address log and to syslog that ipv6mon is starting
3597 */
3598
log_start(struct iface_data * idata)3599 int log_start(struct iface_data *idata){
3600 time_t curtime;
3601 char date[30];
3602
3603 curtime= time(NULL);
3604
3605 if(timestampf == TIMESTAMP_DATE){
3606 ctime_r(&curtime, date);
3607 date[24]=0;
3608
3609 if(fprintf(fplog, "%s %s INI_ADDR (Start logging IPv6 addresses)\n", date, idata->iface) < 0){
3610 if(verbose_f)
3611 syslog(LOG_ERR, "log_start(): fprintf(): %s", strerror(errno));
3612
3613 return(-1);
3614 }
3615 else{
3616 fflush(fplog);
3617 }
3618 }
3619 else{
3620 if(fprintf(fplog, "%lu %s INI_ADDR (Start logging IPv6 addresses)\n", (LUI) curtime, idata->iface) < 0){
3621 if(verbose_f)
3622 syslog(LOG_ERR, "log_start(): fprintf(): %s", strerror(errno));
3623
3624 return(-1);
3625 }
3626 else{
3627 fflush(fplog);
3628 }
3629 }
3630
3631 syslog(LOG_INFO, "Starting IPv6 address monitoring on %s", idata->iface);
3632 return 0;
3633 }
3634
3635
3636 /*
3637 * Function: log_stop()
3638 *
3639 * Logs to the address log and to syslog that ipv6mon is stopping
3640 */
3641
log_stop(struct iface_data * idata)3642 int log_stop(struct iface_data *idata){
3643 time_t curtime;
3644 char date[30];
3645
3646 curtime= time(NULL);
3647
3648 if(timestampf == TIMESTAMP_DATE){
3649 ctime_r(&curtime, date);
3650 date[24]=0;
3651
3652 if(fprintf(fplog, "%s %s STP_ADDR (Stopping IPv6 address monitoring)\n", date, idata->iface) < 0){
3653 syslog(LOG_ERR, "Error writing to address log while shutting down");
3654 return(-1);
3655 }
3656 }
3657 else{
3658 if(fprintf(fplog, "%lu %s STP_ADDR (Stopping IPv6 address monitoring)\n", (LUI) curtime, idata->iface) < 0){
3659 syslog(LOG_ERR, "Error writing to address log while shutting down");
3660 return(-1);
3661 }
3662 }
3663
3664 syslog(LOG_INFO, "Stopping IPv6 address monitoring on %s", idata->iface);
3665 return 0;
3666 }
3667
3668
3669 /*
3670 * Function: sig_term()
3671 *
3672 * Handler for the SIGTERM signal. Sets a flag such that the main loop records in the address log
3673 * and to syslog that ipv6mon is being shut down.
3674 */
3675
sigterm(int signo)3676 void sigterm(int signo){
3677 shutdown_f= 1;
3678 }
3679
3680