Add support for raw DHCPv6 attributes
[project/odhcpd.git] / src / dhcpv4.c
index 38b4f9b..b8e0c95 100644 (file)
@@ -37,7 +37,7 @@ static void handle_dhcpv4(void *addr, void *data, size_t len,
 static struct dhcpv4_assignment* dhcpv4_lease(struct interface *iface,
                enum dhcpv4_msg msg, const uint8_t *mac, struct in_addr reqaddr,
                const char *hostname);
-
+static const char *excluded_class = "HOMENET";
 
 // Create socket and register events
 int init_dhcpv4(void)
@@ -49,6 +49,7 @@ int init_dhcpv4(void)
 int setup_dhcpv4_interface(struct interface *iface, bool enable)
 {
        if (iface->dhcpv4_event.uloop.fd > 0) {
+               uloop_fd_delete(&iface->dhcpv4_event.uloop);
                close(iface->dhcpv4_event.uloop.fd);
                iface->dhcpv4_event.uloop.fd = -1;
        }
@@ -58,6 +59,11 @@ int setup_dhcpv4_interface(struct interface *iface, bool enable)
                        INIT_LIST_HEAD(&iface->dhcpv4_assignments);
 
                int sock = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP);
+               if (sock < 0) {
+                       syslog(LOG_ERR, "Failed to create DHCPv4 server socket: %s",
+                                       strerror(errno));
+                       return -1;
+               }
 
                // Basic IPv6 configuration
                int val = 1;
@@ -65,7 +71,7 @@ int setup_dhcpv4_interface(struct interface *iface, bool enable)
                setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val));
                setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &val, sizeof(val));
 
-               val = IPTOS_CLASS_CS6;
+               val = IPTOS_PREC_INTERNETCONTROL;
                setsockopt(sock, IPPROTO_IP, IP_TOS, &val, sizeof(val));
 
                val = IP_PMTUDISC_DONT;
@@ -119,8 +125,8 @@ int setup_dhcpv4_interface(struct interface *iface, bool enable)
                                end = addr.s_addr & mask.s_addr;
 
                                if (ntohl(mask.s_addr) <= 0xffffff00) {
-                                       iface->dhcpv4_start.s_addr = start | htonl(20);
-                                       iface->dhcpv4_end.s_addr = end | htonl(199);
+                                       iface->dhcpv4_start.s_addr = start | htonl(100);
+                                       iface->dhcpv4_end.s_addr = end | htonl(250);
                                } else {
                                        iface->dhcpv4_start.s_addr = start | htonl(10);
                                        iface->dhcpv4_end.s_addr = end | htonl(59);
@@ -136,7 +142,11 @@ int setup_dhcpv4_interface(struct interface *iface, bool enable)
                        // Construct entry
                        size_t hostlen = strlen(lease->hostname) + 1;
                        struct dhcpv4_assignment *a = calloc(1, sizeof(*a) + hostlen);
-
+                       if (!a) {
+                               syslog(LOG_ERR, "Calloc failed for static lease on interface %s",
+                                       iface->ifname);
+                               return -1;
+                       }
                        a->addr = ntohl(lease->ipaddr.s_addr);
                        memcpy(a->hwaddr, lease->mac.ether_addr_octet, sizeof(a->hwaddr));
                        memcpy(a->hostname, lease->hostname, hostlen);
@@ -168,7 +178,7 @@ int setup_dhcpv4_interface(struct interface *iface, bool enable)
 
 
                if (iface->dhcpv4_leasetime < 60)
-                       iface->dhcpv4_leasetime = 1800;
+                       iface->dhcpv4_leasetime = 43200;
 
                iface->dhcpv4_event.uloop.fd = sock;
                iface->dhcpv4_event.handle_dgram = handle_dhcpv4;
@@ -284,6 +294,13 @@ static void handle_dhcpv4(void *addr, void *data, size_t len,
                } else if (opt->type == DHCPV4_OPT_SERVERID && opt->len == 4) {
                        if (memcmp(opt->data, &ifaddr.sin_addr, 4))
                                return;
+               } else if (opt->type == DHCPV4_OPT_USER_CLASS) {
+                       uint8_t *c = opt->data, *cend = &opt->data[opt->len];
+                       for (; c < cend && &c[*c] < cend; c = &c[1 + *c]) {
+                               size_t elen = strlen(excluded_class);
+                               if (*c == elen && !memcmp(&c[1], excluded_class, elen))
+                                       return; // Ignore from homenet
+                       }
                }
        }
 
@@ -463,6 +480,10 @@ static struct dhcpv4_assignment* dhcpv4_lease(struct interface *iface,
 
                if (!a && !iface->no_dynamic_dhcp) { // Create new binding
                        a = calloc(1, sizeof(*a) + hostlen);
+                       if (!a) {
+                               syslog(LOG_ERR, "Failed to calloc binding on interface %s", iface->ifname);
+                               return NULL;
+                       }
                        memcpy(a->hwaddr, mac, sizeof(a->hwaddr));
                        memcpy(a->hostname, hostname, hostlen);
 
@@ -471,6 +492,10 @@ static struct dhcpv4_assignment* dhcpv4_lease(struct interface *iface,
 
                if (assigned && !a->hostname[0] && hostname) {
                        a = realloc(a, sizeof(*a) + hostlen);
+                       if (!a) {
+                               syslog(LOG_ERR, "Failed to realloc binding on interface %s", iface->ifname);
+                               return NULL;
+                       }
                        memcpy(a->hostname, hostname, hostlen);
 
                        // Fixup list