chiark / gitweb /
dhcp-network: add check for DHCP.chaddr
authorMichal Sekletar <msekleta@redhat.com>
Thu, 19 Jun 2014 13:14:14 +0000 (15:14 +0200)
committerMichal Sekletar <msekleta@redhat.com>
Mon, 7 Jul 2014 10:17:55 +0000 (12:17 +0200)
Check that received DHCP packets actually include our MAC address in
chaddr field. BPF interpreter has 32 bit wide registers but MAC address
is 48 bits long so we have to do check in two steps.

src/libsystemd-network/dhcp-internal.h
src/libsystemd-network/dhcp-network.c
src/libsystemd-network/sd-dhcp-client.c
src/libsystemd-network/test-dhcp-client.c

index 6f6f1218d956ed8e574342b321a8cd272f817c67..1069c8a03bac515a729cb765ef7db0b1af91a943 100644 (file)
 
 #include <stdint.h>
 #include <linux/if_packet.h>
 
 #include <stdint.h>
 #include <linux/if_packet.h>
+#include <net/ethernet.h>
 
 #include "socket-util.h"
 
 #include "sd-dhcp-client.h"
 #include "dhcp-protocol.h"
 
 
 #include "socket-util.h"
 
 #include "sd-dhcp-client.h"
 #include "dhcp-protocol.h"
 
-int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link, uint32_t xid);
+int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link, uint32_t xid, struct ether_addr mac_addr);
 int dhcp_network_bind_udp_socket(be32_t address, uint16_t port);
 int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link,
                                  const void *packet, size_t len);
 int dhcp_network_bind_udp_socket(be32_t address, uint16_t port);
 int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link,
                                  const void *packet, size_t len);
index 9d579177a433f709faecfd8dc26435262ff31ad9..f119cae7ffd63805963d872ff3574760753ed3fe 100644 (file)
@@ -33,7 +33,7 @@
 #include "dhcp-internal.h"
 
 int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link,
 #include "dhcp-internal.h"
 
 int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link,
-                                 uint32_t xid) {
+                                 uint32_t xid, struct ether_addr mac_addr) {
         struct sock_filter filter[] = {
             BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0),                                 /* A <- packet length */
             BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, sizeof(DHCPPacket), 1, 0),         /* packet >= DHCPPacket ? */
         struct sock_filter filter[] = {
             BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0),                                 /* A <- packet length */
             BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, sizeof(DHCPPacket), 1, 0),         /* packet >= DHCPPacket ? */
@@ -60,7 +60,18 @@ int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link,
             BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.xid)),    /* A <- client identifier */
             BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, xid, 1, 0),                        /* client identifier == xid ? */
             BPF_STMT(BPF_RET + BPF_K, 0),                                          /* ignore */
             BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.xid)),    /* A <- client identifier */
             BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, xid, 1, 0),                        /* client identifier == xid ? */
             BPF_STMT(BPF_RET + BPF_K, 0),                                          /* ignore */
-            /* TODO: match chaddr */
+            BPF_STMT(BPF_LD + BPF_IMM, htobe32(*((unsigned int *) &mac_addr))),                    /* A <- 4 bytes of client's MAC */
+            BPF_STMT(BPF_MISC + BPF_TAX, 0),                                                       /* X <- A */
+            BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.chaddr)),                 /* A <- 4 bytes of MAC from dhcp.chaddr */
+            BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0),                                                /* A xor X */
+            BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 1, 0),                                          /* A == 0 ? */
+            BPF_STMT(BPF_RET + BPF_K, 0),                                                          /* ignore */
+            BPF_STMT(BPF_LD + BPF_IMM, htobe16(*((unsigned short *) (((char *) &mac_addr) + 4)))), /* A <- remainder of client's MAC */
+            BPF_STMT(BPF_MISC + BPF_TAX, 0),                                                       /* X <- A */
+            BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(DHCPPacket, dhcp.chaddr) + 4),             /* A <- remainder of MAC from dhcp.chaddr */
+            BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0),                                                /* A xor X */
+            BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 1, 0),                                          /* A == 0 ? */
+            BPF_STMT(BPF_RET + BPF_K, 0),                                                          /* ignore */
             BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.magic)),  /* A <- DHCP magic cookie */
             BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP_MAGIC_COOKIE, 1, 0),          /* cookie == DHCP magic cookie ? */
             BPF_STMT(BPF_RET + BPF_K, 0),                                          /* ignore */
             BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.magic)),  /* A <- DHCP magic cookie */
             BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP_MAGIC_COOKIE, 1, 0),          /* cookie == DHCP magic cookie ? */
             BPF_STMT(BPF_RET + BPF_K, 0),                                          /* ignore */
index d8a9d20e4c9ed9cda262d8dbaf132c5fd92fddbe..6b19666c3bc46707a44ce6aecb105be3d9635ef0 100644 (file)
@@ -751,7 +751,7 @@ static int client_start(sd_dhcp_client *client) {
 
         client->xid = random_u32();
 
 
         client->xid = random_u32();
 
-        r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid);
+        r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid, client->client_id.mac_addr);
         if (r < 0) {
                 client_stop(client, r);
                 return r;
         if (r < 0) {
                 client_stop(client, r);
                 return r;
@@ -795,7 +795,7 @@ static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata)
         client->state = DHCP_STATE_REBINDING;
         client->attempt = 1;
 
         client->state = DHCP_STATE_REBINDING;
         client->attempt = 1;
 
-        r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid);
+        r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid, client->client_id.mac_addr);
         if (r < 0) {
                 client_stop(client, r);
                 return 0;
         if (r < 0) {
                 client_stop(client, r);
                 return 0;
index 450b6d4d3c9bfc199b4297e5d768574009ee7cd6..7cbe10d5a7a632936382829c08d449dac85e9613 100644 (file)
@@ -196,7 +196,7 @@ int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link,
         return 575;
 }
 
         return 575;
 }
 
-int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link, uint32_t id)
+int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link, uint32_t id, struct ether_addr mac)
 {
         if (socketpair(AF_UNIX, SOCK_STREAM, 0, test_fd) < 0)
                 return -errno;
 {
         if (socketpair(AF_UNIX, SOCK_STREAM, 0, test_fd) < 0)
                 return -errno;