[systemd-devel] How to escape from systemd slice

2014-05-26 Thread Maciej Piechotka
Hi,

I have following problem - I want to run processes from ssh which outlive the 
connection (think tmux or mosh) but I cannot get it to work. I believe that 
the processes are killed when the slice is killed as even opening new PAM 
session does not help and the process is still displayed in the slice.

I'd prefer a method which could be run without elevated priviliges as it's 
most likely to be accepted upstream (mosh - tmux AFAIK believes systemd 
should not kill it).

Best regards

___
systemd-devel mailing list
systemd-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/systemd-devel


[systemd-devel] [PATCH 03/17] sd-dhcp-server: add basic functionality for starting/stopping server

2014-05-26 Thread Tom Gundersen
Bind to UDP socket and listen for messages, discarding anything we receive.
---
 src/libsystemd-network/dhcp-server-internal.h |  2 +
 src/libsystemd-network/sd-dhcp-server.c   | 89 +++
 src/libsystemd-network/test-dhcp-server.c |  6 ++
 src/systemd/sd-dhcp-server.h  |  3 +
 4 files changed, 100 insertions(+)

diff --git a/src/libsystemd-network/dhcp-server-internal.h 
b/src/libsystemd-network/dhcp-server-internal.h
index e09b359..8191ef7 100644
--- a/src/libsystemd-network/dhcp-server-internal.h
+++ b/src/libsystemd-network/dhcp-server-internal.h
@@ -32,6 +32,8 @@ struct sd_dhcp_server {
 
 sd_event *event;
 int event_priority;
+sd_event_source *receive_message;
+int fd;
 };
 
 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 885d68d..a9768f8 100644
--- a/src/libsystemd-network/sd-dhcp-server.c
+++ b/src/libsystemd-network/sd-dhcp-server.c
@@ -20,8 +20,11 @@
   along with systemd; If not, see http://www.gnu.org/licenses/.
 ***/
 
+#include sys/ioctl.h
+
 #include sd-dhcp-server.h
 #include dhcp-server-internal.h
