diff options
-rw-r--r-- | src/libsystemd-network/dhcp-server-internal.h | 5 | ||||
-rw-r--r-- | src/libsystemd-network/sd-dhcp-server.c | 30 | ||||
-rw-r--r-- | src/libsystemd-network/test-dhcp-server.c | 57 |
3 files changed, 88 insertions, 4 deletions
diff --git a/src/libsystemd-network/dhcp-server-internal.h b/src/libsystemd-network/dhcp-server-internal.h index 6484dd37ec..63883fab99 100644 --- a/src/libsystemd-network/dhcp-server-internal.h +++ b/src/libsystemd-network/dhcp-server-internal.h @@ -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); diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c index e4396a0c96..57fb09aca0 100644 --- a/src/libsystemd-network/sd-dhcp-server.c +++ b/src/libsystemd-network/sd-dhcp-server.c @@ -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) { diff --git a/src/libsystemd-network/test-dhcp-server.c b/src/libsystemd-network/test-dhcp-server.c index 2feb124036..dd0f29a04c 100644 --- a/src/libsystemd-network/test-dhcp-server.c +++ b/src/libsystemd-network/test-dhcp-server.c @@ -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; } |