Skip to content

Commit bd7b96f

Browse files
jlevequelguohan
authored andcommitted
[201811][dhcp_relay] Add support for DHCP client(s) on one VLAN and DHCP server(s) on another (#2919)
* Change URL for isc-dhcp source repository * Modify supervisor conf to generate dhcrelay commands with '-id' and '-iu' options * Comments; Also clean up jinja2 syntax * Patch relay to open one socket per interface and send to all servers on all upstream interfaces * Patch relay agent to properly forward BOOTREQUEST only on appropriate interface if it is a directed broadcast * Port upstream patches to isc-dhcp-relay to support upstream/downstream interfaces * Update patch to properly support interfaces with multiple IP addresses assigned * Pass --enable-use-sockets to configure instead of uncommenting USE_SOCKETS directly
1 parent 116246d commit bd7b96f

9 files changed

+700
-18
lines changed

dockers/docker-dhcp-relay/docker-dhcp-relay.supervisord.conf.j2

+20-15
Original file line numberDiff line numberDiff line change
@@ -32,28 +32,33 @@ stderr_logfile=syslog
3232
{% if num_relays.count > 0 %}
3333
[group:isc-dhcp-relay]
3434
programs=
35-
{%- set add_preceding_comma = { 'flag': False } -%}
36-
{%- for vlan_name in VLAN -%}
37-
{%- if VLAN[vlan_name]['dhcp_servers'] -%}
38-
{%- if add_preceding_comma.flag %},{% endif -%}
39-
{%- set _dummy = add_preceding_comma.update({'flag': True}) -%}
35+
{%- set add_preceding_comma = { 'flag': False } %}
36+
{% for vlan_name in VLAN %}
37+
{% if VLAN[vlan_name]['dhcp_servers'] %}
38+
{% if add_preceding_comma.flag %},{% endif %}
39+
{% set _dummy = add_preceding_comma.update({'flag': True}) %}
4040
isc-dhcp-relay-{{ vlan_name }}
4141
{%- endif %}
4242
{% endfor %}
4343

4444

4545
{# Create a program entry for each DHCP relay agent instance #}
46-
{% for vlan_name in VLAN -%}
47-
{%- if VLAN[vlan_name]['dhcp_servers'] -%}
46+
{% for vlan_name in VLAN %}
47+
{% if VLAN[vlan_name]['dhcp_servers'] %}
4848
[program:isc-dhcp-relay-{{ vlan_name }}]
49-
command=/usr/sbin/dhcrelay -d -m discard -a %%h:%%p %%P --name-alias-map-file /tmp/port-name-alias-map.txt -i {{ vlan_name }}
50-
{%- for (name, prefix) in INTERFACE -%}
51-
{%- if prefix | ipv4 %} -i {{ name }}{% endif -%}
52-
{%- endfor -%}
53-
{%- for (name, prefix) in PORTCHANNEL_INTERFACE -%}
54-
{%- if prefix | ipv4 %} -i {{ name }}{% endif -%}
55-
{%- endfor -%}
56-
{%- for dhcp_server in VLAN[vlan_name]['dhcp_servers'] %} {{ dhcp_server }}{% endfor %}
49+
{# We treat this VLAN as a downstream interface (-id), as we only want to listen for requests #}
50+
command=/usr/sbin/dhcrelay -d -m discard -a %%h:%%p %%P --name-alias-map-file /tmp/port-name-alias-map.txt -id {{ vlan_name }}
51+
{#- We treat all other interfaces as upstream interfaces (-iu), as we only want to listen for replies #}
52+
{% for (name, prefix) in VLAN_INTERFACE %}
53+
{% if prefix | ipv4 and name != vlan_name %} -iu {{ name }}{% endif -%}
54+
{% endfor %}
55+
{% for (name, prefix) in INTERFACE %}
56+
{% if prefix | ipv4 %} -iu {{ name }}{% endif -%}
57+
{% endfor %}
58+
{% for (name, prefix) in PORTCHANNEL_INTERFACE %}
59+
{% if prefix | ipv4 %} -iu {{ name }}{% endif -%}
60+
{% endfor %}
61+
{% for dhcp_server in VLAN[vlan_name]['dhcp_servers'] %} {{ dhcp_server }}{% endfor %}
5762

5863
priority=3
5964
autostart=false

src/isc-dhcp/Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ $(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% :
1010
rm -rf ./isc-dhcp
1111

1212
# Clone isc-dhcp repo
13-
git clone https://salsa.debian.org/berni/isc-dhcp.git
13+
git clone https://salsa.debian.org/dhcp-team/isc-dhcp.git
1414
pushd ./isc-dhcp
1515

1616
# Reset HEAD to the commit of the proper tag
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
From 0092eed7a80f38078a38fedf601952d0d25c6183 Mon Sep 17 00:00:00 2001
2+
From: Joe LeVeque <[email protected]>
3+
Date: Thu, 2 May 2019 19:20:59 +0000
4+
Subject: [PATCH 1/2] Port upstream changes from commit
5+
f2e70402f0f2955f392edc4eb2dd835b820e25bc to add '-iu' option
6+
7+
---
8+
common/discover.c | 8 +++++++-
9+
relay/dhcrelay.c | 36 +++++++++++++++++++++++++++++++++++-
10+
2 files changed, 42 insertions(+), 2 deletions(-)
11+
12+
diff --git a/common/discover.c b/common/discover.c
13+
index 3cd64a7..e20d9d5 100644
14+
--- a/common/discover.c
15+
+++ b/common/discover.c
16+
@@ -948,8 +948,14 @@ discover_interfaces(int state) {
17+
ir = 0;
18+
else if (state == DISCOVER_UNCONFIGURED)
19+
ir = INTERFACE_REQUESTED | INTERFACE_AUTOMATIC;
20+
- else
21+
+ else {
22+
ir = INTERFACE_REQUESTED;
23+
+ if (state == DISCOVER_RELAY && local_family == AF_INET) {
24+
+ /* We're a v4 relay without specifically requested
25+
+ * interfaces, so mark them all as bidirectional. */
26+
+ ir |= INTERFACE_STREAMS;
27+
+ }
28+
+ }
29+
30+
/* Cycle through the list of interfaces looking for IP addresses. */
31+
while (next_iface(&info, &err, &ifaces)) {
32+
diff --git a/relay/dhcrelay.c b/relay/dhcrelay.c
33+
index 15f0acf..8051e17 100644
34+
--- a/relay/dhcrelay.c
35+
+++ b/relay/dhcrelay.c
36+
@@ -172,6 +172,7 @@ static const char url[] =
37+
" [-m append|replace|forward|discard]\n" \
38+
" [--name-alias-map-file <name-alias-map-file>]\n" \
39+
" [-i interface0 [ ... -i interfaceN]\n" \
40+
+" [-iu interface0 [ ... -iu interfaceN]\n" \
41+
" server0 [ ... serverN]\n\n" \
42+
" dhcrelay -6 [-d] [-q] [-I] [-c <hops>] [-p <port>]\n" \
43+
" [-pf <pid-file>] [--no-pid]\n" \
44+
@@ -188,6 +189,7 @@ static const char url[] =
45+
" [-pf <pid-file>] [--no-pid]\n"\
46+
" [-m append|replace|forward|discard]\n" \
47+
" [-i interface0 [ ... -i interfaceN]\n" \
48+
+" [-iu interface0 [ ... -iu interfaceN]\n" \
49+
" server0 [ ... serverN]\n\n" DHCRELAY_OPTION82_USAGE
50+
#endif
51+
52+
@@ -304,7 +306,34 @@ main(int argc, char **argv) {
53+
isc_result_totext(status));
54+
}
55+
strcpy(tmp->name, argv[i]);
56+
- interface_snorf(tmp, INTERFACE_REQUESTED);
57+
+ interface_snorf(tmp, (INTERFACE_REQUESTED |
58+
+ INTERFACE_STREAMS));
59+
+ interface_dereference(&tmp, MDL);
60+
+ } else if (!strcmp(argv[i], "-iu")) {
61+
+#ifdef DHCPv6
62+
+ if (local_family_set && (local_family == AF_INET6)) {
63+
+ usage();
64+
+ }
65+
+ local_family_set = 1;
66+
+ local_family = AF_INET;
67+
+#endif
68+
+ if (++i == argc) {
69+
+ usage();
70+
+ }
71+
+ if (strlen(argv[i]) >= sizeof(tmp->name)) {
72+
+ log_fatal("%s: interface name too long "
73+
+ "(is %ld)",
74+
+ argv[i], (long)strlen(argv[i]));
75+
+ }
76+
+ status = interface_allocate(&tmp, MDL);
77+
+ if (status != ISC_R_SUCCESS) {
78+
+ log_fatal("%s: interface_allocate: %s",
79+
+ argv[i],
80+
+ isc_result_totext(status));
81+
+ }
82+
+ strcpy(tmp->name, argv[i]);
83+
+ interface_snorf(tmp, (INTERFACE_REQUESTED |
84+
+ INTERFACE_UPSTREAM));
85+
interface_dereference(&tmp, MDL);
86+
} else if (!strcmp(argv[i], "-a")) {
87+
#ifdef DHCPv6
88+
@@ -691,6 +720,11 @@ do_relay4(struct interface_info *ip, struct dhcp_packet *packet,
89+
90+
/* If it's a bootreply, forward it to the client. */
91+
if (packet->op == BOOTREPLY) {
92+
+ if (!(ip->flags & INTERFACE_UPSTREAM)) {
93+
+ log_debug("Dropping reply received on %s", ip->name);
94+
+ return;
95+
+ }
96+
+
97+
if (!(packet->flags & htons(BOOTP_BROADCAST)) &&
98+
can_unicast_without_arp(out)) {
99+
to.sin_addr = packet->yiaddr;
100+
--
101+
2.17.1
102+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
From 1d59a7bd4dc9cb3cd13aedf604a15a8589febe43 Mon Sep 17 00:00:00 2001
2+
From: Joe LeVeque <[email protected]>
3+
Date: Thu, 2 May 2019 19:46:42 +0000
4+
Subject: [PATCH 2/2] Port upstream changes from commit
5+
edd6d8881bc4d8ec4b04173c66c1c840756bbe76 to add '-id' option
6+
7+
---
8+
relay/dhcrelay.c | 89 +++++++++++++++++++++++++++++++++---------------
9+
1 file changed, 61 insertions(+), 28 deletions(-)
10+
11+
diff --git a/relay/dhcrelay.c b/relay/dhcrelay.c
12+
index 8051e17..292ba4f 100644
13+
--- a/relay/dhcrelay.c
14+
+++ b/relay/dhcrelay.c
15+
@@ -142,6 +142,8 @@ static int strip_relay_agent_options(struct interface_info *,
16+
struct interface_info **,
17+
struct dhcp_packet *, unsigned);
18+
19+
+static void request_v4_interface(const char* name, int flags);
20+
+
21+
static int load_interface_alias_map(const char *port_alias_map_file_path);
22+
static int get_interface_alias_by_name(const char *if_name, char *if_alias_out);
23+
static void free_interface_alias_map(void);
24+
@@ -173,6 +175,7 @@ static const char url[] =
25+
" [--name-alias-map-file <name-alias-map-file>]\n" \
26+
" [-i interface0 [ ... -i interfaceN]\n" \
27+
" [-iu interface0 [ ... -iu interfaceN]\n" \
28+
+" [-id interface0 [ ... -id interfaceN]\n" \
29+
" server0 [ ... serverN]\n\n" \
30+
" dhcrelay -6 [-d] [-q] [-I] [-c <hops>] [-p <port>]\n" \
31+
" [-pf <pid-file>] [--no-pid]\n" \
32+
@@ -190,6 +193,7 @@ static const char url[] =
33+
" [-m append|replace|forward|discard]\n" \
34+
" [-i interface0 [ ... -i interfaceN]\n" \
35+
" [-iu interface0 [ ... -iu interfaceN]\n" \
36+
+" [-id interface0 [ ... -id interfaceN]\n" \
37+
" server0 [ ... serverN]\n\n" DHCRELAY_OPTION82_USAGE
38+
#endif
39+
40+
@@ -294,21 +298,8 @@ main(int argc, char **argv) {
41+
if (++i == argc) {
42+
usage();
43+
}
44+
- if (strlen(argv[i]) >= sizeof(tmp->name)) {
45+
- log_fatal("%s: interface name too long "
46+
- "(is %ld)",
47+
- argv[i], (long)strlen(argv[i]));
48+
- }
49+
- status = interface_allocate(&tmp, MDL);
50+
- if (status != ISC_R_SUCCESS) {
51+
- log_fatal("%s: interface_allocate: %s",
52+
- argv[i],
53+
- isc_result_totext(status));
54+
- }
55+
- strcpy(tmp->name, argv[i]);
56+
- interface_snorf(tmp, (INTERFACE_REQUESTED |
57+
- INTERFACE_STREAMS));
58+
- interface_dereference(&tmp, MDL);
59+
+
60+
+ request_v4_interface(argv[i], INTERFACE_STREAMS);
61+
} else if (!strcmp(argv[i], "-iu")) {
62+
#ifdef DHCPv6
63+
if (local_family_set && (local_family == AF_INET6)) {
64+
@@ -320,21 +311,21 @@ main(int argc, char **argv) {
65+
if (++i == argc) {
66+
usage();
67+
}
68+
- if (strlen(argv[i]) >= sizeof(tmp->name)) {
69+
- log_fatal("%s: interface name too long "
70+
- "(is %ld)",
71+
- argv[i], (long)strlen(argv[i]));
72+
+
73+
+ request_v4_interface(argv[i], INTERFACE_UPSTREAM);
74+
+ } else if (!strcmp(argv[i], "-id")) {
75+
+#ifdef DHCPv6
76+
+ if (local_family_set && (local_family == AF_INET6)) {
77+
+ usage();
78+
}
79+
- status = interface_allocate(&tmp, MDL);
80+
- if (status != ISC_R_SUCCESS) {
81+
- log_fatal("%s: interface_allocate: %s",
82+
- argv[i],
83+
- isc_result_totext(status));
84+
+ local_family_set = 1;
85+
+ local_family = AF_INET;
86+
+#endif
87+
+ if (++i == argc) {
88+
+ usage();
89+
}
90+
- strcpy(tmp->name, argv[i]);
91+
- interface_snorf(tmp, (INTERFACE_REQUESTED |
92+
- INTERFACE_UPSTREAM));
93+
- interface_dereference(&tmp, MDL);
94+
+
95+
+ request_v4_interface(argv[i], INTERFACE_DOWNSTREAM);
96+
} else if (!strcmp(argv[i], "-a")) {
97+
#ifdef DHCPv6
98+
if (local_family_set && (local_family == AF_INET6)) {
99+
@@ -782,6 +773,11 @@ do_relay4(struct interface_info *ip, struct dhcp_packet *packet,
100+
if (out)
101+
return;
102+
103+
+ if (!(ip->flags & INTERFACE_DOWNSTREAM)) {
104+
+ log_debug("Dropping request received on %s", ip->name);
105+
+ return;
106+
+ }
107+
+
108+
/* Add relay agent options if indicated. If something goes wrong,
109+
drop the packet. */
110+
if (!(length = add_relay_agent_options(ip, packet, length,
111+
@@ -1991,6 +1987,43 @@ dhcp_set_control_state(control_object_state_t oldstate,
112+
exit(0);
113+
}
114+
115+
+/*!
116+
+ *
117+
+ * \brief Allocate an interface as requested with a given set of flags
118+
+ *
119+
+ * The requested interface is allocated, its flags field is set to
120+
+ * INTERFACE_REQUESTED OR'd with the given flags, and then added to
121+
+ * the list of interfaces.
122+
+ *
123+
+ * \param name - name of the requested interface
124+
+ * \param flags - additional flags for the interface
125+
+ *
126+
+ * \return Nothing
127+
+ */
128+
+void request_v4_interface(const char* name, int flags) {
129+
+ struct interface_info *tmp = NULL;
130+
+ int len = strlen(name);
131+
+ isc_result_t status;
132+
+
133+
+ if (len >= sizeof(tmp->name)) {
134+
+ log_fatal("%s: interface name too long (is %d)", name, len);
135+
+ }
136+
+
137+
+ status = interface_allocate(&tmp, MDL);
138+
+ if (status != ISC_R_SUCCESS) {
139+
+ log_fatal("%s: interface_allocate: %s", name,
140+
+ isc_result_totext(status));
141+
+ }
142+
+
143+
+ log_debug("Requesting: %s as upstream: %c downstream: %c", name,
144+
+ (flags & INTERFACE_UPSTREAM ? 'Y' : 'N'),
145+
+ (flags & INTERFACE_DOWNSTREAM ? 'Y' : 'N'));
146+
+
147+
+ strncpy(tmp->name, name, len);
148+
+ interface_snorf(tmp, (INTERFACE_REQUESTED | flags));
149+
+ interface_dereference(&tmp, MDL);
150+
+}
151+
+
152+
#define MAX_PORT_CONFIG_LINE_LEN 1024
153+
154+
// Allocates and loads global map g_interface_name_alias_map
155+
--
156+
2.17.1
157+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
From ab779f1d59f27f66e6e6bea89287c810e0a10a0f Mon Sep 17 00:00:00 2001
2+
From: Joe LeVeque <[email protected]>
3+
Date: Wed, 15 May 2019 23:48:08 +0000
4+
Subject: [PATCH 1/3] Add --enable-use-sockets to configure flags in
5+
debian/rules
6+
7+
This defines USE_SOCKETS at compile time which forces dhcrelay
8+
to create and bind separate sockets to each interface
9+
---
10+
debian/rules | 2 +-
11+
1 file changed, 1 insertion(+), 1 deletion(-)
12+
13+
diff --git a/debian/rules b/debian/rules
14+
index 4184716..46d6527 100755
15+
--- a/debian/rules
16+
+++ b/debian/rules
17+
@@ -23,7 +23,7 @@ CFLAGS+=-D_PATH_DHCLIENT_CONF='\"/etc/dhcp/dhclient.conf\"'
18+
CFLAGS+=-D_PATH_DHCLIENT_DB='\"$(LEASE_PATH)/dhclient.leases\"'
19+
CFLAGS+=-D_PATH_DHCLIENT6_DB='\"$(LEASE_PATH)/dhclient6.leases\"'
20+
21+
-CONFFLAGS=--prefix=/usr --enable-log-pid --enable-paranoia
22+
+CONFFLAGS=--prefix=/usr --enable-log-pid --enable-paranoia --enable-use-sockets
23+
24+
# cross-architecture building
25+
ifneq ($(DEB_HOST_GNU_TYPE),$(DEB_BUILD_GNU_TYPE))
26+
--
27+
2.17.1
28+

0 commit comments

Comments
 (0)