+#include dhcp-internal.h
 
 sd_dhcp_server *sd_dhcp_server_ref(sd_dhcp_server *server) {
 if (server)
@@ -34,6 +37,8 @@ sd_dhcp_server *sd_dhcp_server_unref(sd_dhcp_server *server) {
 if (server  REFCNT_DEC(server-n_ref) = 0) {
 log_dhcp_server(server, UNREF);
 
+sd_dhcp_server_stop(server);
+
 sd_event_unref(server-event);
 free(server);
 }
@@ -51,6 +56,7 @@ int sd_dhcp_server_new(sd_dhcp_server **ret) {
 return -ENOMEM;
 
 server-n_ref = REFCNT_INIT;
+server-fd = -1;
 
 *ret = server;
 server = NULL;
@@ -90,3 +96,86 @@ sd_event *sd_dhcp_server_get_event(sd_dhcp_server *server) {
 
 return server-event;
 }
+
+int sd_dhcp_server_stop(sd_dhcp_server *server) {
+assert_return(server, -EINVAL);
+
+server-receive_message =
+sd_event_source_unref(server-receive_message);
+
+server-fd = safe_close(server-fd);
+
+log_dhcp_server(server, STOPPED);
+
+return 0;
+}
+
+static int server_receive_message(sd_event_source *s, int fd,
+  uint32_t revents, void *userdata) {
+_cleanup_free_ uint8_t *message = NULL;
+sd_dhcp_server *server = userdata;
+struct iovec iov = {};
+struct msghdr msg = {
+.msg_iov = iov,
+.msg_iovlen = 1,
+};
+int buflen = 0, len, r;
+
+assert(server);
+
+r = ioctl(fd, FIONREAD, buflen);
+if (r  0)
+return r;
+if (buflen  0)
+return -EIO;
+
+message = malloc0(buflen);
+if (!message)
+return -ENOMEM;
+
+iov.iov_base = message;
+iov.iov_len = buflen;
+
+len = recvmsg(fd, msg, 0);
+if (len  buflen)
+return 0;
+
+log_dhcp_server(server, received message);
+
+return 1;
+}
+
+int sd_dhcp_server_start(sd_dhcp_server *server) {
+int r;
+
+assert_return(server, -EINVAL);
+assert_return(server-event, -EINVAL);
+assert_return(!server-receive_message, -EBUSY);
+assert_return(server-fd == -1, -EBUSY);
+
+r = dhcp_network_bind_udp_socket(INADDR_ANY, DHCP_PORT_SERVER);
+if (r  0) {
+sd_dhcp_server_stop(server);
+return r;
+}
+server-fd = r;
+
+r = sd_event_add_io(server-event, server-receive_message,
+server-fd, EPOLLIN,
+server_receive_message, server);
+if (r  0) {
+sd_dhcp_server_stop(server);
+return r;
+}
+
+r = sd_event_source_set_priority(server-receive_message,
+ server-event_priority);
+if (r  0) {
+sd_dhcp_server_stop(server);
+return r;
+}
+
+log_dhcp_server(server, STARTED);
+
+return 0;
+}
diff --git a/src/libsystemd-network/test-dhcp-server.c 
b/src/libsystemd-network/test-dhcp-server.c
index bd0913d..80d2184 100644
--- a/src/libsystemd-network/test-dhcp-server.c
+++ b/src/libsystemd-network/test-dhcp-server.c
@@ -45,6 +45,12 @@ static void test_basic(sd_event *event) {
 
 assert_se(sd_dhcp_server_ref(server) == server);
 assert_se(!sd_dhcp_server_unref(server));
+
+assert_se(sd_dhcp_server_start(server) = 0);
+assert_se(sd_dhcp_server_start(server) == -EBUSY);
+assert_se(sd_dhcp_server_stop(server) = 0);
+assert_se(sd_dhcp_server_stop(server) = 0);
+assert_se(sd_dhcp_server_start(server) = 0);
 }
 
 int main(int argc, char *argv[]) {
diff --git 

[systemd-devel] [PATCH 01/17] dhcp-network: allow UDP socket to listen on any address

2014-05-26 Thread Tom Gundersen
For this to work nicely we need to use REUSEADDR so that more than one socket
can be open at the same time. Also, we request the ifindex to be appended
to incoming messages, so we know whence it came.
---
 src/libsystemd-network/dhcp-network.c | 15 +--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/src/libsystemd-network/dhcp-network.c 
b/src/libsystemd-network/dhcp-network.c
index dd26ef3..6fac80e 100644
--- a/src/libsystemd-network/dhcp-network.c
+++ b/src/libsystemd-network/dhcp-network.c
@@ -68,7 +68,7 @@ int dhcp_network_bind_raw_socket(int index, union 
sockaddr_union *link,
 .filter = filter
 };
 _cleanup_close_ int s = -1;
-int r, one = 1;
+int r, on = 1;
 
 assert(index  0);
 assert(link);
@@ -77,7 +77,7 @@ int dhcp_network_bind_raw_socket(int index, union 
sockaddr_union *link,
 if (s  0)
 return -errno;
 
-r = setsockopt (s, SOL_PACKET, PACKET_AUXDATA, one, sizeof(one));
+r = setsockopt (s, SOL_PACKET, PACKET_AUXDATA, on, sizeof(on));
 if (r  0)
 return -errno;
 
@@ -117,6 +117,17 @@ int dhcp_network_bind_udp_socket(be32_t address, uint16_t 
port) {
 r = setsockopt(s, IPPROTO_IP, IP_TOS, tos, sizeof(tos));
 if (r  0)
 return -errno;
+if (address == INADDR_ANY) {
+int on = 1;
+
+r = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, on, sizeof(on));
+if (r  0)
+return -errno;
+
+r = setsockopt(s, IPPROTO_IP, IP_PKTINFO, on, sizeof(on));
+if (r  0)
+return -errno;
+}
 
 r = bind(s, src.sa, sizeof(src.in));
 if (r  0)
-- 
1.9.0

___
systemd-devel mailing list
systemd-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/systemd-devel


[systemd-devel] [RFC] sd-dhcp-server: add a basic DHCPv4 server library

2014-05-26 Thread Tom Gundersen
This is the beginning of DHCPv4 server support in networkd.

The main usecase I'm targeting is to be able to hand out DHCP
leases to containers on the local machine.

I have attempted to keep the library as minimal as possible to
make reviewing easier, but we'd abviously need a few more
features before this would be generally useful (in particular
we need to provide more options in the leases we hand out).

Feedback welcome!

Cheers,

Tom

___
systemd-devel mailing list
systemd-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/systemd-devel


[systemd-devel] [PATCH 06/17] sd-dhcp-server: add basic message parsing

2014-05-26 Thread Tom Gundersen
Parse the maximum message size the client can accept and the client id, falling 
back to
sane defaults if they are not set.
---
 src/libsystemd-network/dhcp-server-internal.h | 15 +
 src/libsystemd-network/sd-dhcp-server.c   | 88 ++-
 2 files changed, 101 insertions(+), 2 deletions(-)

diff --git a/src/libsystemd-network/dhcp-server-internal.h 
b/src/libsystemd-network/dhcp-server-internal.h
index 63883fa..3d49cba 100644
--- a/src/libsystemd-network/dhcp-server-internal.h
+++ b/src/libsystemd-network/dhcp-server-internal.h
@@ -40,6 +40,21 @@ struct sd_dhcp_server {
 int index;
 };
 
+typedef struct DHCPClientId {
+size_t length;
+uint8_t *data;
+} DHCPClientId;
+
+typedef struct DHCPRequest {
+/* received message */
+DHCPMessage *message;
+
+/* options */
+DHCPClientId client_id;
+size_t max_optlen;
+be32_t server_id;
+} DHCPRequest;
+
 DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp_server*, sd_dhcp_server_unref);
 #define _cleanup_dhcp_server_unref_ _cleanup_(sd_dhcp_server_unrefp)
 
diff --git a/src/libsystemd-network/sd-dhcp-server.c 
b/src/libsystemd-network/sd-dhcp-server.c
index 57fb09a..b1f2fa0 100644
--- a/src/libsystemd-network/sd-dhcp-server.c
+++ b/src/libsystemd-network/sd-dhcp-server.c
@@ -113,9 +113,84 @@ int sd_dhcp_server_stop(sd_dhcp_server *server) {
 return 0;
 }
 
+static int parse_request(uint8_t code, uint8_t len, const uint8_t *option,
+ void *user_data) {
+DHCPRequest *req = user_data;
+
+assert(req);
+
+switch(code) {
+case DHCP_OPTION_SERVER_IDENTIFIER:
+if (len == 4)
+req-server_id = *(be32_t*)option;
+
+break;
+case DHCP_OPTION_CLIENT_IDENTIFIER:
+if (len = 2) {
+uint8_t *data;
+
+data = memdup(option, len);
+if (!data)
+return -ENOMEM;
+
+free(req-client_id.data);
+req-client_id.data = data;
+req-client_id.length = len;
+}
+
+break;
+case DHCP_OPTION_MAXIMUM_MESSAGE_SIZE:
+if (len == 2)
+req-max_optlen = be16toh(*(be16_t*)option) -
+  - sizeof(DHCPPacket);
+
+break;
+}
+
+return 0;
+}
+
+static void dhcp_request_free(DHCPRequest *req) {
+if (!req)
+return;
+
+free(req-client_id.data);
+free(req);
+}
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(DHCPRequest*, dhcp_request_free);
+#define _cleanup_dhcp_request_free_ _cleanup_(dhcp_request_freep)
+
+static int ensure_sane_request(DHCPRequest *req, DHCPMessage *message) {
+assert(req);
+assert(message);
+
+req-message = message;
+
+/* set client id based on mac address if client did not send an 
explicit one */
+if (!req-client_id.data) {
+uint8_t *data;
+
+data = new0(uint8_t, ETH_ALEN + 1);
+if (!data)
+return -ENOMEM;
+
+req-client_id.length = ETH_ALEN + 1;
+req-client_id.data = data;
+req-client_id.data[0] = 0x01;
+memcpy(req-client_id.data[1], message-chaddr, ETH_ALEN);
+}
+
+if (req-max_optlen  DHCP_MIN_OPTIONS_SIZE)
+req-max_optlen = DHCP_MIN_OPTIONS_SIZE;
+
+return 0;
+}
+
 int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
size_t length) {
-int type;
+_cleanup_dhcp_request_free_ DHCPRequest *req = NULL;
+int type, r;
 
 assert(server);
 assert(message);
@@ -125,10 +200,19 @@ int dhcp_server_handle_message(sd_dhcp_server *server, 
DHCPMessage *message,
 message-hlen != ETHER_ADDR_LEN)
 return 0;
 
-type = dhcp_option_parse(message, length, NULL, NULL);
+req = new0(DHCPRequest, 1);
+if (!req)
+return -ENOMEM;
+
+type = dhcp_option_parse(message, length, parse_request, req);
 if (type  0)
 return 0;
 
+r = ensure_sane_request(req, message);
+if (r  0)
+/* this only fails on critical errors */
+return r;
+
 log_dhcp_server(server, received message of type %d, type);
 
 return 1;
-- 
1.9.0

___
systemd-devel mailing list
systemd-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/systemd-devel


[systemd-devel] [PATCH 02/17] sd-dhcp-server: add basic functionality for creating/destroying server instance

2014-05-26 Thread Tom Gundersen
---
 .gitignore|  1 +
 Makefile.am   | 12 
 src/libsystemd-network/dhcp-network.c |  1 +
 src/libsystemd-network/dhcp-server-internal.h | 40 
 src/libsystemd-network/sd-dhcp-server.c   | 92 +++
 src/libsystemd-network/test-dhcp-server.c | 62 ++
 src/systemd/sd-dhcp-server.h  | 41 
 7 files changed, 249 insertions(+)
 create mode 100644 src/libsystemd-network/dhcp-server-internal.h
 create mode 100644 src/libsystemd-network/sd-dhcp-server.c
 create mode 100644 src/libsystemd-network/test-dhcp-server.c
 create mode 100644 src/systemd/sd-dhcp-server.h

diff --git a/.gitignore b/.gitignore
index 908c563..94bc5e7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -138,6 +138,7 @@
 /test-date
 /test-device-nodes
 /test-dhcp-client
+/test-dhcp-server
 /test-dhcp-option
 /test-resolve
 /test-ellipsize
diff --git a/Makefile.am b/Makefile.am
index 4b60735..023d7f0 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -2491,15 +2491,18 @@ libsystemd_network_la_CFLAGS = \
 libsystemd_network_la_SOURCES = \
src/systemd/sd-network.h \
src/systemd/sd-dhcp-client.h \
+   src/systemd/sd-dhcp-server.h \
src/systemd/sd-dhcp-lease.h \
src/systemd/sd-ipv4ll.h \
src/network/sd-network.c \
src/network/network-util.h \
src/libsystemd-network/sd-dhcp-client.c \
+   src/libsystemd-network/sd-dhcp-server.c \
src/libsystemd-network/dhcp-network.c \
src/libsystemd-network/dhcp-option.c \
src/libsystemd-network/dhcp-packet.c \
src/libsystemd-network/dhcp-internal.h \
+   src/libsystemd-network/dhcp-server-internal.h \
src/libsystemd-network/dhcp-protocol.h \
src/libsystemd-network/dhcp-lease-internal.h \
src/libsystemd-network/sd-dhcp-lease.c \
@@ -2539,6 +2542,14 @@ test_dhcp_client_LDADD = \
libsystemd-internal.la \
libsystemd-shared.la
 
+test_dhcp_server_SOURCES = \
+   src/libsystemd-network/test-dhcp-server.c
+
+test_dhcp_server_LDADD = \
+   libsystemd-network.la \
+   libsystemd-internal.la \
+   libsystemd-shared.la
+
 test_ipv4ll_SOURCES = \
src/systemd/sd-ipv4ll.h \
src/libsystemd-network/ipv4ll-internal.h \
@@ -2553,6 +2564,7 @@ test_ipv4ll_LDADD = \
 tests += \
test-dhcp-option \
test-dhcp-client \
+   test-dhcp-server \
test-ipv4ll
 
 # 
--
diff --git a/src/libsystemd-network/dhcp-network.c 
b/src/libsystemd-network/dhcp-network.c
index 6fac80e..266bf13 100644
--- a/src/libsystemd-network/dhcp-network.c
+++ b/src/libsystemd-network/dhcp-network.c
@@ -117,6 +117,7 @@ int dhcp_network_bind_udp_socket(be32_t address, uint16_t 
port) {
 r = setsockopt(s, IPPROTO_IP, IP_TOS, tos, sizeof(tos));
 if (r  0)
 return -errno;
+
 if (address == INADDR_ANY) {
 int on = 1;
 
diff --git a/src/libsystemd-network/dhcp-server-internal.h 
b/src/libsystemd-network/dhcp-server-internal.h
new file mode 100644
index 000..e09b359
--- /dev/null
+++ b/src/libsystemd-network/dhcp-server-internal.h
@@ -0,0 +1,40 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright (C) 2013 Intel Corporation. All rights reserved.
+  Copyright (C) 2014 Tom Gundersen
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see http://www.gnu.org/licenses/.
+***/
+
+#include sd-event.h
+#include sd-dhcp-server.h
+
+#include refcnt.h
+#include util.h
+#include log.h
+
+struct sd_dhcp_server {
+RefCount n_ref;
+
+sd_event *event;
+int event_priority;
+};
+
+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__)
diff --git a/src/libsystemd-network/sd-dhcp-server.c 
b/src/libsystemd-network/sd-dhcp-server.c
new file mode 100644
index 000..885d68d
--- /dev/null
+++ b/src/libsystemd-network/sd-dhcp-server.c
@@ -0,0 +1,92 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 

[systemd-devel] [PATCH 04/17] sd-dhcp-server: bind to a given interface

2014-05-26 Thread Tom Gundersen
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 8191ef7..6484dd3 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 a9768f8..e4396a0 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 80d2184..2feb124 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 47962e5..ab63294 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);
-- 
1.9.0

___
systemd-devel mailing list
systemd-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/systemd-devel


[systemd-devel] [PATCH 10/17] sd-dhcp-server: add basic DISCOVER/OFFER support

2014-05-26 Thread Tom Gundersen
---
 src/libsystemd-network/sd-dhcp-server.c   | 81 ++-
 src/libsystemd-network/test-dhcp-server.c | 14 +++---
 2 files changed, 86 insertions(+), 9 deletions(-)

diff --git a/src/libsystemd-network/sd-dhcp-server.c 
b/src/libsystemd-network/sd-dhcp-server.c
index cea7390..be6938b 100644
--- a/src/libsystemd-network/sd-dhcp-server.c
+++ b/src/libsystemd-network/sd-dhcp-server.c
@@ -27,6 +27,8 @@
 #include dhcp-server-internal.h
 #include dhcp-internal.h
 
+#define DHCP_DEFAULT_LEASE_TIME 60
+
 int sd_dhcp_server_set_address(sd_dhcp_server *server, struct in_addr 
*address) {
 assert_return(server, -EINVAL);
 assert_return(address, -EINVAL);
@@ -277,6 +279,64 @@ int dhcp_server_send_packet(sd_dhcp_server *server,
 sizeof(DHCPPacket) + 
optoffset);
 }
 
+static int server_message_init(sd_dhcp_server *server, DHCPPacket **ret,
+   uint8_t type, size_t *_optoffset, DHCPRequest 
*req) {
+_cleanup_free_ DHCPPacket *packet = NULL;
+size_t optoffset;
+int r;
+
+assert(server);
+assert(ret);
+assert(_optoffset);
+assert(type == DHCP_OFFER);
+
+packet = malloc0(sizeof(DHCPPacket) + req-max_optlen);
+if (!packet)
+return -ENOMEM;
+
+r = dhcp_message_init(packet-dhcp, BOOTREPLY, 
be32toh(req-message-xid),
+  type, req-max_optlen, optoffset);
+if (r  0)
+return r;
+
+packet-dhcp.flags = req-message-flags;
+packet-dhcp.giaddr = req-message-giaddr;
+memcpy(packet-dhcp.chaddr, req-message-chaddr, ETH_ALEN);
+
+*_optoffset = optoffset;
+*ret = packet;
+packet = NULL;
+
+return 0;
+}
+
+static int server_send_offer(sd_dhcp_server *server, DHCPRequest *req) {
+_cleanup_free_ DHCPPacket *packet = NULL;
+size_t offset;
+be32_t lease_time;
+int r;
+
+r = server_message_init(server, packet, DHCP_OFFER, offset, req);
+if (r  0)
+return r;
+
+/* for now offer a random IP */
+packet-dhcp.yiaddr = random_u32();
+
+/* for ten seconds */
+lease_time = htobe32(DHCP_DEFAULT_LEASE_TIME);
+r = dhcp_option_append(packet-dhcp, req-max_optlen, offset, 0,
+   DHCP_OPTION_IP_ADDRESS_LEASE_TIME, 4, 
lease_time);
+if (r  0)
+return r;
+
+r = dhcp_server_send_packet(server, req, packet, DHCP_OFFER, offset);
+if (r  0)
+return r;
+
+return 0;
+}
+
 static int parse_request(uint8_t code, uint8_t len, const uint8_t *option,
  void *user_data) {
 DHCPRequest *req = user_data;
@@ -377,9 +437,26 @@ int dhcp_server_handle_message(sd_dhcp_server *server, 
DHCPMessage *message,
 /* this only fails on critical errors */
 return r;
 
-log_dhcp_server(server, received message of type %d, type);
+switch(type) {
+case DHCP_DISCOVER:
+log_dhcp_server(server, DISCOVER (0x%x),
+be32toh(req-message-xid));
+
+r = server_send_offer(server, req);
+if (r  0) {
+log_dhcp_server(server, could not send offer: %s,
+strerror(-r));
+return 0;
+} else {
+log_dhcp_server(server, OFFER (0x%x),
+be32toh(req-message-xid));
+return DHCP_OFFER;
+}
+
+break;
+}
 
-return 1;
+return 0;
 }
 
 static int server_receive_message(sd_event_source *s, int fd,
diff --git a/src/libsystemd-network/test-dhcp-server.c 
b/src/libsystemd-network/test-dhcp-server.c
index 0cbb4df..ed3aaf9 100644
--- a/src/libsystemd-network/test-dhcp-server.c
+++ b/src/libsystemd-network/test-dhcp-server.c
@@ -94,13 +94,13 @@ static void test_message_handler(void) {
 assert_se(sd_dhcp_server_attach_event(server, NULL, 0) = 0);
 assert_se(sd_dhcp_server_start(server) = 0);
 
-assert_se(dhcp_server_handle_message(server, (DHCPMessage*)test, 
sizeof(test)) == 1);
+assert_se(dhcp_server_handle_message(server, (DHCPMessage*)test, 
sizeof(test)) == DHCP_OFFER);
 
 test.end = 0;
 /* TODO, shouldn't this fail? */
-assert_se(dhcp_server_handle_message(server, (DHCPMessage*)test, 
sizeof(test)) == 1);
+assert_se(dhcp_server_handle_message(server, (DHCPMessage*)test, 
sizeof(test)) == DHCP_OFFER);
 test.end = DHCP_OPTION_END;
-assert_se(dhcp_server_handle_message(server, (DHCPMessage*)test, 
sizeof(test)) == 1);
+assert_se(dhcp_server_handle_message(server, (DHCPMessage*)test, 
sizeof(test)) == DHCP_OFFER);
 

[systemd-devel] [PATCH 08/17] sd-dhcp-server: add support for setting the server address

2014-05-26 Thread Tom Gundersen
---
 src/libsystemd-network/dhcp-server-internal.h |  1 +
 src/libsystemd-network/sd-dhcp-server.c   | 13 +
 src/libsystemd-network/test-dhcp-server.c | 17 +
 src/systemd/sd-dhcp-server.h  |  1 +
 4 files changed, 32 insertions(+)

diff --git a/src/libsystemd-network/dhcp-server-internal.h 
b/src/libsystemd-network/dhcp-server-internal.h
index 6c2f2b4..58a9877 100644
--- a/src/libsystemd-network/dhcp-server-internal.h
+++ b/src/libsystemd-network/dhcp-server-internal.h
@@ -39,6 +39,7 @@ struct sd_dhcp_server {
 int fd_raw;
 
 int index;
+be32_t address;
 };
 
 typedef struct DHCPClientId {
diff --git a/src/libsystemd-network/sd-dhcp-server.c 
b/src/libsystemd-network/sd-dhcp-server.c
index ecdc15d..7d6170c 100644
--- a/src/libsystemd-network/sd-dhcp-server.c
+++ b/src/libsystemd-network/sd-dhcp-server.c
@@ -27,6 +27,17 @@
 #include dhcp-server-internal.h
 #include dhcp-internal.h
 
+int sd_dhcp_server_set_address(sd_dhcp_server *server, struct in_addr 
*address) {
+assert_return(server, -EINVAL);
+assert_return(address, -EINVAL);
+assert_return(address-s_addr, -EINVAL);
+assert_return(server-address == htobe32(INADDR_ANY), -EBUSY);
+
+server-address = address-s_addr;
+
+return 0;
+}
+
 sd_dhcp_server *sd_dhcp_server_ref(sd_dhcp_server *server) {
 if (server)
 assert_se(REFCNT_INC(server-n_ref) = 2);
@@ -60,6 +71,7 @@ int sd_dhcp_server_new(sd_dhcp_server **ret, int ifindex) {
 server-n_ref = REFCNT_INIT;
 server-fd_raw = -1;
 server-fd = -1;
+server-address = htobe32(INADDR_ANY);
 server-index = ifindex;
 
 *ret = server;
@@ -281,6 +293,7 @@ int sd_dhcp_server_start(sd_dhcp_server *server) {
 assert_return(!server-receive_message, -EBUSY);
 assert_return(server-fd_raw == -1, -EBUSY);
 assert_return(server-fd == -1, -EBUSY);
+assert_return(server-address != htobe32(INADDR_ANY), -EBUSY);
 
 r = socket(AF_PACKET, SOCK_DGRAM | SOCK_NONBLOCK, 0);
 if (r  0) {
diff --git a/src/libsystemd-network/test-dhcp-server.c 
b/src/libsystemd-network/test-dhcp-server.c
index dd0f29a..0cbb4df 100644
--- a/src/libsystemd-network/test-dhcp-server.c
+++ b/src/libsystemd-network/test-dhcp-server.c
@@ -32,6 +32,12 @@
 
 static void test_basic(sd_event *event) {
 _cleanup_dhcp_server_unref_ sd_dhcp_server *server = NULL;
+struct in_addr address_lo = {
+.s_addr = htonl(INADDR_LOOPBACK),
+};
+struct in_addr address_any = {
+.s_addr = htonl(INADDR_ANY),
+};
 
 /* attach to loopback interface */
 assert_se(sd_dhcp_server_new(server, 1) = 0);
@@ -48,6 +54,11 @@ static void test_basic(sd_event *event) {
 assert_se(sd_dhcp_server_ref(server) == server);
 assert_se(!sd_dhcp_server_unref(server));
 
+assert_se(sd_dhcp_server_start(server) == -EBUSY);
+assert_se(sd_dhcp_server_set_address(server, address_any) == -EINVAL);
+assert_se(sd_dhcp_server_set_address(server, address_lo) = 0);
+assert_se(sd_dhcp_server_set_address(server, address_lo) == -EBUSY);
+
 assert_se(sd_dhcp_server_start(server) = 0);
 assert_se(sd_dhcp_server_start(server) == -EBUSY);
 assert_se(sd_dhcp_server_stop(server) = 0);
@@ -74,8 +85,14 @@ static void test_message_handler(void) {
 .option_type.type = DHCP_DISCOVER,
 .end = DHCP_OPTION_END,
 };
+struct in_addr address_lo = {
+.s_addr = htonl(INADDR_LOOPBACK),
+};
 
 assert_se(sd_dhcp_server_new(server, 1) = 0);
+assert_se(sd_dhcp_server_set_address(server, address_lo) = 0);
+assert_se(sd_dhcp_server_attach_event(server, NULL, 0) = 0);
+assert_se(sd_dhcp_server_start(server) = 0);
 
 assert_se(dhcp_server_handle_message(server, (DHCPMessage*)test, 
sizeof(test)) == 1);
 
diff --git a/src/systemd/sd-dhcp-server.h b/src/systemd/sd-dhcp-server.h
index ab63294..5edeffc 100644
--- a/src/systemd/sd-dhcp-server.h
+++ b/src/systemd/sd-dhcp-server.h
@@ -41,4 +41,5 @@ sd_event *sd_dhcp_server_get_event(sd_dhcp_server *client);
 int sd_dhcp_server_start(sd_dhcp_server *server);
 int sd_dhcp_server_stop(sd_dhcp_server *server);
 
+int sd_dhcp_server_set_address(sd_dhcp_server *server, struct in_addr 
*address);
 #endif
-- 
1.9.0

___
systemd-devel mailing list
systemd-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/systemd-devel


[systemd-devel] [PATCH 13/17] sd-dhcp-server: add support for clients requesting lease lifetime

2014-05-26 Thread Tom Gundersen
---
 src/libsystemd-network/dhcp-server-internal.h |  1 +
 src/libsystemd-network/sd-dhcp-server.c   | 14 ++
 2 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/src/libsystemd-network/dhcp-server-internal.h 
b/src/libsystemd-network/dhcp-server-internal.h
index cd480e7..ce2e260 100644
--- a/src/libsystemd-network/dhcp-server-internal.h
+++ b/src/libsystemd-network/dhcp-server-internal.h
@@ -58,6 +58,7 @@ typedef struct DHCPRequest {
 size_t max_optlen;
 be32_t server_id;
 be32_t requested_ip;
+int lifetime;
 } DHCPRequest;
 
 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 b82bef8..3de61f7 100644
--- a/src/libsystemd-network/sd-dhcp-server.c
+++ b/src/libsystemd-network/sd-dhcp-server.c
@@ -337,8 +337,7 @@ static int server_send_offer(sd_dhcp_server *server, 
DHCPRequest *req, be32_t ad
 
 packet-dhcp.yiaddr = address;
 
-/* for ten seconds */
-lease_time = htobe32(DHCP_DEFAULT_LEASE_TIME);
+lease_time = htobe32(req-lifetime);
 r = dhcp_option_append(packet-dhcp, req-max_optlen, offset, 0,
DHCP_OPTION_IP_ADDRESS_LEASE_TIME, 4, 
lease_time);
 if (r  0)
@@ -363,8 +362,7 @@ static int server_send_ack(sd_dhcp_server *server, 
DHCPRequest *req, be32_t addr
 
 packet-dhcp.yiaddr = address;
 
-/* for ten seconds */
-lease_time = htobe32(DHCP_DEFAULT_LEASE_TIME);
+lease_time = htobe32(req-lifetime);
 r = dhcp_option_append(packet-dhcp, req-max_optlen, offset, 0,
DHCP_OPTION_IP_ADDRESS_LEASE_TIME, 4, 
lease_time);
 if (r  0)
@@ -400,6 +398,11 @@ static int parse_request(uint8_t code, uint8_t len, const 
uint8_t *option,
 assert(req);
 
 switch(code) {
+case DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
+if (len == 4)
+req-lifetime = be32toh(*(be32_t*)option);
+
+break;
 case DHCP_OPTION_REQUESTED_IP_ADDRESS:
 if (len == 4)
 req-requested_ip = *(be32_t*)option;
@@ -469,6 +472,9 @@ static int ensure_sane_request(DHCPRequest *req, 
DHCPMessage *message) {
 if (req-max_optlen  DHCP_MIN_OPTIONS_SIZE)
 req-max_optlen = DHCP_MIN_OPTIONS_SIZE;
 
+if (!req-lifetime)
+req-lifetime = DHCP_DEFAULT_LEASE_TIME;
+
 return 0;
 }
 
-- 
1.9.0

___
systemd-devel mailing list
systemd-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/systemd-devel


[systemd-devel] [PATCH 07/17] sd-dhcp-server: bind to raw socket for sending

2014-05-26 Thread Tom Gundersen
We would like to use the UDP socket, but we cannot as we need to specify
the MAC address manually.
---
 src/libsystemd-network/dhcp-server-internal.h |  1 +
 src/libsystemd-network/sd-dhcp-server.c   | 11 +++
 2 files changed, 12 insertions(+)

diff --git a/src/libsystemd-network/dhcp-server-internal.h 
b/src/libsystemd-network/dhcp-server-internal.h
index 3d49cba..6c2f2b4 100644
--- a/src/libsystemd-network/dhcp-server-internal.h
+++ b/src/libsystemd-network/dhcp-server-internal.h
@@ -36,6 +36,7 @@ struct sd_dhcp_server {
 int event_priority;
 sd_event_source *receive_message;
 int fd;
+int fd_raw;
 
 int index;
 };
diff --git a/src/libsystemd-network/sd-dhcp-server.c 
b/src/libsystemd-network/sd-dhcp-server.c
index b1f2fa0..ecdc15d 100644
--- a/src/libsystemd-network/sd-dhcp-server.c
+++ b/src/libsystemd-network/sd-dhcp-server.c
@@ -58,6 +58,7 @@ int sd_dhcp_server_new(sd_dhcp_server **ret, int ifindex) {
 return -ENOMEM;
 
 server-n_ref = REFCNT_INIT;
+server-fd_raw = -1;
 server-fd = -1;
 server-index = ifindex;
 
@@ -106,6 +107,7 @@ int sd_dhcp_server_stop(sd_dhcp_server *server) {
 server-receive_message =
 sd_event_source_unref(server-receive_message);
 
+server-fd_raw = safe_close(server-fd_raw);
 server-fd = safe_close(server-fd);
 
 log_dhcp_server(server, STOPPED);
@@ -277,8 +279,17 @@ int sd_dhcp_server_start(sd_dhcp_server *server) {
 assert_return(server, -EINVAL);
 assert_return(server-event, -EINVAL);
 assert_return(!server-receive_message, -EBUSY);
+assert_return(server-fd_raw == -1, -EBUSY);
 assert_return(server-fd == -1, -EBUSY);
 
+r = socket(AF_PACKET, SOCK_DGRAM | SOCK_NONBLOCK, 0);
+if (r  0) {
+r = -errno;
+sd_dhcp_server_stop(server);
+return r;
+}
+server-fd_raw = r;
+
 r = dhcp_network_bind_udp_socket(INADDR_ANY, DHCP_PORT_SERVER);
 if (r  0) {
 sd_dhcp_server_stop(server);
-- 
1.9.0

___
systemd-devel mailing list
systemd-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/systemd-devel


[systemd-devel] [PATCH 05/17] sd-dhcp-server: add basic message handling and verification

2014-05-26 Thread Tom Gundersen
---
 src/libsystemd-network/dhcp-server-internal.h |  5 +++
 src/libsystemd-network/sd-dhcp-server.c   | 30 --
 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 6484dd3..63883fa 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 e4396a0..57fb09a 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 2feb124..dd0f29a 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;
+

[systemd-devel] [PATCH 12/17] sd-dhcp-server: add basic NAK support

2014-05-26 Thread Tom Gundersen
---
 src/libsystemd-network/sd-dhcp-server.c   | 36 +++
 src/libsystemd-network/test-dhcp-server.c |  6 +++---
 2 files changed, 35 insertions(+), 7 deletions(-)

diff --git a/src/libsystemd-network/sd-dhcp-server.c 
b/src/libsystemd-network/sd-dhcp-server.c
index 01cd8be..b82bef8 100644
--- a/src/libsystemd-network/sd-dhcp-server.c
+++ b/src/libsystemd-network/sd-dhcp-server.c
@@ -303,7 +303,7 @@ static int server_message_init(sd_dhcp_server *server, 
DHCPPacket **ret,
 assert(server);
 assert(ret);
 assert(_optoffset);
-assert(IN_SET(type, DHCP_OFFER, DHCP_ACK));
+assert(IN_SET(type, DHCP_OFFER, DHCP_ACK, DHCP_NAK));
 
 packet = malloc0(sizeof(DHCPPacket) + req-max_optlen);
 if (!packet)
@@ -377,6 +377,22 @@ static int server_send_ack(sd_dhcp_server *server, 
DHCPRequest *req, be32_t addr
 return 0;
 }
 
+static int server_send_nak(sd_dhcp_server *server, DHCPRequest *req) {
+_cleanup_free_ DHCPPacket *packet = NULL;
+size_t offset;
+int r;
+
+r = server_message_init(server, packet, DHCP_NAK, offset, req);
+if (r  0)
+return r;
+
+r = dhcp_server_send_packet(server, req, packet, DHCP_NAK, offset);
+if (r  0)
+return r;
+
+return 0;
+}
+
 static int parse_request(uint8_t code, uint8_t len, const uint8_t *option,
  void *user_data) {
 DHCPRequest *req = user_data;
@@ -514,6 +530,7 @@ int dhcp_server_handle_message(sd_dhcp_server *server, 
DHCPMessage *message,
 case DHCP_REQUEST:
 {
 be32_t address;
+bool init_reboot = false;
 
 /* see RFC 2131, section 4.3.2 */
 
@@ -545,8 +562,9 @@ int dhcp_server_handle_message(sd_dhcp_server *server, 
DHCPMessage *message,
 /* this MUST be zero */
 return 0;
 
-/* TODO: check if requested IP is correct, NAK if not 
*/
+/* TODO: check more carefully if IP is correct */
 address = req-requested_ip;
+init_reboot = true;
 } else {
 log_dhcp_server(server, REQUEST (rebinding/renewing) 
(0x%x),
 be32toh(req-message-xid));
@@ -574,8 +592,18 @@ int dhcp_server_handle_message(sd_dhcp_server *server, 
DHCPMessage *message,
 be32toh(req-message-xid));
 return DHCP_ACK;
 }
-} else
-return 0;
+} else if (init_reboot) {
+r = server_send_nak(server, req);
+if (r  0) {
+log_dhcp_server(server, could not send nak: 
%s,
+strerror(-r));
+return 0;
+} else {
+log_dhcp_server(server, NAK (0x%x),
+be32toh(req-message-xid));
+return DHCP_NAK;
+}
+}
 
 break;
 }
diff --git a/src/libsystemd-network/test-dhcp-server.c 
b/src/libsystemd-network/test-dhcp-server.c
index 7255a69..ea256b9 100644
--- a/src/libsystemd-network/test-dhcp-server.c
+++ b/src/libsystemd-network/test-dhcp-server.c
@@ -150,7 +150,7 @@ static void test_message_handler(void) {
 test.option_requested_ip.code = DHCP_OPTION_REQUESTED_IP_ADDRESS;
 test.option_requested_ip.length = 4;
 test.option_requested_ip.address = htobe32(0x12345678);
-assert_se(dhcp_server_handle_message(server, (DHCPMessage*)test, 
sizeof(test)) == 0);
+assert_se(dhcp_server_handle_message(server, (DHCPMessage*)test, 
sizeof(test)) == DHCP_NAK);
 test.option_server_id.code = DHCP_OPTION_SERVER_IDENTIFIER;
 test.option_server_id.length = 4;
 test.option_server_id.address = htobe32(INADDR_LOOPBACK);
@@ -159,8 +159,8 @@ static void test_message_handler(void) {
 test.option_server_id.address = htobe32(0x12345678);
 test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 3);
 assert_se(dhcp_server_handle_message(server, (DHCPMessage*)test, 
sizeof(test)) == 0);
-test.option_server_id.address = htobe32(INADDR_LOOPBACK + 3);
-test.option_requested_ip.address = htobe32(0x12345678);
+test.option_server_id.address = htobe32(INADDR_LOOPBACK);
+test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 30);
 assert_se(dhcp_server_handle_message(server, (DHCPMessage*)test, 
sizeof(test)) == 0);
 }
 
-- 
1.9.0

___
systemd-devel mailing list

[systemd-devel] [PATCH 11/17] sd-dhcp-server: add basic REQUEST/ACK support

2014-05-26 Thread Tom Gundersen
---
 src/libsystemd-network/dhcp-server-internal.h |   3 +
 src/libsystemd-network/sd-dhcp-server.c   | 135 +-
 src/libsystemd-network/test-dhcp-server.c |  37 +++
 src/systemd/sd-dhcp-server.h  |   1 +
 4 files changed, 171 insertions(+), 5 deletions(-)

diff --git a/src/libsystemd-network/dhcp-server-internal.h 
b/src/libsystemd-network/dhcp-server-internal.h
index 381304e..cd480e7 100644
--- a/src/libsystemd-network/dhcp-server-internal.h
+++ b/src/libsystemd-network/dhcp-server-internal.h
@@ -40,6 +40,8 @@ struct sd_dhcp_server {
 
 int index;
 be32_t address;
+be32_t pool_start;
+size_t pool_size;
 };
 
 typedef struct DHCPClientId {
@@ -55,6 +57,7 @@ typedef struct DHCPRequest {
 DHCPClientId client_id;
 size_t max_optlen;
 be32_t server_id;
+be32_t requested_ip;
 } DHCPRequest;
 
 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 be6938b..01cd8be 100644
--- a/src/libsystemd-network/sd-dhcp-server.c
+++ b/src/libsystemd-network/sd-dhcp-server.c
@@ -29,6 +29,21 @@
 
 #define DHCP_DEFAULT_LEASE_TIME 60
 
+int sd_dhcp_server_set_lease_pool(sd_dhcp_server *server, struct in_addr 
*address,
+  size_t size) {
+assert_return(server, -EINVAL);
+assert_return(address, -EINVAL);
+assert_return(address-s_addr, -EINVAL);
+assert_return(size, -EINVAL);
+assert_return(server-pool_start == htobe32(INADDR_ANY), -EBUSY);
+assert_return(!server-pool_size, -EBUSY);
+
+server-pool_start = address-s_addr;
+server-pool_size = size;
+
+return 0;
+}
+
 int sd_dhcp_server_set_address(sd_dhcp_server *server, struct in_addr 
*address) {
 assert_return(server, -EINVAL);
 assert_return(address, -EINVAL);
@@ -288,7 +303,7 @@ static int server_message_init(sd_dhcp_server *server, 
DHCPPacket **ret,
 assert(server);
 assert(ret);
 assert(_optoffset);
-assert(type == DHCP_OFFER);
+assert(IN_SET(type, DHCP_OFFER, DHCP_ACK));
 
 packet = malloc0(sizeof(DHCPPacket) + req-max_optlen);
 if (!packet)
@@ -310,7 +325,7 @@ static int server_message_init(sd_dhcp_server *server, 
DHCPPacket **ret,
 return 0;
 }
 
-static int server_send_offer(sd_dhcp_server *server, DHCPRequest *req) {
+static int server_send_offer(sd_dhcp_server *server, DHCPRequest *req, be32_t 
address) {
 _cleanup_free_ DHCPPacket *packet = NULL;
 size_t offset;
 be32_t lease_time;
@@ -320,8 +335,7 @@ static int server_send_offer(sd_dhcp_server *server, 
DHCPRequest *req) {
 if (r  0)
 return r;
 
-/* for now offer a random IP */
-packet-dhcp.yiaddr = random_u32();
+packet-dhcp.yiaddr = address;
 
 /* for ten seconds */
 lease_time = htobe32(DHCP_DEFAULT_LEASE_TIME);
@@ -337,6 +351,32 @@ static int server_send_offer(sd_dhcp_server *server, 
DHCPRequest *req) {
 return 0;
 }
 
+static int server_send_ack(sd_dhcp_server *server, DHCPRequest *req, be32_t 
address) {
+_cleanup_free_ DHCPPacket *packet = NULL;
+size_t offset;
+be32_t lease_time;
+int r;
+
+r = server_message_init(server, packet, DHCP_ACK, offset, req);
+if (r  0)
+return r;
+
+packet-dhcp.yiaddr = address;
+
+/* for ten seconds */
+lease_time = htobe32(DHCP_DEFAULT_LEASE_TIME);
+r = dhcp_option_append(packet-dhcp, req-max_optlen, offset, 0,
+   DHCP_OPTION_IP_ADDRESS_LEASE_TIME, 4, 
lease_time);
+if (r  0)
+return r;
+
+r = dhcp_server_send_packet(server, req, packet, DHCP_ACK, offset);
+if (r  0)
+return r;
+
+return 0;
+}
+
 static int parse_request(uint8_t code, uint8_t len, const uint8_t *option,
  void *user_data) {
 DHCPRequest *req = user_data;
@@ -344,6 +384,11 @@ static int parse_request(uint8_t code, uint8_t len, const 
uint8_t *option,
 assert(req);
 
 switch(code) {
+case DHCP_OPTION_REQUESTED_IP_ADDRESS:
+if (len == 4)
+req-requested_ip = *(be32_t*)option;
+
+break;
 case DHCP_OPTION_SERVER_IDENTIFIER:
 if (len == 4)
 req-server_id = *(be32_t*)option;
@@ -439,10 +484,21 @@ int dhcp_server_handle_message(sd_dhcp_server *server, 
DHCPMessage *message,
 
 switch(type) {
 case DHCP_DISCOVER:
+{
+be32_t address;
+
 log_dhcp_server(server, DISCOVER (0x%x),
 be32toh(req-message-xid));
 
-r = server_send_offer(server, req);
+if 

[systemd-devel] [PATCH 15/17] sd-dhcp-server: add dummy DECLINE support

2014-05-26 Thread Tom Gundersen
---
 src/libsystemd-network/sd-dhcp-server.c | 9 +
 1 file changed, 9 insertions(+)

diff --git a/src/libsystemd-network/sd-dhcp-server.c 
b/src/libsystemd-network/sd-dhcp-server.c
index 44ca645..3ed93d8 100644
--- a/src/libsystemd-network/sd-dhcp-server.c
+++ b/src/libsystemd-network/sd-dhcp-server.c
@@ -623,6 +623,15 @@ int dhcp_server_handle_message(sd_dhcp_server *server, 
DHCPMessage *message,
 
 break;
 }
+case DHCP_DECLINE:
+log_dhcp_server(server, DECLINE (0x%x),
+be32toh(req-message-xid));
+
+/* TODO: make sure we don't offer this address again */
+
+return 1;
+
+break;
 case DHCP_REQUEST:
 {
 be32_t address;
-- 
1.9.0

___
systemd-devel mailing list
systemd-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/systemd-devel


[systemd-devel] [PATCH 16/17] sd-dhcp-server: add RELEASE support

2014-05-26 Thread Tom Gundersen
---
 src/libsystemd-network/sd-dhcp-server.c | 27 ++-
 1 file changed, 26 insertions(+), 1 deletion(-)

diff --git a/src/libsystemd-network/sd-dhcp-server.c 
b/src/libsystemd-network/sd-dhcp-server.c
index 3ed93d8..2d789be 100644
--- a/src/libsystemd-network/sd-dhcp-server.c
+++ b/src/libsystemd-network/sd-dhcp-server.c
@@ -544,7 +544,7 @@ static int get_pool_offset(sd_dhcp_server *server, be32_t 
requested_ip) {
 
 if (be32toh(requested_ip)  be32toh(server-pool_start) ||
 be32toh(requested_ip) = be32toh(server-pool_start) +
-  + server-pool_size)
+ + server-pool_size)
 return -EINVAL;
 
 return (be32toh(requested_ip) -
@@ -740,6 +740,31 @@ int dhcp_server_handle_message(sd_dhcp_server *server, 
DHCPMessage *message,
 
 break;
 }
+case DHCP_RELEASE: {
+int pool_offset;
+
+log_dhcp_server(server, RELEASE (0x%x),
+be32toh(req-message-xid));
+
+if (!existing_lease)
+return 0;
+
+if (existing_lease-address != req-message-ciaddr)
+return 0;
+
+pool_offset = get_pool_offset(server, req-message-ciaddr);
+if (pool_offset  0)
+return 0;
+
+if (server-bound_leases[pool_offset] == existing_lease) {
+server-bound_leases[pool_offset] = NULL;
+hashmap_remove(server-leases_by_client_id, 
existing_lease);
+dhcp_lease_free(existing_lease);
+
+return 1;
+} else
+return 0;
+}
 }
 
 return 0;
-- 
1.9.0

___
systemd-devel mailing list
systemd-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/systemd-devel


[systemd-devel] [PATCH 09/17] sd-dhcp-server: add support for sending messages

2014-05-26 Thread Tom Gundersen
---
 src/libsystemd-network/dhcp-server-internal.h |   3 +
 src/libsystemd-network/sd-dhcp-server.c   | 150 ++
 2 files changed, 153 insertions(+)

diff --git a/src/libsystemd-network/dhcp-server-internal.h 
b/src/libsystemd-network/dhcp-server-internal.h
index 58a9877..381304e 100644
--- a/src/libsystemd-network/dhcp-server-internal.h
+++ b/src/libsystemd-network/dhcp-server-internal.h
@@ -64,3 +64,6 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp_server*, 
sd_dhcp_server_unref);
 
 int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
size_t length);
+int dhcp_server_send_packet(sd_dhcp_server *server,
+DHCPRequest *req, DHCPPacket *packet,
+int type, size_t optoffset);
diff --git a/src/libsystemd-network/sd-dhcp-server.c 
b/src/libsystemd-network/sd-dhcp-server.c
index 7d6170c..cea7390 100644
--- a/src/libsystemd-network/sd-dhcp-server.c
+++ b/src/libsystemd-network/sd-dhcp-server.c
@@ -127,6 +127,156 @@ int sd_dhcp_server_stop(sd_dhcp_server *server) {
 return 0;
 }
 
+static int dhcp_server_send_unicast_raw(sd_dhcp_server *server, DHCPPacket 
*packet,
+size_t len) {
+union sockaddr_union link = {
+.ll.sll_family = AF_PACKET,
+.ll.sll_protocol = htons(ETH_P_IP),
+.ll.sll_ifindex = server-index,
+.ll.sll_halen = ETH_ALEN,
+};
+int r;
+
+assert(server);
+assert(server-index  0);
+assert(server-address);
+assert(packet);
+assert(len  sizeof(DHCPPacket));
+
+memcpy(link.ll.sll_addr, packet-dhcp.chaddr, ETH_ALEN);
+
+dhcp_packet_append_ip_headers(packet, server-address, 
DHCP_PORT_SERVER,
+  packet-dhcp.yiaddr, DHCP_PORT_CLIENT, 
len);
+
+r = dhcp_network_send_raw_socket(server-fd_raw, link, packet, len);
+if (r  0)
+return r;
+
+return 0;
+}
+
+static int dhcp_server_send_udp(sd_dhcp_server *server, be32_t destination,
+DHCPMessage *message, size_t len) {
+union sockaddr_union dest = {
+.in.sin_family = AF_INET,
+.in.sin_port = htobe16(DHCP_PORT_CLIENT),
+.in.sin_addr.s_addr = destination,
+};
+struct iovec iov = {
+.iov_base = message,
+.iov_len = len,
+};
+uint8_t cmsgbuf[CMSG_LEN(sizeof(struct in_pktinfo))] = {};
+struct msghdr msg = {
+.msg_name = dest,
+.msg_namelen = sizeof(dest.in),
+.msg_iov = iov,
+.msg_iovlen = 1,
+.msg_control = cmsgbuf,
+.msg_controllen = sizeof(cmsgbuf),
+};
+struct cmsghdr *cmsg;
+struct in_pktinfo *pktinfo;
+int r;
+
+assert(server);
+assert(server-fd  0);
+assert(message);
+assert(len  sizeof(DHCPMessage));
+
+cmsg = CMSG_FIRSTHDR(msg);
+assert(cmsg);
+
+cmsg-cmsg_level = IPPROTO_IP;
+cmsg-cmsg_type = IP_PKTINFO;
+cmsg-cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
+
+/* we attach source interface and address info to the message
+   rather than binding the socket. This will be mostly useful
+   when we gain support for arbitrary number of server addresses
+ */
+pktinfo = (struct in_pktinfo*) CMSG_DATA(cmsg);
+assert(pktinfo);
+
+pktinfo-ipi_ifindex = server-index;
+pktinfo-ipi_spec_dst.s_addr = server-address;
+
+r = sendmsg(server-fd, msg, 0);
+if (r  0)
+return -errno;
+
+return 0;
+}
+
+static bool requested_broadcast(DHCPRequest *req) {
+assert(req);
+
+return req-message-flags  htobe16(0x8000);
+}
+
+int dhcp_server_send_packet(sd_dhcp_server *server,
+DHCPRequest *req, DHCPPacket *packet,
+int type, size_t optoffset) {
+be32_t destination = INADDR_ANY;
+int r;
+
+assert(server);
+assert(req);
+assert(req-max_optlen);
+assert(optoffset = req-max_optlen);
+assert(packet);
+
+r = dhcp_option_append(packet-dhcp, req-max_optlen, optoffset, 0,
+   DHCP_OPTION_SERVER_IDENTIFIER,
+   4, server-address);
+if (r  0)
+return r;
+
+r = dhcp_option_append(packet-dhcp, req-max_optlen, optoffset, 0,
+   DHCP_OPTION_END, 0, NULL);
+if (r  0)
+return r;
+
+/* RFC 2131 Section 4.1
+
+   If the ’giaddr’ field in a DHCP message from a client is non-zero,
+   the server sends any return messages to the ’DHCP server’ port on 
the
+   BOOTP 

[systemd-devel] [PATCH 17/17] networkd: add dhcp server support

2014-05-26 Thread Tom Gundersen
When enabled in [Network] it will set up a dhcp server on the interface, 
listening
on one of its statically configured IPv4 addresses and with a fixed size pool of
leases determined from it.

Example:

[Match]
Name=ve-arch-tree

[Network]
Address=192.168.12.5/24
DHCPServer=yes

[Route]
Gateway=192.168.12.5
Destination=192.168.12.0/24

In this case we will configure ve-arch-tree with the address 192.168.12.5 and
hand out addresses in the range 192.168.12.6 - 192.168.12.38.

In the future, we should (as suggested by Lennart) introduce a syntax to pick 
the
server address automatically.
---
 src/network/networkd-link.c  | 101 ++-
 src/network/networkd-network-gperf.gperf |   1 +
 src/network/networkd.h   |   5 ++
 3 files changed, 93 insertions(+), 14 deletions(-)

diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 6677b94..b80a002 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -174,19 +174,6 @@ void link_drop(Link *link) {
 return;
 }
 
-static int link_enter_configured(Link *link) {
-assert(link);
-assert(link-state == LINK_STATE_SETTING_ROUTES);
-
-log_info_link(link, link configured);
-
-link-state = LINK_STATE_CONFIGURED;
-
-link_save(link);
-
-return 0;
-}
-
 static void link_enter_unmanaged(Link *link) {
 assert(link);
 
@@ -227,6 +214,16 @@ static int link_stop_clients(Link *link) {
 }
 }
 
+if (link-network-dhcp_server) {
+assert(link-dhcp_server);
+
+k = sd_dhcp_server_stop(link-dhcp_server);
+if (k  0) {
+log_warning_link(link, Could not stop DHCPv4 server: 
%s, strerror(-r));
+r = k;
+}
+}
+
 return r;
 }
 
@@ -245,6 +242,37 @@ static void link_enter_failed(Link *link) {
 link_save(link);
 }
 
+static int link_enter_configured(Link *link) {
+int r;
+
+assert(link);
+assert(link-network);
+assert(link-state == LINK_STATE_SETTING_ROUTES);
+
+
+if (link-network-dhcp_server) {
+log_debug_link(link, offering DHCPv4 leases);
+
+r = sd_dhcp_server_start(link-dhcp_server);
+if (r  0) {
+log_warning_link(link, could not start DHCPv4 server 
+ instance: %s, strerror(-r));
+
+link_enter_failed(link);
+
+return 0;
+}
+}
+
+log_info_link(link, link configured);
+
+link-state = LINK_STATE_CONFIGURED;
+
+link_save(link);
+
+return 0;
+}
+
 static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
 Link *link = userdata;
 int r;
@@ -1663,7 +1691,52 @@ static int link_configure(Link *link) {
 }
 }
 
-if (link_has_carrier(link-flags, link-kernel_operstate)) {
+if (link-network-dhcp_server) {
+Address *address;
+
+r = sd_dhcp_server_new(link-dhcp_server, link-ifindex);
+if (r  0)
+return r;
+
+r = sd_dhcp_server_attach_event(link-dhcp_server, NULL, 0);
+if (r  0)
+return r;
+
+LIST_FOREACH(addresses, address,
+ link-network-static_addresses) {
+struct in_addr pool_start;
+
+if (address-family != AF_INET)
+continue;
+
+/* currently this is picked essentially at random */
+r = sd_dhcp_server_set_address(link-dhcp_server,
+   address-in_addr.in);
+if (r  0)
+return r;
+
+/* offer 32 addresses starting from the address 
following the server address */
+pool_start.s_addr = 
htobe32(be32toh(address-in_addr.in.s_addr) + 1);
+r = sd_dhcp_server_set_lease_pool(link-dhcp_server,
+  pool_start, 32);
+
+break;
+}
+
+/* TODO:
+r = sd_dhcp_server_set_router(link-dhcp_server,
+  main_address-in_addr.in);
+if (r  0)
+return r;
+
+r = sd_dhcp_server_set_prefixlen(link-dhcp_server,
+ main_address-prefixlen);
+if (r  0)
+return r;
+*/
+}
+
+if (link_has_carrier(link-flags, link-operstate)) {
 r = link_acquire_conf(link);
 if 

[systemd-devel] [PATCH 14/17] sd-dhcp-server: track bound leases

2014-05-26 Thread Tom Gundersen
Make sure we don't hand out the same IP twice. We still don't
handle lease expiry.
---
 src/libsystemd-network/dhcp-server-internal.h |  25 -
 src/libsystemd-network/sd-dhcp-server.c   | 136 --
 src/libsystemd-network/test-dhcp-server.c |  59 +++
 3 files changed, 206 insertions(+), 14 deletions(-)

diff --git a/src/libsystemd-network/dhcp-server-internal.h 
b/src/libsystemd-network/dhcp-server-internal.h
index ce2e260..7fe7253 100644
--- a/src/libsystemd-network/dhcp-server-internal.h
+++ b/src/libsystemd-network/dhcp-server-internal.h
@@ -23,12 +23,25 @@
 #include sd-event.h
 #include sd-dhcp-server.h
 
+#include hashmap.h
 #include refcnt.h
 #include util.h
 #include log.h
 
 #include dhcp-internal.h
 
+typedef struct DHCPClientId {
+size_t length;
+uint8_t *data;
+} DHCPClientId;
+
+typedef struct DHCPLease {
+DHCPClientId client_id;
+
+be32_t address;
+usec_t expiration;
+} DHCPLease;
+
 struct sd_dhcp_server {
 RefCount n_ref;
 
@@ -42,12 +55,11 @@ struct sd_dhcp_server {
 be32_t address;
 be32_t pool_start;
 size_t pool_size;
-};
+size_t next_offer;
 
-typedef struct DHCPClientId {
-size_t length;
-uint8_t *data;
-} DHCPClientId;
+Hashmap *leases_by_client_id;
+DHCPLease **bound_leases;
+};
 
 typedef struct DHCPRequest {
 /* received message */
@@ -71,3 +83,6 @@ int dhcp_server_handle_message(sd_dhcp_server *server, 
DHCPMessage *message,
 int dhcp_server_send_packet(sd_dhcp_server *server,
 DHCPRequest *req, DHCPPacket *packet,
 int type, size_t optoffset);
+
+unsigned long client_id_hash_func(const void *p, const uint8_t 
hash_key[HASH_KEY_SIZE]);
+int client_id_compare_func(const void *_a, const void *_b);
diff --git a/src/libsystemd-network/sd-dhcp-server.c 
b/src/libsystemd-network/sd-dhcp-server.c
index 3de61f7..44ca645 100644
--- a/src/libsystemd-network/sd-dhcp-server.c
+++ b/src/libsystemd-network/sd-dhcp-server.c
@@ -23,6 +23,8 @@
 #include sys/ioctl.h
 #include netinet/if_ether.h
 
+#include siphash24.h
+
 #include sd-dhcp-server.h
 #include dhcp-server-internal.h
 #include dhcp-internal.h
@@ -37,6 +39,11 @@ int sd_dhcp_server_set_lease_pool(sd_dhcp_server *server, 
struct in_addr *addres
 assert_return(size, -EINVAL);
 assert_return(server-pool_start == htobe32(INADDR_ANY), -EBUSY);
 assert_return(!server-pool_size, -EBUSY);
+assert_return(!server-bound_leases, -EBUSY);
+
+server-bound_leases = new0(DHCPLease*, size);
+if (!server-bound_leases)
+return -ENOMEM;
 
 server-pool_start = address-s_addr;
 server-pool_size = size;
@@ -62,13 +69,63 @@ sd_dhcp_server *sd_dhcp_server_ref(sd_dhcp_server *server) {
 return server;
 }
 
+unsigned long client_id_hash_func(const void *p, const uint8_t 
hash_key[HASH_KEY_SIZE]) {
+uint64_t u;
+const DHCPClientId *id = p;
+
+assert(id);
+assert(id-length);
+assert(id-data);
+
+siphash24((uint8_t*) u, id-data, id-length, hash_key);
+
+return (unsigned long) u;
+}
+
+int client_id_compare_func(const void *_a, const void *_b) {
+const DHCPClientId *a, *b;
+
+a = _a;
+b = _b;
+
+assert(!a-length || a-data);
+assert(!b-length || b-data);
+
+if (a-length != b-length)
+return a-length  b-length ? -1 : 1;
+
+return memcmp(a-data, b-data, a-length);
+}
+
+static void dhcp_lease_free(DHCPLease *lease) {
+if (!lease)
+return;
+
+free(lease-client_id.data);
+free(lease);
+}
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(DHCPLease*, dhcp_lease_free);
+#define _cleanup_dhcp_lease_free_ _cleanup_(dhcp_lease_freep)
+
 sd_dhcp_server *sd_dhcp_server_unref(sd_dhcp_server *server) {
 if (server  REFCNT_DEC(server-n_ref) = 0) {
+DHCPLease *lease;
+Iterator i;
+
 log_dhcp_server(server, UNREF);
 
 sd_dhcp_server_stop(server);
 
 sd_event_unref(server-event);
+
+HASHMAP_FOREACH(lease, server-leases_by_client_id, i) {
+hashmap_remove(server-leases_by_client_id, lease);
+dhcp_lease_free(lease);
+}
+
+hashmap_free(server-leases_by_client_id);
+free(server-bound_leases);
 free(server);
 }
 
@@ -90,6 +147,7 @@ int sd_dhcp_server_new(sd_dhcp_server **ret, int ifindex) {
 server-fd = -1;
 server-address = htobe32(INADDR_ANY);
 server-index = ifindex;
+server-leases_by_client_id = hashmap_new(client_id_hash_func, 
client_id_compare_func);
 
 *ret = server;
 server = NULL;
@@ -478,9 +536,25 @@ static int ensure_sane_request(DHCPRequest *req, 
DHCPMessage *message) 

Re: [systemd-devel] [PATCH 17/17] networkd: add dhcp server support

2014-05-26 Thread Zbigniew Jędrzejewski-Szmek
On Mon, May 26, 2014 at 09:39:46PM +0200, Tom Gundersen wrote:
 When enabled in [Network] it will set up a dhcp server on the interface, 
 listening
 on one of its statically configured IPv4 addresses and with a fixed size pool 
 of
 leases determined from it.
Hi Tom,
before looking at the code, a couple of general questions:
- does the DHCP server have to be part of networkd? Isn't the job
  of acquiring addresses and giving out addresses separate and shouldn't
  two different processes be responsible?
- why the fixed limit of 32 addresses? Shouldn't the default be to give
  out all possible addresses except for the server one?

Zbyszek

 Example:
 
 [Match]
 Name=ve-arch-tree
 
 [Network]
 Address=192.168.12.5/24
 DHCPServer=yes
 
 [Route]
 Gateway=192.168.12.5
 Destination=192.168.12.0/24
 
 In this case we will configure ve-arch-tree with the address 192.168.12.5 and
 hand out addresses in the range 192.168.12.6 - 192.168.12.38.
 
 In the future, we should (as suggested by Lennart) introduce a syntax to pick 
 the
 server address automatically.
 ---
  src/network/networkd-link.c  | 101 
 ++-
  src/network/networkd-network-gperf.gperf |   1 +
  src/network/networkd.h   |   5 ++
  3 files changed, 93 insertions(+), 14 deletions(-)
 
 diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
 index 6677b94..b80a002 100644
 --- a/src/network/networkd-link.c
 +++ b/src/network/networkd-link.c
 @@ -174,19 +174,6 @@ void link_drop(Link *link) {
  return;
  }
  
 -static int link_enter_configured(Link *link) {
 -assert(link);
 -assert(link-state == LINK_STATE_SETTING_ROUTES);
 -
 -log_info_link(link, link configured);
 -
 -link-state = LINK_STATE_CONFIGURED;
 -
 -link_save(link);
 -
 -return 0;
 -}
 -
  static void link_enter_unmanaged(Link *link) {
  assert(link);
  
 @@ -227,6 +214,16 @@ static int link_stop_clients(Link *link) {
  }
  }
  
 +if (link-network-dhcp_server) {
 +assert(link-dhcp_server);
 +
 +k = sd_dhcp_server_stop(link-dhcp_server);
 +if (k  0) {
 +log_warning_link(link, Could not stop DHCPv4 
 server: %s, strerror(-r));
 +r = k;
 +}
 +}
 +
  return r;
  }
  
 @@ -245,6 +242,37 @@ static void link_enter_failed(Link *link) {
  link_save(link);
  }
  
 +static int link_enter_configured(Link *link) {
 +int r;
 +
 +assert(link);
 +assert(link-network);
 +assert(link-state == LINK_STATE_SETTING_ROUTES);
 +
 +
 +if (link-network-dhcp_server) {
 +log_debug_link(link, offering DHCPv4 leases);
 +
 +r = sd_dhcp_server_start(link-dhcp_server);
 +if (r  0) {
 +log_warning_link(link, could not start DHCPv4 
 server 
 + instance: %s, strerror(-r));
 +
 +link_enter_failed(link);
 +
 +return 0;
 +}
 +}
 +
 +log_info_link(link, link configured);
 +
 +link-state = LINK_STATE_CONFIGURED;
 +
 +link_save(link);
 +
 +return 0;
 +}
 +
  static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
  Link *link = userdata;
  int r;
 @@ -1663,7 +1691,52 @@ static int link_configure(Link *link) {
  }
  }
  
 -if (link_has_carrier(link-flags, link-kernel_operstate)) {
 +if (link-network-dhcp_server) {
 +Address *address;
 +
 +r = sd_dhcp_server_new(link-dhcp_server, link-ifindex);
 +if (r  0)
 +return r;
 +
 +r = sd_dhcp_server_attach_event(link-dhcp_server, NULL, 0);
 +if (r  0)
 +return r;
 +
 +LIST_FOREACH(addresses, address,
 + link-network-static_addresses) {
 +struct in_addr pool_start;
 +
 +if (address-family != AF_INET)
 +continue;
 +
 +/* currently this is picked essentially at random */
 +r = sd_dhcp_server_set_address(link-dhcp_server,
 +   address-in_addr.in);
 +if (r  0)
 +return r;
 +
 +/* offer 32 addresses starting from the address 
 following the server address */
 +pool_start.s_addr = 
 htobe32(be32toh(address-in_addr.in.s_addr) + 1);
 +r = sd_dhcp_server_set_lease_pool(link-dhcp_server,
 +  pool_start, 32);
 +
 +break;
 + 

Re: [systemd-devel] [PATCH 17/17] networkd: add dhcp server support

2014-05-26 Thread Cristian Rodríguez

El 26/05/14 22:38, Zbigniew Jędrzejewski-Szmek escribió:

On Mon, May 26, 2014 at 09:39:46PM +0200, Tom Gundersen wrote:

When enabled in [Network] it will set up a dhcp server on the interface, 
listening
on one of its statically configured IPv4 addresses and with a fixed size pool of
leases determined from it.

Hi Tom,
before looking at the code, a couple of general questions:
- does the DHCP server have to be part of networkd?


Yeah IMHO the dhcp server should be a separate daemon, that of course 
does not preclude it from sharing code with networkd.


___
systemd-devel mailing list
systemd-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/systemd-devel


Re: [systemd-devel] [PATCH 17/17] networkd: add dhcp server support

2014-05-26 Thread Marcel Holtmann
Hi Cristian,

 When enabled in [Network] it will set up a dhcp server on the interface, 
 listening
 on one of its statically configured IPv4 addresses and with a fixed size 
 pool of
 leases determined from it.
 Hi Tom,
 before looking at the code, a couple of general questions:
 - does the DHCP server have to be part of networkd?
 
 Yeah IMHO the dhcp server should be a separate daemon, that of course does 
 not preclude it from sharing code with networkd.

that is not a good idea. Why would you make the DHCP server a separate daemon. 
That is just asking for trouble.

The only way to provide a proper integration is if the DHCP server is part of 
systemd-networkd. Otherwise you are just wasting time in trying to figure out 
on how to handle configuration and update of states between two daemon.

Regards

Marcel

___
systemd-devel mailing list
systemd-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/systemd-devel