From 3a864fe4a894745ac61f1ecabd7cadf04139a284 Mon Sep 17 00:00:00 2001 From: Tom Gundersen Date: Sat, 24 May 2014 19:38:17 +0200 Subject: sd-dhcp-server: bind to a given interface We will (at least at first), restrict our focus to running the server on at most one interface. --- src/libsystemd-network/dhcp-server-internal.h | 2 ++ src/libsystemd-network/sd-dhcp-server.c | 22 +++++++++++++++++++++- src/libsystemd-network/test-dhcp-server.c | 3 ++- src/systemd/sd-dhcp-server.h | 2 +- 4 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/libsystemd-network/dhcp-server-internal.h b/src/libsystemd-network/dhcp-server-internal.h index 8191ef7fd7..6484dd37ec 100644 --- a/src/libsystemd-network/dhcp-server-internal.h +++ b/src/libsystemd-network/dhcp-server-internal.h @@ -34,6 +34,8 @@ struct sd_dhcp_server { int event_priority; sd_event_source *receive_message; int fd; + + int index; }; DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp_server*, sd_dhcp_server_unref); diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c index a9768f8fa2..e4396a0c96 100644 --- a/src/libsystemd-network/sd-dhcp-server.c +++ b/src/libsystemd-network/sd-dhcp-server.c @@ -46,10 +46,11 @@ sd_dhcp_server *sd_dhcp_server_unref(sd_dhcp_server *server) { return NULL; } -int sd_dhcp_server_new(sd_dhcp_server **ret) { +int sd_dhcp_server_new(sd_dhcp_server **ret, int ifindex) { _cleanup_dhcp_server_unref_ sd_dhcp_server *server = NULL; assert_return(ret, -EINVAL); + assert_return(ifindex > 0, -EINVAL); server = new0(sd_dhcp_server, 1); if (!server) @@ -57,6 +58,7 @@ int sd_dhcp_server_new(sd_dhcp_server **ret) { server->n_ref = REFCNT_INIT; server->fd = -1; + server->index = ifindex; *ret = server; server = NULL; @@ -113,12 +115,16 @@ int sd_dhcp_server_stop(sd_dhcp_server *server) { static int server_receive_message(sd_event_source *s, int fd, uint32_t revents, void *userdata) { _cleanup_free_ uint8_t *message = NULL; + uint8_t cmsgbuf[CMSG_LEN(sizeof(struct in_pktinfo))]; sd_dhcp_server *server = userdata; struct iovec iov = {}; struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1, + .msg_control = cmsgbuf, + .msg_controllen = sizeof(cmsgbuf), }; + struct cmsghdr *cmsg; int buflen = 0, len, r; assert(server); @@ -140,6 +146,20 @@ static int server_receive_message(sd_event_source *s, int fd, if (len < buflen) return 0; + for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { + if (cmsg->cmsg_level == IPPROTO_IP && + cmsg->cmsg_type == IP_PKTINFO && + cmsg->cmsg_len == CMSG_LEN(sizeof(struct in_pktinfo))) { + struct in_pktinfo *info = (struct in_pktinfo*)CMSG_DATA(cmsg); + + /* TODO figure out if this can be done as a filter on the socket, like for IPv6 */ + if (server->index != info->ipi_ifindex) + return 0; + + break; + } + } + log_dhcp_server(server, "received message"); return 1; diff --git a/src/libsystemd-network/test-dhcp-server.c b/src/libsystemd-network/test-dhcp-server.c index 80d2184b70..2feb124036 100644 --- a/src/libsystemd-network/test-dhcp-server.c +++ b/src/libsystemd-network/test-dhcp-server.c @@ -32,7 +32,8 @@ static void test_basic(sd_event *event) { _cleanup_dhcp_server_unref_ sd_dhcp_server *server = NULL; - assert_se(sd_dhcp_server_new(&server) >= 0); + /* attach to loopback interface */ + assert_se(sd_dhcp_server_new(&server, 1) >= 0); assert_se(server); assert_se(sd_dhcp_server_attach_event(server, event, 0) >= 0); diff --git a/src/systemd/sd-dhcp-server.h b/src/systemd/sd-dhcp-server.h index 47962e550c..ab63294ac5 100644 --- a/src/systemd/sd-dhcp-server.h +++ b/src/systemd/sd-dhcp-server.h @@ -32,7 +32,7 @@ typedef struct sd_dhcp_server sd_dhcp_server; sd_dhcp_server *sd_dhcp_server_ref(sd_dhcp_server *server); sd_dhcp_server *sd_dhcp_server_unref(sd_dhcp_server *server); -int sd_dhcp_server_new(sd_dhcp_server **ret); +int sd_dhcp_server_new(sd_dhcp_server **ret, int ifindex); int sd_dhcp_server_attach_event(sd_dhcp_server *client, sd_event *event, int priority); int sd_dhcp_server_detach_event(sd_dhcp_server *client); -- cgit v1.2.3-54-g00ecf