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