• 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 static void sighandler(_unused int signal)
 71 {
 72         uloop_end();
 73 }
 74 
 75 static void print_usage(const char *app)
 76 {
 77         printf("== %s Usage ==\n"
 78                "Features: ra ndp dhcpv6"
 79 #ifdef DHCPV4_SUPPORT
 80                " dhcpv4"
 81 #else
 82                " no-dhcpv4"
 83 #endif /* DHCPV4_SUPPORT */
 84 #ifdef WITH_UBUS
 85                " ubus"
 86 #else
 87                " no-ubus"
 88 #endif /* WITH_UBUS */
 89                "\n"
 90                "\n"
 91                "        -c <dir>        Read UCI configuration files from <dir>\n"
 92                "        -l <int>        Specify log level 0..7 (default %d)\n"
 93                "        -f              Log to stderr instead of syslog\n"
 94                "        -h              Print this help text and exit\n",
 95                app, config.log_level);
 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:fh")) != -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 'h':
144                         print_usage(argv[0]);
145                         return 0;
146                 }
147         }
148 
149         if (config.log_syslog) {
150                 openlog("odhcpd", LOG_PERROR | LOG_PID, LOG_DAEMON);
151                 setlogmask(LOG_UPTO(config.log_level));
152         }
153 
154         uloop_init();
155 
156         if (getuid() != 0) {
157                 error("Must be run as root!");
158                 return 2;
159         }
160 
161         ioctl_sock = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
162         if (ioctl_sock < 0)
163                 return 4;
164 
165         signal(SIGUSR1, SIG_IGN);
166         signal(SIGINT, sighandler);
167         signal(SIGTERM, sighandler);
168 
169         if (netlink_init())
170                 return 4;
171 
172         if (ipv6_enabled()) {
173                 if (router_init())
174                         return 4;
175 
176                 if (dhcpv6_init())
177                         return 4;
178 
179                 if (ndp_init())
180                         return 4;
181         }
182 #ifndef DHCPV4_SUPPORT
183         else
184                 return 4;
185 #else
186         if (dhcpv4_init())
187                 return 4;
188 #endif
189 
190         odhcpd_run();
191         return 0;
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_addr(struct interface *iface, struct in6_addr *addr)
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                 *addr = iface->addr6[m].addr.in6;
404                 return 0;
405         }
406 
407         return odhcpd_get_interface_linklocal_addr(iface, addr);
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, _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))
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 
759 int odhcpd_netmask2bitlen(bool inet6, void *mask)
760 {
761         int bits;
762         struct in_addr *v4;
763         struct in6_addr *v6;
764 
765         if (inet6)
766                 for (bits = 0, v6 = mask;
767                      bits < 128 && (v6->s6_addr[bits / 8] << (bits % 8)) & 128;
768                      bits++);
769         else
770                 for (bits = 0, v4 = mask;
771                      bits < 32 && (ntohl(v4->s_addr) << bits) & 0x80000000;
772                      bits++);
773 
774         return bits;
775 }
776 
777 bool odhcpd_bitlen2netmask(bool inet6, unsigned int bits, void *mask)
778 {
779         uint8_t b;
780         struct in_addr *v4;
781         struct in6_addr *v6;
782 
783         if (inet6)
784         {
785                 if (bits > 128)
786                         return false;
787 
788                 v6 = mask;
789 
790                 for (unsigned int i = 0; i < sizeof(v6->s6_addr); i++)
791                 {
792                         b = (bits > 8) ? 8 : bits;
793                         v6->s6_addr[i] = (uint8_t)(0xFF << (8 - b));
794                         bits -= b;
795                 }
796         }
797         else
798         {
799                 if (bits > 32)
800                         return false;
801 
802                 v4 = mask;
803                 v4->s_addr = bits ? htonl(~((1 << (32 - bits)) - 1)) : 0;
804         }
805 
806         return true;
807 }
808 
809 bool odhcpd_valid_hostname(const char *name)
810 {
811 #define MAX_LABEL       63
812         const char *c, *label, *label_end;
813         int label_sz = 0;
814 
815         for (c = name, label_sz = 0, label = name, label_end = name + strcspn(name, ".") - 1;
816                         *c && label_sz <= MAX_LABEL; c++) {
817                 if ((*c >= '' && *c <= '9') ||
818                     (*c >= 'A' && *c <= 'Z') ||
819                     (*c >= 'a' && *c <= 'z')) {
820                         label_sz++;
821                         continue;
822                 }
823 
824                 if ((*c == '_' || *c == '-') && c != label && c != label_end) {
825                         label_sz++;
826                         continue;
827                 }
828 
829                 if (*c == '.') {
830                         if (*(c + 1)) {
831                                 label = c + 1;
832                                 label_end = label + strcspn(label, ".") - 1;
833                                 label_sz = 0;
834                         }
835                         continue;
836                 }
837 
838                 return false;
839         }
840 
841         return (label_sz && label_sz <= MAX_LABEL ? true : false);
842 }
843 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt