1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 /* nm-dhcp-manager.c - Handle the DHCP daemon for NetworkManager
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 *
18 * Copyright (C) 2008 - 2011 Red Hat, Inc.
19 *
20 */
21
22 #include <glib.h>
23 #include <dbus/dbus-glib.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
26 #include <string.h>
27
28 #include "nm-test-helpers.h"
29 #include <nm-utils.h>
30
31 #include "nm-dhcp-manager.h"
32
33 typedef struct {
34 const char *name;
35 const char *value;
36 } Option;
37
38 static void
39 destroy_gvalue (gpointer data)
40 {
41 GValue *value = (GValue *) data;
42
43 g_value_unset (value);
44 g_slice_free (GValue, value);
45 }
46
47 static GValue *
48 string_to_byte_array_gvalue (const char *str)
49 {
50 GByteArray *array;
51 GValue *val;
52
53 array = g_byte_array_sized_new (strlen (str));
54 g_byte_array_append (array, (const guint8 *) str, strlen (str));
55
56 val = g_slice_new0 (GValue);
57 g_value_init (val, DBUS_TYPE_G_UCHAR_ARRAY);
58 g_value_take_boxed (val, array);
59
60 return val;
61 }
62
63 static GHashTable *
64 fill_table (Option *test_options, GHashTable *table)
65 {
66 Option *opt;
67
68 if (!table)
69 table = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, destroy_gvalue);
70 for (opt = test_options; opt->name; opt++) {
71 g_hash_table_insert (table,
72 (gpointer) opt->name,
73 string_to_byte_array_gvalue (opt->value));
74 }
75 return table;
76 }
77
78 static Option generic_options[] = {
79 { "new_subnet_mask", "255.255.255.0" },
80 { "new_ip_address", "192.168.1.106" },
81 { "new_network_number", "192.168.1.0" },
82 { "interface", "eth0" },
83 { "reason", "BOUND" },
84 { "new_expiry", "1232324877" },
85 { "new_dhcp_lease_time", "3600" },
86 { "new_dhcp_server_identifier", "192.168.1.1" },
87 { "new_routers", "192.168.1.1" },
88 { "new_domain_name_servers", "216.254.95.2 216.231.41.2" },
89 { "new_dhcp_message_type", "5" },
90 { "new_broadcast_address", "192.168.1.255" },
91 { "new_domain_search", "foobar.com blah.foobar.com" },
92 { "new_host_name", "nmreallywhipsthe" },
93 { "new_domain_name", "lamasass.com" },
94 { "new_interface_mtu", "987" },
95 { "new_static_routes", "10.1.1.5 10.1.1.1 100.99.88.56 10.1.1.1" },
96 { NULL, NULL }
97 };
98
99 static void
100 test_generic_options (const char *client)
101 {
102 GHashTable *options;
103 NMIP4Config *ip4_config;
104 const NMPlatformIP4Address *address;
105 const NMPlatformIP4Route *route;
106 guint32 tmp;
107 const char *expected_addr = "192.168.1.106";
108 const char *expected_gw = "192.168.1.1";
109 const char *expected_dns1 = "216.254.95.2";
110 const char *expected_dns2 = "216.231.41.2";
111 const char *expected_search1 = "foobar.com";
112 const char *expected_search2 = "blah.foobar.com";
113 const char *expected_route1_dest = "10.1.1.5";
114 const char *expected_route1_gw = "10.1.1.1";
115 const char *expected_route2_dest = "100.99.88.56";
116 const char *expected_route2_gw = "10.1.1.1";
117
118 options = fill_table (generic_options, NULL);
119 ip4_config = nm_dhcp_manager_test_ip4_options_to_config (client, "eth0", options, "rebind");
120 ASSERT (ip4_config != NULL,
121 "dhcp-generic", "failed to parse DHCP4 options");
122
123 /* IP4 address */
124 ASSERT (nm_ip4_config_get_num_addresses (ip4_config) == 1,
125 "dhcp-generic", "unexpected number of IP addresses");
126 address = nm_ip4_config_get_address (ip4_config, 0);
127
128 ASSERT (inet_pton (AF_INET, expected_addr, &tmp) > 0,
129 "dhcp-generic", "couldn't convert expected IP address");
130 ASSERT (address->address == tmp,
131 "dhcp-generic", "unexpected IP address");
132
133 ASSERT (address->plen == 24,
134 "dhcp-generic", "unexpected IP address prefix length");
135
136 /* Gateway */
137 ASSERT (inet_pton (AF_INET, expected_gw, &tmp) > 0,
138 "dhcp-generic", "couldn't convert expected IP gateway");
139 ASSERT (nm_ip4_config_get_gateway (ip4_config) == tmp,
140 "dhcp-generic", "unexpected IP gateway");
141
142 ASSERT (nm_ip4_config_get_ptp_address (ip4_config) == 0,
143 "dhcp-generic", "unexpected PTP address");
144
145 ASSERT (nm_ip4_config_get_num_wins (ip4_config) == 0,
146 "dhcp-generic", "unexpected number of WINS servers");
147
148 ASSERT (nm_ip4_config_get_mtu (ip4_config) == 987,
149 "dhcp-generic", "unexpected MTU");
150
151 /* Domain searches */
152 ASSERT (nm_ip4_config_get_num_searches (ip4_config) == 2,
153 "dhcp-generic", "unexpected number of domain searches");
154 ASSERT (strcmp (nm_ip4_config_get_search (ip4_config, 0), expected_search1) == 0,
155 "dhcp-generic", "unexpected domain search #1");
156 ASSERT (strcmp (nm_ip4_config_get_search (ip4_config, 1), expected_search2) == 0,
157 "dhcp-generic", "unexpected domain search #2");
158
159 /* DNS servers */
160 ASSERT (nm_ip4_config_get_num_nameservers (ip4_config) == 2,
161 "dhcp-generic", "unexpected number of domain name servers");
162 ASSERT (inet_pton (AF_INET, expected_dns1, &tmp) > 0,
163 "dhcp-generic", "couldn't convert expected DNS server address #1");
164 ASSERT (nm_ip4_config_get_nameserver (ip4_config, 0) == tmp,
165 "dhcp-generic", "unexpected domain name server #1");
166 ASSERT (inet_pton (AF_INET, expected_dns2, &tmp) > 0,
167 "dhcp-generic", "couldn't convert expected DNS server address #2");
168 ASSERT (nm_ip4_config_get_nameserver (ip4_config, 1) == tmp,
169 "dhcp-generic", "unexpected domain name server #2");
170
171 /* Routes */
172 ASSERT (nm_ip4_config_get_num_routes (ip4_config) == 2,
173 "dhcp-generic", "unexpected number of routes");
174
175 /* Route #1 */
176 route = nm_ip4_config_get_route (ip4_config, 0);
177 ASSERT (inet_pton (AF_INET, expected_route1_dest, &tmp) > 0,
178 "dhcp-generic", "couldn't convert expected route destination #1");
179 ASSERT (route->network == tmp,
180 "dhcp-generic", "unexpected route #1 destination");
181
182 ASSERT (inet_pton (AF_INET, expected_route1_gw, &tmp) > 0,
183 "dhcp-generic", "couldn't convert expected route next hop #1");
184 ASSERT (route->gateway == tmp,
185 "dhcp-generic", "unexpected route #1 next hop");
186
187 ASSERT (route->plen == 32,
188 "dhcp-generic", "unexpected route #1 prefix");
189 ASSERT (route->metric == 0,
190 "dhcp-generic", "unexpected route #1 metric");
191
192 /* Route #2 */
193 route = nm_ip4_config_get_route (ip4_config, 1);
194 ASSERT (inet_pton (AF_INET, expected_route2_dest, &tmp) > 0,
195 "dhcp-generic", "couldn't convert expected route destination #2");
196 ASSERT (route->network == tmp,
197 "dhcp-generic", "unexpected route #2 destination");
198
199 ASSERT (inet_pton (AF_INET, expected_route2_gw, &tmp) > 0,
200 "dhcp-generic", "couldn't convert expected route next hop #2");
201 ASSERT (route->gateway == tmp,
202 "dhcp-generic", "unexpected route #2 next hop");
203
204 ASSERT (route->plen == 32,
205 "dhcp-generic", "unexpected route #2 prefix");
206 ASSERT (route->metric == 0,
207 "dhcp-generic", "unexpected route #2 metric");
208
209 g_hash_table_destroy (options);
210 }
211
212 static Option wins_options[] = {
213 { "new_netbios_name_servers", "63.12.199.5 150.4.88.120" },
214 { NULL, NULL }
215 };
216
217 static void
218 test_wins_options (const char *client)
219 {
220 GHashTable *options;
221 NMIP4Config *ip4_config;
222 const NMPlatformIP4Address *address;
223 guint32 tmp;
224 const char *expected_wins1 = "63.12.199.5";
225 const char *expected_wins2 = "150.4.88.120";
226
227 options = fill_table (generic_options, NULL);
228 options = fill_table (wins_options, options);
229
230 ip4_config = nm_dhcp_manager_test_ip4_options_to_config (client, "eth0", options, "rebind");
231 ASSERT (ip4_config != NULL,
232 "dhcp-wins", "failed to parse DHCP4 options");
233
234 /* IP4 address */
235 ASSERT (nm_ip4_config_get_num_addresses (ip4_config) == 1,
236 "dhcp-wins", "unexpected number of IP addresses");
(1) Event returned_pointer: |
Pointer "address" returned by "nm_ip4_config_get_address(ip4_config, 0U)" is never used. |
237 address = nm_ip4_config_get_address (ip4_config, 0);
238
239 ASSERT (nm_ip4_config_get_num_wins (ip4_config) == 2,
240 "dhcp-wins", "unexpected number of WINS servers");
241 ASSERT (inet_pton (AF_INET, expected_wins1, &tmp) > 0,
242 "dhcp-wins", "couldn't convert expected WINS server address #1");
243 ASSERT (nm_ip4_config_get_wins (ip4_config, 0) == tmp,
244 "dhcp-wins", "unexpected WINS server #1");
245 ASSERT (inet_pton (AF_INET, expected_wins2, &tmp) > 0,
246 "dhcp-wins", "couldn't convert expected WINS server address #1");
247 ASSERT (nm_ip4_config_get_wins (ip4_config, 1) == tmp,
248 "dhcp-wins", "unexpected WINS server #1");
249
250 g_hash_table_destroy (options);
251 }
252
253 static void
254 ip4_test_route (const char *test,
255 NMIP4Config *ip4_config,
256 guint route_num,
257 const char *expected_dest,
258 const char *expected_gw,
259 guint expected_prefix)
260 {
261 const NMPlatformIP4Route *route;
262 guint32 tmp;
263
264 route = nm_ip4_config_get_route (ip4_config, route_num);
265 ASSERT (inet_pton (AF_INET, expected_dest, &tmp) > 0,
266 test, "couldn't convert expected route destination #1");
267 ASSERT (route->network == tmp,
268 test, "unexpected route %d destination", route_num + 1);
269
270 ASSERT (inet_pton (AF_INET, expected_gw, &tmp) > 0,
271 test, "couldn't convert expected route next hop %d",
272 route_num + 1);
273 ASSERT (route->gateway == tmp,
274 test, "unexpected route %d next hop", route_num + 1);
275
276 ASSERT (route->plen == expected_prefix,
277 test, "unexpected route %d prefix", route_num + 1);
278 ASSERT (route->metric == 0,
279 test, "unexpected route %d metric", route_num + 1);
280 }
281
282 static void
283 ip4_test_gateway (const char *test,
284 NMIP4Config *ip4_config,
285 const char *expected_gw)
286 {
287 guint32 tmp;
288
289 ASSERT (nm_ip4_config_get_num_addresses (ip4_config) == 1,
290 test, "unexpected number of IP addresses");
291 ASSERT (inet_pton (AF_INET, expected_gw, &tmp) > 0,
292 test, "couldn't convert expected IP gateway");
293 ASSERT (nm_ip4_config_get_gateway (ip4_config) == tmp,
294 test, "unexpected IP gateway");
295 }
296
297 static void
298 test_classless_static_routes_1 (const char *client)
299 {
300 GHashTable *options;
301 NMIP4Config *ip4_config;
302 const char *expected_route1_dest = "192.168.10.0";
303 const char *expected_route1_gw = "192.168.1.1";
304 const char *expected_route2_dest = "10.0.0.0";
305 const char *expected_route2_gw = "10.17.66.41";
306 static Option data[] = {
307 /* dhclient custom format */
308 { "new_rfc3442_classless_static_routes", "24 192 168 10 192 168 1 1 8 10 10 17 66 41" },
309 { NULL, NULL }
310 };
311
312 options = fill_table (generic_options, NULL);
313 options = fill_table (data, options);
314
315 ip4_config = nm_dhcp_manager_test_ip4_options_to_config (client, "eth0", options, "rebind");
316 ASSERT (ip4_config != NULL,
317 "dhcp-classless-1", "failed to parse DHCP4 options");
318
319 /* IP4 routes */
320 ASSERT (nm_ip4_config_get_num_routes (ip4_config) == 2,
321 "dhcp-classless-1", "unexpected number of IP routes");
322 ip4_test_route ("dhcp-classless-1", ip4_config, 0,
323 expected_route1_dest, expected_route1_gw, 24);
324 ip4_test_route ("dhcp-classless-1", ip4_config, 1,
325 expected_route2_dest, expected_route2_gw, 8);
326
327 g_hash_table_destroy (options);
328 }
329
330 static void
331 test_classless_static_routes_2 (const char *client)
332 {
333 GHashTable *options;
334 NMIP4Config *ip4_config;
335 const char *expected_route1_dest = "192.168.10.0";
336 const char *expected_route1_gw = "192.168.1.1";
337 const char *expected_route2_dest = "10.0.0.0";
338 const char *expected_route2_gw = "10.17.66.41";
339 static Option data[] = {
340 /* dhcpcd format */
341 { "new_classless_static_routes", "192.168.10.0/24 192.168.1.1 10.0.0.0/8 10.17.66.41" },
342 { NULL, NULL }
343 };
344
345 options = fill_table (generic_options, NULL);
346 options = fill_table (data, options);
347
348 ip4_config = nm_dhcp_manager_test_ip4_options_to_config (client, "eth0", options, "rebind");
349 ASSERT (ip4_config != NULL,
350 "dhcp-classless-2", "failed to parse DHCP4 options");
351
352 /* IP4 routes */
353 ASSERT (nm_ip4_config_get_num_routes (ip4_config) == 2,
354 "dhcp-classless-2", "unexpected number of IP routes");
355 ip4_test_route ("dhcp-classless-2", ip4_config, 0,
356 expected_route1_dest, expected_route1_gw, 24);
357 ip4_test_route ("dhcp-classless-2", ip4_config, 1,
358 expected_route2_dest, expected_route2_gw, 8);
359
360 g_hash_table_destroy (options);
361 }
362
363 static void
364 test_fedora_dhclient_classless_static_routes (const char *client)
365 {
366 GHashTable *options;
367 NMIP4Config *ip4_config;
368 const char *expected_route1_dest = "129.210.177.128";
369 const char *expected_route1_gw = "192.168.0.113";
370 const char *expected_route2_dest = "2.0.0.0";
371 const char *expected_route2_gw = "10.34.255.6";
372 const char *expected_gateway = "192.168.0.113";
373 static Option data[] = {
374 /* Fedora dhclient format */
375 { "new_classless_static_routes", "0 192.168.0.113 25.129.210.177.132 192.168.0.113 7.2 10.34.255.6" },
376 { NULL, NULL }
377 };
378
379 options = fill_table (generic_options, NULL);
380 options = fill_table (data, options);
381
382 ip4_config = nm_dhcp_manager_test_ip4_options_to_config (client, "eth0", options, "rebind");
383 ASSERT (ip4_config != NULL,
384 "dhcp-fedora-dhclient-classless", "failed to parse DHCP4 options");
385
386 /* IP4 routes */
387 ASSERT (nm_ip4_config_get_num_routes (ip4_config) == 2,
388 "dhcp-fedora-dhclient-classless", "unexpected number of IP routes");
389 ip4_test_route ("dhcp-fedora-dhclient-classless", ip4_config, 0,
390 expected_route1_dest, expected_route1_gw, 25);
391 ip4_test_route ("dhcp-fedora-dhclient-classless", ip4_config, 1,
392 expected_route2_dest, expected_route2_gw, 7);
393
394 /* Gateway */
395 ip4_test_gateway ("dhcp-fedora-dhclient-classless", ip4_config, expected_gateway);
396
397 g_hash_table_destroy (options);
398 }
399
400 static void
401 test_dhclient_invalid_classless_routes_1 (const char *client)
402 {
403 GHashTable *options;
404 NMIP4Config *ip4_config;
405 const char *expected_route1_dest = "192.168.10.0";
406 const char *expected_route1_gw = "192.168.1.1";
407 static Option data[] = {
408 /* dhclient format */
409 { "new_rfc3442_classless_static_routes", "24 192 168 10 192 168 1 1 45 10 17 66 41" },
410 { NULL, NULL }
411 };
412
413 options = fill_table (generic_options, NULL);
414 options = fill_table (data, options);
415
416 ip4_config = nm_dhcp_manager_test_ip4_options_to_config (client, "eth0", options, "rebind");
417 ASSERT (ip4_config != NULL,
418 "dhcp-dhclient-classless-invalid-1", "failed to parse DHCP4 options");
419
420 /* IP4 routes */
421 ASSERT (nm_ip4_config_get_num_routes (ip4_config) == 1,
422 "dhcp-dhclient-classless-invalid-1", "unexpected number of IP routes");
423
424 ip4_test_route ("dhcp-dhclient-classless-invalid-1", ip4_config, 0,
425 expected_route1_dest, expected_route1_gw, 24);
426
427 g_hash_table_destroy (options);
428 }
429
430 static void
431 test_dhcpcd_invalid_classless_routes_1 (const char *client)
432 {
433 GHashTable *options;
434 NMIP4Config *ip4_config;
435 const char *expected_route1_dest = "10.1.1.5";
436 const char *expected_route1_gw = "10.1.1.1";
437 const char *expected_route2_dest = "100.99.88.56";
438 const char *expected_route2_gw = "10.1.1.1";
439 static Option data[] = {
440 /* dhcpcd format */
441 { "new_classless_static_routes", "192.168.10.0/24 192.168.1.1 10.0.adfadf/44 10.17.66.41" },
442 { NULL, NULL }
443 };
444
445 options = fill_table (generic_options, NULL);
446 options = fill_table (data, options);
447
448 ip4_config = nm_dhcp_manager_test_ip4_options_to_config (client, "eth0", options, "rebind");
449 ASSERT (ip4_config != NULL,
450 "dhcp-dhcpcd-classless-invalid-1", "failed to parse DHCP4 options");
451
452 /* Test falling back to old-style static routes if the classless static
453 * routes are invalid.
454 */
455 ASSERT (nm_ip4_config_get_num_routes (ip4_config) == 2,
456 "dhcp-dhcpcdp-classless-invalid-1", "unexpected number of routes");
457 ip4_test_route ("dhcp-dhcpcdp-classless-invalid-1", ip4_config, 0,
458 expected_route1_dest, expected_route1_gw, 32);
459 ip4_test_route ("dhcp-dhcpcdp-classless-invalid-1", ip4_config, 1,
460 expected_route2_dest, expected_route2_gw, 32);
461
462 g_hash_table_destroy (options);
463 }
464
465 static void
466 test_dhclient_invalid_classless_routes_2 (const char *client)
467 {
468 GHashTable *options;
469 NMIP4Config *ip4_config;
470 const char *expected_route1_dest = "10.1.1.5";
471 const char *expected_route1_gw = "10.1.1.1";
472 const char *expected_route2_dest = "100.99.88.56";
473 const char *expected_route2_gw = "10.1.1.1";
474 static Option data[] = {
475 { "new_rfc3442_classless_static_routes", "45 10 17 66 41 24 192 168 10 192 168 1 1" },
476 { NULL, NULL }
477 };
478
479 options = fill_table (generic_options, NULL);
480 options = fill_table (data, options);
481
482 ip4_config = nm_dhcp_manager_test_ip4_options_to_config (client, "eth0", options, "rebind");
483 ASSERT (ip4_config != NULL,
484 "dhcp-dhclient-classless-invalid-2", "failed to parse DHCP4 options");
485
486 /* Test falling back to old-style static routes if the classless static
487 * routes are invalid.
488 */
489 ASSERT (nm_ip4_config_get_num_routes (ip4_config) == 2,
490 "dhcp-dhclient-classless-invalid-2", "unexpected number of routes");
491 ip4_test_route ("dhcp-dhclient-classless-invalid-2", ip4_config, 0,
492 expected_route1_dest, expected_route1_gw, 32);
493 ip4_test_route ("dhcp-dhclient-classless-invalid-2", ip4_config, 1,
494 expected_route2_dest, expected_route2_gw, 32);
495
496 g_hash_table_destroy (options);
497 }
498
499 static void
500 test_dhcpcd_invalid_classless_routes_2 (const char *client)
501 {
502 GHashTable *options;
503 NMIP4Config *ip4_config;
504 const char *expected_route1_dest = "10.1.1.5";
505 const char *expected_route1_gw = "10.1.1.1";
506 const char *expected_route2_dest = "100.99.88.56";
507 const char *expected_route2_gw = "10.1.1.1";
508 static Option data[] = {
509 { "new_classless_static_routes", "10.0.adfadf/44 10.17.66.41 192.168.10.0/24 192.168.1.1" },
510 { NULL, NULL }
511 };
512
513 options = fill_table (generic_options, NULL);
514 options = fill_table (data, options);
515
516 ip4_config = nm_dhcp_manager_test_ip4_options_to_config (client, "eth0", options, "rebind");
517 ASSERT (ip4_config != NULL,
518 "dhcp-dhcpcd-classless-invalid-2", "failed to parse DHCP4 options");
519
520 /* Test falling back to old-style static routes if the classless static
521 * routes are invalid.
522 */
523
524 /* Routes */
525 ASSERT (nm_ip4_config_get_num_routes (ip4_config) == 2,
526 "dhcp-dhcpcd-classless-invalid-2", "unexpected number of routes");
527 ip4_test_route ("dhcp-dhcpcd-classless-invalid-2", ip4_config, 0,
528 expected_route1_dest, expected_route1_gw, 32);
529 ip4_test_route ("dhcp-dhcpcd-classless-invalid-2", ip4_config, 1,
530 expected_route2_dest, expected_route2_gw, 32);
531
532 g_hash_table_destroy (options);
533 }
534
535 static void
536 test_dhclient_invalid_classless_routes_3 (const char *client)
537 {
538 GHashTable *options;
539 NMIP4Config *ip4_config;
540 const char *expected_route1_dest = "192.168.10.0";
541 const char *expected_route1_gw = "192.168.1.1";
542 static Option data[] = {
543 { "new_rfc3442_classless_static_routes", "24 192 168 10 192 168 1 1 32 128 10 17 66 41" },
544 { NULL, NULL }
545 };
546
547 options = fill_table (generic_options, NULL);
548 options = fill_table (data, options);
549
550 ip4_config = nm_dhcp_manager_test_ip4_options_to_config (client, "eth0", options, "rebind");
551 ASSERT (ip4_config != NULL,
552 "dhcp-dhclient-classless-invalid-3", "failed to parse DHCP4 options");
553
554 /* IP4 routes */
555 ASSERT (nm_ip4_config_get_num_routes (ip4_config) == 1,
556 "dhcp-dhclient-classless-invalid-3", "unexpected number of IP routes");
557 ip4_test_route ("dhcp-dhclient-classless-invalid-3", ip4_config, 0,
558 expected_route1_dest, expected_route1_gw, 24);
559
560 g_hash_table_destroy (options);
561 }
562
563 static void
564 test_dhcpcd_invalid_classless_routes_3 (const char *client)
565 {
566 GHashTable *options;
567 NMIP4Config *ip4_config;
568 const char *expected_route1_dest = "192.168.10.0";
569 const char *expected_route1_gw = "192.168.1.1";
570 static Option data[] = {
571 { "new_classless_static_routes", "192.168.10.0/24 192.168.1.1 128/32 10.17.66.41" },
572 { NULL, NULL }
573 };
574
575 options = fill_table (generic_options, NULL);
576 options = fill_table (data, options);
577
578 ip4_config = nm_dhcp_manager_test_ip4_options_to_config (client, "eth0", options, "rebind");
579 ASSERT (ip4_config != NULL,
580 "dhcp-dhcpcd-classless-invalid-3", "failed to parse DHCP4 options");
581
582 /* IP4 routes */
583 ASSERT (nm_ip4_config_get_num_routes (ip4_config) == 1,
584 "dhcp-dhcpcd-classless-invalid-3", "unexpected number of IP routes");
585 ip4_test_route ("dhcp-dhcpcd-classless-invalid-3", ip4_config, 0,
586 expected_route1_dest, expected_route1_gw, 24);
587
588 g_hash_table_destroy (options);
589 }
590
591 static void
592 test_dhclient_gw_in_classless_routes (const char *client)
593 {
594 GHashTable *options;
595 NMIP4Config *ip4_config;
596 const char *expected_route1_dest = "192.168.10.0";
597 const char *expected_route1_gw = "192.168.1.1";
598 const char *expected_gateway = "192.2.3.4";
599 static Option data[] = {
600 { "new_rfc3442_classless_static_routes", "24 192 168 10 192 168 1 1 0 192 2 3 4" },
601 { NULL, NULL }
602 };
603
604 options = fill_table (generic_options, NULL);
605 options = fill_table (data, options);
606
607 ip4_config = nm_dhcp_manager_test_ip4_options_to_config (client, "eth0", options, "rebind");
608 ASSERT (ip4_config != NULL,
609 "dhcp-dhclient-classless-gateway", "failed to parse DHCP4 options");
610
611 /* IP4 routes */
612 ASSERT (nm_ip4_config_get_num_routes (ip4_config) == 1,
613 "dhcp-dhclient-classless-gateway", "unexpected number of IP routes");
614 ip4_test_route ("dhcp-dhclient-classless-gateway", ip4_config, 0,
615 expected_route1_dest, expected_route1_gw, 24);
616
617 /* Gateway */
618 ip4_test_gateway ("dhcp-dhclient-classless-gateway", ip4_config, expected_gateway);
619
620 g_hash_table_destroy (options);
621 }
622
623 static void
624 test_dhcpcd_gw_in_classless_routes (const char *client)
625 {
626 GHashTable *options;
627 NMIP4Config *ip4_config;
628 const char *expected_route1_dest = "192.168.10.0";
629 const char *expected_route1_gw = "192.168.1.1";
630 const char *expected_gateway = "192.2.3.4";
631 static Option data[] = {
632 { "new_classless_static_routes", "192.168.10.0/24 192.168.1.1 0.0.0.0/0 192.2.3.4" },
633 { NULL, NULL }
634 };
635
636 options = fill_table (generic_options, NULL);
637 options = fill_table (data, options);
638
639 ip4_config = nm_dhcp_manager_test_ip4_options_to_config (client, "eth0", options, "rebind");
640 ASSERT (ip4_config != NULL,
641 "dhcp-dhcpcd-classless-gateway", "failed to parse DHCP4 options");
642
643 /* IP4 routes */
644 ASSERT (nm_ip4_config_get_num_routes (ip4_config) == 1,
645 "dhcp-dhcpcd-classless-gateway", "unexpected number of IP routes");
646 ip4_test_route ("dhcp-dhcpcd-classless-gateway", ip4_config, 0,
647 expected_route1_dest, expected_route1_gw, 24);
648
649 /* Gateway */
650 ip4_test_gateway ("dhcp-dhcpcd-classless-gateway", ip4_config, expected_gateway);
651
652 g_hash_table_destroy (options);
653 }
654
655 static Option escaped_searches_options[] = {
656 { "new_domain_search", "host1\\032host2\\032host3" },
657 { NULL, NULL }
658 };
659
660 static void
661 test_escaped_domain_searches (const char *client)
662 {
663 GHashTable *options;
664 NMIP4Config *ip4_config;
665 const char *expected_search0 = "host1";
666 const char *expected_search1 = "host2";
667 const char *expected_search2 = "host3";
668
669 options = fill_table (generic_options, NULL);
670 options = fill_table (escaped_searches_options, options);
671
672 ip4_config = nm_dhcp_manager_test_ip4_options_to_config (client, "eth0", options, "rebind");
673 ASSERT (ip4_config != NULL,
674 "dhcp-escaped-domain-searches", "failed to parse DHCP4 options");
675
676 /* domain searches */
677 ASSERT (nm_ip4_config_get_num_searches (ip4_config) == 3,
678 "dhcp-escaped-domain-searches", "unexpected number of searches");
679 ASSERT (!strcmp (nm_ip4_config_get_search (ip4_config, 0), expected_search0),
680 "dhcp-escaped-domain-searches", "unexpected domain search #1");
681 ASSERT (!strcmp (nm_ip4_config_get_search (ip4_config, 1), expected_search1),
682 "dhcp-escaped-domain-searches", "unexpected domain search #1");
683 ASSERT (!strcmp (nm_ip4_config_get_search (ip4_config, 2), expected_search2),
684 "dhcp-escaped-domain-searches", "unexpected domain search #1");
685
686 g_hash_table_destroy (options);
687 }
688
689 static Option invalid_escaped_searches_options[] = {
690 { "new_domain_search", "host1\\aahost2\\032host3" },
691 { NULL, NULL }
692 };
693
694 static void
695 test_invalid_escaped_domain_searches (const char *client)
696 {
697 GHashTable *options;
698 NMIP4Config *ip4_config;
699
700 options = fill_table (generic_options, NULL);
701 options = fill_table (invalid_escaped_searches_options, options);
702
703 ip4_config = nm_dhcp_manager_test_ip4_options_to_config (client, "eth0", options, "rebind");
704 ASSERT (ip4_config != NULL,
705 "dhcp-invalid-escaped-domain-searches", "failed to parse DHCP4 options");
706
707 /* domain searches */
708 ASSERT (nm_ip4_config_get_num_searches (ip4_config) == 0,
709 "dhcp-invalid-escaped-domain-searches", "unexpected domain searches");
710
711 g_hash_table_destroy (options);
712 }
713
714 static void
715 test_ip4_missing_prefix (const char *client, const char *ip, guint32 expected_prefix)
716 {
717 GHashTable *options;
718 NMIP4Config *ip4_config;
719 const NMPlatformIP4Address *address;
720
721 options = fill_table (generic_options, NULL);
722 g_hash_table_insert (options, "new_ip_address", string_to_byte_array_gvalue (ip));
723 g_hash_table_remove (options, "new_subnet_mask");
724
725 ip4_config = nm_dhcp_manager_test_ip4_options_to_config (client, "eth0", options, "rebind");
726 ASSERT (ip4_config != NULL,
727 "dhcp-ip4-missing-prefix", "failed to parse DHCP4 options");
728
729 ASSERT (nm_ip4_config_get_num_addresses (ip4_config) == 1,
730 "dhcp-ip4-missing-prefix", "unexpected number of IP4 addresses (not 1)");
731
732 address = nm_ip4_config_get_address (ip4_config, 0);
733 ASSERT (address,
734 "dhcp-ip4-missing-prefix", "missing IP4 address #1");
735
736 ASSERT (address->plen == expected_prefix,
737 "dhcp-ip4-missing-prefix", "unexpected IP4 address prefix %d (expected %d)",
738 address->plen, expected_prefix);
739
740 g_hash_table_destroy (options);
741 }
742
743 static void
744 test_ip4_prefix_classless (const char *client)
745 {
746 GHashTable *options;
747 NMIP4Config *ip4_config;
748 const NMPlatformIP4Address *address;
749
750 /* Ensure that the missing-subnet-mask handler doesn't mangle classless
751 * subnet masks at all. The handler should trigger only if the server
752 * doesn't send the subnet mask.
753 */
754
755 options = fill_table (generic_options, NULL);
756 g_hash_table_insert (options, "new_ip_address", string_to_byte_array_gvalue ("172.16.54.22"));
757 g_hash_table_insert (options, "new_subnet_mask", string_to_byte_array_gvalue ("255.255.252.0"));
758
759 ip4_config = nm_dhcp_manager_test_ip4_options_to_config (client, "eth0", options, "rebind");
760 ASSERT (ip4_config != NULL,
761 "dhcp-ip4-prefix-classless", "failed to parse DHCP4 options");
762
763 ASSERT (nm_ip4_config_get_num_addresses (ip4_config) == 1,
764 "dhcp-ip4-prefix-classless", "unexpected number of IP4 addresses (not 1)");
765
766 address = nm_ip4_config_get_address (ip4_config, 0);
767 ASSERT (address,
768 "dhcp-ip4-prefix-classless", "missing IP4 address #1");
769
770 ASSERT (address->plen == 22,
771 "dhcp-ip4-prefix-classless", "unexpected IP4 address prefix %d (expected 22)",
772 address->plen);
773
774 g_hash_table_destroy (options);
775 }
776
777 int main (int argc, char **argv)
778 {
779 GError *error = NULL;
780 char *base;
781 const char *clients[2][2] = { {DHCLIENT_PATH, "dhclient"}, {DHCPCD_PATH, "dhcpcd"} };
782 guint32 i;
783
784 g_type_init ();
785
786 if (!nm_utils_init (&error))
787 FAIL ("nm-utils-init", "failed to initialize libnm-util: %s", error->message);
788
789 /* The tests */
790 for (i = 0; i < 2; i++) {
791 const char *client_path = clients[i][0];
792 const char *client = clients[i][1];
793
794 if (!client_path || !strlen (client_path))
795 continue;
796
797 test_generic_options (client);
798 test_wins_options (client);
799 test_classless_static_routes_1 (client);
800 test_classless_static_routes_2 (client);
801 test_fedora_dhclient_classless_static_routes (client);
802 test_dhclient_invalid_classless_routes_1 (client);
803 test_dhcpcd_invalid_classless_routes_1 (client);
804 test_dhclient_invalid_classless_routes_2 (client);
805 test_dhcpcd_invalid_classless_routes_2 (client);
806 test_dhclient_invalid_classless_routes_3 (client);
807 test_dhcpcd_invalid_classless_routes_3 (client);
808 test_dhclient_gw_in_classless_routes (client);
809 test_dhcpcd_gw_in_classless_routes (client);
810 test_escaped_domain_searches (client);
811 test_invalid_escaped_domain_searches (client);
812 test_ip4_missing_prefix (client, "192.168.1.10", 24);
813 test_ip4_missing_prefix (client, "172.16.54.50", 16);
814 test_ip4_missing_prefix (client, "10.1.2.3", 8);
815 test_ip4_prefix_classless (client);
816 }
817
818 base = g_path_get_basename (argv[0]);
819 fprintf (stdout, "%s: SUCCESS\n", base);
820 g_free (base);
821 return 0;
822 }
823
824