aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichal Kazior <michal@plume.com>2020-12-15 09:53:40 +0000
committerDenys Vlasenko <vda.linux@googlemail.com>2020-12-15 21:44:21 +0100
commitb817699e6c5c8efe4fce45e910d66133c9d8c482 (patch)
treeea4ad25a0ca09d8b5e1e7853bc52b85d94bf64bf
parent01004f9796fd7a5223a40802026d2023e3f9cf28 (diff)
downloadbusybox-w32-b817699e6c5c8efe4fce45e910d66133c9d8c482.tar.gz
busybox-w32-b817699e6c5c8efe4fce45e910d66133c9d8c482.tar.bz2
busybox-w32-b817699e6c5c8efe4fce45e910d66133c9d8c482.zip
udhcp: bind to device even for ucast packets
There are cases where binding to source IP and destination IP is insufficient to guarantee sane xmit netdev. One case where this can fail is when route-matching netdev carrier is down (cable unplugged, wifi disconnected), or the netdev is admin down. Then all the IP based bindings (bind() + connect()) will seemingly succeed but the actual packet can go out through a default gw path. Depending on the network this happens on it can create issues or false alarms. It can also leak some subnet info across networks that shouldn't be routed. As such better be safe than sorry and bind to a netdev to be sure it's used for xmit. function old new delta udhcp_send_kernel_packet 293 336 +43 send_packet 182 188 +6 bcast_or_ucast 37 43 +6 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 3/0 up/down: 55/0) Total: 55 bytes Signed-off-by: Michal Kazior <michal@plume.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--networking/udhcp/common.h3
-rw-r--r--networking/udhcp/dhcpc.c3
-rw-r--r--networking/udhcp/dhcpd.c3
-rw-r--r--networking/udhcp/packet.c18
4 files changed, 23 insertions, 4 deletions
diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h
index 3cbd2d3c8..cc0abd269 100644
--- a/networking/udhcp/common.h
+++ b/networking/udhcp/common.h
@@ -343,7 +343,8 @@ int udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt,
343 343
344int udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt, 344int udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt,
345 uint32_t source_nip, int source_port, 345 uint32_t source_nip, int source_port,
346 uint32_t dest_nip, int dest_port) FAST_FUNC; 346 uint32_t dest_nip, int dest_port,
347 const char *ifname) FAST_FUNC;
347 348
348void udhcp_sp_setup(void) FAST_FUNC; 349void udhcp_sp_setup(void) FAST_FUNC;
349void udhcp_sp_fd_set(struct pollfd *pfds, int extra_fd) FAST_FUNC; 350void udhcp_sp_fd_set(struct pollfd *pfds, int extra_fd) FAST_FUNC;
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c
index 66aa38c20..98720b45b 100644
--- a/networking/udhcp/dhcpc.c
+++ b/networking/udhcp/dhcpc.c
@@ -702,7 +702,8 @@ static int bcast_or_ucast(struct dhcp_packet *packet, uint32_t ciaddr, uint32_t
702 if (server) 702 if (server)
703 return udhcp_send_kernel_packet(packet, 703 return udhcp_send_kernel_packet(packet,
704 ciaddr, CLIENT_PORT, 704 ciaddr, CLIENT_PORT,
705 server, SERVER_PORT); 705 server, SERVER_PORT,
706 client_data.interface);
706 return raw_bcast_from_client_data_ifindex(packet, ciaddr); 707 return raw_bcast_from_client_data_ifindex(packet, ciaddr);
707} 708}
708 709
diff --git a/networking/udhcp/dhcpd.c b/networking/udhcp/dhcpd.c
index de16cf955..9e950ca1f 100644
--- a/networking/udhcp/dhcpd.c
+++ b/networking/udhcp/dhcpd.c
@@ -612,7 +612,8 @@ static void send_packet_to_relay(struct dhcp_packet *dhcp_pkt)
612 612
613 udhcp_send_kernel_packet(dhcp_pkt, 613 udhcp_send_kernel_packet(dhcp_pkt,
614 server_data.server_nip, SERVER_PORT, 614 server_data.server_nip, SERVER_PORT,
615 dhcp_pkt->gateway_nip, SERVER_PORT); 615 dhcp_pkt->gateway_nip, SERVER_PORT,
616 server_data.interface);
616} 617}
617 618
618static void send_packet(struct dhcp_packet *dhcp_pkt, int force_broadcast) 619static void send_packet(struct dhcp_packet *dhcp_pkt, int force_broadcast)
diff --git a/networking/udhcp/packet.c b/networking/udhcp/packet.c
index 51374646d..4d8e005d4 100644
--- a/networking/udhcp/packet.c
+++ b/networking/udhcp/packet.c
@@ -189,7 +189,8 @@ int FAST_FUNC udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt,
189/* Let the kernel do all the work for packet generation */ 189/* Let the kernel do all the work for packet generation */
190int FAST_FUNC udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt, 190int FAST_FUNC udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt,
191 uint32_t source_nip, int source_port, 191 uint32_t source_nip, int source_port,
192 uint32_t dest_nip, int dest_port) 192 uint32_t dest_nip, int dest_port,
193 const char *ifname)
193{ 194{
194 struct sockaddr_in sa; 195 struct sockaddr_in sa;
195 unsigned padding; 196 unsigned padding;
@@ -204,6 +205,21 @@ int FAST_FUNC udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt,
204 } 205 }
205 setsockopt_reuseaddr(fd); 206 setsockopt_reuseaddr(fd);
206 207
208 /* If interface carrier goes down, unless we
209 * bind socket to a particular netdev, the packet
210 * can go out through another interface, eg. via
211 * default route despite being bound to a specific
212 * source IP. As such, bind to device hard and fail
213 * otherwise. Sending renewal packets on foreign
214 * interfaces makes no sense.
215 */
216 if (ifname) {
217 if (setsockopt_bindtodevice(fd, ifname) < 0) {
218 msg = "bindtodevice";
219 goto ret_close;
220 }
221 }
222
207 memset(&sa, 0, sizeof(sa)); 223 memset(&sa, 0, sizeof(sa));
208 sa.sin_family = AF_INET; 224 sa.sin_family = AF_INET;
209 sa.sin_port = htons(source_port); 225 sa.sin_port = htons(source_port);