This implements ignoring of nameservers and / or routes in leases as
well as completely ignoring servers (you cannot block rogue DHCP servers
in pf because bpf sees packets before pf).

Various people voiced the need for these features.
Tests, OKs?

diff --git dhcpleased.c dhcpleased.c
index 36a4a21c21a..e005d7de9ae 100644
--- dhcpleased.c
+++ dhcpleased.c
@@ -569,6 +569,20 @@ main_dispatch_engine(int fd, short event, void *bula)
                            sizeof(imsg_interface.if_index));
                        break;
                }
+               case IMSG_WITHDRAW_ROUTES: {
+                       struct imsg_configure_interface imsg_interface;
+                       if (IMSG_DATA_SIZE(imsg) != sizeof(imsg_interface))
+                               fatalx("%s: IMSG_CONFIGURE_INTERFACE wrong "
+                                   "length: %lu", __func__,
+                                   IMSG_DATA_SIZE(imsg));
+                       memcpy(&imsg_interface, imsg.data,
+                           sizeof(imsg_interface));
+                       if (imsg_interface.routes_len >= MAX_DHCP_ROUTES)
+                               fatalx("%s: too many routes in imsg", __func__);
+                       if (imsg_interface.routes_len > 0)
+                               configure_routes(RTM_DELETE, &imsg_interface);
+                       break;
+               }
                case IMSG_PROPOSE_RDNS: {
                        struct imsg_propose_rdns         rdns;
                        if (IMSG_DATA_SIZE(imsg) != sizeof(rdns))
diff --git dhcpleased.conf.5 dhcpleased.conf.5
index 9e6846f899e..b856113bac1 100644
--- dhcpleased.conf.5
+++ dhcpleased.conf.5
@@ -57,6 +57,17 @@ A list of interfaces to overwrite defaults:
 .Ic interface
 options are as follows:
 .Bl -tag -width Ds
+.It Ic ignore dns
+Ignore nameservers from leases on this interface.
+The default is to not ignore nameservers.
+.It Ic ignore routes
+Ignore routes from leases on this interface.
+The default is to not ignore routes.
+.It Ic ignore Ar server-ip
+Ignore leases from
+.Ar server-ip .
+This option can be listed multiple times.
+The default is to not ignore servers.
 .It Ic send client id Ar client-id
 Send the dhcp client identifier option with a value of
 .Ar client-id .
diff --git dhcpleased.h dhcpleased.h
index 7f6ec87ad19..1d20b77dbd3 100644
--- dhcpleased.h
+++ dhcpleased.h
@@ -151,6 +151,12 @@
 #define        DHCPRELEASE     7
 #define        DHCPINFORM      8
 
+/* Ignore parts of DHCP lease */
+#define        IGN_ROUTES      1
+#define        IGN_DNS         2
+
+#define        MAX_SERVERS     16      /* max servers that can be ignores per 
if */
+
 #define        IMSG_DATA_SIZE(imsg)    ((imsg).hdr.len - IMSG_HEADER_SIZE)
 #define        DHCP_SNAME_LEN          64
 #define        DHCP_FILE_LEN           128
@@ -216,6 +222,7 @@ enum imsg_type {
        IMSG_DECONFIGURE_INTERFACE,
        IMSG_PROPOSE_RDNS,
        IMSG_WITHDRAW_RDNS,
+       IMSG_WITHDRAW_ROUTES,
        IMSG_REPROPOSE_RDNS,
        IMSG_REQUEST_REBOOT,
 };
@@ -246,6 +253,9 @@ struct iface_conf {
        int                              vc_id_len;
        uint8_t                         *c_id;
        int                              c_id_len;
+       int                              ignore;
+       struct in_addr                   ignore_servers[MAX_SERVERS];
+       int                              ignore_servers_len;
 };
 
 struct dhcpleased_conf {
@@ -304,6 +314,8 @@ const char  *sin_to_str(struct sockaddr_in *);
 
 /* frontend.c */
 struct iface_conf      *find_iface_conf(struct iface_conf_head *, char *);
+int                    *changed_ifaces(struct dhcpleased_conf *, struct
+                            dhcpleased_conf *);
 
 /* printconf.c */
 void   print_config(struct dhcpleased_conf *);
diff --git engine.c engine.c
index 076a57e9ba6..67693c358ee 100644
--- engine.c
+++ engine.c
@@ -139,6 +139,7 @@ void                         
send_configure_interface(struct dhcpleased_iface *);
 void                    send_rdns_proposal(struct dhcpleased_iface *);
 void                    send_deconfigure_interface(struct dhcpleased_iface *);
 void                    send_rdns_withdraw(struct dhcpleased_iface *);
+void                    send_routes_withdraw(struct dhcpleased_iface *);
 void                    parse_lease(struct dhcpleased_iface *,
                             struct imsg_ifinfo *);
 int                     engine_imsg_compose_main(int, pid_t, void *, uint16_t);
@@ -506,13 +507,37 @@ engine_dispatch_main(int fd, short event, void *bula)
                            IMSG_DATA_SIZE(imsg));
                        iface_conf->c_id_len = IMSG_DATA_SIZE(imsg);
                        break;
-               case IMSG_RECONF_END:
+               case IMSG_RECONF_END: {
+                       struct dhcpleased_iface *iface;
+                       int                     *ifaces;
+                       int                      i, if_index;
+                       char                    *if_name;
+                       char                     ifnamebuf[IF_NAMESIZE];
+
                        if (nconf == NULL)
                                fatalx("%s: IMSG_RECONF_END without "
                                    "IMSG_RECONF_CONF", __func__);
+                       ifaces = changed_ifaces(engine_conf, nconf);
                        merge_config(engine_conf, nconf);
                        nconf = NULL;
+                       for (i = 0; ifaces[i] != 0; i++) {
+                               if_index = ifaces[i];
+                               if_name = if_indextoname(if_index, ifnamebuf);
+                               iface = get_dhcpleased_iface_by_id(if_index);
+                               if (if_name == NULL || iface == NULL)
+                                       continue;
+                               iface_conf = find_iface_conf(
+                                   &engine_conf->iface_list, if_name);
+                               if (iface_conf == NULL)
+                                       continue;
+                               if (iface_conf->ignore & IGN_DNS)
+                                       send_rdns_withdraw(iface);
+                               if (iface_conf->ignore & IGN_ROUTES)
+                                       send_routes_withdraw(iface);
+                       }
+                       free(ifaces);
                        break;
+               }
 #endif /* SMALL */
                default:
                        log_debug("%s: unexpected imsg %d", __func__,
@@ -760,6 +785,18 @@ parse_dhcp(struct dhcpleased_iface *iface, struct 
imsg_dhcp *dhcp)
        if (inet_ntop(AF_INET, &ip->ip_dst, hbuf_dst, sizeof(hbuf_dst)) == NULL)
                hbuf_dst[0] = '\0';
 
+#ifndef SMALL
+       if (iface_conf != NULL) {
+               for (i = 0; (int)i < iface_conf->ignore_servers_len; i++) {
+                       if (iface_conf->ignore_servers[i].s_addr ==
+                           ip->ip_src.s_addr) {
+                               log_debug("ignoring server %s", hbuf_src);
+                               return;
+                       }
+               }
+       }
+#endif /* SMALL */
+
        if (rem < sizeof(*udp))
                goto too_short;
 
@@ -1203,13 +1240,30 @@ parse_dhcp(struct dhcpleased_iface *iface, struct 
imsg_dhcp *dhcp)
                iface->server_identifier.s_addr = server_identifier.s_addr;
                iface->requested_ip.s_addr = dhcp_hdr->yiaddr.s_addr;
                iface->mask.s_addr = subnet_mask.s_addr;
-               iface->routes_len = routes_len;
-               memcpy(iface->routes, routes, sizeof(iface->routes));
+#ifndef SMALL
+               if (iface_conf != NULL && iface_conf->ignore & IGN_ROUTES) {
+                       iface->routes_len = 0;
+                       memset(iface->routes, 0, sizeof(iface->routes));
+               } else
+#endif /* SMALL */
+               {
+                       iface->routes_len = routes_len;
+                       memcpy(iface->routes, routes, sizeof(iface->routes));
+               }
                iface->lease_time = lease_time;
                iface->renewal_time = renewal_time;
                iface->rebinding_time = rebinding_time;
-               memcpy(iface->nameservers, nameservers,
-                   sizeof(iface->nameservers));
+
+#ifndef SMALL
+               if (iface_conf != NULL && iface_conf->ignore & IGN_DNS) {
+                       memset(iface->nameservers, 0,
+                           sizeof(iface->nameservers));
+               } else
+#endif /* SMALL */
+               {
+                       memcpy(iface->nameservers, nameservers,
+                           sizeof(iface->nameservers));
+               }
 
                iface->siaddr.s_addr = dhcp_hdr->siaddr.s_addr;
 
@@ -1520,6 +1574,28 @@ send_deconfigure_interface(struct dhcpleased_iface 
*iface)
        memset(iface->routes, 0, sizeof(iface->routes));
 }
 
+void
+send_routes_withdraw(struct dhcpleased_iface *iface)
+{
+       struct imsg_configure_interface  imsg;
+
+       if (iface->requested_ip.s_addr == INADDR_ANY || iface->routes_len == 0)
+               return;
+
+       imsg.if_index = iface->if_index;
+       imsg.rdomain = iface->rdomain;
+       imsg.addr.s_addr = iface->requested_ip.s_addr;
+       imsg.mask.s_addr = iface->mask.s_addr;
+       imsg.siaddr.s_addr = iface->siaddr.s_addr;
+       strlcpy(imsg.file, iface->file, sizeof(imsg.file));
+       strlcpy(imsg.domainname, iface->domainname, sizeof(imsg.domainname));
+       strlcpy(imsg.hostname, iface->hostname, sizeof(imsg.hostname));
+       imsg.routes_len = iface->routes_len;
+       memcpy(imsg.routes, iface->routes, sizeof(imsg.routes));
+       engine_imsg_compose_main(IMSG_WITHDRAW_ROUTES, 0, &imsg,
+           sizeof(imsg));
+}
+
 void
 log_rdns(struct dhcpleased_iface *iface, int withdraw)
 {
diff --git frontend.c frontend.c
index 6e17b9c6c62..e52cfae0b25 100644
--- frontend.c
+++ frontend.c
@@ -96,8 +96,6 @@ void           send_discover(struct iface *);
 void            send_request(struct iface *);
 void            bpf_send_packet(struct iface *, uint8_t *, ssize_t);
 void            udp_send_packet(struct iface *, uint8_t *, ssize_t);
-int            *changed_ifaces(struct dhcpleased_conf *, struct
-                    dhcpleased_conf *);
 int             iface_conf_cmp(struct iface_conf *, struct iface_conf *);
 
 LIST_HEAD(, iface)              interfaces;
@@ -1215,6 +1213,13 @@ iface_conf_cmp(struct iface_conf *a, struct iface_conf 
*b)
                return 1;
        if (memcmp(a->c_id, b->c_id, a->c_id_len) != 0)
                return 1;
+       if (a->ignore != b->ignore)
+               return 1;
+       if (a->ignore_servers_len != b->ignore_servers_len)
+               return 1;
+       if (memcmp(a->ignore_servers, b->ignore_servers,
+           a->ignore_servers_len * sizeof (struct in_addr)) != 0)
+               return 1;
        return 0;
 }
 #endif /* SMALL */
diff --git parse.y parse.y
index 947ed038f95..dc6f16d4400 100644
--- parse.y
+++ parse.y
@@ -108,7 +108,7 @@ typedef struct {
 
 %}
 
-%token DHCP_IFACE ERROR SEND VENDOR CLASS ID CLIENT
+%token DHCP_IFACE ERROR SEND VENDOR CLASS ID CLIENT IGNORE DNS ROUTES
 
 %token <v.string>      STRING
 %token <v.number>      NUMBER
@@ -275,6 +275,31 @@ ifaceoptsl : SEND VENDOR CLASS ID STRING {
                        iface_conf->c_id[0] = DHO_DHCP_CLIENT_IDENTIFIER;
                        iface_conf->c_id[1] = iface_conf->c_id_len - 2;
                }
+               | IGNORE ROUTES {
+                       iface_conf->ignore |= IGN_ROUTES;
+               }
+               | IGNORE DNS {
+                       iface_conf->ignore |= IGN_DNS;
+               }
+               | IGNORE STRING {
+                       int res;
+
+                       if (iface_conf->ignore_servers_len >= MAX_SERVERS) {
+                               yyerror("too many servers to ignore");
+                               free($2);
+                               YYERROR;
+                       }
+                       res = inet_pton(AF_INET, $2,
+                           &iface_conf->ignore_servers[
+                           iface_conf->ignore_servers_len++]);
+
+                       if (res != 1) {
+                               yyerror("Invalid server IP %s", $2);
+                               free($2);
+                               YYERROR;
+                       }
+                       free($2);
+               }
                ;
 %%
 
@@ -312,8 +337,11 @@ lookup(char *s)
        static const struct keywords keywords[] = {
                {"class",               CLASS},
                {"client",              CLIENT},
+               {"dns",                 DNS},
                {"id",                  ID},
+               {"ignore",              IGNORE},
                {"interface",           DHCP_IFACE},
+               {"routes",              ROUTES},
                {"send",                SEND},
                {"vendor",              VENDOR},
        };
diff --git printconf.c printconf.c
index 16b33bbfe40..86eef19baf3 100644
--- printconf.c
+++ printconf.c
@@ -106,11 +106,24 @@ void
 print_config(struct dhcpleased_conf *conf)
 {
        struct iface_conf       *iface;
+       int                      i;
+       char                     hbuf[INET_ADDRSTRLEN];
 
        SIMPLEQ_FOREACH(iface, &conf->iface_list, entry) {
                printf("interface %s {\n", iface->name);
                print_dhcp_options("\t", iface->c_id, iface->c_id_len);
                print_dhcp_options("\t", iface->vc_id, iface->vc_id_len);
+               if (iface->ignore & IGN_DNS)
+                       printf("\tignore dns\n");
+               if (iface->ignore & IGN_ROUTES)
+                       printf("\tignore routes\n");
+               for (i = 0; i < iface->ignore_servers_len; i++) {
+                       if (inet_ntop(AF_INET, &iface->ignore_servers[i],
+                           hbuf, sizeof(hbuf)) == NULL)
+                               continue;
+                       printf("\tignore %s\n", hbuf);
+
+               }
                printf("}\n");
        }
 }



-- 
I'm not entirely sure you are real.

Reply via email to