Currently dnsmasq provides PXE style DHCP Proxy server support only for clients with a Vendor Class Identifier matching "^PXEClient.*". PXE is only defined for a few architectures, but the Proxy mechanism is independent of the arch, so it could be used for any boot client.
For it to actually work it also needs support from bootloaders, e.g. u-boot, barebox, ... Signed-off-by: Stefan Brüns <[email protected]> --- src/dnsmasq.h | 2 +- src/option.c | 8 ++++++++ src/rfc2131.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 71 insertions(+), 3 deletions(-) diff --git a/src/dnsmasq.h b/src/dnsmasq.h index cf1a782..1eb0313 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -973,7 +973,7 @@ extern struct daemon { int override; int enable_pxe; int doing_ra, doing_dhcp6; - struct dhcp_netid_list *dhcp_ignore, *dhcp_ignore_names, *dhcp_gen_names; + struct dhcp_netid_list *dhcp_ignore, *dhcp_ignore_names, *dhcp_gen_names, *dhcp_force_proxy; struct dhcp_netid_list *force_broadcast, *bootp_dynamic; struct hostsfile *dhcp_hosts_file, *dhcp_opts_file, *dynamic_dirs; int dhcp_max, tftp_max; diff --git a/src/option.c b/src/option.c index ecc2619..0870d06 100644 --- a/src/option.c +++ b/src/option.c @@ -154,6 +154,7 @@ struct myoption { #define LOPT_HOST_INOTIFY 342 #define LOPT_DNSSEC_STAMP 343 #define LOPT_TFTP_NO_FAIL 344 +#define LOPT_FORCE_PROXY 345 #ifdef HAVE_GETOPT_LONG static const struct option opts[] = @@ -313,6 +314,7 @@ static const struct myoption opts[] = { "quiet-dhcp6", 0, 0, LOPT_QUIET_DHCP6 }, { "quiet-ra", 0, 0, LOPT_QUIET_RA }, { "dns-loop-detect", 0, 0, LOPT_LOOP_DETECT }, + { "dhcp-force-proxy", 1, 0, LOPT_FORCE_PROXY }, { NULL, 0, 0, 0 } }; @@ -3405,6 +3407,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma case LOPT_BROADCAST: /* --dhcp-broadcast */ case '3': /* --bootp-dynamic */ case LOPT_GEN_NAMES: /* --dhcp-generate-names */ + case LOPT_FORCE_PROXY: /* --dhcp-force-proxy */ { struct dhcp_netid_list *new = opt_malloc(sizeof(struct dhcp_netid_list)); struct dhcp_netid *list = NULL; @@ -3428,6 +3431,11 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma new->next = daemon->dhcp_gen_names; daemon->dhcp_gen_names = new; } + else if (option == LOPT_FORCE_PROXY) + { + new->next = daemon->dhcp_force_proxy; + daemon->dhcp_force_proxy = new; + } else { new->next = daemon->dhcp_ignore_names; diff --git a/src/rfc2131.c b/src/rfc2131.c index 9f69ed5..99621da 100644 --- a/src/rfc2131.c +++ b/src/rfc2131.c @@ -73,7 +73,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index, struct dhcp_vendor *vendor; struct dhcp_mac *mac; struct dhcp_netid_list *id_list; - int clid_len = 0, ignore = 0, do_classes = 0, selecting = 0, pxearch = -1; + int clid_len = 0, ignore = 0, do_classes = 0, selecting = 0, pxearch = -1, force_proxy = 0; struct dhcp_packet *mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base; unsigned char *end = (unsigned char *)(mess + 1); unsigned char *real_end = (unsigned char *)(mess + 1); @@ -486,6 +486,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index, netid = &known_id; } + my_syslog(MS_DHCP | LOG_INFO, _("Msg type: %d PXE: %d"), mess_type, pxe); if (mess_type == 0 && !pxe) { /* BOOTP request */ @@ -746,6 +747,11 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index, if (match_netid(id_list->list, tagif_netid, 0)) ignore = 1; + /* if all the netids in the proxy force list are present, allow proxy mode */ + for (id_list = daemon->dhcp_force_proxy; id_list; id_list = id_list->next) + if (match_netid(id_list->list, tagif_netid, 0)) + force_proxy = 1; + /* If configured, we can override the server-id to be the address of the relay, so that all traffic goes via the relay and can pick up agent-id info. This can be configured for all relays, or by address. */ @@ -767,7 +773,61 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index, /* Can have setting to ignore the client ID for a particular MAC address or hostname */ if (have_config(config, CONFIG_NOCLID)) clid = NULL; - + + if (force_proxy) + { + if (mess_type == DHCPDISCOVER) + { + struct dhcp_context *tmp; + + log_packet("DHCPDISCOVER", NULL, emac, emac_len, iface_name, NULL, message, mess->xid); + + for (tmp = context; tmp; tmp = tmp->current) + if ((tmp->flags & CONTEXT_PROXY) && + match_netid(tmp->filter, tagif_netid, 1)) + break; + + if (tmp) + { + if ((opt = option_find(mess, sz, OPTION_PXE_UUID, 17))) + { + memcpy(pxe_uuid, option_ptr(opt, 0), 17); + uuid = pxe_uuid; + my_syslog(MS_DHCP | LOG_INFO, _("PXE UUID found")); + } + + if ((opt = option_find(mess, sz, OPTION_REQUESTED_OPTIONS, 0))) + { + req_options = (unsigned char *)daemon->dhcp_buff2; + memcpy(req_options, option_ptr(opt, 0), option_len(opt)); + req_options[option_len(opt)] = OPTION_END; + } + + if (tmp->netid.net) + { + tmp->netid.next = netid; + tagif_netid = run_tag_if(&tmp->netid); + } + + mess->yiaddr.s_addr = 0; + mess->ciaddr.s_addr = 0; + mess->flags |= htons(0x8000); /* broadcast */ + + clear_packet(mess, end); + + log_tags(tagif_netid, ntohl(mess->xid)); + log_packet("DHCPOFFER", NULL, emac, emac_len, iface_name, ignore ? "force-proxy-ignored" : "force-proxy", NULL, mess->xid); + + option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPOFFER); + option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(tmp->local.s_addr)); + do_options(tmp, mess, end, req_options, offer_hostname, NULL, + netid, subnet_addr, fqdn_flags, borken_opt, -1, uuid, vendor_class_len, now, 0xffffffff, 0); + + return ignore ? 0 : dhcp_packet_size(mess, agent_id, real_end); + } + } + } + /* Check if client is PXE client. */ if (daemon->enable_pxe && (opt = option_find(mess, sz, OPTION_VENDOR_ID, 9)) && -- 2.1.4 _______________________________________________ Dnsmasq-discuss mailing list [email protected] http://lists.thekelleys.org.uk/mailman/listinfo/dnsmasq-discuss
