7e427e21f98e11798b02da54540831a4f24c9da8
[platform/upstream/connman.git] / tools / iptables-unit.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2013-2014  BMW Car IT GmbH.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <glib.h>
27
28 #include "../src/connman.h"
29
30 static bool assert_rule(const char *table_name, const char *rule)
31 {
32         char *cmd, *output, **lines;
33         GError **error = NULL;
34         int i;
35
36         cmd = g_strdup_printf(IPTABLES_SAVE " -t %s", table_name);
37         g_spawn_command_line_sync(cmd, &output, NULL, NULL, error);
38         g_free(cmd);
39
40         lines = g_strsplit(output, "\n", 0);
41         g_free(output);
42
43         for (i = 0; lines[i]; i++) {
44                 DBG("lines[%02d]: %s\n", i, lines[i]);
45                 if (g_strcmp0(lines[i], rule) == 0)
46                         break;
47         }
48         g_strfreev(lines);
49
50         if (!lines[i])
51                 return false;
52
53         return true;
54 }
55
56 static void assert_rule_exists(const char *table_name, const char *rule)
57 {
58         if (g_strcmp0(IPTABLES_SAVE, "") == 0) {
59                 DBG("iptables-save is missing, no assertion possible");
60                 return;
61         }
62
63         g_assert(assert_rule(table_name, rule));
64 }
65
66 static void assert_rule_not_exists(const char *table_name, const char *rule)
67 {
68         if (g_strcmp0(IPTABLES_SAVE, "") == 0) {
69                 DBG("iptables-save is missing, no assertion possible");
70                 return;
71         }
72
73         g_assert(!assert_rule(table_name, rule));
74 }
75
76 static void test_iptables_chain0(void)
77 {
78         int err;
79
80         err = __connman_iptables_new_chain("filter", "foo");
81         g_assert(err == 0);
82
83         err = __connman_iptables_commit("filter");
84         g_assert(err == 0);
85
86         assert_rule_exists("filter", ":foo - [0:0]");
87
88         err = __connman_iptables_delete_chain("filter", "foo");
89         g_assert(err == 0);
90
91         err = __connman_iptables_commit("filter");
92         g_assert(err == 0);
93
94         assert_rule_not_exists("filter", ":foo - [0:0]");
95 }
96
97 static void test_iptables_chain1(void)
98 {
99         int err;
100
101         err = __connman_iptables_new_chain("filter", "foo");
102         g_assert(err == 0);
103
104         err = __connman_iptables_commit("filter");
105         g_assert(err == 0);
106
107         err = __connman_iptables_flush_chain("filter", "foo");
108         g_assert(err == 0);
109
110         err = __connman_iptables_commit("filter");
111         g_assert(err == 0);
112
113         err = __connman_iptables_delete_chain("filter", "foo");
114         g_assert(err == 0);
115
116         err = __connman_iptables_commit("filter");
117         g_assert(err == 0);
118 }
119
120 static void test_iptables_chain2(void)
121 {
122         int err;
123
124         err = __connman_iptables_change_policy("filter", "INPUT", "DROP");
125         g_assert(err == 0);
126
127         err = __connman_iptables_commit("filter");
128         g_assert(err == 0);
129
130         err = __connman_iptables_change_policy("filter", "INPUT", "ACCEPT");
131         g_assert(err == 0);
132
133         err = __connman_iptables_commit("filter");
134         g_assert(err == 0);
135 }
136
137 static void test_iptables_chain3(void)
138 {
139         int err;
140
141         err = __connman_iptables_new_chain("filter", "user-chain-0");
142         g_assert(err == 0);
143
144         err = __connman_iptables_commit("filter");
145         g_assert(err == 0);
146
147         assert_rule_exists("filter", ":user-chain-0 - [0:0]");
148
149         err = __connman_iptables_new_chain("filter", "user-chain-1");
150         g_assert(err == 0);
151
152         err = __connman_iptables_commit("filter");
153         g_assert(err == 0);
154
155         assert_rule_exists("filter", ":user-chain-0 - [0:0]");
156         assert_rule_exists("filter", ":user-chain-1 - [0:0]");
157
158         err = __connman_iptables_delete_chain("filter", "user-chain-1");
159         g_assert(err == 0);
160
161         err = __connman_iptables_commit("filter");
162         g_assert(err == 0);
163
164         assert_rule_exists("filter", ":user-chain-0 - [0:0]");
165         assert_rule_not_exists("filter", ":user-chain-1 - [0:0]");
166
167         err = __connman_iptables_delete_chain("filter", "user-chain-0");
168         g_assert(err == 0);
169
170         err = __connman_iptables_commit("filter");
171         g_assert(err == 0);
172
173         assert_rule_not_exists("filter", ":user-chain-0 - [0:0]");
174 }
175
176 static void test_iptables_rule0(void)
177 {
178         int err;
179
180         /* Test simple appending and removing a rule */
181
182         err = __connman_iptables_append("filter", "INPUT",
183                                         "-m mark --mark 1 -j LOG");
184         g_assert(err == 0);
185
186         err = __connman_iptables_commit("filter");
187         g_assert(err == 0);
188
189         assert_rule_exists("filter",
190                                 "-A INPUT -m mark --mark 0x1 -j LOG");
191
192         err = __connman_iptables_delete("filter", "INPUT",
193                                         "-m mark --mark 1 -j LOG");
194         g_assert(err == 0);
195
196         err = __connman_iptables_commit("filter");
197         g_assert(err == 0);
198
199         assert_rule_not_exists("filter",
200                                 "-A INPUT -m mark --mark 0x1 -j LOG");
201 }
202
203 static void test_iptables_rule1(void)
204 {
205         int err;
206
207         /* Test if we can do NAT stuff */
208
209         err = __connman_iptables_append("nat", "POSTROUTING",
210                                 "-s 10.10.1.0/24 -o eth0 -j MASQUERADE");
211
212         err = __connman_iptables_commit("nat");
213         g_assert(err == 0);
214
215         assert_rule_exists("nat",
216                 "-A POSTROUTING -s 10.10.1.0/24 -o eth0 -j MASQUERADE");
217
218         err = __connman_iptables_delete("nat", "POSTROUTING",
219                                 "-s 10.10.1.0/24 -o eth0 -j MASQUERADE");
220
221         err = __connman_iptables_commit("nat");
222         g_assert(err == 0);
223
224         assert_rule_not_exists("nat",
225                 "-A POSTROUTING -s 10.10.1.0/24 -o eth0 -j MASQUERADE");
226 }
227
228 static void test_iptables_rule2(void)
229 {
230         int err;
231
232         /* Test if the right rule is removed */
233
234         err = __connman_iptables_append("filter", "INPUT",
235                                         "-m mark --mark 1 -j LOG");
236         g_assert(err == 0);
237
238         err = __connman_iptables_commit("filter");
239         g_assert(err == 0);
240
241         assert_rule_exists("filter",
242                                 "-A INPUT -m mark --mark 0x1 -j LOG");
243
244         err = __connman_iptables_append("filter", "INPUT",
245                                         "-m mark --mark 2 -j LOG");
246         g_assert(err == 0);
247
248         err = __connman_iptables_commit("filter");
249         g_assert(err == 0);
250
251         assert_rule_exists("filter",
252                                 "-A INPUT -m mark --mark 0x1 -j LOG");
253         assert_rule_exists("filter",
254                                 "-A INPUT -m mark --mark 0x2 -j LOG");
255
256         err = __connman_iptables_delete("filter", "INPUT",
257                                         "-m mark --mark 2 -j LOG");
258         g_assert(err == 0);
259
260         err = __connman_iptables_commit("filter");
261         g_assert(err == 0);
262
263         assert_rule_exists("filter",
264                                 "-A INPUT -m mark --mark 0x1 -j LOG");
265         assert_rule_not_exists("filter",
266                                 "-A INPUT -m mark --mark 0x2 -j LOG");
267
268         err = __connman_iptables_delete("filter", "INPUT",
269                                         "-m mark --mark 1 -j LOG");
270         g_assert(err == 0);
271
272         err = __connman_iptables_commit("filter");
273         g_assert(err == 0);
274
275         assert_rule_not_exists("filter",
276                                 "-A INPUT -m mark --mark 0x1 -j LOG");
277 }
278
279 static void test_iptables_target0(void)
280 {
281         int err;
282
283         /* Test if 'fallthrough' targets work */
284
285         err = __connman_iptables_append("filter", "INPUT",
286                                         "-m mark --mark 1");
287         g_assert(err == 0);
288
289         err = __connman_iptables_append("filter", "INPUT",
290                                         "-m mark --mark 2");
291         g_assert(err == 0);
292
293         err = __connman_iptables_commit("filter");
294         g_assert(err == 0);
295
296         assert_rule_exists("filter", "-A INPUT -m mark --mark 0x1");
297         assert_rule_exists("filter", "-A INPUT -m mark --mark 0x2");
298
299         err = __connman_iptables_delete("filter", "INPUT",
300                                         "-m mark --mark 1");
301         g_assert(err == 0);
302
303         err = __connman_iptables_commit("filter");
304         g_assert(err == 0);
305
306         err = __connman_iptables_delete("filter", "INPUT",
307                                         "-m mark --mark 2");
308         g_assert(err == 0);
309
310         err = __connman_iptables_commit("filter");
311         g_assert(err == 0);
312
313         assert_rule_not_exists("filter", "-A INPUT -m mark --mark 0x1");
314         assert_rule_not_exists("filter", "-A INPUT -m mark --mark 0x2");
315 }
316
317 struct connman_notifier *nat_notifier;
318
319 struct connman_service {
320         char *dummy;
321 };
322
323 char *connman_service_get_interface(struct connman_service *service)
324 {
325         return "eth0";
326 }
327
328 int connman_notifier_register(struct connman_notifier *notifier)
329 {
330         nat_notifier = notifier;
331
332         return 0;
333 }
334
335 void connman_notifier_unregister(struct connman_notifier *notifier)
336 {
337         nat_notifier = NULL;
338 }
339
340 static void test_nat_basic0(void)
341 {
342         int err;
343
344         err = __connman_nat_enable("bridge", "192.168.2.1", 24);
345         g_assert(err == 0);
346
347         /* test that table is empty */
348         err = __connman_iptables_append("nat", "POSTROUTING",
349                                         "-s 192.168.2.1/24 -o eth0 -j MASQUERADE");
350         g_assert(err == 0);
351
352         err = __connman_iptables_commit("nat");
353         g_assert(err == 0);
354
355         assert_rule_exists("nat",
356                 "-A POSTROUTING -s 192.168.2.0/24 -o eth0 -j MASQUERADE");
357
358         err = __connman_iptables_delete("nat", "POSTROUTING",
359                                         "-s 192.168.2.1/24 -o eth0 -j MASQUERADE");
360         g_assert(err == 0);
361
362         err = __connman_iptables_commit("nat");
363         g_assert(err == 0);
364
365         assert_rule_not_exists("nat",
366                 "-A POSTROUTING -s 192.168.2.0/24 -o eth0 -j MASQUERADE");
367
368         __connman_nat_disable("bridge");
369 }
370
371 static void test_nat_basic1(void)
372 {
373         struct connman_service *service;
374         int err;
375
376         service = g_try_new0(struct connman_service, 1);
377         g_assert(service);
378
379         nat_notifier->default_changed(service);
380
381         err = __connman_nat_enable("bridge", "192.168.2.1", 24);
382         g_assert(err == 0);
383
384         /* test that table is not empty */
385         err = __connman_iptables_append("nat", "POSTROUTING",
386                                         "-s 192.168.2.1/24 -o eth0 -j MASQUERADE");
387         g_assert(err == 0);
388
389         err = __connman_iptables_commit("nat");
390         g_assert(err == 0);
391
392         __connman_nat_disable("bridge");
393
394         /* test that table is empty again */
395         err = __connman_iptables_delete("nat", "POSTROUTING",
396                                         "-s 192.168.2.1/24 -o eth0 -j MASQUERADE");
397         g_assert(err == 0);
398
399         err = __connman_iptables_commit("nat");
400         g_assert(err == 0);
401
402         g_free(service);
403 }
404
405 static void test_firewall_basic0(void)
406 {
407         struct firewall_context *ctx;
408         int err;
409
410         ctx = __connman_firewall_create();
411         g_assert(ctx);
412
413         err = __connman_firewall_add_rule(ctx, "filter", "INPUT",
414                                         "-m mark --mark 999 -j LOG");
415         g_assert(err == 0);
416
417         err = __connman_firewall_enable(ctx);
418         g_assert(err == 0);
419
420         assert_rule_exists("filter", ":connman-INPUT - [0:0]");
421         assert_rule_exists("filter", "-A INPUT -j connman-INPUT");
422         assert_rule_exists("filter", "-A connman-INPUT -m mark --mark 0x3e7 -j LOG");
423
424         err = __connman_firewall_disable(ctx);
425         g_assert(err == 0);
426
427         assert_rule_not_exists("filter", ":connman-INPUT - [0:0]");
428         assert_rule_not_exists("filter", "-A INPUT -j connman-INPUT");
429         assert_rule_not_exists("filter", "-A connman-INPUT -m mark --mark 0x3e7 -j LOG");
430
431         __connman_firewall_destroy(ctx);
432 }
433
434 static void test_firewall_basic1(void)
435 {
436         struct firewall_context *ctx;
437         int err;
438
439         ctx = __connman_firewall_create();
440         g_assert(ctx);
441
442         err = __connman_firewall_add_rule(ctx, "filter", "INPUT",
443                                         "-m mark --mark 999 -j LOG");
444         g_assert(err == 0);
445
446         err = __connman_firewall_add_rule(ctx, "filter", "OUTPUT",
447                                         "-m mark --mark 999 -j LOG");
448         g_assert(err == 0);
449
450         err = __connman_firewall_enable(ctx);
451         g_assert(err == 0);
452
453         err = __connman_firewall_disable(ctx);
454         g_assert(err == 0);
455
456         __connman_firewall_destroy(ctx);
457 }
458
459 static void test_firewall_basic2(void)
460 {
461         struct firewall_context *ctx;
462         int err;
463
464         ctx = __connman_firewall_create();
465         g_assert(ctx);
466
467         err = __connman_firewall_add_rule(ctx, "mangle", "INPUT",
468                                         "-j CONNMARK --restore-mark");
469         g_assert(err == 0);
470
471         err = __connman_firewall_add_rule(ctx, "mangle", "POSTROUTING",
472                                         "-j CONNMARK --save-mark");
473         g_assert(err == 0);
474
475         err = __connman_firewall_enable(ctx);
476         g_assert(err == 0);
477
478         err = __connman_firewall_disable(ctx);
479         g_assert(err == 0);
480
481         __connman_firewall_destroy(ctx);
482 }
483
484 static gchar *option_debug = NULL;
485
486 static bool parse_debug(const char *key, const char *value,
487                                         gpointer user_data, GError **error)
488 {
489         if (value)
490                 option_debug = g_strdup(value);
491         else
492                 option_debug = g_strdup("*");
493
494         return true;
495 }
496
497 static GOptionEntry options[] = {
498         { "debug", 'd', G_OPTION_FLAG_OPTIONAL_ARG,
499                                 G_OPTION_ARG_CALLBACK, parse_debug,
500                                 "Specify debug options to enable", "DEBUG" },
501         { NULL },
502 };
503
504 int main(int argc, char *argv[])
505 {
506         GOptionContext *context;
507         GError *error = NULL;
508         int err;
509
510         g_test_init(&argc, &argv, NULL);
511
512         context = g_option_context_new(NULL);
513         g_option_context_add_main_entries(context, options, NULL);
514
515         if (!g_option_context_parse(context, &argc, &argv, &error)) {
516                 if (error) {
517                         g_printerr("%s\n", error->message);
518                         g_error_free(error);
519                 } else
520                         g_printerr("An unknown error occurred\n");
521                 return 1;
522         }
523
524         g_option_context_free(context);
525
526         __connman_log_init(argv[0], option_debug, false, false,
527                         "Unit Tests Connection Manager", VERSION);
528
529         __connman_iptables_init();
530         __connman_firewall_init();
531         __connman_nat_init();
532
533         g_test_add_func("/iptables/chain0", test_iptables_chain0);
534         g_test_add_func("/iptables/chain1", test_iptables_chain1);
535         g_test_add_func("/iptables/chain2", test_iptables_chain2);
536         g_test_add_func("/iptables/chain3", test_iptables_chain3);
537         g_test_add_func("/iptables/rule0",  test_iptables_rule0);
538         g_test_add_func("/iptables/rule1",  test_iptables_rule1);
539         g_test_add_func("/iptables/rule2",  test_iptables_rule2);
540         g_test_add_func("/iptables/target0", test_iptables_target0);
541         g_test_add_func("/nat/basic0", test_nat_basic0);
542         g_test_add_func("/nat/basic1", test_nat_basic1);
543         g_test_add_func("/firewall/basic0", test_firewall_basic0);
544         g_test_add_func("/firewall/basic1", test_firewall_basic1);
545         g_test_add_func("/firewall/basic2", test_firewall_basic2);
546
547         err = g_test_run();
548
549         __connman_nat_cleanup();
550         __connman_firewall_cleanup();
551         __connman_iptables_cleanup();
552
553         g_free(option_debug);
554
555         return err;
556 }