router: advertise removed addresses as invalid in 3 consecutive RAs
[project/odhcpd.git] / src / odhcpd.c
index 0e0002d95159e402e4c004b76021312ec58c667c..9797507db27fc2f00569de3507f57f11683643c1 100644 (file)
@@ -43,9 +43,7 @@
 #include <libubox/uloop.h>
 #include "odhcpd.h"
 
-
-
-static int ioctl_sock;
+static int ioctl_sock = -1;
 static int urandom_fd = -1;
 
 static void sighandler(_unused int signal)
@@ -53,7 +51,6 @@ static void sighandler(_unused int signal)
        uloop_end();
 }
 
-
 static void print_usage(const char *app)
 {
        printf(
@@ -64,6 +61,17 @@ static void print_usage(const char *app)
        );
 }
 
+static bool ipv6_enabled(void)
+{
+       int fd = socket(AF_INET6, SOCK_DGRAM, 0);
+
+       if (fd < 0)
+               return false;
+
+       close(fd);
+
+       return true;
+}
 
 int main(int argc, char **argv)
 {
@@ -91,6 +99,9 @@ int main(int argc, char **argv)
 
        ioctl_sock = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
 
+       if (ioctl_sock < 0)
+               return 4;
+
        if ((urandom_fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC)) < 0)
                return 4;
 
@@ -101,16 +112,20 @@ int main(int argc, char **argv)
        if (netlink_init())
                return 4;
 
-       if (router_init())
-               return 4;
+       if (ipv6_enabled()) {
+               if (router_init())
+                       return 4;
 
-       if (dhcpv6_init())
-               return 4;
+               if (dhcpv6_init())
+                       return 4;
 
-       if (ndp_init())
+               if (ndp_init())
+                       return 4;
+       }
+#ifndef DHCPV4_SUPPORT
+       else
                return 4;
-
-#ifdef DHCPV4_SUPPORT
+#else
        if (dhcpv4_init())
                return 4;
 #endif
