This patch modifies the DHCP client to support sending DHCP requests through an 
IPv6 GRE tunnel.

The sendto system call on a SOCK_DGRAM packet socket fails when used with an 
IPv6 GRE tunnel.
This occurs because the GRE tunnel implementation in the Linux kernel does not 
add a hardware
header to the packet, resulting in an "Invalid Argument" error.

Using a raw socket, the patch ensures proper functionality when using DHCP over 
IPv6 GRE tunnels.

Signed-off-by: Emanuele Santini <[email protected]>
---
 networking/udhcp/common.h |  2 +-
 networking/udhcp/dhcpc.c  |  2 +-
 networking/udhcp/dhcpd.c  |  2 +-
 networking/udhcp/packet.c | 84 +++++++++++++++++++++++++--------------
 4 files changed, 58 insertions(+), 32 deletions(-)

diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h
index 3ef371a7c..805aeff73 100644
--- a/networking/udhcp/common.h
+++ b/networking/udhcp/common.h
@@ -367,7 +367,7 @@ int udhcp_recv_kernel_packet(struct dhcp_packet *packet, 
int fd) FAST_FUNC;
 int udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt,
                uint32_t source_nip, int source_port,
                uint32_t dest_nip, int dest_port, const uint8_t *dest_arp,
-               int ifindex) FAST_FUNC;
+               const char *if_name) FAST_FUNC;
 
 int udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt,
                uint32_t source_nip, int source_port,
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c
index e44086c2e..d38118b53 100644
--- a/networking/udhcp/dhcpc.c
+++ b/networking/udhcp/dhcpc.c
@@ -693,7 +693,7 @@ static int raw_bcast_from_client_data_ifindex(struct 
dhcp_packet *packet, uint32
        return udhcp_send_raw_packet(packet,
                /*src*/ src_nip, CLIENT_PORT,
                /*dst*/ INADDR_BROADCAST, SERVER_PORT, MAC_BCAST_ADDR,
-               client_data.ifindex);
+               client_data.interface);
 }
 
 static int bcast_or_ucast(struct dhcp_packet *packet, uint32_t ciaddr, 
uint32_t server)
diff --git a/networking/udhcp/dhcpd.c b/networking/udhcp/dhcpd.c
index 2904119e5..ca904542a 100644
--- a/networking/udhcp/dhcpd.c
+++ b/networking/udhcp/dhcpd.c
@@ -603,7 +603,7 @@ static void send_packet_to_client(struct dhcp_packet 
*dhcp_pkt, int force_broadc
        udhcp_send_raw_packet(dhcp_pkt,
                /*src*/ server_data.server_nip, SERVER_PORT,
                /*dst*/ ciaddr, CLIENT_PORT, chaddr,
-               server_data.ifindex);
+               server_data.interface);
 }
 
 /* Send a packet to gateway_nip using the kernel ip stack */
diff --git a/networking/udhcp/packet.c b/networking/udhcp/packet.c
index f9dc11d01..678040b55 100644
--- a/networking/udhcp/packet.c
+++ b/networking/udhcp/packet.c
@@ -11,6 +11,7 @@
 #include <netinet/in.h>
 #include <netinet/if_ether.h>
 #include <netpacket/packet.h>
+#include <net/if.h>
 
 #if ENABLE_UDHCPC || ENABLE_UDHCPD
 void FAST_FUNC udhcp_init_header(struct dhcp_packet *packet, char type)
@@ -105,38 +106,47 @@ int FAST_FUNC udhcp_recv_kernel_packet(struct dhcp_packet 
*packet, int fd)
        return bytes;
 }
 
-/* Construct a ip/udp header for a packet, send packet */
+/* Construct a eth/ip/udp header for a packet, send packet */
 int FAST_FUNC udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt,
-               uint32_t source_nip, int source_port,
-               uint32_t dest_nip, int dest_port, const uint8_t *dest_arp,
-               int ifindex)
+                               uint32_t source_nip, int source_port,
+                               uint32_t dest_nip, int dest_port, const uint8_t 
*dest_arp,
+                               const char *if_name)
 {
        struct sockaddr_ll dest_sll;
-       struct ip_udp_dhcp_packet packet;
+       struct ethhdr *eth;
+       struct ip_udp_dhcp_packet *packet;
+       struct ifreq if_dev;
        unsigned padding;
        int fd;
        int result = -1;
        const char *msg;
 
-       fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
+       const int packet_size = sizeof(struct ethhdr) + sizeof(struct 
ip_udp_dhcp_packet);
+       char datagram[packet_size];
+
+       fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP));
        if (fd < 0) {
                msg = "socket(%s)";
                goto ret_msg;
        }
 
        memset(&dest_sll, 0, sizeof(dest_sll));
-       memset(&packet, 0, offsetof(struct ip_udp_dhcp_packet, data));
-       packet.data = *dhcp_pkt; /* struct copy */
+       memset(&datagram, 0, packet_size);
+       eth = (struct ethhdr*)&datagram[0];
+       packet = (struct ip_udp_dhcp_packet*)&datagram[sizeof(struct ethhdr)];
+
+       // Copy data into the packet
+       memcpy(&packet->data, dhcp_pkt, sizeof(struct dhcp_packet));
 
        dest_sll.sll_family = AF_PACKET;
        dest_sll.sll_protocol = htons(ETH_P_IP);
-       dest_sll.sll_ifindex = ifindex;
+       dest_sll.sll_ifindex = if_nametoindex(if_name);
        /*dest_sll.sll_hatype = ARPHRD_???;*/
        /*dest_sll.sll_pkttype = PACKET_???;*/
        dest_sll.sll_halen = 6;
        memcpy(dest_sll.sll_addr, dest_arp, 6);
 
-//TODO: is bind() necessary? we sendto() to this destination, should work 
anyway
+       //TODO: is bind() necessary? we sendto() to this destination, should 
work anyway
        if (bind(fd, (struct sockaddr *)&dest_sll, sizeof(dest_sll)) < 0) {
                msg = "bind(%s)";
                goto ret_close;
@@ -156,36 +166,52 @@ int FAST_FUNC udhcp_send_raw_packet(struct dhcp_packet 
*dhcp_pkt,
         * Thus, we retain enough padding to not go below 300 BOOTP bytes.
         * Some devices have filters which drop DHCP packets shorter than that.
         */
-       padding = DHCP_OPTIONS_BUFSIZE - 1 - 
udhcp_end_option(packet.data.options);
+       padding = DHCP_OPTIONS_BUFSIZE - 1 - 
udhcp_end_option(packet->data.options);
        if (padding > DHCP_SIZE - 300)
                padding = DHCP_SIZE - 300;
 
-       packet.ip.protocol = IPPROTO_UDP;
-       packet.ip.saddr = source_nip;
-       packet.ip.daddr = dest_nip;
-       packet.udp.source = htons(source_port);
-       packet.udp.dest = htons(dest_port);
+       // Get source address
+       strcpy(if_dev.ifr_name, if_name);
+       result = ioctl(fd, SIOCGIFHWADDR, &if_dev);
+       if (result < 0) {
+               msg = "ioctl";
+               goto ret_close;
+       }
+
+       // Setup Ethernet packet
+       memcpy(eth->h_dest, (void*)dest_arp, 6); /* Dest MAC */
+       memcpy(eth->h_source, (void*)if_dev.ifr_hwaddr.sa_data, 6); /* Source 
MAC */
+       eth->h_proto = htons(ETH_P_IP);
+
+       packet->ip.protocol = IPPROTO_UDP;
+       packet->ip.saddr = source_nip;
+       packet->ip.daddr = dest_nip;
+       packet->udp.source = htons(source_port);
+       packet->udp.dest = htons(dest_port);
        /* size, excluding IP header: */
-       packet.udp.len = htons(UDP_DHCP_SIZE - padding);
+       packet->udp.len = htons(UDP_DHCP_SIZE - padding);
        /* for UDP checksumming, ip.len is set to UDP packet len */
-       packet.ip.tot_len = packet.udp.len;
-       packet.udp.check = inet_cksum(&packet,
-                       IP_UDP_DHCP_SIZE - padding);
+       packet->ip.tot_len = packet->udp.len;
+       packet->udp.check = inet_cksum(packet,
+                                                                  
IP_UDP_DHCP_SIZE - padding);
        /* but for sending, it is set to IP packet len */
-       packet.ip.tot_len = htons(IP_UDP_DHCP_SIZE - padding);
-       packet.ip.ihl = sizeof(packet.ip) >> 2;
-       packet.ip.version = IPVERSION;
-       packet.ip.ttl = IPDEFTTL;
-       packet.ip.check = inet_cksum(&packet.ip, sizeof(packet.ip));
+       packet->ip.tot_len = htons(IP_UDP_DHCP_SIZE - padding);
+       packet->ip.ihl = sizeof(packet->ip) >> 2;
+       packet->ip.version = IPVERSION;
+       packet->ip.ttl = IPDEFTTL;
+       packet->ip.check = inet_cksum(&packet->ip, sizeof(packet->ip));
 
        udhcp_dump_packet(dhcp_pkt);
-       result = sendto(fd, &packet, IP_UDP_DHCP_SIZE - padding, /*flags:*/ 0,
-                       (struct sockaddr *) &dest_sll, sizeof(dest_sll));
+
+       result = sendto(fd, &datagram, sizeof(struct ethhdr) + IP_UDP_DHCP_SIZE 
- padding, /*flags:*/ 0,
+                                       (struct sockaddr *) &dest_sll, 
sizeof(dest_sll));
+
        msg = "sendto";
- ret_close:
+
+       ret_close:
        close(fd);
        if (result < 0) {
- ret_msg:
+               ret_msg:
                bb_perror_msg(msg, "PACKET");
        }
        return result;
-- 
2.47.1

_______________________________________________
busybox mailing list
[email protected]
https://lists.busybox.net/mailman/listinfo/busybox

Reply via email to