|
| 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 | + |
0 commit comments