@@ -124,10 +139,13 @@ int main(int argc, char **argv)
 int odhcpd_get_interface_config(const char *ifname, const char *what)
 {
        char buf[64];
-       const char *sysctl_pattern = "/proc/sys/net/ipv6/conf/%s/%s";
-       snprintf(buf, sizeof(buf), sysctl_pattern, ifname, what);
+       
+       snprintf(buf, sizeof(buf), "/proc/sys/net/ipv6/conf/%s/%s", ifname, what);
 
        int fd = open(buf, O_RDONLY);
+       if (fd < 0)
+               return -1;
+
        ssize_t len = read(fd, buf, sizeof(buf) - 1);
        close(fd);
 
@@ -189,11 +207,11 @@ ssize_t odhcpd_send(int socket, struct sockaddr_in6 *dest,
 
        ssize_t sent = sendmsg(socket, &msg, MSG_DONTWAIT);
        if (sent < 0)
-               syslog(LOG_NOTICE, "Failed to send to %s%%%s (%m)",
-                               ipbuf, iface->ifname);
+               syslog(LOG_ERR, "Failed to send to %s%%%s@%s (%m)",
+                               ipbuf, iface->name, iface->ifname);
        else
-               syslog(LOG_DEBUG, "Sent %li bytes to %s%%%s",
-                               (long)sent, ipbuf, iface->ifname);
+               syslog(LOG_DEBUG, "Sent %zd bytes to %s%%%s@%s",
+                               sent, ipbuf, iface->name, iface->ifname);
        return sent;
 }
 
@@ -235,6 +253,9 @@ int odhcpd_get_interface_dns_addr(const struct interface *iface, struct in6_addr
        time_t now = odhcpd_time();
        ssize_t m = -1;
 
+       if (!iface->dns_service)
+               return -1;
+
        for (size_t i = 0; i < iface->addr6_len; ++i) {
                if (iface->addr6[i].valid <= (uint32_t)now)
                        continue;
@@ -271,36 +292,15 @@ int odhcpd_get_interface_dns_addr(const struct interface *iface, struct in6_addr
 struct interface* odhcpd_get_interface_by_index(int ifindex)
 {
        struct interface *iface;
-       list_for_each_entry(iface, &interfaces, head)
-               if (iface->ifindex == ifindex)
-                       return iface;
-
-       return NULL;
-}
 
-
-struct interface* odhcpd_get_interface_by_name(const char *name)
-{
-       struct interface *iface;
-       list_for_each_entry(iface, &interfaces, head)
-               if (!strcmp(iface->ifname, name))
-                       return iface;
-
-       return NULL;
-}
-
-
-struct interface* odhcpd_get_master_interface(void)
-{
-       struct interface *iface;
-       list_for_each_entry(iface, &interfaces, head)
-               if (iface->master)
+       avl_for_each_element(&interfaces, iface, avl) {
+               if (iface->ifindex == ifindex)
                        return iface;
+       }
 
        return NULL;
 }
 
-
 /* Convenience function to receive and do basic validation of packets */
 static void odhcpd_receive_packets(struct uloop_fd *u, _unused unsigned int events)
 {
@@ -317,9 +317,9 @@ static void odhcpd_receive_packets(struct uloop_fd *u, _unused unsigned int even
        if (u->error) {
                int ret = -1;
                socklen_t ret_len = sizeof(ret);
-               getsockopt(u->fd, SOL_SOCKET, SO_ERROR, &ret, &ret_len);
+
                u->error = false;
-               if (e->handle_error)
+               if (e->handle_error && getsockopt(u->fd, SOL_SOCKET, SO_ERROR, &ret, &ret_len) == 0)
                        e->handle_error(e, ret);
        }
 
@@ -391,18 +391,19 @@ static void odhcpd_receive_packets(struct uloop_fd *u, _unused unsigned int even
 
                /* From netlink */
                if (addr.nl.nl_family == AF_NETLINK) {
-                       syslog(LOG_DEBUG, "Received %li Bytes from %s%%%s", (long)len,
-                                       ipbuf, "netlink");
+                       syslog(LOG_DEBUG, "Received %zd Bytes from %s%%netlink", len,
+                                       ipbuf);
                        e->handle_dgram(&addr, data_buf, len, NULL, dest);
                        return;
                } else if (destiface != 0) {
                        struct interface *iface;
-                       list_for_each_entry(iface, &interfaces, head) {
+
+                       avl_for_each_element(&interfaces, iface, avl) {
                                if (iface->ifindex != destiface)
                                        continue;
 
-                               syslog(LOG_DEBUG, "Received %li Bytes from %s%%%s", (long)len,
-                                               ipbuf, iface->ifname);
+                               syslog(LOG_DEBUG, "Received %zd Bytes from %s%%%s@%s", len,
+                                               ipbuf, iface->name, iface->ifname);
 
                                e->handle_dgram(&addr, data_buf, len, iface, dest);
                        }
@@ -440,7 +441,7 @@ int odhcpd_urandom(void *data, size_t len)
 time_t odhcpd_time(void)
 {
        struct timespec ts;
-       syscall(SYS_clock_gettime, CLOCK_MONOTONIC, &ts);
+       clock_gettime(CLOCK_MONOTONIC, &ts);
        return ts.tv_sec;
 }
 
@@ -575,3 +576,38 @@ bool odhcpd_bitlen2netmask(bool inet6, unsigned int bits, void *mask)
 
        return true;
 }
+
+bool odhcpd_valid_hostname(const char *name)
+{
+#define MAX_LABEL      63
+       const char *c, *label, *label_end;
+       int label_sz = 0;
+
+       for (c = name, label_sz = 0, label = name, label_end = name + strcspn(name, ".") - 1;
+                       *c && label_sz <= MAX_LABEL; c++) {
+               if ((*c >= '0' && *c <= '9') ||
+                   (*c >= 'A' && *c <= 'Z') ||
+                   (*c >= 'a' && *c <= 'z')) {
+                       label_sz++;
+                       continue;
+               }
+
+               if ((*c == '_' || *c == '-') && c != label && c != label_end) {
+                       label_sz++;
+                       continue;
+               }
+
+               if (*c == '.') {
+                       if (*(c + 1)) {
+                               label = c + 1;
+                               label_end = label + strcspn(label, ".") - 1;
+                               label_sz = 0;
+                       }
+                       continue;
+               }
+
+               return false;
+       }
+
+       return (label_sz && label_sz <= MAX_LABEL ? true : false);
+}