1 /*
2  * radns - Router Advertisement DNS
3  *
4  * Small program to listen for IPv6 Router Advertisements with the
5  * RDNSS (Recursive DNS Server) option.
6  *
7  * If we see an RDNSS option, we get the IPv6 address to the recursive
8  * DNS and store it in a file in the resolv.conf format, resolver(5).
9  *
10  * Originally written by Michael Cardell Widerkrantz (MC) for
11  * Stickybit AB and then maintained by MC.
12  *
13  * Contact:
14  *
15  *   mc at the domain hack.org
16  *
17  * Copyright (c) 2008, Stickybit AB.
18  * All rights reserved.
19  *
20  * Copyright (c) 2009, 2010, 2011 Michael Cardell Widerkrantz.
21  * All rights reserved.
22  *
23  * Redistribution and use in source and binary forms, with or without
24  * modification, are permitted provided that the following conditions
25  * are met:
26  *
27  *   * Redistributions of source code must retain the above copyright
28  *     notice, this list of conditions and the following disclaimer.
29  *
30  *   * Redistributions in binary form must reproduce the above
31  *     copyright notice, this list of conditions and the following
32  *     disclaimer in the documentation and/or other materials provided
33  *     with the distribution.
34  *
35  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
36  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
37  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
38  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
39  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
40  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
41  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
42  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
43  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
44  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
45  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
46  *
47  */
48 
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <stdint.h>
52 #include <stdarg.h>
53 #include <stdbool.h>
54 #include <syslog.h>
55 #include <unistd.h>
56 #include <signal.h>
57 #include <getopt.h>
58 #include <pwd.h>
59 #include <time.h>
60 #include <sys/socket.h>
61 #include <sys/wait.h>
62 #include <sys/uio.h>
63 #include <net/if.h>
64 #include <netinet/in.h>
65 #include <netinet/ip6.h>
66 #include <netinet/icmp6.h>
67 #include <arpa/inet.h>
68 #include <sys/stat.h>
69 #include <fcntl.h>
70 #include <string.h>
71 #include <errno.h>
72 
73 #include "list.h"
74 
75 /* #define TEST 1 */
76 
77 #define RESOLVEFILE "./resolv.conf"
78 
79 #define PIDFILE "/var/run/radns.pid"
80 
81 #define USER "radns"
82 
83 /* The Resolving DNS Server option, RFC 6106. */
84 #define ND_OPT_RDNSS  25
85 
86 /* The DNS Search List option, RFC 6106. */
87 #define ND_OPT_DNSSL 31
88 
89 /* Space for "nameserver %s \n" where %s is the IPv6 address */
90 #define NSADDRSIZE (13 + INET6_ADDRSTRLEN)
91 
92 /*
93  * XXX PACKETSIZE really taken out of the blue. Expected size of
94  * incoming packets is:
95  *
96  *   ICMP6 header  8 bytes
97  *   RA            minimum 24 bytes
98  *   RDNSS option  minimum 24 bytes
99  *
100  * That is, minimum 56 bytes, with unknown max for patological cases.
101  */
102 #define PACKETSIZE 1024
103 
104 /*
105  * Minimum length in bytes of the RDNSS option if we're going to care
106  * about it. Exactly 3 * 8 = 24 octets if there is one IPv6 address.
107  */
108 #define RDNSSMINLEN 24
109 
110 /*
111  * Lifetime that never expires.
112  */
113 #define NEVEREXP 0xffffffff
114 
115 /*
116  * Maximum number of octets in a domain name as per RFC 1035
117  */
118 #define MAXNAME 255
119 
120 char *progname; /* argv[0] */
121 char *filename = RESOLVEFILE;
122 char *pidfilename = PIDFILE;
123 char *scriptname = NULL;
124 bool progdone;                /* true when we exit the program. */
125 int verbose = 0;                /* how much debug output? */
126 int localerrno;                 /* our own copy of errno. */
127 bool childcare = false;       /* true when we need to reap zombies. */
128 
129 /*
130  * Default for maximum number of stored resolver addresses. Can be
131  * overridden by a runtime option.
132  *
133  * XXX A default called MAXNS might be in resolv.h, depending on
134  * system. We might want to use that as default if it exists.
135  */
136 int maxres = 3;
137 
138 /*
139  * Default for maximum number of stored domain suffixes.
140  */
141 int maxsuf = 6;
142 
143 struct resolver
144 {
145     struct in6_addr addr;       /* Address to DNS server. */
146     char ifname[IFNAMSIZ];      /* Interface name we received this data on. */
147     time_t expire;              /* Expire time of this data. */
148     bool neverexp;
149     struct item *item;          /* Pointer to our place in the list. */
150 };
151 
152 struct suffix
153 {
154     char name[255];
155     int len;               /* Length of domain name suffix. */
156     char ifname[IFNAMSIZ];      /* Interface name we received this data on. */
157     time_t expire;              /* Expire time of this data. */
158     bool neverexp;
159     struct item *item;          /* Pointer to our place in the list. */
160 };
161 
162 /* Recursive DNS Server (RDNSS) option in Router Advertisments. */
163 struct radns_opt_rdnss
164 {
165     uint8_t nd_opt_type; /* Should be 25 (0x19) for RDNSS */
166     uint8_t nd_opt_len; /* Length: 3 (* 8 octets) if one IPv6
167                            address. No of addresses = (Length -
168                            1) / 2.  If less than 3, disregard.*/
169     uint16_t nd_opt_rdns_res; /* Reserved. */
170     uint32_t nd_opt_rdns_life; /* The maximum time in seconds to
171                                   use this from the time it was
172                                   sent. */
173 } __attribute__((__packed__));
174 
175 /* DNS Search List option in Router Advertisments. */
176 struct radns_opt_dnssl
177 {
178     uint8_t nd_opt_type;
179     uint8_t nd_opt_len;
180     uint16_t nd_opt_dnssl_res;
181     uint32_t nd_opt_dnssl_life;
182 } __attribute__((__packed__));
183 
184 static struct resolver *expirenext(struct item *reslist);
185 static struct resolver *findresolv(struct in6_addr addr, struct item *reslist);
186 static bool rdnss(const struct radns_opt_rdnss *rdnssp, int optlen,
187            int lenleft, struct item **reslist, int *storedres,
188            char ifname[IFNAMSIZ]);
189 static bool dnssl(const struct radns_opt_dnssl *dnsslp, int optlen,
190            int lenleft, struct item **suflist, int *storedsuf,
191            char ifname[IFNAMSIZ]);
192 static int dnsname(char *domain, uint8_t *name, int buflen);
193 static void hexdump(uint8_t *buf, uint16_t len);
194 static void printhelp(void);
195 void sigcatch(int sig);
196 static int exithook(char *filename, char *ifname);
197 static int writeresolv(struct item *suflist, int storedsuf,
198                        struct item *reslist);
199 static void logmsg(int pri, const char *message, ...);
200 static bool expireresolv(struct item **reslist, int *storedres);
201 static bool addresolver(struct item **reslist, int *storedres, uint32_t ttl,
202                         struct in6_addr addr, char *ifname);
203 static bool addsuffix(struct item **suflist, int *storedsuf, uint32_t ttl,
204                       char *name, int namelen, char *ifname);
205 static struct suffix *sufexpirenext(struct item *suflist);
206 static bool expiresuffix(struct item **suflist, int *storedsuf);
207 static struct suffix *findsuffix(char *name, int namelen, struct item *suflist);
208 static bool handle_icmp6(int sock, struct item **suflist, int *storedsuf,
209                          struct item **reslist, int *storedres,
210                          char ifname[IFNAMSIZ]);
211 static int mkpidfile(uid_t owner, gid_t group);
212 
213 #ifdef TEST
214 static void deladdr(struct item **reslist, int *storedres,
215                     struct in6_addr addr);
216 static void printrewrite(bool rewrite);
217 static void listsuf(struct item *suflist);
218 static void listres(struct item *reslist);
219 static void printrewrite(bool rewrite);
220 #endif
221 
222 /*
223  * Find resolver in list reslist that will expire next. Returns a
224  * pointer to the resolver or NULL if there are no resolvers.
225  */
expirenext(struct item * reslist)226 static struct resolver *expirenext(struct item *reslist)
227 {
228     time_t least = 0;
229     struct resolver *res;
230     struct resolver *leastres = NULL;
231     struct item *item;
232 
233     for (item = reslist; item != NULL; item = item->next)
234     {
235         res = item->data;
236         if (0 != res->expire)
237         {
238             if (0 == least || res->expire < least)
239             {
240                 least = res->expire;
241                 leastres = res;
242             }
243         }
244     }
245 
246     return leastres;
247 }
248 
249 /*
250  * Find resolver with address addr in list reslist. Returns a pointer
251  * to the matching resolver or NULL if not found.
252  */
findresolv(struct in6_addr addr,struct item * reslist)253 static struct resolver *findresolv(struct in6_addr addr, struct item *reslist)
254 {
255     struct item *item;
256     struct resolver *res;
257 
258     for (item = reslist; item != NULL; item = item->next)
259     {
260         res = item->data;
261         if (0 == memcmp(&addr, &res->addr, sizeof (addr)))
262         {
263             return res;
264         }
265     }
266 
267     return NULL;
268 }
269 
rdnss(const struct radns_opt_rdnss * rdnssp,int optlen,int lenleft,struct item ** reslist,int * storedres,char ifname[IFNAMSIZ])270 static bool rdnss(const struct radns_opt_rdnss *rdnssp, int optlen,
271                   int lenleft, struct item **reslist, int *storedres,
272                   char ifname[IFNAMSIZ])
273 {
274     int nr_of_addrs;
275     int i;
276     struct in6_addr *addrp;      /* An IPv6 address. */
277     uint8_t *datap;            /* An octet pointer we use for running
278                                  * through data in rdnssp. */
279     bool rewrite = false;
280 
281     datap = (uint8_t *)rdnssp;
282 
283     /* We got an RDNSS option, that is,
284      *
285      * type, length, reserved,
286      * lifetime
287      * addresses
288      */
289 
290     if (verbose > 2)
291     {
292         printf("  reserved: %d\n", rdnssp->nd_opt_rdns_res);
293         printf("  lifetime: %d\n", ntohl(rdnssp->nd_opt_rdns_life));
294     }
295 
296     /* Extract DNS address(es) from option. */
297 
298     /*
299      * Length should be 3 (* 8 octets) if there is one IPv6
300      * address. If less than 3 * 8 octets, disregard this
301      * option.
302      */
303     if (optlen < RDNSSMINLEN)
304     {
305         /* No IPv6 address here. Throw away. */
306         logmsg(LOG_INFO, "No IPv6 address in RDNSS option.\n");
307         return rewrite;
308     }
309 
310     /* Move to first IPv6 address. */
311     datap += sizeof (struct radns_opt_rdnss);
312     lenleft -= sizeof (struct radns_opt_rdnss);
313 
314     if (lenleft <= 0)
315     {
316         /* Out of data! */
317         logmsg(LOG_INFO, "RDNSS option: Out of data.\n");
318         return rewrite;
319     }
320 
321     /* How many addresses to DNS servers are there? */
322     nr_of_addrs = (rdnssp->nd_opt_len - 1) / 2;
323 
324     if (verbose > 0)
325     {
326         printf("%d address(es) to resolving DNS servers found.\n",
327                nr_of_addrs);
328     }
329 
330     /* Find the addresses and store them. */
331     for (i = 0; i < nr_of_addrs
332              && (unsigned)lenleft > sizeof (struct in6_addr); i ++)
333     {
334         addrp = (struct in6_addr *)datap;
335 
336         rewrite = addresolver(reslist, storedres,
337                               ntohl(rdnssp->nd_opt_rdns_life),
338                               *addrp, ifname);
339 
340         /* Move to next address, if any. */
341         datap += sizeof (struct in6_addr);
342         lenleft -= sizeof (struct in6_addr);
343     } /* for */
344 
345     /* Tell caller if we need to rewrite the file. */
346     return rewrite;
347 }
348 
349 
350 /*
351  * Get a series of labels with RFC 1035 encoding in name and add them
352  * to a domain string, domain.
353  *
354  * Returns length of final domain string which also happens to be the
355  * number of bytes consumed by parsing in name.
356  *
357  * From RFC 1035:
358  *
359  *   Domain names in messages are expressed in terms of a sequence of
360  *   labels. Each label is represented as a one octet length field
361  *   followed by that number of octets. Since every domain name ends
362  *   with the null label of the root, a domain name is terminated by a
363  *   length byte of zero. The high order two bits of every length
364  *   octet must be zero, and the remaining six bits of the length
365  *   field limit the label to 63 octets or less.
366  *
367  *   To simplify implementations, the total length of a domain name
368  *   (i.e., label octets and label length octets) is restricted to 255
369  *   octets or less.
370  */
dnsname(char * domain,uint8_t * name,int buflen)371 static int dnsname(char *domain, uint8_t *name, int buflen)
372 {
373     uint8_t len;                /* Length of label. */
374     uint8_t domleft = MAXNAME; /* Number of octets left free in domain. */
375     int strlen;                 /* Length of domain string. */
376     uint8_t *bytep;             /* Octet pointer used to walk the name. */
377 
378     strlen = 0;
379 
380     /*
381      * Walk through each label and copy each label to the domain
382      * string adding "." between them. When we run out of buffer
383      * (pathological) or find a zero length (fine) we're done.
384      */
385     for (bytep = name; buflen > 0 && (uint8_t) *bytep != 0; )
386     {
387         len = *bytep;
388         bytep ++;
389         domleft --;
390 
391         if (domleft > len && len <= (uint8_t)buflen)
392         {
393             if (len != 0)
394             {
395                 memcpy(&domain[strlen], bytep, len);
396                 bytep += len;
397                 domleft -= len;
398                 buflen -= len;
399 
400                 strlen += len;
401             }
402 
403             domain[strlen] = '.';
404             strlen ++;
405         }
406     }
407 
408     return strlen;
409 }
410 
dnssl(const struct radns_opt_dnssl * dnsslp,int optlen,int lenleft,struct item ** suflist,int * storedsuf,char ifname[IFNAMSIZ])411 static bool dnssl(const struct radns_opt_dnssl *dnsslp, int optlen,
412                   int lenleft, struct item **suflist, int *storedsuf,
413                   char ifname[IFNAMSIZ])
414 {
415     uint8_t *datap;            /* An octet pointer we use for running
416                                  * through data in rdnssp. */
417     bool rewrite = false;
418     char domain[MAXNAME];
419     int domlen;
420     int optlenleft = optlen;
421 
422     if (verbose > 0)
423     {
424         printf("We received a DNSSL!\n");
425     }
426 
427     datap = (uint8_t *)dnsslp;
428 
429     if (verbose > 2)
430     {
431         printf("  reserved: %d\n", dnsslp->nd_opt_dnssl_res);
432         printf("  lifetime: %d\n", ntohl(dnsslp->nd_opt_dnssl_life));
433     }
434 
435     /*
436      * Length is at minimum 2 (* 8 octets) if there is exactly one
437      * domain. If less, we disregard this option.
438      */
439     if (optlen < 2)
440     {
441         logmsg(LOG_INFO, "No Domain Suffix in DNSSL option.\n");
442         return rewrite;
443     }
444 
445     /*
446     Domain Names of DNS Search List
447                   One or more domain names of DNS Search List that MUST
448                   be encoded using the technique described in Section
449                   3.1 of [RFC1035].  By this technique, each domain
450                   name is represented as a sequence of labels ending in
451                   a zero octet, defined as domain name representation.
452                   For more than one domain name, the corresponding
453                   domain name representations are concatenated as they
454                   are.  Note that for the simple decoding, the domain
455                   names MUST NOT be encoded in a compressed form, as
456                   described in Section 4.1.4 of [RFC1035].  Because the
457                   size of this field MUST be a multiple of 8 octets,
458                   for the minimum multiple including the domain name
459                   representations, the remaining octets other than the
460                   encoding parts of the domain name representations
461                   MUST be padded with zeros.
462     */
463 
464     /* Move to first domain suffix. */
465     datap += sizeof (struct radns_opt_dnssl);
466     lenleft -= sizeof (struct radns_opt_dnssl);
467     optlenleft -= sizeof (struct radns_opt_dnssl);
468 
469     if (lenleft <= 0)
470     {
471         /* Out of data! */
472         logmsg(LOG_INFO, "DNSSL option: Out of data.\n");
473         return rewrite;
474     }
475 
476     while (optlenleft > 0 && lenleft > 0)
477     {
478         domlen = dnsname(domain, datap, optlenleft);
479         if (0 == domlen)
480         {
481             break;
482         }
483 
484         datap += domlen + 1;
485         lenleft -= domlen + 1;
486         optlenleft -= domlen + 1;
487 
488         if (verbose > 0)
489         {
490             printf("Got domain suffix:\n");
491             hexdump((uint8_t *)domain, domlen);
492         }
493 
494         rewrite = addsuffix(suflist, storedsuf,
495                             ntohl(dnsslp->nd_opt_dnssl_life), domain, domlen,
496                             ifname);
497     }
498 
499     return rewrite;
500 }
501 
502 /*
503  * Callback function when we get an ICMP6 message on socket sock.
504  *
505  * Returns true if we need to rewrite the resolv file and false
506  * otherwise.
507  */
handle_icmp6(int sock,struct item ** suflist,int * storedsuf,struct item ** reslist,int * storedres,char ifname[IFNAMSIZ])508 static bool handle_icmp6(int sock, struct item **suflist, int *storedsuf,
509                          struct item **reslist, int *storedres,
510                          char ifname[IFNAMSIZ])
511 {
512     uint8_t buf[PACKETSIZE];   /* The entire ICMP6 message. */
513     int buflen;                 /* The lenght of the ICMP6 buffer. */
514     uint8_t ancbuf[CMSG_SPACE(sizeof (struct in6_pktinfo)) ]; /* Ancillary
515                                                                * data. */
516     const struct nd_router_advert *ra; /* A Router Advertisement */
517     struct nd_opt_hdr *ndhdr;
518     uint8_t *datap;            /* An octet pointer we use for running
519                                  * through data in buf. */
520     int lenleft;                /* Length left in buf, in bytes,
521                                  * counting from datap. */
522     struct sockaddr_in6 src;    /* Source address of RA packet. */
523     struct iovec iov[1] =
524         {
525             { .iov_base = buf, .iov_len = sizeof (buf) }
526         };                      /* Incoming buffer. */
527     struct msghdr msg =
528         {
529             .msg_name = &src,
530             .msg_namelen = sizeof (src),
531             .msg_iov = iov,
532             .msg_iovlen = sizeof (iov) / sizeof (iov[0]),
533             .msg_control = ancbuf,
534             .msg_controllen = sizeof (ancbuf)
535         };                      /* Incoming message. */
536     struct in6_pktinfo *pktinfo = NULL; /* Metadata about the packet. */
537     struct cmsghdr *cmsgp;       /* Pointer to ancillary data. */
538     bool rewrite = false;
539 
540     if (-1 == (buflen = recvmsg(sock, &msg, 0)))
541     {
542         logmsg(LOG_ERR, "read error on raw socket\n");
543         return rewrite;
544     }
545 
546     if (msg.msg_flags & (MSG_TRUNC | MSG_CTRUNC))
547     {
548         logmsg(LOG_ERR, "truncated message\n");
549         return rewrite;
550     }
551 
552     /* Find our packet information (asked for by the IP6_RECVPKTINFO). */
553     for (cmsgp = CMSG_FIRSTHDR(&msg); cmsgp != NULL;
554          cmsgp = CMSG_NXTHDR(&msg, cmsgp))
555     {
556         if (cmsgp->cmsg_len == 0)
557         {
558             logmsg(LOG_ERR, "ancillary data with zero length.\n");
559             return rewrite;
560         }
561 
562         if ((cmsgp->cmsg_level == IPPROTO_IPV6) && (cmsgp->cmsg_type
563                                                     == IPV6_PKTINFO))
564         {
565             pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsgp);
566         }
567     }
568 
569     if (NULL != pktinfo)
570     {
571         /* Convert it to an interface name. */
572         if (NULL == if_indextoname(pktinfo->ipi6_ifindex, ifname))
573         {
574             logmsg(LOG_ERR, "couldn't find interface name: index %d\n",
575                    pktinfo->ipi6_ifindex);
576             strncpy(ifname, "<none>", IFNAMSIZ);
577         }
578     }
579     else
580     {
581         logmsg(LOG_ERR, "couldn't get ancillary data for packet.");
582         strncpy(ifname, "<none>", IFNAMSIZ);
583     }
584 
585     if (verbose > 0)
586     {
587         char srcaddrstr[INET6_ADDRSTRLEN];
588 
589         if (NULL == inet_ntop(AF_INET6, &src.sin6_addr, srcaddrstr,
590                               INET6_ADDRSTRLEN))
591         {
592             logmsg(LOG_ERR, "Couldn't convert IPv6 address to string\n");
593             return rewrite;
594         }
595 
596         printf("Received an IPv6 Router Advertisement from %s on interface "
597                "%s\n", srcaddrstr, ifname);
598 
599         if (NULL == inet_ntop(AF_INET6, &pktinfo->ipi6_addr, srcaddrstr,
600                               INET6_ADDRSTRLEN))
601         {
602             logmsg(LOG_ERR, "Couldn't convert IPv6 address to string\n");
603             return rewrite;
604         }
605 
606         printf("Sent to: %s\n", srcaddrstr);
607     }
608 
609     if (verbose > 2)
610     {
611         hexdump(buf, buflen);
612     }
613 
614     /*
615      * Keep buf and buflen pristine for possible later use. Walk the
616      * buffer with datap.
617      */
618     datap = buf;
619     lenleft = buflen;
620 
621     /* Get the router advertisement. */
622     ra = (struct nd_router_advert *)datap;
623 
624     /* Check that it really is an RA, code 134 */
625     if (ra->nd_ra_type != ND_ROUTER_ADVERT && ra->nd_ra_code != 0)
626     {
627         logmsg(LOG_INFO, "Not a Router Advertisement. Type: %d, code: %d. "
628                 "Why did we get it?\n",
629                 ra->nd_ra_type, ra->nd_ra_code);
630         return rewrite;
631     }
632 
633 /*
634 
635   RFC 4861, Neighbor Discovery for IP version 6 (IPv6), which defines
636   Router Advertisements says they look like this:
637 
638   0                   1                   2                   3
639   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
640   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
641   |     Type      |     Code      |          Checksum             |
642   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
643   | Cur Hop Limit |M|O|  Reserved |       Router Lifetime         |
644   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
645   |                         Reachable Time                        |
646   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
647   |                          Retrans Timer                        |
648   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
649   |   Options ...
650   +-+-+-+-+-+-+-+-+-+-+-+-
651 */
652 
653     if (verbose > 1)
654     {
655         printf("ICMP6 header\n");
656         printf("  nd_ra_type: %d\n", ra->nd_ra_type);
657         printf("  nd_ra_code: %d\n", ra->nd_ra_code);
658         printf("  nd_ra_cksum: %d\n", ra->nd_ra_cksum);
659 
660         printf("RA:\n");
661         printf("...\n");
662         printf("  nd_ra_reachable: %ld\n", (long)ra->nd_ra_reachable);
663         printf("  nd_ra_retransmit: %ld\n", (long)ra->nd_ra_retransmit);
664     }
665 
666     /* Move pass the RA header to any options we might find. */
667     datap += sizeof (struct nd_router_advert);
668     lenleft -= sizeof (struct nd_router_advert);
669 
670     if (0 >= lenleft)
671     {
672         /* Out of data. */
673         logmsg(LOG_INFO, "Missing data after RA header.\n");
674         return rewrite;
675     }
676 
677     /*
678      * Check for the options we want. We're looking for option RDNSS,
679      * 25.
680      */
681     if (verbose > 0)
682     {
683         printf("RA options:\n");
684     }
685     while (lenleft > 0)
686     {
687         int optlen;
688 
689         /*
690          * This is what an option looks like:
691          *
692          * 0                   1                   2                   3
693          * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
694          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
695          * |     Type      |    Length     |              ...              |
696          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
697          * ~                              ...                              ~
698          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
699          *
700          *
701          * Types:
702          *
703          * Source Link-Layer Address                    1
704          * Target Link-Layer Address                    2
705          * Prefix Information                           3
706          * Redirected Header                            4
707          * MTU                                          5
708          *
709          * RDNSS                                       25
710          *
711          * Length above is measured as a number of 64 bit components
712          * including the type and length bytes.
713          */
714 
715         ndhdr = (struct nd_opt_hdr *)datap;
716 
717         if (verbose > 0)
718         {
719             printf("  option type %d (0x%x)\n", ndhdr->nd_opt_type,
720                  ndhdr->nd_opt_type);
721         }
722 
723         /*
724          * The nd_opt_len is the number of 64 bit units the option
725          * contains including header.
726          */
727         optlen = ndhdr->nd_opt_len * 8;
728 
729         if (verbose > 2)
730         {
731             printf("  option length in header: %d (0x%x)\n", ndhdr->nd_opt_len,
732                    ndhdr->nd_opt_len);
733 
734             printf("  actual length in bytes: %d\n", optlen);
735 
736             hexdump(datap, optlen);
737         }
738 
739         switch (ndhdr->nd_opt_type)
740         {
741             bool rb;
742 
743         case ND_OPT_RDNSS:
744             rb = rdnss((const struct radns_opt_rdnss *)datap,
745                        optlen, lenleft, reslist, storedres,
746                        ifname);
747 
748             rewrite = rewrite || rb;
749 
750             break;
751 
752         case ND_OPT_DNSSL:
753             rb = dnssl((const struct radns_opt_dnssl *)datap,
754                        optlen, lenleft, suflist, storedsuf, ifname);
755 
756             rewrite = rewrite || rb;
757 
758             break;
759 
760         default:
761             /* Not a known option. */
762             if (verbose > 1)
763             {
764                 printf("Unknown RA option. Skipping...\n");
765             }
766             break;
767         } /* switch */
768 
769         /* Advance beyond this option. */
770         datap += optlen;
771         lenleft -= optlen;
772     } /* while */
773 
774     /* Tell caller if we need to rewrite resolv file. */
775     return rewrite;
776 }
777 
778 /*
779  * Log a message either through syslog if we are daemonized or through
780  * stderr if we're running in the foreground.
781  *
782  * pri is the syslog priority, such as LOG_INFO, message is the string
783  * including format characters and the rest is optional variables
784  * referenced by the format characters.
785  *
786  */
logmsg(int pri,const char * message,...)787 static void logmsg(int pri, const char *message, ...)
788 {
789     va_list ap;
790 
791     va_start(ap, message);
792 
793     if (verbose > 0)
794     {
795         vfprintf(stderr, message, ap);
796     }
797     else
798     {
799         vsyslog(pri, message, ap);
800     }
801 
802     va_end(ap);
803 }
804 
805 /*
806  * Call an external script to handle, for instance, interfacing with
807  * the resolvconf program.
808  *
809  * filename is our own 'resolv.conf' and ifname is the name of the
810  * local interface where we received the RA.
811  *
812  * Returns 0 on success.
813  */
exithook(char * filename,char * ifname)814 static int exithook(char *filename, char *ifname)
815 {
816     pid_t pid;
817 
818     if (NULL == scriptname)
819     {
820         /* No script. */
821         return 0;
822     }
823 
824     pid = fork();
825     if (-1 == pid)
826     {
827         logmsg(LOG_ERR, "couldn't fork.\n");
828         return -1;
829     }
830     else if (0 == pid)
831     {
832         char *argv[2];
833         char *env[3];
834 
835         /* We're in the child. */
836 
837         argv[0] = scriptname;
838         argv[1] = NULL;
839 
840         if (NULL == (env[0] = calloc(sizeof (char), 3 + 1 + strlen(ifname))))
841         {
842             logmsg(LOG_ERR, "out of memory.\n");
843             exit(1);
844         }
845         snprintf(env[0], 3 + 1 + strlen(ifname), "if=%s", ifname);
846 
847         if (NULL == (env[1] = calloc(sizeof (char), 12 + 1 + strlen(filename))))
848         {
849             logmsg(LOG_ERR, "out of memory.\n");
850             exit(1);
851         }
852         snprintf(env[1], 12 + 1 + strlen(filename), "resolv_conf=%s", filename);
853 
854         env[2] = NULL;
855 
856         if (-1 == execve(scriptname, argv, env))
857         {
858             localerrno = errno;
859             logmsg(LOG_ERR, "couldn't exec(): %s\nexiting...\n",
860                    strerror(localerrno));
861             exit(1);
862         }
863     } /* child */
864 
865     return 0;
866 }
867 
868 /*
869  * Write all the resolver addresses in list reslist in resolv file.
870  * Returns 0 if successful, -1 otherwise.
871  */
writeresolv(struct item * suflist,int storedsuf,struct item * reslist)872 static int writeresolv(struct item *suflist, int storedsuf,
873                        struct item *reslist)
874 {
875     int filefd;
876     char buf[NSADDRSIZE];
877     char *tmpfn;
878     struct item *item;
879     struct resolver *res;
880     struct suffix *suf;
881 
882     /*
883      * Create a temporary file in the same directory as our real
884      * resolver file.
885      */
886     if (-1 == asprintf(&tmpfn, "%s-work", filename))
887     {
888         logmsg(LOG_ERR, "Out of memory in writeresolv().\n");
889         return -1;
890     }
891 
892     if (-1 == (filefd = open(tmpfn, O_CREAT | O_WRONLY | O_TRUNC, 0644)))
893     {
894         logmsg(LOG_ERR, "Couldn't open working file %s\n", tmpfn);
895         goto bad;
896     }
897 
898     if (verbose > 2)
899     {
900         printf("Writing addresses to temporary file %s.\n", tmpfn);
901     }
902 
903     if (storedsuf > 0)
904     {
905         if (-1 == write(filefd, "search ", 7))
906         {
907             perror("write");
908             goto bad;
909         }
910 
911         /* Write search list to file. */
912         for (item = suflist; item != NULL; item = item->next)
913         {
914             suf = item->data;
915 
916             /* FIXME: Do this in one write(). */
917             if (-1 == write(filefd, suf->name, suf->len))
918             {
919                 perror("write");
920                 goto bad;
921             }
922             if (-1 == write(filefd, " ", 1))
923             {
924                 perror("write");
925                 goto bad;
926             }
927         } /* for */
928 
929         if (-1 == write(filefd, "\n", 1))
930         {
931             perror("write");
932             goto bad;
933         }
934     } /* if storedsuf */
935 
936     /* Write addresses to file. */
937     for (item = reslist; item != NULL; item = item->next)
938     {
939         char addrstr[INET6_ADDRSTRLEN];
940 
941         res = item->data;
942 
943         if (NULL == inet_ntop(AF_INET6, &res->addr,
944                               addrstr, INET6_ADDRSTRLEN))
945         {
946             logmsg(LOG_ERR, "Couldn't convert IPv6 address to "
947                    "string\n");
948         }
949         else
950         {
951             if (-1 == snprintf(buf, NSADDRSIZE, "nameserver %s\n",
952                                addrstr))
953             {
954                 perror("asprintf");
955                 goto bad;
956             }
957 
958             if (-1 == write(filefd, buf, strlen(buf)))
959             {
960                 perror("write");
961                 goto bad;
962             }
963         }
964     } /* for */
965 
966     /* Set file mode. */
967     if (-1 == fchmod(filefd, 0644))
968     {
969 	localerrno = errno;
970         logmsg(LOG_ERR, "Couldn't set file mode on %s: %s\n", tmpfn,
971                strerror(localerrno));
972         goto bad;
973     }
974 
975     close(filefd);
976 
977     /* Rename the temporary file to the real resolv.conf file. */
978 
979     if (verbose > 0)
980     {
981         printf("Creating resolver file %s.\n", filename);
982     }
983 
984     if (-1 == (rename(tmpfn, filename)))
985     {
986 	localerrno = errno;
987         logmsg(LOG_ERR, "Couldn't rename %s to %s: %s\n", tmpfn, filename,
988                strerror(localerrno));
989         goto bad;
990     }
991 
992     free(tmpfn);
993     return 0;
994 
995 bad:
996     close(filefd);
997     free(tmpfn);
998     return -1;
999 }
1000 
1001 /*
1002  * Dump the contents of pointer buf of length len as 16 bytes (32
1003  * hexadecimal digits) per row.
1004  */
hexdump(uint8_t * buf,uint16_t len)1005 static void hexdump(uint8_t *buf, uint16_t len)
1006 {
1007     uint8_t *row; /* Pointer to rows of 16 bytes each. */
1008     uint8_t *byte; /* Pointer to each byte in the row. */
1009     uint8_t *max; /* Pointer to the maximum address in buf. */
1010 
1011     /*
1012      * Start the row where the buffer begins. Remember where it ends
1013      * (max). Stop when row is at max.
1014      *
1015      * For every byte in each row, print the value. If we reach the
1016      * 16th byte, start a new row.
1017      */
1018     row = buf;
1019     max = &buf[len];
1020     for (byte = 0; byte != max; row = byte)
1021     {
1022         /* Print byte offset. */
1023         printf("%07tx ", row - buf);
1024 
1025         for (byte = row; byte != max && byte != (row + 16); byte ++)
1026         {
1027             printf("%02x ", *byte);
1028         }
1029 
1030         (void)putchar('\n');
1031     } /* Outer for */
1032 }
1033 
1034 /* Prints a helpful message. */
printhelp(void)1035 static void printhelp(void)
1036 {
1037     fprintf(stderr, "Usage: %s [-v [-v] [-v]] [-f filename] [-l max suffixes ]"
1038             "\n[-m max resolvers] [-u user] [-s script] [-p pidfile ]\n",
1039             progname);
1040 
1041     fprintf(stderr, "\n\n-f filename gives the filename the DNS resolving "
1042             "address is written to.\n Default is ./resolv.conf.\n");
1043     fprintf(stderr, "\n\n-l number-of-domain-suffixes sets an upper limit of "
1044             "how many domain suffixes\n to store in search list. 0 means no "
1045             "upper limit.\n");
1046     fprintf(stderr, "\n\n-m number-of-resolvers sets an upper limit of how "
1047             "many resolver addresses\n to store. 0 means no upper limit.\n");
1048     fprintf(stderr, "\n\n-u user sets username to drop privileges to. "
1049             "Default is 'radns'.\n");
1050     fprintf(stderr, "\n\n-s script executes 'script' after changing resolv "
1051             "file.\n");
1052     fprintf(stderr, "\n\n-p pidfile writes the process ID to 'pidfile'. "
1053             "By default it writes\n the process ID to %s.\n", PIDFILE);
1054 
1055     fprintf(stderr, "\n\n-v means more verbosity. Repeat for more.\n");
1056     fprintf(stderr, "\n\n-V to get version information.\n");
1057 }
1058 
1059 /* Signal handler for SIGCHLD. */
sigcatch(int sig)1060 void sigcatch(int sig)
1061 {
1062     if (SIGCHLD == sig)
1063     {
1064         /* A child process died. Tell main loop to deal with it. */
1065         childcare = true;
1066     }
1067     else
1068     {
1069         progdone = true;
1070     }
1071 }
1072 
findsuffix(char * name,int namelen,struct item * suflist)1073 static struct suffix *findsuffix(char *name, int namelen, struct item *suflist)
1074 {
1075     struct item *item;
1076     struct suffix *suf;
1077 
1078     for (item = suflist; item != NULL; item = item->next)
1079     {
1080         suf = item->data;
1081 
1082         if (namelen == suf->len && 0 == memcmp(name, suf->name, suf->len))
1083         {
1084             return suf;
1085         }
1086     }
1087 
1088     return NULL;
1089 }
1090 
sufexpirenext(struct item * suflist)1091 static struct suffix *sufexpirenext(struct item *suflist)
1092 {
1093     time_t least = 0;
1094     struct suffix *suf;
1095     struct suffix *leastsuf = NULL;
1096     struct item *item;
1097 
1098     for (item = suflist; item != NULL; item = item->next)
1099     {
1100         suf = item->data;
1101         if (0 != suf->expire)
1102         {
1103             if (0 == least || suf->expire < least)
1104             {
1105                 least = suf->expire;
1106                 leastsuf = suf;
1107             }
1108         }
1109     }
1110 
1111     return leastsuf;
1112 }
1113 
expiresuffix(struct item ** suflist,int * storedsuf)1114 static bool expiresuffix(struct item **suflist, int *storedsuf)
1115 {
1116     int expired = false;
1117     struct timespec now;
1118     struct item *item;
1119     struct suffix *suf;
1120 
1121     if (-1 == clock_gettime(CLOCK_MONOTONIC, &now))
1122     {
1123         logmsg(LOG_ERR, "Couldn't get current time. Can't expire.\n");
1124         return expired;
1125     }
1126 
1127     for (item = *suflist; item != NULL; item = item->next)
1128     {
1129         suf = item->data;
1130         if (NEVEREXP == (unsigned) suf->expire)
1131         {
1132             break;
1133         }
1134 
1135         if (0 != suf->expire && suf->expire <= now.tv_sec)
1136         {
1137             expired = true;
1138 
1139             freeitem(suflist, storedsuf, suf->item);
1140 
1141             if (verbose > 1)
1142             {
1143                 printf("Suffix expired.\n");
1144             }
1145         }
1146     } /* for */
1147 
1148     return expired;
1149 }
1150 
1151 /*
1152  * Add or update a domain name suffix in list suflist. Returns true if
1153  * we need to rewrite the resolv file.
1154  */
addsuffix(struct item ** suflist,int * storedsuf,uint32_t ttl,char * name,int namelen,char * ifname)1155 static bool addsuffix(struct item **suflist, int *storedsuf, uint32_t ttl,
1156                       char *name, int namelen, char *ifname)
1157 {
1158     struct timespec now;
1159     struct suffix *suf;
1160     struct item *item;
1161 
1162     if (-1 == clock_gettime(CLOCK_MONOTONIC, &now))
1163     {
1164         logmsg(LOG_ERR, "Couldn't get current time. Can't set expire time.\n");
1165         now.tv_sec = 0;
1166     }
1167 
1168     /* Do we know this address already? */
1169     suf = findsuffix(name, namelen, *suflist);
1170 
1171     if (verbose > 0)
1172     {
1173         printf("New suffix is ");
1174 
1175         if (NULL == suf)
1176         {
1177             printf("unknown.\n");
1178         }
1179         else
1180         {
1181             printf("already known.\n");
1182         }
1183     }
1184 
1185     if (NULL != suf)
1186     {
1187         /* Yes we know this suffix. */
1188         if (0 == ttl)
1189         {
1190             /*
1191              * TTL from RA is 0, so we're asked to delete this domain
1192              * suffix. Requires rewriting of file. Finished.
1193              */
1194             if (verbose > 0)
1195             {
1196                 printf("We have been asked to remove it, so we do.\n");
1197             }
1198 
1199             freeitem(suflist, storedsuf, suf->item);
1200             return true;
1201         }
1202         else
1203         {
1204             /*
1205              * Time to live != 0: Increase expire time or set the
1206              * resolver to never expire. Doesn't require rewriting.
1207              * Finished.
1208              */
1209             if (verbose > 0)
1210             {
1211                 printf("Updating ttl with %d seconds from now.\n", ttl);
1212             }
1213             if (NEVEREXP == ttl)
1214             {
1215                 suf->neverexp = true;
1216             }
1217             else
1218             {
1219                 suf->expire = now.tv_sec + ttl;
1220             }
1221 
1222             return false;
1223         }
1224     }
1225     else
1226     {
1227         /*
1228          * The new suffix is unknown to us.
1229          *
1230          * Insert at head. If the list has a maximum number of items
1231          * and we're full, replace the suffix about to expire next.
1232          *
1233          * Requires rewriting of resolv file.
1234          *
1235          */
1236 
1237         if (verbose > 1)
1238         {
1239             printf("%d suffixes of max %d already stored.\n", *storedsuf,
1240                    maxsuf);
1241         }
1242 
1243         /* 0 is the special case of unlimited number of elements. */
1244         if (0 != maxsuf && *storedsuf == maxsuf)
1245         {
1246             /*
1247              * We're full. Find the first to expire and replace that.
1248              */
1249             if (verbose > 1)
1250             {
1251                 printf("We're full. Finding a suffix to replace.");
1252             }
1253             suf = sufexpirenext(*suflist);
1254         }
1255         else
1256         {
1257             if (verbose > 1)
1258             {
1259                 printf("Adding a new suffix.\n");
1260             }
1261 
1262             item = additem(suflist);
1263             if (NULL == item)
1264             {
1265                 logmsg(LOG_ERR, "Couldn't allocate memory for new suffix.\n");
1266                 return false;
1267             }
1268 
1269             suf = malloc(sizeof (struct suffix));
1270             if (NULL == suf)
1271             {
1272                 logmsg(LOG_ERR, "Couldn't allocate memory for new suffix.\n");
1273                 delitem(suflist, item);
1274                 return false;
1275             }
1276 
1277             item->data = suf;
1278             suf->item = item;
1279 
1280             (*storedsuf) ++;
1281         }
1282 
1283         memcpy(suf->name, name, namelen);
1284         suf->len = namelen;
1285         strncpy(suf->ifname, ifname, IFNAMSIZ);
1286 
1287         if (NEVEREXP == ttl)
1288         {
1289             if (verbose > 2)
1290             {
1291                 printf("Never expire.\n");
1292             }
1293             suf->neverexp = true;
1294         }
1295         else
1296         {
1297             if (verbose > 2)
1298             {
1299                 printf("New expire is now (%d) + ttl (%d) = %d\n", (int)now.tv_sec,
1300                        ttl, (int)now.tv_sec + ttl);
1301             }
1302             suf->expire = now.tv_sec + ttl;
1303         }
1304 
1305         return true;
1306     }
1307 }
1308 
1309 /*
1310  * Add or update a resolver address in list reslist. Returns true if
1311  * we need to rewrite the resolv file.
1312  *
1313  * storedres - pointer to number of stored resolvers.
1314  * ttl - time to live as from RA.
1315  * addr - the IPv6 address to the resolver.
1316  * ifname - interface name string
1317  */
addresolver(struct item ** reslist,int * storedres,uint32_t ttl,struct in6_addr addr,char * ifname)1318 static bool addresolver(struct item **reslist, int *storedres, uint32_t ttl,
1319                         struct in6_addr addr, char *ifname)
1320 {
1321     struct timespec now;
1322     struct resolver *res;
1323     struct item *item;
1324 
1325     if (-1 == clock_gettime(CLOCK_MONOTONIC, &now))
1326     {
1327         logmsg(LOG_ERR, "Couldn't get current time. Can't set expire time.\n");
1328         now.tv_sec = 0;
1329     }
1330 
1331     /* Do we know this address already? */
1332     res = findresolv(addr, *reslist);
1333 
1334     if (verbose > 0)
1335     {
1336         char addrstr[INET6_ADDRSTRLEN];
1337 
1338         if (NULL == inet_ntop(AF_INET6, &addr, addrstr, INET6_ADDRSTRLEN))
1339         {
1340             logmsg(LOG_ERR, "Couldn't convert IPv6 address to string.\n");
1341             return false;
1342         }
1343 
1344         printf("%s is ", addrstr);
1345         if (NULL == res)
1346         {
1347             printf("unknown.\n");
1348         }
1349         else
1350         {
1351             printf("already known.\n");
1352         }
1353     }
1354 
1355     if (NULL != res)
1356     {
1357         /* Yes we know this address. */
1358         if (0 == ttl)
1359         {
1360             /*
1361              * TTL from RA is 0, so we're asked to delete this
1362              * resolver. Requires rewriting of file. Finished.
1363              */
1364             if (verbose > 0)
1365             {
1366                 printf("We have been asked to remove it, so we do.\n");
1367             }
1368 
1369             freeitem(reslist, storedres, res->item);
1370 
1371             return true;
1372         }
1373         else
1374         {
1375             /*
1376              * Time to live != 0: Increase expire time or set the
1377              * resolver to never expire. Doesn't require rewriting.
1378              * Finished.
1379              */
1380             if (verbose > 0)
1381             {
1382                 printf("Updating ttl with %d seconds from now.\n", ttl);
1383             }
1384             if (NEVEREXP == ttl)
1385             {
1386                 res->neverexp = true;
1387             }
1388             else
1389             {
1390                 res->expire = now.tv_sec + ttl;
1391             }
1392 
1393             return false;
1394         }
1395     }
1396     else
1397     {
1398         /*
1399          * The new resolver is unknown to us.
1400          *
1401          * Insert at head. If the list has a maximum number of items
1402          * and we're full, replace the resolver about to expire next.
1403          *
1404          * Requires rewriting of resolv file.
1405          *
1406          */
1407 
1408         if (verbose > 1)
1409         {
1410             printf("%d resolvers of max %d already stored.\n", *storedres,
1411                    maxres);
1412         }
1413 
1414         /* 0 is the special case of unlimited number of elements. */
1415         if (0 != maxres && *storedres == maxres)
1416         {
1417             /*
1418              * We're full. Find the first address to expire and
1419              * replace that.
1420              */
1421             if (verbose > 1)
1422             {
1423                 printf("We're full. Finding a resolver to replace.");
1424             }
1425             res = expirenext(*reslist);
1426         }
1427         else
1428         {
1429             /* We have room. Add new item. */
1430             if (verbose > 1)
1431             {
1432                 printf("Adding a new resolver.\n");
1433             }
1434 
1435             item = additem(reslist);
1436             if (NULL == item)
1437             {
1438                 logmsg(LOG_ERR, "Couldn't allocate memory for new resolver.\n");
1439                 return false;
1440             }
1441 
1442             res = malloc(sizeof (struct resolver));
1443             if (NULL == res)
1444             {
1445                 logmsg(LOG_ERR, "Couldn't allocate memory for new resolver.\n");
1446                 delitem(reslist, item);
1447                 return false;
1448             }
1449 
1450             item->data = res;
1451             res->item = item;
1452             (*storedres) ++;
1453         }
1454 
1455         memcpy(&res->addr, &addr, sizeof (struct in6_addr));
1456         strncpy(res->ifname, ifname, IFNAMSIZ);
1457 
1458         if (NEVEREXP == ttl)
1459         {
1460             if (verbose > 2)
1461             {
1462                 printf("Never expire.\n");
1463             }
1464             res->neverexp = true;
1465         }
1466         else
1467         {
1468             if (verbose > 2)
1469             {
1470                 printf("New expire is now (%d) + ttl (%d) = %d\n", (int)now.tv_sec,
1471                        ttl, (int)now.tv_sec + ttl);
1472             }
1473             res->expire = now.tv_sec + ttl;
1474         }
1475 
1476         return true;
1477     }
1478 }
1479 
1480 /*
1481  * Delete any expired DNS resolvers in list reslist with storedres
1482  * number of resolvers. Returns need to rewrite.
1483  */
expireresolv(struct item ** reslist,int * storedres)1484 static bool expireresolv(struct item **reslist, int *storedres)
1485 {
1486     int expired = false;
1487     struct timespec now;
1488     struct item *item;
1489     struct resolver *res;
1490 
1491     if (-1 == clock_gettime(CLOCK_MONOTONIC, &now))
1492     {
1493         logmsg(LOG_ERR, "Couldn't get current time. Can't expire.\n");
1494         return expired;
1495     }
1496 
1497     for (item = *reslist; item != NULL; item = item->next)
1498     {
1499         res = item->data;
1500         if (NEVEREXP == (unsigned) res->expire)
1501         {
1502             break;
1503         }
1504 
1505         if (0 != res->expire && res->expire <= now.tv_sec)
1506         {
1507             expired = true;
1508 
1509             freeitem(reslist, storedres, res->item);
1510 
1511             if (verbose > 1)
1512             {
1513                 char srcaddrstr[INET6_ADDRSTRLEN];
1514 
1515                 if (NULL == inet_ntop(AF_INET6, &res->addr,
1516                                       srcaddrstr, INET6_ADDRSTRLEN))
1517                 {
1518                     logmsg(LOG_ERR, "Couldn't convert IPv6 address to "
1519                            "string\n");
1520                 }
1521                 else
1522                 {
1523                     printf("Resolver %s expired.\n", srcaddrstr);
1524                 }
1525             }
1526         } /* if expire */
1527     } /* for */
1528 
1529     return expired;
1530 }
1531 
1532 /*
1533  * Write a file with the current process ID.
1534  *
1535  * Returns 0 on success.
1536  */
mkpidfile(uid_t owner,gid_t group)1537 static int mkpidfile(uid_t owner, gid_t group)
1538 {
1539     int filefd;
1540     char *buf = NULL;
1541     int rc = 0;
1542 
1543     if (-1 == (filefd = open(pidfilename, O_CREAT | O_WRONLY | O_TRUNC, 0644)))
1544     {
1545         logmsg(LOG_ERR, "couldn't open pidfile %s\n", pidfilename);
1546         rc = -1;
1547 	goto end;
1548     }
1549 
1550     if (-1 == asprintf(&buf, "%u\n", (unsigned) getpid()))
1551     {
1552 	logmsg(LOG_ERR, "couldn't allocate memory for pid\n");
1553         rc = -1;
1554 	goto end;
1555     }
1556 
1557     if (-1 == write(filefd, buf, strlen(buf)))
1558     {
1559 	localerrno = errno;
1560 	logmsg(LOG_ERR, "couldn't write pid: %s\n", strerror(localerrno));
1561         rc = -1;
1562 	goto end;
1563     }
1564 
1565     /*
1566      * Change owner of file to our new user so we are allowed to
1567      * remove it later, after dropping privileges.
1568      */
1569     if (0 != lchown(pidfilename, owner, group))
1570     {
1571         localerrno = errno;
1572 	logmsg(LOG_ERR, "couldn't change owner of file %s\n", pidfilename,
1573                strerror(localerrno));
1574         rc = -1;
1575         goto end;
1576     }
1577 
1578 end:
1579     close(filefd);
1580 
1581     if (NULL != buf)
1582     {
1583 	free(buf);
1584     }
1585 
1586     return rc;
1587 }
1588 
1589 #ifdef TEST
1590 /*
1591  * Delete the resolver with address addr in list reslist.
1592  */
deladdr(struct item ** reslist,int * storedres,struct in6_addr addr)1593 static void deladdr(struct item **reslist, int *storedres, struct in6_addr addr)
1594 {
1595     struct resolver *res;
1596 
1597     res = findresolv(addr, *reslist);
1598     if (NULL == res)
1599     {
1600     }
1601     else
1602     {
1603         freeitem(reslist, storedres, res->item);
1604     }
1605 }
1606 
1607 /*
1608  * Print a list of all domain suffixes in suflist to stdout.
1609  */
listsuf(struct item * suflist)1610 static void listsuf(struct item *suflist)
1611 {
1612     struct item *item;
1613     struct suffix *suf;
1614     int i;
1615 
1616     for (item = suflist, i = 1; item != NULL; item = item->next, i ++)
1617     {
1618         suf = item->data;
1619 
1620         printf("%i: received on if %s, expires at %d\n", i,
1621                suf->ifname, (int)suf->expire);
1622 
1623         write(1, suf->name, suf->len);
1624         putchar('\n');
1625     }
1626 }
1627 
1628 
1629 /*
1630  * Print a list of all resolvers in reslist to stdout.
1631  */
listres(struct item * reslist)1632 static void listres(struct item *reslist)
1633 {
1634     struct item *item;
1635     struct resolver *res;
1636     int i;
1637     char addrstr[INET6_ADDRSTRLEN];
1638 
1639     for (item = reslist, i = 1; item != NULL; item = item->next, i ++)
1640     {
1641         res = item->data;
1642         if (0 == res->expire)
1643         {
1644             printf("%i:  empty.\n", i);
1645         }
1646         else
1647         {
1648             if (NULL == inet_ntop(AF_INET6, &res->addr,
1649                                   addrstr, INET6_ADDRSTRLEN))
1650             {
1651                 logmsg(LOG_ERR, "Couldn't convert IPv6 address to "
1652                        "string\n");
1653             }
1654             else
1655             {
1656                 printf("%i:  %s, if %s, expire at %d\n", i, addrstr,
1657                        res->ifname, (int)res->expire);
1658             }
1659         }
1660     }
1661 }
1662 
1663 /*
1664  * Print on stdout if we need to rewrite or not.
1665  */
printrewrite(bool rewrite)1666 static void printrewrite(bool rewrite)
1667 {
1668     if (rewrite)
1669     {
1670         printf("Rewrite.\n");
1671     }
1672     else
1673     {
1674         printf("No rewrite.\n");
1675     }
1676 }
1677 
1678 #endif
1679 
1680 /************************************************************************/
1681 /* Test main                                                            */
1682 /************************************************************************/
1683 #ifdef TEST
main(void)1684 int main(void)
1685 {
1686     struct item *reslist = NULL; /* Linked list of resolvers. */
1687     struct item *suflist = NULL; /* Linked list of domain suffixes. */
1688     int storedres = 0;
1689     int storedsuf = 0;
1690     struct in6_addr addr;
1691     bool rewrite;
1692     struct suffix *suf;
1693 
1694         char domain[MAXNAME];
1695     int domainlen;
1696 
1697     domainlen = dnsname(domain, (uint8_t *)"\007example\003com\000", 13);
1698 
1699     printf("Domain length %d\n", domainlen);
1700     hexdump((uint8_t *)domain, domainlen);
1701 
1702     domainlen = dnsname(domain, (uint8_t *)"\007example\003com\000foobar",
1703                         13 + 6);
1704 
1705     printf("Domain length %d\n", domainlen);
1706     hexdump((uint8_t *)domain, domainlen);
1707 
1708     printf("Suffixes (should be none)\n");
1709     listsuf(suflist);
1710 
1711     printf("Adding hack.org.\n");
1712     rewrite = addsuffix(&suflist, &storedsuf, 30, "hack.org.", 9, "em0");
1713     printrewrite(rewrite);
1714     listsuf(suflist);
1715 
1716     suf = sufexpirenext(suflist);
1717 
1718     printf("Deleting suffix.\n");
1719     freeitem(&suflist, &storedsuf, suf->item);
1720     listsuf(suflist);
1721 
1722     printf("Resolvers (should be none):\n");
1723     listres(reslist);
1724 
1725     /* Add a new resolver. */
1726     puts("\n1:");
1727     if (-1 == inet_pton(AF_INET6, "::1", &addr))
1728     {
1729         logmsg(LOG_ERR, "Couldn't convert IPv6 address to string\n");
1730         exit(1);
1731     }
1732     rewrite = addresolver(&reslist, &storedres, 30, addr, "em0");
1733     printrewrite(rewrite);
1734     listres(reslist);
1735     sleep(1);
1736 
1737     puts("\nAdd the same again:");
1738     if (-1 == inet_pton(AF_INET6, "::1", &addr))
1739     {
1740         logmsg(LOG_ERR, "Couldn't convert IPv6 address to string\n");
1741         exit(1);
1742     }
1743     rewrite = addresolver(&reslist, &storedres, 30, addr, "em0");
1744     printrewrite(rewrite);
1745     listres(reslist);
1746     sleep(1);
1747 
1748     /* Add a new resolver. */
1749     puts("\n3:");
1750     if (-1 == inet_pton(AF_INET6, "fe80::216:d3ff:fe21:5a5a", &addr))
1751     {
1752         logmsg(LOG_ERR, "Couldn't convert IPv6 address to string\n");
1753         exit(1);
1754     }
1755     rewrite = addresolver(&reslist,&storedres, 120, addr, "em0");
1756     printrewrite(rewrite);
1757     listres(reslist);
1758     sleep(1);
1759 
1760     /* Delete a resolver. */
1761     if (-1 == inet_pton(AF_INET6, "::1", &addr))
1762     {
1763         logmsg(LOG_ERR, "Couldn't convert IPv6 address to string\n");
1764         exit(1);
1765     }
1766     printf("Deleting ::1.\n");
1767     deladdr(&reslist, &storedres, addr);
1768 
1769     /* Add a new resolver. */
1770     puts("\n4:");
1771     if (-1 == inet_pton(AF_INET6, "2001::216:d3ff:fe21:5a5a", &addr))
1772     {
1773         logmsg(LOG_ERR, "Couldn't convert IPv6 address to string\n");
1774         exit(1);
1775     }
1776     rewrite = addresolver(&reslist,&storedres, 120, addr, "em0");
1777     printrewrite(rewrite);
1778     listres(reslist);
1779     sleep(1);
1780 
1781     /* Add a new resolver. */
1782     puts("\n5:");
1783     if (-1 == inet_pton(AF_INET6, "2001:16d8:ffff:1:213:2ff:fe0e:9cfa", &addr))
1784     {
1785         logmsg(LOG_ERR, "Couldn't convert IPv6 address to string\n");
1786         exit(1);
1787     }
1788     rewrite = addresolver(&reslist,&storedres, 120, addr, "wlan1");
1789     printrewrite(rewrite);
1790     listres(reslist);
1791     sleep(1);
1792 
1793     /* Add a new resolver. */
1794     puts("\n6:");
1795     if (-1 == inet_pton(AF_INET6, "2001:16d8:ffff:1:213:2ff:cafe:babe", &addr))
1796     {
1797         logmsg(LOG_ERR, "Couldn't convert IPv6 address to string\n");
1798         exit(1);
1799     }
1800     rewrite = addresolver(&reslist,&storedres, 120, addr, "wlan1");
1801     printrewrite(rewrite);
1802     listres(reslist);
1803     sleep(1);
1804 
1805     delallitems(&reslist, &storedres);
1806 
1807     exit(0);
1808 }
1809 #else
1810 /************************************************************************/
1811 /* Real main                                                            */
1812 /************************************************************************/
main(int argc,char ** argv)1813 int main(int argc, char **argv)
1814 {
1815     char ch;                    /* Option character */
1816     int sock;               /* Raw socket file descriptor */
1817     struct icmp6_filter filter; /* Filter for raw socket. */
1818     int on;                     /* Just a flag for setsockopts... */
1819     fd_set in;
1820     int found;
1821     char *user = USER;          /* Username we will run as. */
1822     struct passwd *pw;          /* User data, for uid and gid. */
1823     struct sigaction sigact;    /* Signal handler. */
1824     struct stat sb;             /* For stat() */
1825     struct item *reslist = NULL; /* List of resolver addresses. */
1826     int storedres = 0;           /* Number of addresses in list. */
1827     struct item *suflist = NULL; /* List of domain suffixes. */
1828     int storedsuf = 0;           /* Number of suffixes in list. */
1829     char ifname[IFNAMSIZ];       /* Name of local interface. */
1830 
1831     progname = argv[0];
1832 
1833     /* Install signal handlers. */
1834 
1835     sigact.sa_flags = 0;
1836     sigact.sa_handler = sigcatch;
1837     sigemptyset(&sigact.sa_mask);
1838 
1839     sigaction(SIGCHLD, &sigact, NULL);
1840     sigaction(SIGINT, &sigact, NULL);
1841     sigaction(SIGQUIT, &sigact, NULL);
1842     sigaction(SIGTERM, &sigact, NULL);
1843 
1844     sigact.sa_handler = SIG_IGN;
1845     sigaction(SIGHUP, &sigact, NULL);
1846 
1847     while (1)
1848     {
1849         ch = getopt(argc, argv, "f:l:m:s:p:u:vV");
1850         if (-1 == ch)
1851         {
1852             /* No more options, break out of while loop. */
1853             break;
1854         }
1855 
1856         switch (ch)
1857         {
1858         case 'f':
1859             filename = optarg;
1860             break;
1861         case 'l':
1862             maxsuf = atoi(optarg);
1863             break;
1864         case 'm':
1865             maxres = atoi(optarg);
1866             break;
1867         case 'p':
1868             pidfilename = optarg;
1869             break;
1870         case 's':
1871             scriptname = optarg;
1872             break;
1873         case 'u':
1874             user = optarg;
1875             break;
1876         case 'v':
1877             verbose ++;
1878             break;
1879         case 'V':
1880             fprintf(stderr, "radns version %s\n", VERSION);
1881             exit(0);
1882             break;
1883         default:
1884             printhelp();
1885             exit(1);
1886         }
1887     } /* while */
1888 
1889     if (-1 == (sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)))
1890     {
1891         logmsg(LOG_ERR, "Error from socket(). Perhaps you're not running as "
1892                "root? Terminating.\n");
1893         exit(1);
1894     }
1895 
1896     /*
1897      * Daemonize if we're not told to do otherwise. Don't change
1898      * directory to /, though.
1899      */
1900     if (0 == verbose)
1901     {
1902         openlog(argv[0], LOG_PID | LOG_NDELAY, LOG_DAEMON);
1903 
1904         if (0 != daemon(1, 0))
1905         {
1906             logmsg(LOG_ERR, "Error from daemon(). Terminating.\n");
1907             exit(1);
1908         }
1909     }
1910 
1911     /* Get user information. */
1912     if (NULL == (pw = getpwnam(user)))
1913     {
1914         logmsg(LOG_ERR, "couldn't find user '%s'.\n", user);
1915         exit(1);
1916     }
1917 
1918     /* Write our pid to a file. We still need to be root to be able to
1919      * write to /var/run...
1920      */
1921     if (-1 == mkpidfile(pw->pw_uid, pw->pw_gid))
1922     {
1923         logmsg(LOG_ERR, "Couldn't create pid file.\n");
1924     }
1925 
1926     /* Dropping privileges. */
1927     /* FIXME: setgroups() as well? */
1928     if (0 != setgid(pw->pw_gid) || 0 != setuid(pw->pw_uid))
1929     {
1930         logmsg(LOG_ERR, "couldn't drop privileges\n");
1931         exit(1);
1932     }
1933 
1934     /****************** Now running as radns user. ******************/
1935 
1936     /* Check if there's a script. */
1937     if (NULL != scriptname && 0 != stat(scriptname, &sb))
1938     {
1939         localerrno = errno;
1940         logmsg(LOG_ERR, "Script file %s: %s. Terminating.\n", scriptname,
1941                strerror(localerrno));
1942         exit(1);
1943     }
1944 
1945     /* Initialize resolv file and make sure we can write to it early. */
1946     if (0 != writeresolv(suflist, storedsuf, reslist))
1947     {
1948         logmsg(LOG_ERR, "Couldn't create resolv file %s. Exiting...\n",
1949                filename);
1950         exit(1);
1951     }
1952 
1953     /* Set a filter so we only get ICMPv6 packets. */
1954     ICMP6_FILTER_SETBLOCKALL(&filter);
1955     ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filter);
1956 
1957     if (-1 == setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filter,
1958                          sizeof(filter)))
1959     {
1960         logmsg(LOG_ERR, "Error from setsockopt(). Terminating.\n");
1961         exit(1);
1962     }
1963 
1964     /*
1965      * Ask for ancillary data with each ICMPv6 packet so we can get
1966      * the incoming interface name.
1967      */
1968     on = 1;
1969     if (-1 == setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on,
1970                          sizeof(on)))
1971     {
1972         logmsg(LOG_ERR, "Error from setsockopt(). Terminating.\n");
1973         exit(1);
1974     }
1975 
1976     /* Main loop. */
1977     for (progdone = false; !progdone; )
1978     {
1979         int status;
1980         bool newresolv = false;
1981         struct timeval tv;
1982         struct timespec now;
1983         struct resolver *res;
1984 
1985         /* Figure out when to wake up. */
1986         if (-1 == clock_gettime(CLOCK_MONOTONIC, &now))
1987         {
1988             logmsg(LOG_ERR, "Couldn't get current time.\n");
1989             now.tv_sec = 0;
1990             now.tv_nsec = 0;
1991         }
1992 
1993         res = expirenext(reslist);
1994         if (NULL == res)
1995         {
1996             tv.tv_sec = 0;
1997         }
1998         else
1999         {
2000             tv.tv_sec = res->expire - now.tv_sec;
2001             tv.tv_usec = 0;
2002         }
2003 
2004         FD_ZERO(&in);
2005         FD_SET(sock, &in);
2006 
2007         if (0 == tv.tv_sec)
2008         {
2009             /* No timeout. Block while waiting for incoming packet. */
2010             found = select(sock + 1, &in, NULL, NULL, NULL);
2011         }
2012         else
2013         {
2014             /* Wait for incoming packet or the next expire. */
2015             found = select(sock + 1, &in, NULL, NULL, &tv);
2016         }
2017 
2018         if (-1 == found)
2019         {
2020             localerrno = errno;
2021             if (EINTR != localerrno)
2022             {
2023                 logmsg(LOG_ERR, "select failed: %s\n", strerror(localerrno));
2024                 exit(1);
2025             }
2026         }
2027         else
2028         {
2029             if (-1 != sock && FD_ISSET(sock, &in))
2030             {
2031                 if (handle_icmp6(sock, &suflist, &storedsuf, &reslist,
2032                                  &storedres, ifname))
2033                 {
2034                     /* We got a new message and we need to rewrite. */
2035                     newresolv = true;
2036                 }
2037             } /* sock */
2038         } /* if found */
2039 
2040         /* Check for expired DNS servers. */
2041         if (expireresolv(&reslist, &storedres))
2042         {
2043             /* Some resolvers expired. Maybe do something. */
2044             newresolv = true;
2045         }
2046 
2047         /* Check for expired domain suffixes. */
2048         if (expiresuffix(&suflist, &storedsuf))
2049         {
2050             /* Some suffixes expired. Maybe do something. */
2051             newresolv = true;
2052         }
2053 
2054         if (newresolv)
2055         {
2056             /* Write address(es) to file. */
2057             writeresolv(suflist, storedsuf, reslist);
2058 
2059             /* Call external script, if any. */
2060             (void)exithook(filename, ifname);
2061 
2062             newresolv = false;
2063         }
2064 
2065         /* Reap any zombie exit hook script(s) we might have. */
2066         if (childcare)
2067         {
2068             while (-1 != waitpid(-1, &status, WNOHANG))
2069                 ;
2070             childcare = false;
2071         }
2072 
2073     } /* for */
2074 
2075     logmsg(LOG_INFO, "Terminating.\n");
2076 
2077     /* Free all resolvers and suffixes. Write an empty resolv file. */
2078     delallitems(&reslist, &storedres);
2079     delallitems(&suflist, &storedsuf);
2080     writeresolv(suflist, storedsuf, reslist);
2081 
2082     exit(0);
2083 }
2084 #endif
2085