On 2021-08-08 12:14 -07, patrick keshishian <sids...@boxsoft.com> wrote:
> On Sun, Aug 08, 2021 at 12:37:54PM +0200, Florian Obser wrote:
>> 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 */
>
> Typo in comment: ignored (not ignores)

thanks, fixed in my tree.

>
> Should there be a mention of a limitation in the man page where
> it states the option can be listed multiple times?

I really do hope that 16 is enough for everybody. If it turns out not
then we should probably bite the bullet and implement this with a proper
list. So for now I don't want to document the limitation.

>
> --patrick
>
>
>> +
>>  #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.
>> 
>

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

Reply via email to