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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt