Discussion:
[Dnsmasq-discuss] [PATCH] Allow PXE style proxy mode for arbitrary Vendor Classes
Stefan Brüns
2015-08-28 12:54:36 UTC
Permalink
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 <***@rwth-aachen.de>
---
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
Stefan Bruens
2015-10-04 22:03:49 UTC
Permalink
Post by Stefan Brüns
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, ...
Any chance to have this included in dnsmasq?

Kind regards,

Stefan
--
Stefan Brüns / Bergstraße 21 / 52062 Aachen
home: +49 241 53809034 mobile: +49 151 50412019
work: +49 2405 49936-424
Simon Kelley
2015-10-05 21:55:14 UTC
Permalink
Post by Stefan Bruens
Post by Stefan Brüns
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, ...
Any chance to have this included in dnsmasq?
Kind regards,
Stefan
Apologies for not responding. Looking at these patches is on my TODO
list for when I settle down to some winter programming.


Cheers,

Simon.

Loading...