[201803][dhcp_relay] Add support for DHCP client(s) on one VLAN and DHCP server(s) on another (#2857)
* Change URL for isc-dhcp source repository * Port upstream patches to isc-dhcp-relay to support upstream/downstream interfaces * 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 interfaace if it is a directed broadcast * Update patch to properly support interfaces with multiple IP addresses assigned * Pass --enable-use-sockets to configure instead of uncommenting USE_SOCKETS directly
This commit is contained in:
parent
ca4f587597
commit
bce72c9228
@ -32,28 +32,33 @@ stderr_logfile=syslog
|
||||
{% if num_relays.count > 0 %}
|
||||
[group:isc-dhcp-relay]
|
||||
programs=
|
||||
{%- set add_preceding_comma = { 'flag': False } -%}
|
||||
{%- for vlan_name in VLAN -%}
|
||||
{%- if VLAN[vlan_name]['dhcp_servers'] -%}
|
||||
{%- if add_preceding_comma.flag %},{% endif -%}
|
||||
{%- set _dummy = add_preceding_comma.update({'flag': True}) -%}
|
||||
{%- set add_preceding_comma = { 'flag': False } %}
|
||||
{% for vlan_name in VLAN %}
|
||||
{% if VLAN[vlan_name]['dhcp_servers'] %}
|
||||
{% if add_preceding_comma.flag %},{% endif %}
|
||||
{% set _dummy = add_preceding_comma.update({'flag': True}) %}
|
||||
isc-dhcp-relay-{{ vlan_name }}
|
||||
{%- endif %}
|
||||
{% endfor %}
|
||||
|
||||
|
||||
{# Create a program entry for each DHCP relay agent instance #}
|
||||
{% for vlan_name in VLAN -%}
|
||||
{%- if VLAN[vlan_name]['dhcp_servers'] -%}
|
||||
{% for vlan_name in VLAN %}
|
||||
{% if VLAN[vlan_name]['dhcp_servers'] %}
|
||||
[program:isc-dhcp-relay-{{ vlan_name }}]
|
||||
command=/usr/sbin/dhcrelay -d -m discard -a %%h:%%p %%P --name-alias-map-file /tmp/port-name-alias-map.txt -i {{ vlan_name }}
|
||||
{%- for (name, prefix) in INTERFACE -%}
|
||||
{%- if prefix | ipv4 %} -i {{ name }}{% endif -%}
|
||||
{%- endfor -%}
|
||||
{%- for (name, prefix) in PORTCHANNEL_INTERFACE -%}
|
||||
{%- if prefix | ipv4 %} -i {{ name }}{% endif -%}
|
||||
{%- endfor -%}
|
||||
{%- for dhcp_server in VLAN[vlan_name]['dhcp_servers'] %} {{ dhcp_server }}{% endfor %}
|
||||
{# We treat this VLAN as a downstream interface (-id), as we only want to listen for requests #}
|
||||
command=/usr/sbin/dhcrelay -d -m discard -a %%h:%%p %%P --name-alias-map-file /tmp/port-name-alias-map.txt -id {{ vlan_name }}
|
||||
{#- We treat all other interfaces as upstream interfaces (-iu), as we only want to listen for replies #}
|
||||
{% for (name, prefix) in VLAN_INTERFACE %}
|
||||
{% if prefix | ipv4 and name != vlan_name %} -iu {{ name }}{% endif -%}
|
||||
{% endfor %}
|
||||
{% for (name, prefix) in INTERFACE %}
|
||||
{% if prefix | ipv4 %} -iu {{ name }}{% endif -%}
|
||||
{% endfor %}
|
||||
{% for (name, prefix) in PORTCHANNEL_INTERFACE %}
|
||||
{% if prefix | ipv4 %} -iu {{ name }}{% endif -%}
|
||||
{% endfor %}
|
||||
{% for dhcp_server in VLAN[vlan_name]['dhcp_servers'] %} {{ dhcp_server }}{% endfor %}
|
||||
|
||||
priority=3
|
||||
autostart=false
|
||||
|
@ -11,7 +11,7 @@ $(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% :
|
||||
rm -rf ./isc-dhcp
|
||||
|
||||
# Clone isc-dhcp repo
|
||||
git clone https://salsa.debian.org/berni/isc-dhcp.git
|
||||
git clone https://salsa.debian.org/dhcp-team/isc-dhcp.git
|
||||
pushd ./isc-dhcp
|
||||
|
||||
# Reset HEAD to the commit of the proper tag
|
||||
|
@ -0,0 +1,102 @@
|
||||
From 0092eed7a80f38078a38fedf601952d0d25c6183 Mon Sep 17 00:00:00 2001
|
||||
From: Joe LeVeque <jolevequ@microsoft.com>
|
||||
Date: Thu, 2 May 2019 19:20:59 +0000
|
||||
Subject: [PATCH 1/2] Port upstream changes from commit
|
||||
f2e70402f0f2955f392edc4eb2dd835b820e25bc to add '-iu' option
|
||||
|
||||
---
|
||||
common/discover.c | 8 +++++++-
|
||||
relay/dhcrelay.c | 36 +++++++++++++++++++++++++++++++++++-
|
||||
2 files changed, 42 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/common/discover.c b/common/discover.c
|
||||
index 3cd64a7..e20d9d5 100644
|
||||
--- a/common/discover.c
|
||||
+++ b/common/discover.c
|
||||
@@ -948,8 +948,14 @@ discover_interfaces(int state) {
|
||||
ir = 0;
|
||||
else if (state == DISCOVER_UNCONFIGURED)
|
||||
ir = INTERFACE_REQUESTED | INTERFACE_AUTOMATIC;
|
||||
- else
|
||||
+ else {
|
||||
ir = INTERFACE_REQUESTED;
|
||||
+ if (state == DISCOVER_RELAY && local_family == AF_INET) {
|
||||
+ /* We're a v4 relay without specifically requested
|
||||
+ * interfaces, so mark them all as bidirectional. */
|
||||
+ ir |= INTERFACE_STREAMS;
|
||||
+ }
|
||||
+ }
|
||||
|
||||
/* Cycle through the list of interfaces looking for IP addresses. */
|
||||
while (next_iface(&info, &err, &ifaces)) {
|
||||
diff --git a/relay/dhcrelay.c b/relay/dhcrelay.c
|
||||
index 15f0acf..8051e17 100644
|
||||
--- a/relay/dhcrelay.c
|
||||
+++ b/relay/dhcrelay.c
|
||||
@@ -172,6 +172,7 @@ static const char url[] =
|
||||
" [-m append|replace|forward|discard]\n" \
|
||||
" [--name-alias-map-file <name-alias-map-file>]\n" \
|
||||
" [-i interface0 [ ... -i interfaceN]\n" \
|
||||
+" [-iu interface0 [ ... -iu interfaceN]\n" \
|
||||
" server0 [ ... serverN]\n\n" \
|
||||
" dhcrelay -6 [-d] [-q] [-I] [-c <hops>] [-p <port>]\n" \
|
||||
" [-pf <pid-file>] [--no-pid]\n" \
|
||||
@@ -188,6 +189,7 @@ static const char url[] =
|
||||
" [-pf <pid-file>] [--no-pid]\n"\
|
||||
" [-m append|replace|forward|discard]\n" \
|
||||
" [-i interface0 [ ... -i interfaceN]\n" \
|
||||
+" [-iu interface0 [ ... -iu interfaceN]\n" \
|
||||
" server0 [ ... serverN]\n\n" DHCRELAY_OPTION82_USAGE
|
||||
#endif
|
||||
|
||||
@@ -304,7 +306,34 @@ main(int argc, char **argv) {
|
||||
isc_result_totext(status));
|
||||
}
|
||||
strcpy(tmp->name, argv[i]);
|
||||
- interface_snorf(tmp, INTERFACE_REQUESTED);
|
||||
+ interface_snorf(tmp, (INTERFACE_REQUESTED |
|
||||
+ INTERFACE_STREAMS));
|
||||
+ interface_dereference(&tmp, MDL);
|
||||
+ } else if (!strcmp(argv[i], "-iu")) {
|
||||
+#ifdef DHCPv6
|
||||
+ if (local_family_set && (local_family == AF_INET6)) {
|
||||
+ usage();
|
||||
+ }
|
||||
+ local_family_set = 1;
|
||||
+ local_family = AF_INET;
|
||||
+#endif
|
||||
+ if (++i == argc) {
|
||||
+ usage();
|
||||
+ }
|
||||
+ if (strlen(argv[i]) >= sizeof(tmp->name)) {
|
||||
+ log_fatal("%s: interface name too long "
|
||||
+ "(is %ld)",
|
||||
+ argv[i], (long)strlen(argv[i]));
|
||||
+ }
|
||||
+ status = interface_allocate(&tmp, MDL);
|
||||
+ if (status != ISC_R_SUCCESS) {
|
||||
+ log_fatal("%s: interface_allocate: %s",
|
||||
+ argv[i],
|
||||
+ isc_result_totext(status));
|
||||
+ }
|
||||
+ strcpy(tmp->name, argv[i]);
|
||||
+ interface_snorf(tmp, (INTERFACE_REQUESTED |
|
||||
+ INTERFACE_UPSTREAM));
|
||||
interface_dereference(&tmp, MDL);
|
||||
} else if (!strcmp(argv[i], "-a")) {
|
||||
#ifdef DHCPv6
|
||||
@@ -691,6 +720,11 @@ do_relay4(struct interface_info *ip, struct dhcp_packet *packet,
|
||||
|
||||
/* If it's a bootreply, forward it to the client. */
|
||||
if (packet->op == BOOTREPLY) {
|
||||
+ if (!(ip->flags & INTERFACE_UPSTREAM)) {
|
||||
+ log_debug("Dropping reply received on %s", ip->name);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
if (!(packet->flags & htons(BOOTP_BROADCAST)) &&
|
||||
can_unicast_without_arp(out)) {
|
||||
to.sin_addr = packet->yiaddr;
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,157 @@
|
||||
From 1d59a7bd4dc9cb3cd13aedf604a15a8589febe43 Mon Sep 17 00:00:00 2001
|
||||
From: Joe LeVeque <jolevequ@microsoft.com>
|
||||
Date: Thu, 2 May 2019 19:46:42 +0000
|
||||
Subject: [PATCH 2/2] Port upstream changes from commit
|
||||
edd6d8881bc4d8ec4b04173c66c1c840756bbe76 to add '-id' option
|
||||
|
||||
---
|
||||
relay/dhcrelay.c | 89 +++++++++++++++++++++++++++++++++---------------
|
||||
1 file changed, 61 insertions(+), 28 deletions(-)
|
||||
|
||||
diff --git a/relay/dhcrelay.c b/relay/dhcrelay.c
|
||||
index 8051e17..292ba4f 100644
|
||||
--- a/relay/dhcrelay.c
|
||||
+++ b/relay/dhcrelay.c
|
||||
@@ -142,6 +142,8 @@ static int strip_relay_agent_options(struct interface_info *,
|
||||
struct interface_info **,
|
||||
struct dhcp_packet *, unsigned);
|
||||
|
||||
+static void request_v4_interface(const char* name, int flags);
|
||||
+
|
||||
static int load_interface_alias_map(const char *port_alias_map_file_path);
|
||||
static int get_interface_alias_by_name(const char *if_name, char *if_alias_out);
|
||||
static void free_interface_alias_map(void);
|
||||
@@ -173,6 +175,7 @@ static const char url[] =
|
||||
" [--name-alias-map-file <name-alias-map-file>]\n" \
|
||||
" [-i interface0 [ ... -i interfaceN]\n" \
|
||||
" [-iu interface0 [ ... -iu interfaceN]\n" \
|
||||
+" [-id interface0 [ ... -id interfaceN]\n" \
|
||||
" server0 [ ... serverN]\n\n" \
|
||||
" dhcrelay -6 [-d] [-q] [-I] [-c <hops>] [-p <port>]\n" \
|
||||
" [-pf <pid-file>] [--no-pid]\n" \
|
||||
@@ -190,6 +193,7 @@ static const char url[] =
|
||||
" [-m append|replace|forward|discard]\n" \
|
||||
" [-i interface0 [ ... -i interfaceN]\n" \
|
||||
" [-iu interface0 [ ... -iu interfaceN]\n" \
|
||||
+" [-id interface0 [ ... -id interfaceN]\n" \
|
||||
" server0 [ ... serverN]\n\n" DHCRELAY_OPTION82_USAGE
|
||||
#endif
|
||||
|
||||
@@ -294,21 +298,8 @@ main(int argc, char **argv) {
|
||||
if (++i == argc) {
|
||||
usage();
|
||||
}
|
||||
- if (strlen(argv[i]) >= sizeof(tmp->name)) {
|
||||
- log_fatal("%s: interface name too long "
|
||||
- "(is %ld)",
|
||||
- argv[i], (long)strlen(argv[i]));
|
||||
- }
|
||||
- status = interface_allocate(&tmp, MDL);
|
||||
- if (status != ISC_R_SUCCESS) {
|
||||
- log_fatal("%s: interface_allocate: %s",
|
||||
- argv[i],
|
||||
- isc_result_totext(status));
|
||||
- }
|
||||
- strcpy(tmp->name, argv[i]);
|
||||
- interface_snorf(tmp, (INTERFACE_REQUESTED |
|
||||
- INTERFACE_STREAMS));
|
||||
- interface_dereference(&tmp, MDL);
|
||||
+
|
||||
+ request_v4_interface(argv[i], INTERFACE_STREAMS);
|
||||
} else if (!strcmp(argv[i], "-iu")) {
|
||||
#ifdef DHCPv6
|
||||
if (local_family_set && (local_family == AF_INET6)) {
|
||||
@@ -320,21 +311,21 @@ main(int argc, char **argv) {
|
||||
if (++i == argc) {
|
||||
usage();
|
||||
}
|
||||
- if (strlen(argv[i]) >= sizeof(tmp->name)) {
|
||||
- log_fatal("%s: interface name too long "
|
||||
- "(is %ld)",
|
||||
- argv[i], (long)strlen(argv[i]));
|
||||
+
|
||||
+ request_v4_interface(argv[i], INTERFACE_UPSTREAM);
|
||||
+ } else if (!strcmp(argv[i], "-id")) {
|
||||
+#ifdef DHCPv6
|
||||
+ if (local_family_set && (local_family == AF_INET6)) {
|
||||
+ usage();
|
||||
}
|
||||
- status = interface_allocate(&tmp, MDL);
|
||||
- if (status != ISC_R_SUCCESS) {
|
||||
- log_fatal("%s: interface_allocate: %s",
|
||||
- argv[i],
|
||||
- isc_result_totext(status));
|
||||
+ local_family_set = 1;
|
||||
+ local_family = AF_INET;
|
||||
+#endif
|
||||
+ if (++i == argc) {
|
||||
+ usage();
|
||||
}
|
||||
- strcpy(tmp->name, argv[i]);
|
||||
- interface_snorf(tmp, (INTERFACE_REQUESTED |
|
||||
- INTERFACE_UPSTREAM));
|
||||
- interface_dereference(&tmp, MDL);
|
||||
+
|
||||
+ request_v4_interface(argv[i], INTERFACE_DOWNSTREAM);
|
||||
} else if (!strcmp(argv[i], "-a")) {
|
||||
#ifdef DHCPv6
|
||||
if (local_family_set && (local_family == AF_INET6)) {
|
||||
@@ -782,6 +773,11 @@ do_relay4(struct interface_info *ip, struct dhcp_packet *packet,
|
||||
if (out)
|
||||
return;
|
||||
|
||||
+ if (!(ip->flags & INTERFACE_DOWNSTREAM)) {
|
||||
+ log_debug("Dropping request received on %s", ip->name);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
/* Add relay agent options if indicated. If something goes wrong,
|
||||
drop the packet. */
|
||||
if (!(length = add_relay_agent_options(ip, packet, length,
|
||||
@@ -1991,6 +1987,43 @@ dhcp_set_control_state(control_object_state_t oldstate,
|
||||
exit(0);
|
||||
}
|
||||
|
||||
+/*!
|
||||
+ *
|
||||
+ * \brief Allocate an interface as requested with a given set of flags
|
||||
+ *
|
||||
+ * The requested interface is allocated, its flags field is set to
|
||||
+ * INTERFACE_REQUESTED OR'd with the given flags, and then added to
|
||||
+ * the list of interfaces.
|
||||
+ *
|
||||
+ * \param name - name of the requested interface
|
||||
+ * \param flags - additional flags for the interface
|
||||
+ *
|
||||
+ * \return Nothing
|
||||
+ */
|
||||
+void request_v4_interface(const char* name, int flags) {
|
||||
+ struct interface_info *tmp = NULL;
|
||||
+ int len = strlen(name);
|
||||
+ isc_result_t status;
|
||||
+
|
||||
+ if (len >= sizeof(tmp->name)) {
|
||||
+ log_fatal("%s: interface name too long (is %d)", name, len);
|
||||
+ }
|
||||
+
|
||||
+ status = interface_allocate(&tmp, MDL);
|
||||
+ if (status != ISC_R_SUCCESS) {
|
||||
+ log_fatal("%s: interface_allocate: %s", name,
|
||||
+ isc_result_totext(status));
|
||||
+ }
|
||||
+
|
||||
+ log_debug("Requesting: %s as upstream: %c downstream: %c", name,
|
||||
+ (flags & INTERFACE_UPSTREAM ? 'Y' : 'N'),
|
||||
+ (flags & INTERFACE_DOWNSTREAM ? 'Y' : 'N'));
|
||||
+
|
||||
+ strncpy(tmp->name, name, len);
|
||||
+ interface_snorf(tmp, (INTERFACE_REQUESTED | flags));
|
||||
+ interface_dereference(&tmp, MDL);
|
||||
+}
|
||||
+
|
||||
#define MAX_PORT_CONFIG_LINE_LEN 1024
|
||||
|
||||
// Allocates and loads global map g_interface_name_alias_map
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,28 @@
|
||||
From ab779f1d59f27f66e6e6bea89287c810e0a10a0f Mon Sep 17 00:00:00 2001
|
||||
From: Joe LeVeque <jolevequ@microsoft.com>
|
||||
Date: Wed, 15 May 2019 23:48:08 +0000
|
||||
Subject: [PATCH 1/3] Add --enable-use-sockets to configure flags in
|
||||
debian/rules
|
||||
|
||||
This defines USE_SOCKETS at compile time which forces dhcrelay
|
||||
to create and bind separate sockets to each interface
|
||||
---
|
||||
debian/rules | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/debian/rules b/debian/rules
|
||||
index 4184716..46d6527 100755
|
||||
--- a/debian/rules
|
||||
+++ b/debian/rules
|
||||
@@ -23,7 +23,7 @@ CFLAGS+=-D_PATH_DHCLIENT_CONF='\"/etc/dhcp/dhclient.conf\"'
|
||||
CFLAGS+=-D_PATH_DHCLIENT_DB='\"$(LEASE_PATH)/dhclient.leases\"'
|
||||
CFLAGS+=-D_PATH_DHCLIENT6_DB='\"$(LEASE_PATH)/dhclient6.leases\"'
|
||||
|
||||
-CONFFLAGS=--prefix=/usr --enable-log-pid --enable-paranoia
|
||||
+CONFFLAGS=--prefix=/usr --enable-log-pid --enable-paranoia --enable-use-sockets
|
||||
|
||||
# cross-architecture building
|
||||
ifneq ($(DEB_HOST_GNU_TYPE),$(DEB_BUILD_GNU_TYPE))
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,122 @@
|
||||
From c26520f36ebcd1f143312fc61440ed3d546c7504 Mon Sep 17 00:00:00 2001
|
||||
From: Joe LeVeque <jolevequ@microsoft.com>
|
||||
Date: Wed, 8 May 2019 18:08:13 +0000
|
||||
Subject: [PATCH 2/3] Bugfix: Ensure HAVE_SO_BINDTODEVICE has a chance to be
|
||||
defined before it is referenced
|
||||
|
||||
---
|
||||
includes/osdep.h | 93 ++++++++++++++++++++++++------------------------
|
||||
1 file changed, 47 insertions(+), 46 deletions(-)
|
||||
|
||||
diff --git a/includes/osdep.h b/includes/osdep.h
|
||||
index 5ae0c35..670b356 100644
|
||||
--- a/includes/osdep.h
|
||||
+++ b/includes/osdep.h
|
||||
@@ -139,52 +139,6 @@
|
||||
# define USE_UPF_RECEIVE
|
||||
#endif
|
||||
|
||||
-/* Porting::
|
||||
-
|
||||
- If you add support for sending packets directly out an interface,
|
||||
- and your support does not do ARP or routing, you must use a fallback
|
||||
- mechanism to deal with packets that need to be sent to routers.
|
||||
- Currently, all low-level packet interfaces use BSD sockets as a
|
||||
- fallback. */
|
||||
-
|
||||
-#if defined (USE_BPF_SEND) || defined (USE_NIT_SEND) || \
|
||||
- defined (USE_DLPI_SEND) || defined (USE_UPF_SEND) || \
|
||||
- defined (USE_LPF_SEND) || \
|
||||
- (defined (USE_SOCKET_SEND) && defined (HAVE_SO_BINDTODEVICE))
|
||||
-# define USE_SOCKET_FALLBACK
|
||||
-# define USE_FALLBACK
|
||||
-#endif
|
||||
-
|
||||
-/* Porting::
|
||||
-
|
||||
- If you add support for sending packets directly out an interface
|
||||
- and need to be able to assemble packets, add the USE_XXX_SEND
|
||||
- definition for your interface to the list tested below. */
|
||||
-
|
||||
-#if defined (USE_RAW_SEND) || defined (USE_BPF_SEND) || \
|
||||
- defined (USE_NIT_SEND) || defined (USE_UPF_SEND) || \
|
||||
- defined (USE_DLPI_SEND) || defined (USE_LPF_SEND)
|
||||
-# define PACKET_ASSEMBLY
|
||||
-#endif
|
||||
-
|
||||
-/* Porting::
|
||||
-
|
||||
- If you add support for receiving packets directly from an interface
|
||||
- and need to be able to decode raw packets, add the USE_XXX_RECEIVE
|
||||
- definition for your interface to the list tested below. */
|
||||
-
|
||||
-#if defined (USE_RAW_RECEIVE) || defined (USE_BPF_SEND) || \
|
||||
- defined (USE_NIT_RECEIVE) || defined (USE_UPF_RECEIVE) || \
|
||||
- defined (USE_DLPI_RECEIVE) || defined (USE_LPF_RECEIVE)
|
||||
-# define PACKET_DECODING
|
||||
-#endif
|
||||
-
|
||||
-/* If we don't have a DLPI packet filter, we have to filter in userland.
|
||||
- Probably not worth doing, actually. */
|
||||
-#if defined (USE_DLPI_RECEIVE) && !defined (USE_DLPI_PFMOD)
|
||||
-# define USERLAND_FILTER
|
||||
-#endif
|
||||
-
|
||||
/* jmp_buf is assumed to be a struct unless otherwise defined in the
|
||||
system header. */
|
||||
#ifndef jbp_decl
|
||||
@@ -288,4 +242,51 @@
|
||||
# define STDERR_FILENO 2
|
||||
#endif
|
||||
|
||||
+/* Porting::
|
||||
+
|
||||
+ If you add support for sending packets directly out an interface,
|
||||
+ and your support does not do ARP or routing, you must use a fallback
|
||||
+ mechanism to deal with packets that need to be sent to routers.
|
||||
+ Currently, all low-level packet interfaces use BSD sockets as a
|
||||
+ fallback. */
|
||||
+
|
||||
+#if defined (USE_BPF_SEND) || defined (USE_NIT_SEND) || \
|
||||
+ defined (USE_DLPI_SEND) || defined (USE_UPF_SEND) || \
|
||||
+ defined (USE_LPF_SEND) || \
|
||||
+ (defined (USE_SOCKET_SEND) && defined (HAVE_SO_BINDTODEVICE))
|
||||
+# define USE_SOCKET_FALLBACK
|
||||
+# define USE_FALLBACK
|
||||
+#endif
|
||||
+
|
||||
+/* Porting::
|
||||
+
|
||||
+ If you add support for sending packets directly out an interface
|
||||
+ and need to be able to assemble packets, add the USE_XXX_SEND
|
||||
+ definition for your interface to the list tested below. */
|
||||
+
|
||||
+#if defined (USE_RAW_SEND) || defined (USE_BPF_SEND) || \
|
||||
+ defined (USE_NIT_SEND) || defined (USE_UPF_SEND) || \
|
||||
+ defined (USE_DLPI_SEND) || defined (USE_LPF_SEND)
|
||||
+# define PACKET_ASSEMBLY
|
||||
+#endif
|
||||
+
|
||||
+/* Porting::
|
||||
+
|
||||
+ If you add support for receiving packets directly from an interface
|
||||
+ and need to be able to decode raw packets, add the USE_XXX_RECEIVE
|
||||
+ definition for your interface to the list tested below. */
|
||||
+
|
||||
+#if defined (USE_RAW_RECEIVE) || defined (USE_BPF_SEND) || \
|
||||
+ defined (USE_NIT_RECEIVE) || defined (USE_UPF_RECEIVE) || \
|
||||
+ defined (USE_DLPI_RECEIVE) || defined (USE_LPF_RECEIVE)
|
||||
+# define PACKET_DECODING
|
||||
+#endif
|
||||
+
|
||||
+/* If we don't have a DLPI packet filter, we have to filter in userland.
|
||||
+ Probably not worth doing, actually. */
|
||||
+#if defined (USE_DLPI_RECEIVE) && !defined (USE_DLPI_PFMOD)
|
||||
+# define USERLAND_FILTER
|
||||
+#endif
|
||||
+
|
||||
+
|
||||
#endif /* __ISC_DHCP_OSDEP_H__ */
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,264 @@
|
||||
From d8ed5f313d06829290e49d4d4b5413700affcf26 Mon Sep 17 00:00:00 2001
|
||||
From: Joe LeVeque <jolevequ@microsoft.com>
|
||||
Date: Sun, 5 May 2019 22:52:49 +0000
|
||||
Subject: [PATCH 3/3] If destination of BOOTREQUEST is directed broadcast,
|
||||
forward on that interface. Otherwise forward on fallback or all upstream
|
||||
interfaces
|
||||
|
||||
---
|
||||
common/discover.c | 46 ++++++++++++++++++++---
|
||||
includes/dhcpd.h | 3 ++
|
||||
relay/dhcrelay.c | 96 ++++++++++++++++++++++++++++++++++++++++++-----
|
||||
3 files changed, 130 insertions(+), 15 deletions(-)
|
||||
|
||||
diff --git a/common/discover.c b/common/discover.c
|
||||
index e20d9d5..bf82735 100644
|
||||
--- a/common/discover.c
|
||||
+++ b/common/discover.c
|
||||
@@ -227,6 +227,7 @@ struct iface_conf_list {
|
||||
struct iface_info {
|
||||
char name[IF_NAMESIZE+1]; /* name of the interface, e.g. "bge0" */
|
||||
struct sockaddr_storage addr; /* address information */
|
||||
+ struct sockaddr_storage netmask; /* netmask information */
|
||||
isc_uint64_t flags; /* interface flags, e.g. IFF_LOOPBACK */
|
||||
};
|
||||
|
||||
@@ -401,6 +402,7 @@ struct iface_conf_list {
|
||||
struct iface_info {
|
||||
char name[IFNAMSIZ]; /* name of the interface, e.g. "eth0" */
|
||||
struct sockaddr_storage addr; /* address information */
|
||||
+ struct sockaddr_storage netmask; /* netmask information */
|
||||
isc_uint64_t flags; /* interface flags, e.g. IFF_LOOPBACK */
|
||||
};
|
||||
|
||||
@@ -576,6 +578,17 @@ next_iface4(struct iface_info *info, int *err, struct iface_conf_list *ifaces) {
|
||||
}
|
||||
memcpy(&info->addr, &tmp.ifr_addr, sizeof(tmp.ifr_addr));
|
||||
|
||||
+ if (ioctl(ifaces->sock, SIOCGIFNETMASK, &tmp) < 0) {
|
||||
+ if (errno == EADDRNOTAVAIL) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ log_error("Error getting netmask "
|
||||
+ "for '%s'; %m", name);
|
||||
+ *err = 1;
|
||||
+ return 0;
|
||||
+ }
|
||||
+ memcpy(&info->netmask, &tmp.ifr_netmask, sizeof(tmp.ifr_netmask));
|
||||
+
|
||||
memset(&tmp, 0, sizeof(tmp));
|
||||
strncpy(tmp.ifr_name, name, sizeof(tmp.ifr_name) - 1);
|
||||
if (ioctl(ifaces->sock, SIOCGIFFLAGS, &tmp) < 0) {
|
||||
@@ -779,6 +792,7 @@ struct iface_conf_list {
|
||||
struct iface_info {
|
||||
char name[IFNAMSIZ]; /* name of the interface, e.g. "bge0" */
|
||||
struct sockaddr_storage addr; /* address information */
|
||||
+ struct sockaddr_storage netmask; /* netmask information */
|
||||
isc_uint64_t flags; /* interface flags, e.g. IFF_LOOPBACK */
|
||||
};
|
||||
|
||||
@@ -838,7 +852,8 @@ end_iface_scan(struct iface_conf_list *ifaces) {
|
||||
/* XXX: perhaps create drealloc() rather than do it manually */
|
||||
void
|
||||
add_ipv4_addr_to_interface(struct interface_info *iface,
|
||||
- const struct in_addr *addr) {
|
||||
+ const struct in_addr *addr,
|
||||
+ const struct in_addr *netmask) {
|
||||
/*
|
||||
* We don't expect a lot of addresses per IPv4 interface, so
|
||||
* we use 4, as our "chunk size" for collecting addresses.
|
||||
@@ -849,6 +864,12 @@ add_ipv4_addr_to_interface(struct interface_info *iface,
|
||||
log_fatal("Out of memory saving IPv4 address "
|
||||
"on interface.");
|
||||
}
|
||||
+
|
||||
+ iface->netmasks = dmalloc(4 * sizeof(struct in_addr), MDL);
|
||||
+ if (iface->netmasks == NULL) {
|
||||
+ log_fatal("Out of memory saving IPv4 netmask "
|
||||
+ "on interface.");
|
||||
+ }
|
||||
iface->address_count = 0;
|
||||
iface->address_max = 4;
|
||||
} else if (iface->address_count >= iface->address_max) {
|
||||
@@ -861,14 +882,28 @@ add_ipv4_addr_to_interface(struct interface_info *iface,
|
||||
log_fatal("Out of memory saving IPv4 address "
|
||||
"on interface.");
|
||||
}
|
||||
- memcpy(tmp,
|
||||
- iface->addresses,
|
||||
+ memcpy(tmp,
|
||||
+ iface->addresses,
|
||||
iface->address_max * sizeof(struct in_addr));
|
||||
dfree(iface->addresses, MDL);
|
||||
iface->addresses = tmp;
|
||||
+
|
||||
+ tmp = dmalloc(new_max * sizeof(struct in_addr), MDL);
|
||||
+ if (tmp == NULL) {
|
||||
+ log_fatal("Out of memory saving IPv4 netmask "
|
||||
+ "on interface.");
|
||||
+ }
|
||||
+ memcpy(tmp,
|
||||
+ iface->netmasks,
|
||||
+ iface->address_max * sizeof(struct in_addr));
|
||||
+ dfree(iface->netmasks, MDL);
|
||||
+ iface->netmasks = tmp;
|
||||
+
|
||||
iface->address_max = new_max;
|
||||
}
|
||||
- iface->addresses[iface->address_count++] = *addr;
|
||||
+ iface->addresses[iface->address_count] = *addr;
|
||||
+ iface->netmasks[iface->address_count] = *netmask;
|
||||
+ iface->address_count++;
|
||||
}
|
||||
|
||||
#ifdef DHCPv6
|
||||
@@ -1003,6 +1038,7 @@ discover_interfaces(int state) {
|
||||
if ((info.addr.ss_family == AF_INET) &&
|
||||
(local_family == AF_INET)) {
|
||||
struct sockaddr_in *a = (struct sockaddr_in*)&info.addr;
|
||||
+ struct sockaddr_in *n = (struct sockaddr_in*)&info.netmask;
|
||||
struct iaddr addr;
|
||||
|
||||
/* We don't want the loopback interface. */
|
||||
@@ -1016,7 +1052,7 @@ discover_interfaces(int state) {
|
||||
if (a->sin_addr.s_addr != htonl(INADDR_ANY))
|
||||
tmp->configured = 1;
|
||||
|
||||
- add_ipv4_addr_to_interface(tmp, &a->sin_addr);
|
||||
+ add_ipv4_addr_to_interface(tmp, &a->sin_addr, &n->sin_addr);
|
||||
|
||||
/* invoke the setup hook */
|
||||
addr.len = 4;
|
||||
diff --git a/includes/dhcpd.h b/includes/dhcpd.h
|
||||
index 1fd12db..8b509f1 100644
|
||||
--- a/includes/dhcpd.h
|
||||
+++ b/includes/dhcpd.h
|
||||
@@ -1323,6 +1323,9 @@ struct interface_info {
|
||||
struct in_addr *addresses; /* Addresses associated with this
|
||||
* interface.
|
||||
*/
|
||||
+ struct in_addr *netmasks; /* Netmask associated with this
|
||||
+ * interface.
|
||||
+ */
|
||||
int address_count; /* Number of addresses stored. */
|
||||
int address_max; /* Size of addresses buffer. */
|
||||
struct in6_addr *v6addresses; /* IPv6 addresses associated with
|
||||
diff --git a/relay/dhcrelay.c b/relay/dhcrelay.c
|
||||
index 292ba4f..339be87 100644
|
||||
--- a/relay/dhcrelay.c
|
||||
+++ b/relay/dhcrelay.c
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <syslog.h>
|
||||
#include <signal.h>
|
||||
#include <sys/time.h>
|
||||
+#include <sys/ioctl.h>
|
||||
|
||||
TIME default_lease_time = 43200; /* 12 hours... */
|
||||
TIME max_lease_time = 86400; /* 24 hours... */
|
||||
@@ -799,18 +800,93 @@ do_relay4(struct interface_info *ip, struct dhcp_packet *packet,
|
||||
/* Otherwise, it's a BOOTREQUEST, so forward it to all the
|
||||
servers. */
|
||||
for (sp = servers; sp; sp = sp->next) {
|
||||
- if (send_packet((fallback_interface
|
||||
- ? fallback_interface : interfaces),
|
||||
- NULL, packet, length, ip->addresses[0],
|
||||
- &sp->to, NULL) < 0) {
|
||||
- ++client_packet_errors;
|
||||
+ int packet_relay_attempted = 0;
|
||||
+
|
||||
+ log_debug("Server IP: %s", inet_ntoa(sp->to.sin_addr));
|
||||
+
|
||||
+ /* If the server's IP address is the broadcast IP of one
|
||||
+ of our interfaces, we send it directly on that interface's
|
||||
+ socket, because the kernel will drop directed broadcast
|
||||
+ packets if we send on the fallback. */
|
||||
+ for (out = interfaces; out; out = out->next) {
|
||||
+ int i = 0;
|
||||
+
|
||||
+ // Only relay BOOTREQUEST on upstream interfaces
|
||||
+ if (!(out->flags & INTERFACE_UPSTREAM))
|
||||
+ continue;
|
||||
+
|
||||
+ if (!out->addresses || !out->netmasks)
|
||||
+ continue;
|
||||
+
|
||||
+ for (i = 0; i < out->address_count; i++) {
|
||||
+ struct in_addr bcast_addr;
|
||||
+
|
||||
+ log_debug("Iface %s addr: %s", out->name, inet_ntoa(out->addresses[i]));
|
||||
+ log_debug("Iface %s netmask: %s", out->name, inet_ntoa(out->netmasks[i]));
|
||||
+
|
||||
+ // Broadcast = ip_addr | ~netmask
|
||||
+ bcast_addr.s_addr = out->addresses[i].s_addr | ~out->netmasks[i].s_addr;
|
||||
+ log_debug("Iface %s broadcast: %s", out->name, inet_ntoa(bcast_addr));
|
||||
+
|
||||
+ if (sp->to.sin_addr.s_addr == bcast_addr.s_addr) {
|
||||
+ log_debug("Packet destined for broadcast IP of %s", out->name);
|
||||
+ if (send_packet(out, NULL, packet,
|
||||
+ length, ip->addresses[0],&sp->to, NULL) < 0) {
|
||||
+ ++client_packet_errors;
|
||||
+ } else {
|
||||
+ log_debug("Forwarded BOOTREQUEST for %s to %s on interface %s",
|
||||
+ print_hw_addr(packet->htype, packet->hlen,
|
||||
+ packet->chaddr),
|
||||
+ inet_ntoa(sp->to.sin_addr), out->name);
|
||||
+
|
||||
+ ++client_packets_relayed;
|
||||
+ }
|
||||
+
|
||||
+ packet_relay_attempted = 1;
|
||||
+
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (packet_relay_attempted)
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ if (packet_relay_attempted)
|
||||
+ continue;
|
||||
+
|
||||
+ /* Otherwise, if we have a fallback interface, we send the packet
|
||||
+ on it. If not, we send the packet out all interfaces.*/
|
||||
+ if (fallback_interface) {
|
||||
+ if (send_packet(fallback_interface, NULL, packet,
|
||||
+ length, ip->addresses[0],&sp->to, NULL) < 0) {
|
||||
+ ++client_packet_errors;
|
||||
+ } else {
|
||||
+ log_debug("Forwarded BOOTREQUEST for %s to %s on fallback interface",
|
||||
+ print_hw_addr(packet->htype, packet->hlen,
|
||||
+ packet->chaddr),
|
||||
+ inet_ntoa(sp->to.sin_addr));
|
||||
+
|
||||
+ ++client_packets_relayed;
|
||||
+ }
|
||||
} else {
|
||||
- log_debug("Forwarded BOOTREQUEST for %s to %s",
|
||||
- print_hw_addr(packet->htype, packet->hlen,
|
||||
- packet->chaddr),
|
||||
- inet_ntoa(sp->to.sin_addr));
|
||||
+ for (out = interfaces; out; out = out->next) {
|
||||
+ // Only relay BOOTREQUEST on upstream interfaces
|
||||
+ if (!(out->flags & INTERFACE_UPSTREAM))
|
||||
+ continue;
|
||||
+
|
||||
+ if (send_packet(out, NULL, packet,
|
||||
+ length, ip->addresses[0],&sp->to, NULL) < 0) {
|
||||
+ ++client_packet_errors;
|
||||
+ } else {
|
||||
+ log_debug("Forwarded BOOTREQUEST for %s to %s on interface %s",
|
||||
+ print_hw_addr(packet->htype, packet->hlen,
|
||||
+ packet->chaddr),
|
||||
+ inet_ntoa(sp->to.sin_addr), out->name);
|
||||
|
||||
- ++client_packets_relayed;
|
||||
+ ++client_packets_relayed;
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
--
|
||||
2.17.1
|
||||
|
@ -3,3 +3,8 @@
|
||||
0002-Support-for-obtaining-name-of-physical-interface-tha.patch
|
||||
0003-Support-for-loading-port-alias-map-file-to-replace-p.patch
|
||||
0004-Bugfix-Don-t-print-log-messages-to-stderr-in-release.patch
|
||||
0005-Port-upstream-changes-from-commit-f2e70402f0f2955f39.patch
|
||||
0006-Port-upstream-changes-from-commit-edd6d8881bc4d8ec4b.patch
|
||||
0007-Add-enable-use-sockets-to-configure-flags-in-debian-.patch
|
||||
0008-Bugfix-Ensure-HAVE_SO_BINDTODEVICE-has-a-chance-to-b.patch
|
||||
0009-If-destination-of-BOOTREQUEST-is-directed-broadcast-.patch
|
||||
|
@ -23,7 +23,7 @@ stderr_logfile=syslog
|
||||
programs=isc-dhcp-relay-Vlan1000
|
||||
|
||||
[program:isc-dhcp-relay-Vlan1000]
|
||||
command=/usr/sbin/dhcrelay -d -m discard -a %%h:%%p %%P --name-alias-map-file /tmp/port-name-alias-map.txt -i Vlan1000 -i PortChannel02 -i PortChannel03 -i PortChannel04 -i PortChannel01 192.0.0.1 192.0.0.2
|
||||
command=/usr/sbin/dhcrelay -d -m discard -a %%h:%%p %%P --name-alias-map-file /tmp/port-name-alias-map.txt -id Vlan1000 -iu PortChannel02 -iu PortChannel03 -iu PortChannel04 -iu PortChannel01 192.0.0.1 192.0.0.2
|
||||
priority=3
|
||||
autostart=false
|
||||
autorestart=false
|
||||
|
Reference in New Issue
Block a user