summaryrefslogtreecommitdiff
path: root/networking/udhcp/dhcpc.c
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/dhcpc.c
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/dhcpc.c')
-rw-r--r--networking/udhcp/dhcpc.c34
1 files changed, 24 insertions, 10 deletions
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 */