Skip to content

Commit a6dc654

Browse files
trzhang-msftyxieca
trzhang-msft
authored andcommitted
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
1 parent aee4892 commit a6dc654

File tree

2 files changed

+193
-0
lines changed

2 files changed

+193
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
From 16163f0693e30588216f0f280d5eba8bb53f7001 Mon Sep 17 00:00:00 2001
2+
From: Tianrong Zhang <[email protected]>
3+
Date: Fri, 12 Mar 2021 23:30:56 -0800
4+
Subject: [PATCH] add option -si to support using src intf ip in relay
5+
6+
---
7+
common/socket.c | 119 ++++++++++++++++++++++++++++++++++++-----------
8+
includes/dhcpd.h | 1 +
9+
relay/dhcrelay.c | 8 ++++
10+
3 files changed, 100 insertions(+), 28 deletions(-)
11+
12+
diff --git a/common/socket.c b/common/socket.c
13+
index 483eb9c..da9f501 100644
14+
--- a/common/socket.c
15+
+++ b/common/socket.c
16+
@@ -83,6 +83,29 @@ static unsigned int global_v4_socket_references = 0;
17+
static int global_v4_socket = -1;
18+
#endif
19+
20+
+/*
21+
+ * If set, uses "from" interface IP for packet Tx.
22+
+ * If not set, kernel chooses appropriate src ip for tx pkts
23+
+ */
24+
+int use_src_intf_ip_for_tx;
25+
+
26+
+/*
27+
+ * For both send_packet6() and receive_packet6() we need to allocate
28+
+ * space for the cmsg header information. We do this once and reuse
29+
+ * the buffer. We also need the control buf for send_packet() and
30+
+ * receive_packet() when we use a single socket and IP_PKTINFO to
31+
+ * send the packet out the correct interface.
32+
+ */
33+
+static void *v4_control_buf = NULL;
34+
+static size_t v4_control_buf_len = 0;
35+
+
36+
+static void
37+
+v4_allocate_cmsg_cbuf(void) {
38+
+ v4_control_buf_len = CMSG_SPACE(sizeof(struct in_pktinfo));
39+
+ v4_control_buf = dmalloc(v4_control_buf_len, MDL);
40+
+ return;
41+
+}
42+
+
43+
/*
44+
* If we can't bind() to a specific interface, then we can only have
45+
* a single socket. This variable insures that we don't try to listen
46+
@@ -712,37 +735,77 @@ ssize_t send_packet (interface, packet, raw, len, from, to, hto)
47+
struct hardware *hto;
48+
{
49+
int result;
50+
-#ifdef IGNORE_HOSTUNREACH
51+
- int retry = 0;
52+
- do {
53+
-#endif
54+
-#if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && defined(USE_V4_PKTINFO)
55+
- struct in_pktinfo pktinfo;
56+
-
57+
- if (interface->ifp != NULL) {
58+
- memset(&pktinfo, 0, sizeof (pktinfo));
59+
- pktinfo.ipi_ifindex = interface->ifp->ifr_index;
60+
- if (setsockopt(interface->wfdesc, IPPROTO_IP,
61+
- IP_PKTINFO, (char *)&pktinfo,
62+
- sizeof(pktinfo)) < 0)
63+
- log_fatal("setsockopt: IP_PKTINFO: %m");
64+
+ struct msghdr m;
65+
+ struct iovec v;
66+
+ struct sockaddr_in dst;
67+
+ struct in_pktinfo *pktinfo;
68+
+ struct cmsghdr *cmsg;
69+
+ unsigned int ifindex;
70+
+
71+
+ /*
72+
+ * If necessary allocate space for the control message header.
73+
+ * The space is common between send and receive.
74+
+ */
75+
+
76+
+ if (v4_control_buf == NULL) {
77+
+ v4_allocate_cmsg_cbuf();
78+
+ if (v4_control_buf == NULL) {
79+
+ log_error("send_packet: unable to allocate cmsg header");
80+
+ return(ENOMEM);
81+
}
82+
-#endif
83+
- result = sendto (interface -> wfdesc, (char *)raw, len, 0,
84+
- (struct sockaddr *)to, sizeof *to);
85+
-#ifdef IGNORE_HOSTUNREACH
86+
- } while (to -> sin_addr.s_addr == htonl (INADDR_BROADCAST) &&
87+
- result < 0 &&
88+
- (errno == EHOSTUNREACH ||
89+
- errno == ECONNREFUSED) &&
90+
- retry++ < 10);
91+
-#endif
92+
+ }
93+
+ memset(v4_control_buf, 0, v4_control_buf_len);
94+
+
95+
+ /*
96+
+ * Initialize our message header structure.
97+
+ */
98+
+ memset(&m, 0, sizeof(m));
99+
+
100+
+ /*
101+
+ * Set the target address we're sending to.
102+
+ */
103+
+ memcpy(&dst, to, sizeof(dst));
104+
+ m.msg_name = &dst;
105+
+ m.msg_namelen = sizeof(dst);
106+
+ ifindex = if_nametoindex(interface->name);
107+
+
108+
+ /*
109+
+ * Set the data buffer we're sending. (Using this wacky
110+
+ * "scatter-gather" stuff... we only have a single chunk
111+
+ * of data to send, so we declare a single vector entry.)
112+
+ */
113+
+ v.iov_base = (char *)raw;
114+
+ v.iov_len = len;
115+
+ m.msg_iov = &v;
116+
+ m.msg_iovlen = 1;
117+
+
118+
+ /*
119+
+ * Setting the interface is a bit more involved.
120+
+ *
121+
+ * We have to create a "control message", and set that to
122+
+ * define the IP packet information. We let he kernel decide
123+
+ * the source IP address unless 'use_src_intf_ip_for_tx' is
124+
+ * set, in which case we use the IP address of the ingress
125+
+ * interface we received the request on as the source IP.
126+
+ */
127+
+ m.msg_control = v4_control_buf;
128+
+ m.msg_controllen = v4_control_buf_len;
129+
+ cmsg = CMSG_FIRSTHDR(&m);
130+
+ INSIST(cmsg != NULL);
131+
+ cmsg->cmsg_level = IPPROTO_IP;
132+
+ cmsg->cmsg_type = IP_PKTINFO;
133+
+ cmsg->cmsg_len = CMSG_LEN(sizeof(*pktinfo));
134+
+ pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
135+
+ memset(pktinfo, 0, sizeof(*pktinfo));
136+
+ pktinfo->ipi_ifindex = ifindex;
137+
+ if (use_src_intf_ip_for_tx)
138+
+ pktinfo->ipi_spec_dst = from;
139+
+
140+
+ result = sendmsg(interface->wfdesc, &m, 0);
141+
if (result < 0) {
142+
- log_error ("send_packet: %m");
143+
- if (errno == ENETUNREACH)
144+
- log_error ("send_packet: please consult README file%s",
145+
- " regarding broadcast address.");
146+
+ log_error("send_packet: %m");
147+
}
148+
+
149+
return result;
150+
}
151+
152+
diff --git a/includes/dhcpd.h b/includes/dhcpd.h
153+
index 36cd518..0c25582 100644
154+
--- a/includes/dhcpd.h
155+
+++ b/includes/dhcpd.h
156+
@@ -2660,6 +2660,7 @@ ssize_t send_fallback6(struct interface_info *, struct packet *,
157+
#endif
158+
159+
#ifdef USE_SOCKET_SEND
160+
+extern int use_src_intf_ip_for_tx;
161+
void if_reinitialize_send (struct interface_info *);
162+
void if_register_send (struct interface_info *);
163+
void if_deregister_send (struct interface_info *);
164+
diff --git a/relay/dhcrelay.c b/relay/dhcrelay.c
165+
index 221106a..c44a79d 100644
166+
--- a/relay/dhcrelay.c
167+
+++ b/relay/dhcrelay.c
168+
@@ -97,6 +97,12 @@ struct downstream_intf_list {
169+
isc_boolean_t use_if_id = ISC_FALSE;
170+
#endif
171+
172+
+/*
173+
+ * If not set, kernel chooses what the src ip is.
174+
+ * If set, uses "from" interface IP for packet Tx.
175+
+ */
176+
+extern int use_src_intf_ip_for_tx = 0;
177+
+
178+
/* Maximum size of a packet with agent options added. */
179+
int dhcp_max_agent_option_packet_length = DHCP_MTU_MIN;
180+
181+
@@ -431,6 +437,8 @@ main(int argc, char **argv) {
182+
#endif
183+
} else if (!strcmp(argv[i], "-d")) {
184+
/* no_daemon = 1; */
185+
+ } else if (!strcmp(argv[i], "-si")) {
186+
+ use_src_intf_ip_for_tx = 1;
187+
} else if (!strcmp(argv[i], "-q")) {
188+
quiet = 1;
189+
quiet_interface_discovery = 1;
190+
--
191+
2.17.1
192+

src/isc-dhcp/patch/series

+1
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@
1010
0009-Support-for-dual-tor-scenario.patch
1111
0010-Bugfix-correctly-set-interface-netmask.patch
1212
0011-dhcp-relay-Prevent-Buffer-Overrun.patch
13+
0012-add-option-si-to-support-using-src-intf-ip-in-relay.patch

0 commit comments

Comments
 (0)