DHCP Relay: add option -si to support using src intf ip in relay (#7052)
* add option si to support using src intf ip in relay
This commit is contained in:
parent
aee4892ca4
commit
a6dc65421a
@ -0,0 +1,192 @@
|
|||||||
|
From 16163f0693e30588216f0f280d5eba8bb53f7001 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Tianrong Zhang <trzhang@microsoft.com>
|
||||||
|
Date: Fri, 12 Mar 2021 23:30:56 -0800
|
||||||
|
Subject: [PATCH] add option -si to support using src intf ip in relay
|
||||||
|
|
||||||
|
---
|
||||||
|
common/socket.c | 119 ++++++++++++++++++++++++++++++++++++-----------
|
||||||
|
includes/dhcpd.h | 1 +
|
||||||
|
relay/dhcrelay.c | 8 ++++
|
||||||
|
3 files changed, 100 insertions(+), 28 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/common/socket.c b/common/socket.c
|
||||||
|
index 483eb9c..da9f501 100644
|
||||||
|
--- a/common/socket.c
|
||||||
|
+++ b/common/socket.c
|
||||||
|
@@ -83,6 +83,29 @@ static unsigned int global_v4_socket_references = 0;
|
||||||
|
static int global_v4_socket = -1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
+/*
|
||||||
|
+ * If set, uses "from" interface IP for packet Tx.
|
||||||
|
+ * If not set, kernel chooses appropriate src ip for tx pkts
|
||||||
|
+ */
|
||||||
|
+int use_src_intf_ip_for_tx;
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * For both send_packet6() and receive_packet6() we need to allocate
|
||||||
|
+ * space for the cmsg header information. We do this once and reuse
|
||||||
|
+ * the buffer. We also need the control buf for send_packet() and
|
||||||
|
+ * receive_packet() when we use a single socket and IP_PKTINFO to
|
||||||
|
+ * send the packet out the correct interface.
|
||||||
|
+ */
|
||||||
|
+static void *v4_control_buf = NULL;
|
||||||
|
+static size_t v4_control_buf_len = 0;
|
||||||
|
+
|
||||||
|
+static void
|
||||||
|
+v4_allocate_cmsg_cbuf(void) {
|
||||||
|
+ v4_control_buf_len = CMSG_SPACE(sizeof(struct in_pktinfo));
|
||||||
|
+ v4_control_buf = dmalloc(v4_control_buf_len, MDL);
|
||||||
|
+ return;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* If we can't bind() to a specific interface, then we can only have
|
||||||
|
* a single socket. This variable insures that we don't try to listen
|
||||||
|
@@ -712,37 +735,77 @@ ssize_t send_packet (interface, packet, raw, len, from, to, hto)
|
||||||
|
struct hardware *hto;
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
-#ifdef IGNORE_HOSTUNREACH
|
||||||
|
- int retry = 0;
|
||||||
|
- do {
|
||||||
|
-#endif
|
||||||
|
-#if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && defined(USE_V4_PKTINFO)
|
||||||
|
- struct in_pktinfo pktinfo;
|
||||||
|
-
|
||||||
|
- if (interface->ifp != NULL) {
|
||||||
|
- memset(&pktinfo, 0, sizeof (pktinfo));
|
||||||
|
- pktinfo.ipi_ifindex = interface->ifp->ifr_index;
|
||||||
|
- if (setsockopt(interface->wfdesc, IPPROTO_IP,
|
||||||
|
- IP_PKTINFO, (char *)&pktinfo,
|
||||||
|
- sizeof(pktinfo)) < 0)
|
||||||
|
- log_fatal("setsockopt: IP_PKTINFO: %m");
|
||||||
|
+ struct msghdr m;
|
||||||
|
+ struct iovec v;
|
||||||
|
+ struct sockaddr_in dst;
|
||||||
|
+ struct in_pktinfo *pktinfo;
|
||||||
|
+ struct cmsghdr *cmsg;
|
||||||
|
+ unsigned int ifindex;
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * If necessary allocate space for the control message header.
|
||||||
|
+ * The space is common between send and receive.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+ if (v4_control_buf == NULL) {
|
||||||
|
+ v4_allocate_cmsg_cbuf();
|
||||||
|
+ if (v4_control_buf == NULL) {
|
||||||
|
+ log_error("send_packet: unable to allocate cmsg header");
|
||||||
|
+ return(ENOMEM);
|
||||||
|
}
|
||||||
|
-#endif
|
||||||
|
- result = sendto (interface -> wfdesc, (char *)raw, len, 0,
|
||||||
|
- (struct sockaddr *)to, sizeof *to);
|
||||||
|
-#ifdef IGNORE_HOSTUNREACH
|
||||||
|
- } while (to -> sin_addr.s_addr == htonl (INADDR_BROADCAST) &&
|
||||||
|
- result < 0 &&
|
||||||
|
- (errno == EHOSTUNREACH ||
|
||||||
|
- errno == ECONNREFUSED) &&
|
||||||
|
- retry++ < 10);
|
||||||
|
-#endif
|
||||||
|
+ }
|
||||||
|
+ memset(v4_control_buf, 0, v4_control_buf_len);
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * Initialize our message header structure.
|
||||||
|
+ */
|
||||||
|
+ memset(&m, 0, sizeof(m));
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * Set the target address we're sending to.
|
||||||
|
+ */
|
||||||
|
+ memcpy(&dst, to, sizeof(dst));
|
||||||
|
+ m.msg_name = &dst;
|
||||||
|
+ m.msg_namelen = sizeof(dst);
|
||||||
|
+ ifindex = if_nametoindex(interface->name);
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * Set the data buffer we're sending. (Using this wacky
|
||||||
|
+ * "scatter-gather" stuff... we only have a single chunk
|
||||||
|
+ * of data to send, so we declare a single vector entry.)
|
||||||
|
+ */
|
||||||
|
+ v.iov_base = (char *)raw;
|
||||||
|
+ v.iov_len = len;
|
||||||
|
+ m.msg_iov = &v;
|
||||||
|
+ m.msg_iovlen = 1;
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * Setting the interface is a bit more involved.
|
||||||
|
+ *
|
||||||
|
+ * We have to create a "control message", and set that to
|
||||||
|
+ * define the IP packet information. We let he kernel decide
|
||||||
|
+ * the source IP address unless 'use_src_intf_ip_for_tx' is
|
||||||
|
+ * set, in which case we use the IP address of the ingress
|
||||||
|
+ * interface we received the request on as the source IP.
|
||||||
|
+ */
|
||||||
|
+ m.msg_control = v4_control_buf;
|
||||||
|
+ m.msg_controllen = v4_control_buf_len;
|
||||||
|
+ cmsg = CMSG_FIRSTHDR(&m);
|
||||||
|
+ INSIST(cmsg != NULL);
|
||||||
|
+ cmsg->cmsg_level = IPPROTO_IP;
|
||||||
|
+ cmsg->cmsg_type = IP_PKTINFO;
|
||||||
|
+ cmsg->cmsg_len = CMSG_LEN(sizeof(*pktinfo));
|
||||||
|
+ pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
|
||||||
|
+ memset(pktinfo, 0, sizeof(*pktinfo));
|
||||||
|
+ pktinfo->ipi_ifindex = ifindex;
|
||||||
|
+ if (use_src_intf_ip_for_tx)
|
||||||
|
+ pktinfo->ipi_spec_dst = from;
|
||||||
|
+
|
||||||
|
+ result = sendmsg(interface->wfdesc, &m, 0);
|
||||||
|
if (result < 0) {
|
||||||
|
- log_error ("send_packet: %m");
|
||||||
|
- if (errno == ENETUNREACH)
|
||||||
|
- log_error ("send_packet: please consult README file%s",
|
||||||
|
- " regarding broadcast address.");
|
||||||
|
+ log_error("send_packet: %m");
|
||||||
|
}
|
||||||
|
+
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/includes/dhcpd.h b/includes/dhcpd.h
|
||||||
|
index 36cd518..0c25582 100644
|
||||||
|
--- a/includes/dhcpd.h
|
||||||
|
+++ b/includes/dhcpd.h
|
||||||
|
@@ -2660,6 +2660,7 @@ ssize_t send_fallback6(struct interface_info *, struct packet *,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_SOCKET_SEND
|
||||||
|
+extern int use_src_intf_ip_for_tx;
|
||||||
|
void if_reinitialize_send (struct interface_info *);
|
||||||
|
void if_register_send (struct interface_info *);
|
||||||
|
void if_deregister_send (struct interface_info *);
|
||||||
|
diff --git a/relay/dhcrelay.c b/relay/dhcrelay.c
|
||||||
|
index 221106a..c44a79d 100644
|
||||||
|
--- a/relay/dhcrelay.c
|
||||||
|
+++ b/relay/dhcrelay.c
|
||||||
|
@@ -97,6 +97,12 @@ struct downstream_intf_list {
|
||||||
|
isc_boolean_t use_if_id = ISC_FALSE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
+/*
|
||||||
|
+ * If not set, kernel chooses what the src ip is.
|
||||||
|
+ * If set, uses "from" interface IP for packet Tx.
|
||||||
|
+ */
|
||||||
|
+extern int use_src_intf_ip_for_tx = 0;
|
||||||
|
+
|
||||||
|
/* Maximum size of a packet with agent options added. */
|
||||||
|
int dhcp_max_agent_option_packet_length = DHCP_MTU_MIN;
|
||||||
|
|
||||||
|
@@ -431,6 +437,8 @@ main(int argc, char **argv) {
|
||||||
|
#endif
|
||||||
|
} else if (!strcmp(argv[i], "-d")) {
|
||||||
|
/* no_daemon = 1; */
|
||||||
|
+ } else if (!strcmp(argv[i], "-si")) {
|
||||||
|
+ use_src_intf_ip_for_tx = 1;
|
||||||
|
} else if (!strcmp(argv[i], "-q")) {
|
||||||
|
quiet = 1;
|
||||||
|
quiet_interface_discovery = 1;
|
||||||
|
--
|
||||||
|
2.17.1
|
||||||
|
|
@ -10,3 +10,4 @@
|
|||||||
0009-Support-for-dual-tor-scenario.patch
|
0009-Support-for-dual-tor-scenario.patch
|
||||||
0010-Bugfix-correctly-set-interface-netmask.patch
|
0010-Bugfix-correctly-set-interface-netmask.patch
|
||||||
0011-dhcp-relay-Prevent-Buffer-Overrun.patch
|
0011-dhcp-relay-Prevent-Buffer-Overrun.patch
|
||||||
|
0012-add-option-si-to-support-using-src-intf-ip-in-relay.patch
|
||||||
|
Reference in New Issue
Block a user