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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt