chiark / gitweb /
sd-dhcp-server: add basic NAK support
[elogind.git] / src / libsystemd-network / test-dhcp-server.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright (C) 2013 Intel Corporation. All rights reserved.
7   Copyright (C) 2014 Tom Gundersen
8
9   systemd is free software; you can redistribute it and/or modify it
10   under the terms of the GNU Lesser General Public License as published by
11   the Free Software Foundation; either version 2.1 of the License, or
12   (at your option) any later version.
13
14   systemd is distributed in the hope that it will be useful, but
15   WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17   Lesser General Public License for more details.
18
19   You should have received a copy of the GNU Lesser General Public License
20   along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 ***/
22
23 #include <netinet/if_ether.h>
24 #include <assert.h>
25 #include <errno.h>
26
27 #include "sd-event.h"
28 #include "event-util.h"
29
30 #include "sd-dhcp-server.h"
31 #include "dhcp-server-internal.h"
32
33 static void test_basic(sd_event *event) {
34         _cleanup_dhcp_server_unref_ sd_dhcp_server *server = NULL;
35         struct in_addr address_lo = {
36                 .s_addr = htonl(INADDR_LOOPBACK),
37         };
38         struct in_addr address_any = {
39                 .s_addr = htonl(INADDR_ANY),
40         };
41
42         /* attach to loopback interface */
43         assert_se(sd_dhcp_server_new(&server, 1) >= 0);
44         assert_se(server);
45
46         assert_se(sd_dhcp_server_attach_event(server, event, 0) >= 0);
47         assert_se(sd_dhcp_server_attach_event(server, event, 0) == -EBUSY);
48         assert_se(sd_dhcp_server_get_event(server) == event);
49         assert_se(sd_dhcp_server_detach_event(server) >= 0);
50         assert_se(!sd_dhcp_server_get_event(server));
51         assert_se(sd_dhcp_server_attach_event(server, NULL, 0) >= 0);
52         assert_se(sd_dhcp_server_attach_event(server, NULL, 0) == -EBUSY);
53
54         assert_se(sd_dhcp_server_ref(server) == server);
55         assert_se(!sd_dhcp_server_unref(server));
56
57         assert_se(sd_dhcp_server_start(server) == -EUNATCH);
58         assert_se(sd_dhcp_server_set_address(server, &address_any) == -EINVAL);
59         assert_se(sd_dhcp_server_set_address(server, &address_lo) >= 0);
60         assert_se(sd_dhcp_server_set_address(server, &address_lo) == -EBUSY);
61
62         assert_se(sd_dhcp_server_set_lease_pool(server, &address_any, 1) == -EINVAL);
63         assert_se(sd_dhcp_server_set_lease_pool(server, &address_lo, 0) == -EINVAL);
64         assert_se(sd_dhcp_server_set_lease_pool(server, &address_lo, 1) >= 0);
65         assert_se(sd_dhcp_server_set_lease_pool(server, &address_lo, 1) == -EBUSY);
66
67         assert_se(sd_dhcp_server_start(server) >= 0);
68         assert_se(sd_dhcp_server_start(server) == -EBUSY);
69         assert_se(sd_dhcp_server_stop(server) >= 0);
70         assert_se(sd_dhcp_server_stop(server) >= 0);
71         assert_se(sd_dhcp_server_start(server) >= 0);
72 }
73
74 static void test_message_handler(void) {
75         _cleanup_dhcp_server_unref_ sd_dhcp_server *server = NULL;
76         struct {
77                 DHCPMessage message;
78                 struct {
79                         uint8_t code;
80                         uint8_t length;
81                         uint8_t type;
82                 } _packed_ option_type;
83                 struct {
84                         uint8_t code;
85                         uint8_t length;
86                         be32_t address;
87                 } _packed_ option_requested_ip;
88                 struct {
89                         uint8_t code;
90                         uint8_t length;
91                         be32_t address;
92                 } _packed_ option_server_id;
93                 uint8_t end;
94         } _packed_ test = {
95                 .message.op = BOOTREQUEST,
96                 .message.htype = ARPHRD_ETHER,
97                 .message.hlen = ETHER_ADDR_LEN,
98                 .message.xid = htobe32(0x12345678),
99                 .message.chaddr = { 'A', 'B', 'C', 'D', 'E', 'F' },
100                 .option_type.code = DHCP_OPTION_MESSAGE_TYPE,
101                 .option_type.length = 1,
102                 .option_type.type = DHCP_DISCOVER,
103                 .end = DHCP_OPTION_END,
104         };
105         struct in_addr address_lo = {
106                 .s_addr = htonl(INADDR_LOOPBACK),
107         };
108
109         assert_se(sd_dhcp_server_new(&server, 1) >= 0);
110         assert_se(sd_dhcp_server_set_address(server, &address_lo) >= 0);
111         assert_se(sd_dhcp_server_attach_event(server, NULL, 0) >= 0);
112         assert_se(sd_dhcp_server_start(server) >= 0);
113
114         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0);
115         assert_se(sd_dhcp_server_set_lease_pool(server, &address_lo, 10) >= 0);
116         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER);
117
118         test.end = 0;
119         /* TODO, shouldn't this fail? */
120         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER);
121         test.end = DHCP_OPTION_END;
122         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER);
123
124         test.option_type.code = 0;
125         test.option_type.length = 0;
126         test.option_type.type = 0;
127         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0);
128         test.option_type.code = DHCP_OPTION_MESSAGE_TYPE;
129         test.option_type.length = 1;
130         test.option_type.type = DHCP_DISCOVER;
131         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER);
132
133         test.message.op = 0;
134         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0);
135         test.message.op = BOOTREQUEST;
136         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER);
137
138         test.message.htype = 0;
139         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0);
140         test.message.htype = ARPHRD_ETHER;
141         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER);
142
143         test.message.hlen = 0;
144         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0);
145         test.message.hlen = ETHER_ADDR_LEN;
146         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER);
147
148         test.option_type.type = DHCP_REQUEST;
149         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0);
150         test.option_requested_ip.code = DHCP_OPTION_REQUESTED_IP_ADDRESS;
151         test.option_requested_ip.length = 4;
152         test.option_requested_ip.address = htobe32(0x12345678);
153         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_NAK);
154         test.option_server_id.code = DHCP_OPTION_SERVER_IDENTIFIER;
155         test.option_server_id.length = 4;
156         test.option_server_id.address = htobe32(INADDR_LOOPBACK);
157         test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 3);
158         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_ACK);
159         test.option_server_id.address = htobe32(0x12345678);
160         test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 3);
161         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0);
162         test.option_server_id.address = htobe32(INADDR_LOOPBACK);
163         test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 30);
164         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0);
165 }
166
167 int main(int argc, char *argv[]) {
168         _cleanup_event_unref_ sd_event *e;
169
170         log_set_max_level(LOG_DEBUG);
171         log_parse_environment();
172         log_open();
173
174         assert_se(sd_event_new(&e) >= 0);
175
176         test_basic(e);
177         test_message_handler();
178
179         return 0;
180 }