diff --git a/src/isc-dhcp/patch/0012-add-option-si-to-support-using-src-intf-ip-in-relay.patch b/src/isc-dhcp/patch/0012-add-option-si-to-support-using-src-intf-ip-in-relay.patch new file mode 100644 index 0000000000..7fd9fc3134 --- /dev/null +++ b/src/isc-dhcp/patch/0012-add-option-si-to-support-using-src-intf-ip-in-relay.patch @@ -0,0 +1,192 @@ +From 16163f0693e30588216f0f280d5eba8bb53f7001 Mon Sep 17 00:00:00 2001 +From: Tianrong Zhang +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 + diff --git a/src/isc-dhcp/patch/series b/src/isc-dhcp/patch/series index a34b5bf4b0..5397aa0c6e 100644 --- a/src/isc-dhcp/patch/series +++ b/src/isc-dhcp/patch/series @@ -10,3 +10,4 @@ 0009-Support-for-dual-tor-scenario.patch 0010-Bugfix-correctly-set-interface-netmask.patch 0011-dhcp-relay-Prevent-Buffer-Overrun.patch +0012-add-option-si-to-support-using-src-intf-ip-in-relay.patch