chiark / gitweb /
bus: when connecting to a container's kdbus instance, enter namespace first
[elogind.git] / src / libsystemd-dhcp / test-dhcp-client.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
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <stdlib.h>
23 #include <assert.h>
24 #include <errno.h>
25 #include <stdio.h>
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <unistd.h>
29
30 #include "util.h"
31 #include "socket-util.h"
32
33 #include "dhcp-protocol.h"
34 #include "dhcp-internal.h"
35 #include "sd-dhcp-client.h"
36
37 static struct ether_addr mac_addr = {
38         .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
39 };
40
41 static int test_fd[2];
42
43 static void test_request_basic(sd_event *e)
44 {
45         sd_dhcp_client *client;
46
47         client = sd_dhcp_client_new(e);
48
49         assert(client);
50
51         assert(sd_dhcp_client_set_request_option(NULL, 0) == -EINVAL);
52         assert(sd_dhcp_client_set_request_address(NULL, NULL) == -EINVAL);
53         assert(sd_dhcp_client_set_index(NULL, 0) == -EINVAL);
54
55         assert(sd_dhcp_client_set_index(client, 15) == 0);
56         assert(sd_dhcp_client_set_index(client, -42) == -EINVAL);
57         assert(sd_dhcp_client_set_index(client, -1) == 0);
58
59         assert(sd_dhcp_client_set_request_option(client,
60                                         DHCP_OPTION_SUBNET_MASK) == -EEXIST);
61         assert(sd_dhcp_client_set_request_option(client,
62                                         DHCP_OPTION_ROUTER) == -EEXIST);
63         assert(sd_dhcp_client_set_request_option(client,
64                                         DHCP_OPTION_HOST_NAME) == -EEXIST);
65         assert(sd_dhcp_client_set_request_option(client,
66                                         DHCP_OPTION_DOMAIN_NAME) == -EEXIST);
67         assert(sd_dhcp_client_set_request_option(client,
68                                         DHCP_OPTION_DOMAIN_NAME_SERVER)
69                         == -EEXIST);
70         assert(sd_dhcp_client_set_request_option(client,
71                                         DHCP_OPTION_NTP_SERVER) == -EEXIST);
72
73         assert(sd_dhcp_client_set_request_option(client,
74                                         DHCP_OPTION_PAD) == -EINVAL);
75         assert(sd_dhcp_client_set_request_option(client,
76                                         DHCP_OPTION_END) == -EINVAL);
77         assert(sd_dhcp_client_set_request_option(client,
78                                         DHCP_OPTION_MESSAGE_TYPE) == -EINVAL);
79         assert(sd_dhcp_client_set_request_option(client,
80                                         DHCP_OPTION_OVERLOAD) == -EINVAL);
81         assert(sd_dhcp_client_set_request_option(client,
82                                         DHCP_OPTION_PARAMETER_REQUEST_LIST)
83                         == -EINVAL);
84
85         assert(sd_dhcp_client_set_request_option(client, 33) == 0);
86         assert(sd_dhcp_client_set_request_option(client, 33) == -EEXIST);
87         assert(sd_dhcp_client_set_request_option(client, 44) == 0);
88 }
89
90 static uint16_t client_checksum(void *buf, int len)
91 {
92         uint32_t sum;
93         uint16_t *check;
94         int i;
95         uint8_t *odd;
96
97         sum = 0;
98         check = buf;
99
100         for (i = 0; i < len / 2 ; i++)
101                 sum += check[i];
102
103         if (len & 0x01) {
104                 odd = buf;
105                 sum += odd[len];
106         }
107
108         return ~((sum & 0xffff) + (sum >> 16));
109 }
110
111 static void test_checksum(void)
112 {
113         uint8_t buf[20] = {
114                 0x45, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00,
115                 0x40, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
116                 0xff, 0xff, 0xff, 0xff
117         };
118
119         uint8_t check[2] = {
120                 0x78, 0xae
121         };
122
123         uint16_t *val = (uint16_t *)check;
124
125         assert(client_checksum(&buf, 20) == *val);
126 }
127
128 static int check_options(uint8_t code, uint8_t len, const uint8_t *option,
129                 void *user_data)
130 {
131         return 0;
132 }
133
134 int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link,
135                                  const void *packet, size_t len)
136 {
137         size_t size;
138         _cleanup_free_ DHCPPacket *discover;
139         uint16_t ip_check, udp_check;
140         int res;
141
142         assert(s >= 0);
143         assert(packet);
144
145         size = sizeof(DHCPPacket) + 4;
146         assert(len > size);
147
148         discover = memdup(packet, len);
149
150         assert(memcmp(discover->dhcp.chaddr,
151                       &mac_addr.ether_addr_octet, 6) == 0);
152         assert(discover->ip.ttl == IPDEFTTL);
153         assert(discover->ip.protocol == IPPROTO_UDP);
154         assert(discover->ip.saddr == INADDR_ANY);
155         assert(discover->ip.daddr == INADDR_BROADCAST);
156         assert(discover->udp.source == be16toh(DHCP_PORT_CLIENT));
157         assert(discover->udp.dest == be16toh(DHCP_PORT_SERVER));
158
159         ip_check = discover->ip.check;
160
161         discover->ip.ttl = 0;
162         discover->ip.check = discover->udp.len;
163
164         udp_check = ~client_checksum(&discover->ip.ttl, len - 8);
165         assert(udp_check == 0xffff);
166
167         discover->ip.ttl = IPDEFTTL;
168         discover->ip.check = ip_check;
169
170         ip_check = ~client_checksum(&discover->ip, sizeof(discover->ip));
171         assert(ip_check == 0xffff);
172
173         size = len - sizeof(struct iphdr) - sizeof(struct udphdr);
174
175         res = dhcp_option_parse(&discover->dhcp, size, check_options, NULL);
176         if (res < 0)
177                 return res;
178
179         return 575;
180 }
181
182 int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link)
183 {
184         if (socketpair(AF_UNIX, SOCK_STREAM, 0, test_fd) < 0)
185                 return -errno;
186
187         return test_fd[0];
188 }
189
190 static void test_discover_message(sd_event *e)
191 {
192         sd_dhcp_client *client;
193         int res;
194
195         client = sd_dhcp_client_new(e);
196         assert(client);
197
198         assert(sd_dhcp_client_set_index(client, 42) >= 0);
199         assert(sd_dhcp_client_set_mac(client, &mac_addr) >= 0);
200
201         assert(sd_dhcp_client_set_request_option(client, 248) >= 0);
202
203         res = sd_dhcp_client_start(client);
204
205         assert(res == 0 || res == -EINPROGRESS);
206
207         close(test_fd[0]);
208         close(test_fd[1]);
209 }
210
211 int main(int argc, char *argv[])
212 {
213         sd_event *e;
214
215         assert(sd_event_new(&e) >= 0);
216
217         test_request_basic(e);
218         test_checksum();
219
220         test_discover_message(e);
221         sd_event_run(e, (uint64_t) -1);
222
223         return 0;
224 }