aboutsummaryrefslogtreecommitdiff
path: root/networking/udhcp
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2017-09-29 15:55:24 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2017-09-29 16:02:11 +0200
commita6a3ad327360669e0c12552f680382e3b9713489 (patch)
tree7dcfc65aa41e6f0f22e5b6631c35dbae8b99052f /networking/udhcp
parent2b9acc60c0468379cd24d13bc9e3f3e50761c0c9 (diff)
downloadbusybox-w32-a6a3ad327360669e0c12552f680382e3b9713489.tar.gz
busybox-w32-a6a3ad327360669e0c12552f680382e3b9713489.tar.bz2
busybox-w32-a6a3ad327360669e0c12552f680382e3b9713489.zip
udhcpc: paranoia when using kernel UDP mode for sending renew: server ID may be bogus
With new code, we request that target IP (server ID) must be directly reachable. If it's not, this happens: udhcpc: waiting 2000 seconds udhcpc: entering listen mode: kernel udhcpc: opening listen socket on *:68 wlan0 udhcpc: entering renew state udhcpc: sending renew to 1.1.1.1 udhcpc: send: Network is unreachable ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 1.1.1.1 needs routing, this is fishy! udhcpc: entering rebinding state udhcpc: entering listen mode: raw udhcpc: created raw socket udhcpc: sending renew to 0.0.0.0 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ going to use broadcast which is the desired behavior. Before the patch, packet to 1.1.1.1 was routed over eth0 (!) and maybe even into Internet (!!!). function old new delta udhcpc_main 2752 2763 +11 udhcp_send_kernel_packet 295 301 +6 send_renew 82 84 +2 send_packet 166 168 +2 bcast_or_ucast 23 25 +2 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 5/0 up/down: 23/0) Total: 23 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'networking/udhcp')
-rw-r--r--networking/udhcp/common.h4
-rw-r--r--networking/udhcp/d6_dhcpc.c4
-rw-r--r--networking/udhcp/dhcpc.c34
-rw-r--r--networking/udhcp/dhcpd.c4
-rw-r--r--networking/udhcp/packet.c7
5 files changed, 37 insertions, 16 deletions
diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h
index a9c23a186..04939e707 100644
--- a/networking/udhcp/common.h
+++ b/networking/udhcp/common.h
@@ -308,7 +308,9 @@ int udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt,
308 308
309int udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt, 309int udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt,
310 uint32_t source_nip, int source_port, 310 uint32_t source_nip, int source_port,
311 uint32_t dest_nip, int dest_port) FAST_FUNC; 311 uint32_t dest_nip, int dest_port,
312 int send_flags
313) FAST_FUNC;
312 314
313void udhcp_sp_setup(void) FAST_FUNC; 315void udhcp_sp_setup(void) FAST_FUNC;
314void udhcp_sp_fd_set(struct pollfd *pfds, int extra_fd) FAST_FUNC; 316void udhcp_sp_fd_set(struct pollfd *pfds, int extra_fd) FAST_FUNC;
diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c
index d4bb3507b..c13f23505 100644
--- a/networking/udhcp/d6_dhcpc.c
+++ b/networking/udhcp/d6_dhcpc.c
@@ -702,13 +702,15 @@ static NOINLINE int send_d6_renew(uint32_t xid, struct in6_addr *server_ipv6, st
702 opt_ptr = add_d6_client_options(opt_ptr); 702 opt_ptr = add_d6_client_options(opt_ptr);
703 703
704 bb_error_msg("sending %s", "renew"); 704 bb_error_msg("sending %s", "renew");
705 if (server_ipv6) 705 if (server_ipv6) {
706 return d6_send_kernel_packet( 706 return d6_send_kernel_packet(
707 &packet, (opt_ptr - (uint8_t*) &packet), 707 &packet, (opt_ptr - (uint8_t*) &packet),
708 our_cur_ipv6, CLIENT_PORT6, 708 our_cur_ipv6, CLIENT_PORT6,
709 server_ipv6, SERVER_PORT6, 709 server_ipv6, SERVER_PORT6,
710 client_config.ifindex 710 client_config.ifindex
711 /* TODO? send_flags: MSG_DONTROUTE (see IPv4 code for reason why) */
711 ); 712 );
713 }
712 return d6_mcast_from_client_config_ifindex(&packet, opt_ptr); 714 return d6_mcast_from_client_config_ifindex(&packet, opt_ptr);
713} 715}
714 716
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c
index 6c74996ef..2ae8bcc4d 100644
--- a/networking/udhcp/dhcpc.c
+++ b/networking/udhcp/dhcpc.c
@@ -694,10 +694,16 @@ static int raw_bcast_from_client_config_ifindex(struct dhcp_packet *packet, uint
694 694
695static int bcast_or_ucast(struct dhcp_packet *packet, uint32_t ciaddr, uint32_t server) 695static int bcast_or_ucast(struct dhcp_packet *packet, uint32_t ciaddr, uint32_t server)
696{ 696{
697 if (server) 697 if (server) {
698 /* Without MSG_DONTROUTE, the packet was seen routed over
699 * _other interface_ if server ID is bogus (example: 1.1.1.1).
700 */
698 return udhcp_send_kernel_packet(packet, 701 return udhcp_send_kernel_packet(packet,
699 ciaddr, CLIENT_PORT, 702 ciaddr, CLIENT_PORT,
700 server, SERVER_PORT); 703 server, SERVER_PORT,
704 /*send_flags: "to hosts only on directly connected networks" */ MSG_DONTROUTE
705 );
706 }
701 return raw_bcast_from_client_config_ifindex(packet, ciaddr); 707 return raw_bcast_from_client_config_ifindex(packet, ciaddr);
702} 708}
703 709
@@ -735,7 +741,7 @@ static NOINLINE int send_discover(uint32_t xid, uint32_t requested)
735static NOINLINE int send_select(uint32_t xid, uint32_t server, uint32_t requested) 741static NOINLINE int send_select(uint32_t xid, uint32_t server, uint32_t requested)
736{ 742{
737 struct dhcp_packet packet; 743 struct dhcp_packet packet;
738 struct in_addr addr; 744 struct in_addr temp_addr;
739 745
740/* 746/*
741 * RFC 2131 4.3.2 DHCPREQUEST message 747 * RFC 2131 4.3.2 DHCPREQUEST message
@@ -766,8 +772,8 @@ static NOINLINE int send_select(uint32_t xid, uint32_t server, uint32_t requeste
766 */ 772 */
767 add_client_options(&packet); 773 add_client_options(&packet);
768 774
769 addr.s_addr = requested; 775 temp_addr.s_addr = requested;
770 bb_error_msg("sending select for %s", inet_ntoa(addr)); 776 bb_error_msg("sending select for %s", inet_ntoa(temp_addr));
771 return raw_bcast_from_client_config_ifindex(&packet, INADDR_ANY); 777 return raw_bcast_from_client_config_ifindex(&packet, INADDR_ANY);
772} 778}
773 779
@@ -776,6 +782,7 @@ static NOINLINE int send_select(uint32_t xid, uint32_t server, uint32_t requeste
776static NOINLINE int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr) 782static NOINLINE int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr)
777{ 783{
778 struct dhcp_packet packet; 784 struct dhcp_packet packet;
785 struct in_addr temp_addr;
779 786
780/* 787/*
781 * RFC 2131 4.3.2 DHCPREQUEST message 788 * RFC 2131 4.3.2 DHCPREQUEST message
@@ -806,7 +813,8 @@ static NOINLINE int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr)
806 */ 813 */
807 add_client_options(&packet); 814 add_client_options(&packet);
808 815
809 bb_error_msg("sending %s", "renew"); 816 temp_addr.s_addr = server;
817 bb_error_msg("sending renew to %s", inet_ntoa(temp_addr));
810 return bcast_or_ucast(&packet, ciaddr, server); 818 return bcast_or_ucast(&packet, ciaddr, server);
811} 819}
812 820
@@ -1524,11 +1532,17 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1524 * Anyway, it does recover by eventually failing through 1532 * Anyway, it does recover by eventually failing through
1525 * into INIT_SELECTING state. 1533 * into INIT_SELECTING state.
1526 */ 1534 */
1527 send_renew(xid, server_addr, requested_ip); 1535 if (send_renew(xid, server_addr, requested_ip) >= 0) {
1528 timeout >>= 1; 1536 timeout >>= 1;
1529 continue; 1537 continue;
1538 }
1539 /* else: error sending.
1540 * example: ENETUNREACH seen with server
1541 * which gave us bogus server ID 1.1.1.1
1542 * which wasn't reachable (and probably did not exist).
1543 */
1530 } 1544 }
1531 /* Timed out, enter rebinding state */ 1545 /* Timed out or error, enter rebinding state */
1532 log1("entering rebinding state"); 1546 log1("entering rebinding state");
1533 state = REBINDING; 1547 state = REBINDING;
1534 /* fall right through */ 1548 /* fall right through */
diff --git a/networking/udhcp/dhcpd.c b/networking/udhcp/dhcpd.c
index 05ddc8649..57d8b36c5 100644
--- a/networking/udhcp/dhcpd.c
+++ b/networking/udhcp/dhcpd.c
@@ -588,7 +588,9 @@ static void send_packet_to_relay(struct dhcp_packet *dhcp_pkt)
588 588
589 udhcp_send_kernel_packet(dhcp_pkt, 589 udhcp_send_kernel_packet(dhcp_pkt,
590 server_config.server_nip, SERVER_PORT, 590 server_config.server_nip, SERVER_PORT,
591 dhcp_pkt->gateway_nip, SERVER_PORT); 591 dhcp_pkt->gateway_nip, SERVER_PORT,
592 /*send_flags:*/ 0
593 );
592} 594}
593 595
594static void send_packet(struct dhcp_packet *dhcp_pkt, int force_broadcast) 596static void send_packet(struct dhcp_packet *dhcp_pkt, int force_broadcast)
diff --git a/networking/udhcp/packet.c b/networking/udhcp/packet.c
index 44d9ceec7..ad0028bd0 100644
--- a/networking/udhcp/packet.c
+++ b/networking/udhcp/packet.c
@@ -191,7 +191,8 @@ int FAST_FUNC udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt,
191/* Let the kernel do all the work for packet generation */ 191/* Let the kernel do all the work for packet generation */
192int FAST_FUNC udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt, 192int FAST_FUNC udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt,
193 uint32_t source_nip, int source_port, 193 uint32_t source_nip, int source_port,
194 uint32_t dest_nip, int dest_port) 194 uint32_t dest_nip, int dest_port,
195 int send_flags)
195{ 196{
196 struct sockaddr_in sa; 197 struct sockaddr_in sa;
197 unsigned padding; 198 unsigned padding;
@@ -228,8 +229,8 @@ int FAST_FUNC udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt,
228 padding = DHCP_OPTIONS_BUFSIZE - 1 - udhcp_end_option(dhcp_pkt->options); 229 padding = DHCP_OPTIONS_BUFSIZE - 1 - udhcp_end_option(dhcp_pkt->options);
229 if (padding > DHCP_SIZE - 300) 230 if (padding > DHCP_SIZE - 300)
230 padding = DHCP_SIZE - 300; 231 padding = DHCP_SIZE - 300;
231 result = safe_write(fd, dhcp_pkt, DHCP_SIZE - padding); 232 result = send(fd, dhcp_pkt, DHCP_SIZE - padding, send_flags);
232 msg = "write"; 233 msg = "send";
233 ret_close: 234 ret_close:
234 close(fd); 235 close(fd);
235 if (result < 0) { 236 if (result < 0) {