chiark / gitweb /
sd-dhcp-server: add basic message handling and verification
authorTom Gundersen <teg@jklm.no>
Sat, 24 May 2014 19:04:27 +0000 (21:04 +0200)
committerTom Gundersen <teg@jklm.no>
Fri, 13 Jun 2014 14:53:13 +0000 (16:53 +0200)
src/libsystemd-network/dhcp-server-internal.h
src/libsystemd-network/sd-dhcp-server.c
src/libsystemd-network/test-dhcp-server.c

index 6484dd3..63883fa 100644 (file)
@@ -27,6 +27,8 @@
 #include "util.h"
 #include "log.h"
 
+#include "dhcp-internal.h"
+
 struct sd_dhcp_server {
         RefCount n_ref;
 
@@ -42,3 +44,6 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp_server*, sd_dhcp_server_unref);
 #define _cleanup_dhcp_server_unref_ _cleanup_(sd_dhcp_server_unrefp)
 
 #define log_dhcp_server(client, fmt, ...) log_meta(LOG_DEBUG, __FILE__, __LINE__, __func__, "DHCP SERVER: " fmt, ##__VA_ARGS__)
+
+int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
+                               size_t length);
index e4396a0..57fb09a 100644 (file)
@@ -21,6 +21,7 @@
 ***/
 
 #include <sys/ioctl.h>
+#include <netinet/if_ether.h>
 
 #include "sd-dhcp-server.h"
 #include "dhcp-server-internal.h"
@@ -112,9 +113,30 @@ int sd_dhcp_server_stop(sd_dhcp_server *server) {
         return 0;
 }
 
+int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
+                               size_t length) {
+        int type;
+
+        assert(server);
+        assert(message);
+
+        if (message->op != BOOTREQUEST ||
+            message->htype != ARPHRD_ETHER ||
+            message->hlen != ETHER_ADDR_LEN)
+                return 0;
+
+        type = dhcp_option_parse(message, length, NULL, NULL);
+        if (type < 0)
+                return 0;
+
+        log_dhcp_server(server, "received message of type %d", type);
+
+        return 1;
+}
+
 static int server_receive_message(sd_event_source *s, int fd,
                                   uint32_t revents, void *userdata) {
-        _cleanup_free_ uint8_t *message = NULL;
+        _cleanup_free_ DHCPMessage *message = NULL;
         uint8_t cmsgbuf[CMSG_LEN(sizeof(struct in_pktinfo))];
         sd_dhcp_server *server = userdata;
         struct iovec iov = {};
@@ -145,6 +167,8 @@ static int server_receive_message(sd_event_source *s, int fd,
         len = recvmsg(fd, &msg, 0);
         if (len < buflen)
                 return 0;
+        else if ((size_t)len < sizeof(DHCPMessage))
+                return 0;
 
         for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
                 if (cmsg->cmsg_level == IPPROTO_IP &&
@@ -160,9 +184,7 @@ static int server_receive_message(sd_event_source *s, int fd,
                 }
         }
 
-        log_dhcp_server(server, "received message");
-
-        return 1;
+        return dhcp_server_handle_message(server, message, (size_t)len);
 }
 
 int sd_dhcp_server_start(sd_dhcp_server *server) {
index 2feb124..dd0f29a 100644 (file)
@@ -20,6 +20,7 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <netinet/if_ether.h>
 #include <assert.h>
 #include <errno.h>
 
@@ -54,6 +55,61 @@ static void test_basic(sd_event *event) {
         assert_se(sd_dhcp_server_start(server) >= 0);
 }
 
+static void test_message_handler(void) {
+        _cleanup_dhcp_server_unref_ sd_dhcp_server *server = NULL;
+        struct {
+                DHCPMessage message;
+                struct {
+                        uint8_t code;
+                        uint8_t length;
+                        uint8_t type;
+                } _packed_ option_type;
+                uint8_t end;
+        } _packed_ test = {
+                .message.op = BOOTREQUEST,
+                .message.htype = ARPHRD_ETHER,
+                .message.hlen = ETHER_ADDR_LEN,
+                .option_type.code = DHCP_OPTION_MESSAGE_TYPE,
+                .option_type.length = 1,
+                .option_type.type = DHCP_DISCOVER,
+                .end = DHCP_OPTION_END,
+        };
+
+        assert_se(sd_dhcp_server_new(&server, 1) >= 0);
+
+        assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 1);
+
+        test.end = 0;
+        /* TODO, shouldn't this fail? */
+        assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 1);
+        test.end = DHCP_OPTION_END;
+        assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 1);
+
+        test.option_type.code = 0;
+        test.option_type.length = 0;
+        test.option_type.type = 0;
+        assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0);
+        test.option_type.code = DHCP_OPTION_MESSAGE_TYPE;
+        test.option_type.length = 1;
+        test.option_type.type = DHCP_DISCOVER;
+        assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 1);
+
+        test.message.op = 0;
+        assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0);
+        test.message.op = BOOTREQUEST;
+        assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 1);
+
+        test.message.htype = 0;
+        assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0);
+        test.message.htype = ARPHRD_ETHER;
+        assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 1);
+
+        test.message.hlen = 0;
+        assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0);
+        test.message.hlen = ETHER_ADDR_LEN;
+        assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 1);
+}
+
 int main(int argc, char *argv[]) {
         _cleanup_event_unref_ sd_event *e;
 
@@ -64,6 +120,7 @@ int main(int argc, char *argv[]) {
         assert_se(sd_event_new(&e) >= 0);
 
         test_basic(e);
+        test_message_handler();
 
         return 0;
 }