From 3634c54e8df8b0f3a673f3db8fd03aec8fb84736 Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Wed, 8 Feb 2012 14:22:37 +0000 Subject: [PATCH] dhcp-ignore and dhcp-match implemented for DHCPv6 now. --- src/dhcp-common.c | 30 +++++++++++++++++++++ src/dnsmasq.h | 3 ++- src/option.c | 5 ++++ src/rfc2131.c | 32 ----------------------- src/rfc3315.c | 66 ++++++++++++++++++++++++++++++++++++++++++++--- 5 files changed, 100 insertions(+), 36 deletions(-) diff --git a/src/dhcp-common.c b/src/dhcp-common.c index 3c5349d..bd5be6c 100644 --- a/src/dhcp-common.c +++ b/src/dhcp-common.c @@ -209,5 +209,35 @@ void log_tags(struct dhcp_netid *netid, u32 xid) } } +int match_bytes(struct dhcp_opt *o, unsigned char *p, int len) +{ + int i; + + if (o->len > len) + return 0; + + if (o->len == 0) + return 1; + + if (o->flags & DHOPT_HEX) + { + if (memcmp_masked(o->val, p, o->len, o->u.wildcard_mask)) + return 1; + } + else + for (i = 0; i <= (len - o->len); ) + { + if (memcmp(o->val, p + i, o->len) == 0) + return 1; + + if (o->flags & DHOPT_STRING) + i++; + else + i += o->len; + } + + return 0; +} + #endif diff --git a/src/dnsmasq.h b/src/dnsmasq.h index 722ab09..f83f440 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -695,7 +695,7 @@ extern struct daemon { struct hostsfile *addn_hosts; struct dhcp_context *dhcp, *dhcp6; struct dhcp_config *dhcp_conf; - struct dhcp_opt *dhcp_opts, *dhcp_match, *dhcp_opts6; + struct dhcp_opt *dhcp_opts, *dhcp_match, *dhcp_opts6, *dhcp_match6; struct dhcp_vendor *dhcp_vendors; struct dhcp_mac *dhcp_macs; struct dhcp_boot *boot_config; @@ -1043,3 +1043,4 @@ struct dhcp_netid *option_filter(struct dhcp_netid *tags, struct dhcp_netid *con int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int negonly); char *strip_hostname(char *hostname); void log_tags(struct dhcp_netid *netid, u32 xid); +int match_bytes(struct dhcp_opt *o, unsigned char *p, int len); diff --git a/src/option.c b/src/option.c index fbe1204..a2841d8 100644 --- a/src/option.c +++ b/src/option.c @@ -1333,6 +1333,11 @@ static char *parse_dhcp_opt(char *arg, int flags) !new->netid || new->netid->next) problem = _("illegal dhcp-match"); + else if (is6) + { + new->next = daemon->dhcp_match6; + daemon->dhcp_match6 = new; + } else { new->next = daemon->dhcp_match; diff --git a/src/rfc2131.c b/src/rfc2131.c index d897087..581e7f5 100644 --- a/src/rfc2131.c +++ b/src/rfc2131.c @@ -26,7 +26,6 @@ static void add_extradata_data(struct dhcp_lease *lease, unsigned char *data, si static void add_extradata_opt(struct dhcp_lease *lease, unsigned char *opt); #endif -static int match_bytes(struct dhcp_opt *o, unsigned char *p, int len); static int sanitise(unsigned char *opt, char *buf); static struct in_addr server_id(struct dhcp_context *context, struct in_addr override, struct in_addr fallback); static unsigned int calc_time(struct dhcp_context *context, struct dhcp_config *config, unsigned char *opt); @@ -1400,37 +1399,6 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index, return 0; } -static int match_bytes(struct dhcp_opt *o, unsigned char *p, int len) -{ - int i; - - if (o->len > len) - return 0; - - if (o->len == 0) - return 1; - - if (o->flags & DHOPT_HEX) - { - if (memcmp_masked(o->val, p, o->len, o->u.wildcard_mask)) - return 1; - } - else - for (i = 0; i <= (len - o->len); ) - { - if (memcmp(o->val, p + i, o->len) == 0) - return 1; - - if (o->flags & DHOPT_STRING) - i++; - else - i += o->len; - } - - return 0; -} - - /* find a good value to use as MAC address for logging and address-allocation hashing. This is normally just the chaddr field from the DHCP packet, but eg Firewire will have hlen == 0 and use the client-id instead. diff --git a/src/rfc3315.c b/src/rfc3315.c index 43cb832..93d4fef 100644 --- a/src/rfc3315.c +++ b/src/rfc3315.c @@ -189,7 +189,7 @@ static int dhcp6_no_relay(int msg_type, struct dhcp_netid *tags, struct dhcp_opt *opt_cfg; struct dhcp_vendor *vendor; struct dhcp_context *context_tmp; - unsigned int xid; + unsigned int xid, ignore = 0; unsigned int fqdn_flags = 0x01; /* default to send if we recieve no FQDN option */ /* copy over transaction-id, and save pointer to message type */ @@ -274,6 +274,48 @@ static int dhcp6_no_relay(int msg_type, struct dhcp_netid *tags, } } } + + /* dhcp-match. If we have hex-and-wildcards, look for a left-anchored match. + Otherwise assume the option is an array, and look for a matching element. + If no data given, existance of the option is enough. This code handles + V-I opts too. */ + for (opt_cfg = daemon->dhcp_match6; opt_cfg; opt_cfg = opt_cfg->next) + { + unsigned int len, elen, match = 0; + size_t offset, o2; + + if (opt_cfg->flags & DHOPT_RFC3925) + { + for (opt = opt6_find(packet_options, end, OPTION6_VENDOR_OPTS, 4); + opt; + opt = opt6_find(opt6_next(opt, end), end, OPTION6_VENDOR_OPTS, 4)) + { + void *vopt; + void *vend = opt6_ptr(opt, opt6_len(opt)); + + for (vopt = opt6_find(opt6_ptr(opt, 4), vend, opt_cfg->opt, 0); + vopt; + vopt = opt6_find(opt6_next(vopt, vend), vend, opt_cfg->opt, 0)) + if (match = match_bytes(opt_cfg, opt6_ptr(vopt, 0), opt6_len(vopt))) + break; + } + if (match) + break; + } + else + { + if (!(opt = opt6_find(packet_options, end, opt_cfg->opt, 1))) + continue; + + match = match_bytes(opt_cfg, opt6_ptr(opt, 0), opt6_len(opt)); + } + + if (match) + { + opt_cfg->netid->next = tags; + tags = opt_cfg->netid; + } + } if ((opt = opt6_find(packet_options, end, OPTION6_FQDN, 1))) { @@ -359,9 +401,22 @@ static int dhcp6_no_relay(int msg_type, struct dhcp_netid *tags, known_id.net = "known"; known_id.next = tags; tags = &known_id; + + if (have_config(config, CONFIG_DISABLE)) + ignore = 1; } - + /* if all the netids in the ignore list are present, ignore this client */ + if (daemon->dhcp_ignore) + { + struct dhcp_netid_list *id_list; + + tagif = run_tag_if(tags); + + for (id_list = daemon->dhcp_ignore; id_list; id_list = id_list->next) + if (match_netid(id_list->list, tagif, 0)) + ignore = 1; + } switch (msg_type) { @@ -385,7 +440,10 @@ static int dhcp6_no_relay(int msg_type, struct dhcp_netid *tags, *outmsgtypep = make_lease ? DHCP6REPLY : DHCP6ADVERTISE; log6_packet(msg_type == DHCP6SOLICIT ? "DHCPSOLICIT" : "DHCPREQUEST", - clid, clid_len, NULL, xid, iface_name, NULL); + clid, clid_len, NULL, xid, iface_name, ignore ? "ignored" : NULL); + + if (ignore) + return 0; for (opt = packet_options; opt; opt = opt6_next(opt, end)) { @@ -791,6 +849,8 @@ static int dhcp6_no_relay(int msg_type, struct dhcp_netid *tags, case DHCP6IREQ: { + if (ignore) + return 0; *outmsgtypep = DHCP6REPLY; break; }