-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[dhcp-relay]: add option -si to support using src intf ip in relay (#…
- Loading branch information
trzhang-msft
authored
Mar 15, 2021
1 parent
a0b824f
commit 139fcf5
Showing
3 changed files
with
194 additions
and
1 deletion.
There are no files selected for viewing
File renamed without changes.
192 changes: 192 additions & 0 deletions
192
src/isc-dhcp/patch/0013-add-option-si-to-support-using-src-intf-ip-in-relay.patch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,192 @@ | ||
From a89c0ef099852163aaee7c0704c814293063d6f3 Mon Sep 17 00:00:00 2001 | ||
From: Tianrong Zhang <trzhang@microsoft.com> | ||
Date: Sun, 14 Mar 2021 17:47:07 -0700 | ||
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 e8851b4..ddd1f2e 100644 | ||
--- a/common/socket.c | ||
+++ b/common/socket.c | ||
@@ -78,6 +78,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 | ||
@@ -629,37 +652,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 89bfe82..4f7a71d 100644 | ||
--- a/includes/dhcpd.h | ||
+++ b/includes/dhcpd.h | ||
@@ -2611,6 +2611,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 8aac4b3..1316591 100644 | ||
--- a/relay/dhcrelay.c | ||
+++ b/relay/dhcrelay.c | ||
@@ -85,6 +85,12 @@ int max_hop_count = 10; /* Maximum hop count */ | ||
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; | ||
|
||
@@ -317,6 +323,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 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters