• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/odhcpd/src/odhcpd.c

  1 /**
  2  * Copyright (C) 2012-2013 Steven Barth <steven@midlink.org>
  3  *
  4  * This program is free software; you can redistribute it and/or modify
  5  * it under the terms of the GNU General Public License v2 as published by
  6  * the Free Software Foundation.
  7  *
  8  * This program is distributed in the hope that it will be useful,
  9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 11  * GNU General Public License for more details.
 12  *
 13  */
 14 
 15 #include <time.h>
 16 #include <errno.h>
 17 #include <fcntl.h>
 18 #include <stdio.h>
 19 #include <getopt.h>
 20 #include <stddef.h>
 21 #include <stdlib.h>
 22 #include <string.h>
 23 #include <unistd.h>
 24 #include <signal.h>
 25 #include <stdbool.h>
 26 #include <alloca.h>
 27 #include <inttypes.h>
 28 
 29 #include <arpa/inet.h>
 30 #include <net/if.h>
 31 #include <netinet/ip6.h>
 32 #include <netpacket/packet.h>
 33 #include <linux/netlink.h>
 34 
 35 #include <sys/socket.h>
 36 #include <sys/ioctl.h>
 37 #include <sys/epoll.h>
 38 #include <sys/types.h>
 39 #include <sys/wait.h>
 40 #include <sys/syscall.h>
 41 #include <sys/random.h>
 42 
 43 #include <libubox/uloop.h>
 44 
 45 #include "odhcpd.h"
 46 #include "dhcpv6-ia.h"
 47 
 48 static int ioctl_sock = -1;
 49 
 50 void __iflog(int lvl, const char *fmt, ...)
 51 {
 52         va_list ap;
 53 
 54         if (lvl > config.log_level)
 55                 return;
 56 
 57         va_start(ap, fmt);
 58 
 59         if (config.log_syslog) {
 60                 vsyslog(lvl, fmt, ap);
 61         } else {
 62                 vfprintf(stderr, fmt, ap);
 63                 fprintf(stderr, "\n");
 64         }
 65 
 66         va_end(ap);
 67 }
 68 
 69 _o_noreturn static void print_usage(const char *app, int exit_status)
 70 {
 71         printf("== %s Usage ==\n"
 72                "Features: ra ndp dhcpv6"
 73 #ifdef DHCPV4_SUPPORT
 74                " dhcpv4"
 75 #else
 76                " no-dhcpv4"
 77 #endif /* DHCPV4_SUPPORT */
 78 #ifdef WITH_UBUS
 79                " ubus"
 80 #else
 81                " no-ubus"
 82 #endif /* WITH_UBUS */
 83                "\n"
 84                "\n"
 85                "        -c <dir>        Read UCI configuration files from <dir>\n"
 86                "        -l <int>        Specify log level 0..7 (default %d)\n"
 87                "        -f              Log to stderr instead of syslog\n"
 88 #ifdef WITH_UBUS
 89                "        -u              Disable ubus support\n"
 90 #endif /* WITH_UBUS */
 91                "        -h              Print this help text and exit\n",
 92                app, config.log_level);
 93 
 94         exit(exit_status);
 95 }
 96 
 97 static bool ipv6_enabled(void)
 98 {
 99         int fd = socket(AF_INET6, SOCK_DGRAM, 0);
100 
101         if (fd < 0)
102                 return false;
103 
104         close(fd);
105 
106         return true;
107 }
108 
109 int main(int argc, char **argv)
110 {
111         int opt;
112 
113         while ((opt = getopt(argc, argv, "c:l:fuh")) != -1) {
114                 switch (opt) {
115                 case 'c':
116                         struct stat sb;
117                         char *path;
118 
119                         free(config.uci_cfgdir);
120                         config.uci_cfgdir = NULL;
121 
122                         path = realpath(optarg, NULL);
123                         if (!path || stat(path, &sb) || !S_ISDIR(sb.st_mode)) {
124                                 fprintf(stderr, "%s is not a directory, ignoring\n", optarg);
125                                 free(path);
126                                 break;
127                         }
128 
129                         fprintf(stderr, "Configuration will be read from %s\n", path);
130                         config.uci_cfgdir = path;
131                         break;
132 
133                 case 'l':
134                         config.log_level = (atoi(optarg) & LOG_PRIMASK);
135                         config.log_level_cmdline = true;
136                         fprintf(stderr, "Log level set to %d\n", config.log_level);
137                         break;
138                 case 'f':
139                         config.log_syslog = false;
140                         fprintf(stderr, "Logging to stderr\n");
141                         break;
142                 case 'u':
143                         config.use_ubus = false;
144                         fprintf(stderr, "Ubus support disabled\n");
145                         break;
146                 case 'h':
147                         print_usage(argv[0], EXIT_SUCCESS);
148                 case '?':
149                 default:
150                         print_usage(argv[0], EXIT_FAILURE);
151                 }
152         }
153 
154         if (getuid() != 0) {
155                 error("Must be run as root!");
156                 return 2;
157         }
158 
159         if (config.log_syslog) {
160                 openlog("odhcpd", LOG_PERROR | LOG_PID, LOG_DAEMON);
161                 setlogmask(LOG_UPTO(config.log_level));
162         }
163 
164         uloop_init();
165 
166         ioctl_sock = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
167         if (ioctl_sock < 0)
168                 return 4;
169 
170         if (netlink_init())
171                 return 4;
172 
173         if (ipv6_enabled()) {
174                 if (router_init())
175                         return 4;
176 
177                 if (dhcpv6_init())
178                         return 4;
179 
180                 if (ndp_init())
181                         return 4;
182         }
183 #ifndef DHCPV4_SUPPORT
184         else
185                 return 4;
186 #else
187         if (dhcpv4_init())
188                 return 4;
189 #endif
190 
191         return odhcpd_run();
192 }
193 
194 
195 /* Read IPv6 MTU for interface */
196 int odhcpd_get_interface_config(const char *ifname, const char *what)
197 {
198         char buf[64];
199 
200         snprintf(buf, sizeof(buf), "/proc/sys/net/ipv6/conf/%s/%s", ifname, what);
201 
202         int fd = open(buf, O_RDONLY);
203         if (fd < 0)
204                 return -1;
205 
206         ssize_t len = read(fd, buf, sizeof(buf) - 1);
207         close(fd);
208 
209         if (len < 0)
210                 return -1;
211 
212         buf[len] = 0;
213         return atoi(buf);
214 }
215 
216 
217 /* Read IPv6 MAC for interface */
218 int odhcpd_get_mac(const struct interface *iface, uint8_t mac[6])
219 {
220         struct ifreq ifr;
221 
222         memset(&ifr, 0, sizeof(ifr));
223         strncpy(ifr.ifr_name, iface->ifname, sizeof(ifr.ifr_name) - 1);
224         if (ioctl(ioctl_sock, SIOCGIFHWADDR, &ifr) < 0)
225                 return -1;
226 
227         memcpy(mac, ifr.ifr_hwaddr.sa_data, 6);
228         return 0;
229 }
230 
231 int odhcpd_get_flags(const struct interface *iface)
232 {
233         struct ifreq ifr;
234 
235         memset(&ifr, 0, sizeof(ifr));
236         strncpy(ifr.ifr_name, iface->ifname, sizeof(ifr.ifr_name) - 1);
237         if (ioctl(ioctl_sock, SIOCGIFFLAGS, &ifr) < 0)
238                 return -1;
239 
240         return ifr.ifr_flags;
241 }
242 
243 
244 /* Forwards a packet on a specific interface with optional source address */
245 ssize_t odhcpd_send_with_src(int socket, struct sockaddr_in6 *dest,
246                 struct iovec *iov, size_t iov_len,
247                 const struct interface *iface, const struct in6_addr *src_addr)
248 {
249         /* Construct headers */
250         uint8_t cmsg_buf[CMSG_SPACE(sizeof(struct in6_pktinfo))] = {0};
251         struct msghdr msg = {
252                 .msg_name = (void *) dest,
253                 .msg_namelen = sizeof(*dest),
254                 .msg_iov = iov,
255                 .msg_iovlen = iov_len,
256                 .msg_control = cmsg_buf,
257                 .msg_controllen = sizeof(cmsg_buf),
258                 .msg_flags = 0
259         };
260 
261         /* Set control data (define destination interface) */
262         struct cmsghdr *chdr = CMSG_FIRSTHDR(&msg);
263         chdr->cmsg_level = IPPROTO_IPV6;
264         chdr->cmsg_type = IPV6_PKTINFO;
265         chdr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
266         struct in6_pktinfo *pktinfo = (struct in6_pktinfo*)CMSG_DATA(chdr);
267         pktinfo->ipi6_ifindex = iface->ifindex;
268 
269         /* Set source address if provided */
270         if (src_addr)
271                 pktinfo->ipi6_addr = *src_addr;
272 
273         /* Also set scope ID if link-local */
274         if (IN6_IS_ADDR_LINKLOCAL(&dest->sin6_addr)
275                         || IN6_IS_ADDR_MC_LINKLOCAL(&dest->sin6_addr))
276                 dest->sin6_scope_id = iface->ifindex;
277 
278         char ipbuf[INET6_ADDRSTRLEN];
279         inet_ntop(AF_INET6, &dest->sin6_addr, ipbuf, sizeof(ipbuf));
280 
281         ssize_t sent = sendmsg(socket, &msg, MSG_DONTWAIT);
282         if (sent < 0)
283                 error("Failed to send to %s%%%s@%s (%m)",
284                       ipbuf, iface->name, iface->ifname);
285         else
286                 debug("Sent %zd bytes to %s%%%s@%s",
287                       sent, ipbuf, iface->name, iface->ifname);
288         return sent;
289 }
290 
291 /* Forwards a packet on a specific interface */
292 ssize_t odhcpd_send(int socket, struct sockaddr_in6 *dest,
293                 struct iovec *iov, size_t iov_len,
294                 const struct interface *iface)
295 {
296         return odhcpd_send_with_src(socket, dest, iov, iov_len, iface, NULL);
297 }
298 
299 
300 int odhcpd_get_interface_linklocal_addr(struct interface *iface, struct in6_addr *addr)
301 {
302         /* Return cached address if valid */
303         if (iface->cached_linklocal_valid) {
304                 *addr = iface->cached_linklocal_addr;
305                 return 0;
306         }
307 
308         /* First try to get link-local address from interface addresses */
309         for (size_t i = 0; i < iface->addr6_len; ++i) {
310                 if (IN6_IS_ADDR_LINKLOCAL(&iface->addr6[i].addr.in6)) {
311                         *addr = iface->addr6[i].addr.in6;
312                         /* Cache the result for future use */
313                         iface->cached_linklocal_addr = *addr;
314                         iface->cached_linklocal_valid = true;
315                         return 0;
316                 }
317         }
318 
319         /* Fallback to socket-based method */
320         struct sockaddr_in6 sockaddr;
321         socklen_t alen = sizeof(sockaddr);
322         int sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
323 
324         if (sock >= 0) {
325                 memset(&sockaddr, 0, sizeof(sockaddr));
326                 sockaddr.sin6_family = AF_INET6;
327                 inet_pton(AF_INET6, ALL_IPV6_ROUTERS, &sockaddr.sin6_addr);
328                 sockaddr.sin6_scope_id = iface->ifindex;
329 
330                 if (!connect(sock, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) &&
331                                 !getsockname(sock, (struct sockaddr*)&sockaddr, &alen)) {
332                         *addr = sockaddr.sin6_addr;
333                         /* Cache the result for future use */
334                         iface->cached_linklocal_addr = *addr;
335                         iface->cached_linklocal_valid = true;
336                         close(sock);
337                         return 0;
338                 }
339                 close(sock);
340         }
341 
342         return -1;
343 }
344 
345 /* Try to send with link-local source address for RFC 4861 compliance and macOS compatibility.
346  * RFC 4861, ยง4.2 mandates that Neighbor Advertisement source address MUST be
347  * the link-local address assigned to the interface from which this message is sent. */
348 ssize_t odhcpd_try_send_with_src(int socket, struct sockaddr_in6 *dest,
349                 struct iovec *iov, size_t iov_len,
350                 struct interface *iface)
351 {
352         struct in6_addr src_addr;
353 
354         if (iface->ndp_from_link_local && odhcpd_get_interface_linklocal_addr(iface, &src_addr) == 0) {
355                 return odhcpd_send_with_src(socket, dest, iov, iov_len, iface, &src_addr);
356         } else {
357                 /* Fall back to default behavior if no link-local address is available or flag is disabled */
358                 return odhcpd_send(socket, dest, iov, iov_len, iface);
359         }
360 }
361 
362 /*
363  * DNS address selection criteria order :
364  * - use IPv6 address with valid lifetime if none is yet selected
365  * - use IPv6 address with a preferred lifetime if the already selected IPv6 address is deprecated
366  * - use an IPv6 ULA address if the already selected IPv6 address is not an ULA address
367  * - use the IPv6 address with the longest preferred lifetime
368  */
369 int odhcpd_get_interface_dns_addr6(struct interface *iface, struct in6_addr *dns_addr6)
370 {
371         time_t now = odhcpd_time();
372         ssize_t m = -1;
373 
374         if (!iface->dns_service)
375                 return -1;
376 
377         for (size_t i = 0; i < iface->addr6_len; ++i) {
378                 if (iface->addr6[i].valid_lt <= (uint32_t)now)
379                         continue;
380 
381                 if (m < 0) {
382                         m = i;
383                         continue;
384                 }
385 
386                 if (iface->addr6[m].preferred_lt >= (uint32_t)now &&
387                                 iface->addr6[i].preferred_lt < (uint32_t)now)
388                         continue;
389 
390                 if (IN6_IS_ADDR_ULA(&iface->addr6[i].addr.in6)) {
391                         if (!IN6_IS_ADDR_ULA(&iface->addr6[m].addr.in6)) {
392                                 m = i;
393                                 continue;
394                         }
395                 } else if (IN6_IS_ADDR_ULA(&iface->addr6[m].addr.in6))
396                         continue;
397 
398                 if (iface->addr6[i].preferred_lt > iface->addr6[m].preferred_lt)
399                         m = i;
400         }
401 
402         if (m >= 0) {
403                 *dns_addr6 = iface->addr6[m].addr.in6;
404                 return 0;
405         }
406 
407         return odhcpd_get_interface_linklocal_addr(iface, dns_addr6);
408 }
409 
410 struct interface* odhcpd_get_interface_by_index(int ifindex)
411 {
412         struct interface *iface;
413 
414         avl_for_each_element(&interfaces, iface, avl) {
415                 if (iface->ifindex == ifindex)
416                         return iface;
417         }
418 
419         return NULL;
420 }
421 
422 /* Convenience function to receive and do basic validation of packets */
423 static void odhcpd_receive_packets(struct uloop_fd *u, _o_unused unsigned int events)
424 {
425         struct odhcpd_event *e = container_of(u, struct odhcpd_event, uloop);
426 
427         uint8_t data_buf[8192], cmsg_buf[128];
428         union {
429                 struct sockaddr_in6 in6;
430                 struct sockaddr_in in;
431                 struct sockaddr_ll ll;
432                 struct sockaddr_nl nl;
433         } addr;
434 
435         if (u->error) {
436                 int ret = -1;
437                 socklen_t ret_len = sizeof(ret);
438 
439                 u->error = false;
440                 if (e->handle_error && getsockopt(u->fd, SOL_SOCKET, SO_ERROR, &ret, &ret_len) == 0)
441                         e->handle_error(e, ret);
442         }
443 
444         if (e->recv_msgs) {
445                 e->recv_msgs(e);
446                 return;
447         }
448 
449         while (true) {
450                 struct iovec iov = {data_buf, sizeof(data_buf)};
451                 struct msghdr msg = {
452                         .msg_name = (void *) &addr,
453                         .msg_namelen = sizeof(addr),
454                         .msg_iov = &iov,
455                         .msg_iovlen = 1,
456                         .msg_control = cmsg_buf,
457                         .msg_controllen = sizeof(cmsg_buf),
458                         .msg_flags = 0
459                 };
460 
461                 ssize_t len = recvmsg(u->fd, &msg, MSG_DONTWAIT);
462                 if (len < 0) {
463                         if (errno == EAGAIN)
464                                 break;
465                         else
466                                 continue;
467                 }
468 
469 
470                 /* Extract destination interface */
471                 int destiface = 0;
472                 int *hlim = NULL;
473                 void *dest = NULL;
474                 struct in6_pktinfo *pktinfo;
475                 struct in_pktinfo *pkt4info;
476                 for (struct cmsghdr *ch = CMSG_FIRSTHDR(&msg); ch != NULL; ch = CMSG_NXTHDR(&msg, ch)) {
477                         if (ch->cmsg_level == IPPROTO_IPV6 &&
478                                         ch->cmsg_type == IPV6_PKTINFO) {
479                                 pktinfo = (struct in6_pktinfo*)CMSG_DATA(ch);
480                                 destiface = pktinfo->ipi6_ifindex;
481                                 dest = &pktinfo->ipi6_addr;
482                         } else if (ch->cmsg_level == IPPROTO_IP &&
483                                         ch->cmsg_type == IP_PKTINFO) {
484                                 pkt4info = (struct in_pktinfo*)CMSG_DATA(ch);
485                                 destiface = pkt4info->ipi_ifindex;
486                                 dest = &pkt4info->ipi_addr;
487                         } else if (ch->cmsg_level == IPPROTO_IPV6 &&
488                                         ch->cmsg_type == IPV6_HOPLIMIT) {
489                                 hlim = (int*)CMSG_DATA(ch);
490                         }
491                 }
492 
493                 /* Check hoplimit if received */
494                 if (hlim && *hlim != 255)
495                         continue;
496 
497                 /* Detect interface for packet sockets */
498                 if (addr.ll.sll_family == AF_PACKET)
499                         destiface = addr.ll.sll_ifindex;
500 
501                 char ipbuf[INET6_ADDRSTRLEN] = "kernel";
502                 if (addr.ll.sll_family == AF_PACKET &&
503                                 len >= (ssize_t)sizeof(struct ip6_hdr))
504                         inet_ntop(AF_INET6, &data_buf[8], ipbuf, sizeof(ipbuf));
505                 else if (addr.in6.sin6_family == AF_INET6)
506                         inet_ntop(AF_INET6, &addr.in6.sin6_addr, ipbuf, sizeof(ipbuf));
507                 else if (addr.in.sin_family == AF_INET)
508                         inet_ntop(AF_INET, &addr.in.sin_addr, ipbuf, sizeof(ipbuf));
509 
510                 /* From netlink */
511                 if (addr.nl.nl_family == AF_NETLINK) {
512                         debug("Received %zd Bytes from %s%%netlink", len, ipbuf);
513                         e->handle_dgram(&addr, data_buf, len, NULL, dest);
514                         return;
515                 } else if (destiface != 0) {
516                         struct interface *iface;
517 
518                         avl_for_each_element(&interfaces, iface, avl) {
519                                 if (iface->ifindex != destiface)
520                                         continue;
521 
522                                 debug("Received %zd Bytes from %s%%%s@%s", len,
523                                       ipbuf, iface->name, iface->ifname);
524 
525                                 e->handle_dgram(&addr, data_buf, len, iface, dest);
526                         }
527                 }
528 
529 
530         }
531 }
532 
533 /* Register events for the multiplexer */
534 int odhcpd_register(struct odhcpd_event *event)
535 {
536         event->uloop.cb = odhcpd_receive_packets;
537         return uloop_fd_add(&event->uloop, ULOOP_READ |
538                         ((event->handle_error) ? ULOOP_ERROR_CB : 0));
539 }
540 
541 int odhcpd_deregister(struct odhcpd_event *event)
542 {
543         event->uloop.cb = NULL;
544         return uloop_fd_delete(&event->uloop);
545 }
546 
547 void odhcpd_process(struct odhcpd_event *event)
548 {
549         odhcpd_receive_packets(&event->uloop, 0);
550 }
551 
552 void odhcpd_urandom(void *data, size_t len)
553 {
554         static bool warned_once = false;
555 
556         while (true) {
557                 ssize_t r;
558 
559                 if (len == 0)
560                         return;
561 
562                 r = getrandom(data, len, GRND_INSECURE);
563                 if (r < 0) {
564                         if (errno == EINTR)
565                                 continue;
566 
567                         if (!warned_once) {
568                                 error("getrandom(): %m");
569                                 warned_once = true;
570                         }
571 
572                         return;
573                 }
574 
575                 len -= r;
576                 data = (uint8_t *)data + r;
577         }
578 }
579 
580 time_t odhcpd_time(void)
581 {
582         struct timespec ts;
583         clock_gettime(CLOCK_MONOTONIC_COARSE, &ts);
584         return ts.tv_sec;
585 }
586 
587 
588 static const char hexdigits[] = "0123456789abcdef";
589 static const int8_t hexvals[] = {
590         -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -2, -1, -1, -2, -1, -1,
591         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
592         -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
593          0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1,
594         -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
595         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
596         -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
597         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
598 };
599 
600 ssize_t odhcpd_unhexlify(uint8_t *dst, size_t len, const char *src)
601 {
602         size_t c;
603         for (c = 0; c < len && src[0] && src[1]; ++c) {
604                 int8_t x = (int8_t)*src++;
605                 int8_t y = (int8_t)*src++;
606                 if (x < 0 || (x = hexvals[x]) < 0
607                                 || y < 0 || (y = hexvals[y]) < 0)
608                         return -1;
609                 dst[c] = x << 4 | y;
610                 while (((int8_t)*src) < 0 ||
611                                 (*src && hexvals[(uint8_t)*src] < 0))
612                         src++;
613         }
614 
615         return c;
616 }
617 
618 
619 void odhcpd_hexlify(char *dst, const uint8_t *src, size_t len)
620 {
621         for (size_t i = 0; i < len; ++i) {
622                 *dst++ = hexdigits[src[i] >> 4];
623                 *dst++ = hexdigits[src[i] & 0x0f];
624         }
625         *dst = 0;
626 }
627 
628 const char *odhcpd_print_mac(const uint8_t *mac, const size_t len)
629 {
630         static char buf[32];
631 
632         snprintf(buf, sizeof(buf), "%02x", mac[0]);
633         for (size_t i = 1, j = 2; i < len && j < sizeof(buf); i++, j += 3)
634                 snprintf(buf + j, sizeof(buf) - j, ":%02x", mac[i]);
635 
636         return buf;
637 }
638 
639 int odhcpd_bmemcmp(const void *av, const void *bv, size_t bits)
640 {
641         const uint8_t *a = av, *b = bv;
642         size_t bytes = bits / 8;
643         bits %= 8;
644 
645         int res = memcmp(a, b, bytes);
646         if (res == 0 && bits > 0)
647                 res = (a[bytes] >> (8 - bits)) - (b[bytes] >> (8 - bits));
648 
649         return res;
650 }
651 
652 
653 void odhcpd_bmemcpy(void *av, const void *bv, size_t bits)
654 {
655         uint8_t *a = av;
656         const uint8_t *b = bv;
657 
658         size_t bytes = bits / 8;
659         bits %= 8;
660         memcpy(a, b, bytes);
661 
662         if (bits > 0) {
663                 uint8_t mask = (1 << (8 - bits)) - 1;
664                 a[bytes] = (a[bytes] & mask) | ((~mask) & b[bytes]);
665         }
666 }
667 
668 void odhcpd_enum_addr6(struct interface *iface, struct dhcpv6_lease *lease,
669                        time_t now, odhcpd_enum_addr6_cb_t func, void *arg)
670 {
671         struct odhcpd_ipaddr *addrs = iface->addr6;
672         size_t m = get_preferred_addr(addrs, iface->addr6_len);
673 
674         for (size_t i = 0; i < iface->addr6_len; ++i) {
675                 struct in6_addr addr;
676                 uint32_t preferred_lt, valid_lt;
677                 int prefix = lease->length;
678 
679                 if (!valid_addr(&addrs[i], now))
680                         continue;
681 
682                 /* Filter Out Prefixes */
683                 if (ADDR_MATCH_PIO_FILTER(&addrs[i], iface)) {
684                         char addrbuf[INET6_ADDRSTRLEN];
685                         info("Address %s filtered out on %s",
686                              inet_ntop(AF_INET6, &addrs[i].addr.in6, addrbuf, sizeof(addrbuf)),
687                              iface->name);
688                         continue;
689                 }
690 
691                 if (lease->flags & OAF_DHCPV6_NA) {
692                         if (!ADDR_ENTRY_VALID_IA_ADDR(iface, i, m, addrs))
693                                 continue;
694 
695                         addr = in6_from_prefix_and_iid(&addrs[i], lease->assigned_host_id);
696                 } else {
697                         if (!valid_prefix_length(lease, addrs[i].prefix_len))
698                                 continue;
699 
700                         addr = addrs[i].addr.in6;
701                         addr.s6_addr32[1] |= htonl(lease->assigned_subnet_id);
702                         addr.s6_addr32[2] = addr.s6_addr32[3] = 0;
703                 }
704 
705                 preferred_lt = addrs[i].preferred_lt;
706                 if (preferred_lt > (uint32_t)lease->preferred_until)
707                         preferred_lt = lease->preferred_until;
708 
709                 if (preferred_lt > (uint32_t)lease->valid_until)
710                         preferred_lt = lease->valid_until;
711 
712                 if (preferred_lt != UINT32_MAX)
713                         preferred_lt -= now;
714 
715                 valid_lt = addrs[i].valid_lt;
716                 if (valid_lt > (uint32_t)lease->valid_until)
717                         valid_lt = lease->valid_until;
718 
719                 if (valid_lt != UINT32_MAX)
720                         valid_lt -= now;
721 
722                 func(lease, &addr, prefix, preferred_lt, valid_lt, arg);
723         }
724 }
725 
726 int odhcpd_parse_addr6_prefix(const char *str, struct in6_addr *addr, uint8_t *prefix)
727 {
728         size_t len;
729         char *delim;
730 
731         *prefix = 0;
732         if (!str)
733                 return -1;
734 
735         len = strlen(str);
736 
737         char buf[len + 1];
738         memcpy(buf, str, len);
739         buf[len] = '\0';
740 
741         delim = memchr(buf, '/', len);
742         if (!delim)
743                 return -1;
744 
745         *(delim++) = '\0';
746 
747         if (inet_pton(AF_INET6, buf, addr) != 1)
748                 return -1;
749 
750         if (sscanf(delim, "%" SCNu8, prefix) != 1 || *prefix > 128) {
751                 *prefix = 0;
752                 return -1;
753         }
754 
755         return 0;
756 }
757 
758 bool odhcpd_hostname_valid(const char *name)
759 {
760         const char *c, *label, *label_end;
761         int label_sz = 0;
762 
763         for (c = name, label_sz = 0, label = name, label_end = name + strcspn(name, ".") - 1;
764                         *c && label_sz <= DNS_MAX_LABEL_LEN; c++) {
765                 if ((*c >= '' && *c <= '9') ||
766                     (*c >= 'A' && *c <= 'Z') ||
767                     (*c >= 'a' && *c <= 'z')) {
768                         label_sz++;
769                         continue;
770                 }
771 
772                 /* FIXME: underscore is not allowed in RFC 1035, RFC 1123? */
773                 if ((*c == '_' || *c == '-') && c != label && c != label_end) {
774                         label_sz++;
775                         continue;
776                 }
777 
778                 if (*c == '.') {
779                         if (*(c + 1)) {
780                                 label = c + 1;
781                                 label_end = label + strcspn(label, ".") - 1;
782                                 label_sz = 0;
783                         }
784                         continue;
785                 }
786 
787                 return false;
788         }
789 
790         return (label_sz && label_sz <= DNS_MAX_LABEL_LEN ? true : false);
791 }
792 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt