]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
When the dhcp server is running in dom0 and the client in domU,
authorRoy Marples <roy@marples.name>
Thu, 24 Mar 2011 17:59:20 +0000 (17:59 +0000)
committerRoy Marples <roy@marples.name>
Thu, 24 Mar 2011 17:59:20 +0000 (17:59 +0000)
packets (that are not explicitely checksumed in the userspace)
sent to the another domain have partial UDP checksums (offload)
only, but are marked as such. This patch reads and checks the
mark to decide whether to verify the UDP checksum or not.
Based on the ISC dhcp patch by David Cantrell.
Thanks to Marius Tomaschewski.

arp.c
bpf.c
dhcpcd.c
lpf.c
net.c
net.h

diff --git a/arp.c b/arp.c
index 89d63fe861bbf59048ad7efead4ec244f3b354bc..907ac1131e2c9160322f52b94e5d92c217035eec 100644 (file)
--- a/arp.c
+++ b/arp.c
@@ -1,6 +1,6 @@
 /* 
  * dhcpcd - DHCP client daemon
- * Copyright (c) 2006-2008 Roy Marples <roy@marples.name>
+ * Copyright (c) 2006-2011 Roy Marples <roy@marples.name>
  * All rights reserved
 
  * Redistribution and use in source and binary forms, with or without
@@ -119,7 +119,7 @@ handle_arp_packet(void *arg)
        state->fail.s_addr = 0;
        for(;;) {
                bytes = get_raw_packet(iface, ETHERTYPE_ARP,
-                   arp_buffer, sizeof(arp_buffer));
+                   arp_buffer, sizeof(arp_buffer), NULL);
                if (bytes == 0 || bytes == -1)
                        return;
                /* We must have a full ARP header */
diff --git a/bpf.c b/bpf.c
index beda1ba0e887923e51f6b2510568cd06c4e228a2..1c30c762145d0e5d6d82aa7d1d22eb80d082520a 100644 (file)
--- a/bpf.c
+++ b/bpf.c
@@ -1,6 +1,6 @@
 /*
  * dhcpcd - DHCP client daemon
- * Copyright (c) 2006-2008 Roy Marples <roy@marples.name>
+ * Copyright (c) 2006-2011 Roy Marples <roy@marples.name>
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -160,7 +160,7 @@ send_raw_packet(const struct interface *iface, int protocol,
  * So we pass the buffer in the API so we can loop on >1 packet. */
 ssize_t
 get_raw_packet(struct interface *iface, int protocol,
-    void *data, ssize_t len)
+    void *data, ssize_t len, int *partialcsum)
 {
        int fd = -1;
        struct bpf_hdr packet;
@@ -172,6 +172,9 @@ get_raw_packet(struct interface *iface, int protocol,
        else
                fd = iface->raw_fd;
 
+       if (partialcsum != NULL)
+               *partialcsum = 0; /* Not supported on BSD */
+
        for (;;) {
                if (iface->buffer_len == 0) {
                        bytes = read(fd, iface->buffer, iface->buffer_size);
index ade5e62b369d1a9d4e9c48fa17dd7e07980f79a1..6e9305fd08fbcb23ad15759f9a6a2af153bdbade 100644 (file)
--- a/dhcpcd.c
+++ b/dhcpcd.c
@@ -641,7 +641,7 @@ handle_dhcp_packet(void *arg)
        const uint8_t *pp;
        ssize_t bytes;
        struct in_addr from;
-       int i;
+       int i, partialcsum = 0;
 
        /* We loop through until our buffer is empty.
         * The benefit is that if we get >1 DHCP packet in our buffer and
@@ -649,10 +649,10 @@ handle_dhcp_packet(void *arg)
        packet = xmalloc(udp_dhcp_len);
        for(;;) {
                bytes = get_raw_packet(iface, ETHERTYPE_IP,
-                   packet, udp_dhcp_len);
+                   packet, udp_dhcp_len, &partialcsum);
                if (bytes == 0 || bytes == -1)
                        break;
-               if (valid_udp_packet(packet, bytes, &from) == -1) {
+               if (valid_udp_packet(packet, bytes, &from, partialcsum) == -1) {
                        syslog(LOG_ERR, "%s: invalid UDP packet from %s",
                            iface->name, inet_ntoa(from));
                        continue;
diff --git a/lpf.c b/lpf.c
index 2907d9082f7fbc6ce50fff3a326a052dc72afd14..853d0a3234846a4b2d7ce76f4297c32e8c63569f 100644 (file)
--- a/lpf.c
+++ b/lpf.c
@@ -1,6 +1,6 @@
 /*
  * dhcpcd - DHCP client daemon
- * Copyright (c) 2006-2009 Roy Marples <roy@marples.name>
+ * Copyright (c) 2006-2011 Roy Marples <roy@marples.name>
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -36,7 +36,7 @@
 #ifdef __linux__
 # include <asm/types.h> /* needed for 2.4 kernels for the below header */
 # include <linux/filter.h>
-# include <netpacket/packet.h>
+# include <linux/if_packet.h>
 # define bpf_insn              sock_filter
 # define BPF_SKIPTYPE
 # define BPF_ETHCOOK           -ETH_HLEN
@@ -76,6 +76,9 @@ open_socket(struct interface *iface, int protocol)
        } su;
        struct sock_fprog pf;
        int *fd;
+#ifdef PACKET_AUXDATA
+       int n;
+#endif
 
        if ((s = socket(PF_PACKET, SOCK_DGRAM, htons(protocol))) == -1)
                return -1;
@@ -98,6 +101,13 @@ open_socket(struct interface *iface, int protocol)
        }
        if (setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &pf, sizeof(pf)) != 0)
                goto eexit;
+#ifdef PACKET_AUXDATA
+       n = 1;
+       if (setsockopt(s, SOL_PACKET, PACKET_AUXDATA, &n, sizeof(n)) != 0) {
+               if (errno != ENOPROTOOPT)
+                       goto eexit;
+       }
+#endif
        if (set_cloexec(s) == -1)
                goto eexit;
        if (set_nonblock(s) == -1)
@@ -152,17 +162,53 @@ send_raw_packet(const struct interface *iface, int protocol,
 }
 
 ssize_t
-get_raw_packet(struct interface *iface, int protocol, void *data, ssize_t len)
+get_raw_packet(struct interface *iface, int protocol,
+    void *data, ssize_t len, int *partialcsum)
 {
+       struct iovec iov = {
+               .iov_base = data,
+               .iov_len = len,
+       };
+       struct msghdr msg = {
+               .msg_iov = &iov,
+               .msg_iovlen = 1,
+       };
+#ifdef PACKET_AUXDATA
+       unsigned char cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
+       struct cmsghdr *cmsg;
+       struct tpacket_auxdata *aux;
+#endif
+
        ssize_t bytes;
        int fd = -1;
 
+#ifdef PACKET_AUXDATA
+       msg.msg_control = cmsgbuf;
+       msg.msg_controllen = sizeof(cmsgbuf);
+#endif
+
        if (protocol == ETHERTYPE_ARP)
                fd = iface->arp_fd;
        else
                fd = iface->raw_fd;
-       bytes = read(fd, data, len);
+       bytes = recvmsg(fd, &msg, 0);
        if (bytes == -1)
                return errno == EAGAIN ? 0 : -1;
+       if (partialcsum != NULL) {
+               *partialcsum = 0;
+#ifdef PACKET_AUXDATA
+               for (cmsg = CMSG_FIRSTHDR(&msg);
+                    cmsg;
+                    cmsg = CMSG_NXTHDR(&msg, cmsg))
+               {
+                       if (cmsg->cmsg_level == SOL_PACKET &&
+                           cmsg->cmsg_type == PACKET_AUXDATA) {
+                               aux = (void *)CMSG_DATA(cmsg);
+                               *partialcsum = aux->tp_status &
+                                   TP_STATUS_CSUMNOTREADY;
+                       }
+               }
+#endif
+       }
        return bytes;
 }
diff --git a/net.c b/net.c
index e26b8d488b78cd108339da5cd2953672abf18bce..e87c9c84201abb10c6b555c8a194bff78d378152 100644 (file)
--- a/net.c
+++ b/net.c
@@ -1,6 +1,6 @@
 /* 
  * dhcpcd - DHCP client daemon
- * Copyright (c) 2006-2010 Roy Marples <roy@marples.name>
+ * Copyright (c) 2006-2011 Roy Marples <roy@marples.name>
  * All rights reserved
 
  * Redistribution and use in source and binary forms, with or without
@@ -726,7 +726,8 @@ get_udp_data(const uint8_t **data, const uint8_t *udp)
 }
 
 int
-valid_udp_packet(const uint8_t *data, size_t data_len, struct in_addr *from)
+valid_udp_packet(const uint8_t *data, size_t data_len, struct in_addr *from,
+    int noudpcsum)
 {
        struct udp_dhcp_packet packet;
        uint16_t bytes, udpsum;
@@ -754,19 +755,22 @@ valid_udp_packet(const uint8_t *data, size_t data_len, struct in_addr *from)
                errno = EINVAL;
                return -1;
        }
-       udpsum = packet.udp.uh_sum;
-       packet.udp.uh_sum = 0;
-       packet.ip.ip_hl = 0;
-       packet.ip.ip_v = 0;
-       packet.ip.ip_tos = 0;
-       packet.ip.ip_len = packet.udp.uh_ulen;
-       packet.ip.ip_id = 0;
-       packet.ip.ip_off = 0;
-       packet.ip.ip_ttl = 0;
-       packet.ip.ip_sum = 0;
-       if (udpsum && checksum(&packet, bytes) != udpsum) {
-               errno = EINVAL;
-               return -1;
+
+       if (noudpcsum == 0) {
+               udpsum = packet.udp.uh_sum;
+               packet.udp.uh_sum = 0;
+               packet.ip.ip_hl = 0;
+               packet.ip.ip_v = 0;
+               packet.ip.ip_tos = 0;
+               packet.ip.ip_len = packet.udp.uh_ulen;
+               packet.ip.ip_id = 0;
+               packet.ip.ip_off = 0;
+               packet.ip.ip_ttl = 0;
+               packet.ip.ip_sum = 0;
+               if (udpsum && checksum(&packet, bytes) != udpsum) {
+                       errno = EINVAL;
+                       return -1;
+               }
        }
 
        return 0;
diff --git a/net.h b/net.h
index 16ba168320b2b1bcbde2b78baaa8ff325a5202ef..6941c4ce054dabf6142a6ebea7b76d2d11efa5f2 100644 (file)
--- a/net.h
+++ b/net.h
@@ -140,14 +140,14 @@ extern const size_t udp_dhcp_len;
 ssize_t make_udp_packet(uint8_t **, const uint8_t *, size_t,
     struct in_addr, struct in_addr);
 ssize_t get_udp_data(const uint8_t **, const uint8_t *);
-int valid_udp_packet(const uint8_t *, size_t, struct in_addr *);
+int valid_udp_packet(const uint8_t *, size_t, struct in_addr *, int noudpcsum);
 
 int open_socket(struct interface *, int);
 ssize_t send_packet(const struct interface *, struct in_addr, 
     const uint8_t *, ssize_t);
 ssize_t send_raw_packet(const struct interface *, int,
     const void *, ssize_t);
-ssize_t get_raw_packet(struct interface *, int, void *, ssize_t);
+ssize_t get_raw_packet(struct interface *, int, void *, ssize_t, int *);
 
 int init_sockets(void);
 int open_link_socket(void);