Merge pull request #13 from dedeckeh/bugfixes
[project/odhcpd.git] / src / dhcpv4.c
index 7a68f66..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;
@@ -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);
@@ -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