Imported Upstream version 1.35
[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 #include <errno.h>
28
29 #include "../src/connman.h"
30
31 static bool assert_rule(const char *table_name, const char *rule)
32 {
33         char *cmd, *output, **lines;
34         GError **error = NULL;
35         int i;
36         bool ret = true;
37
38         cmd = g_strdup_printf(IPTABLES_SAVE " -t %s", table_name);
39         g_spawn_command_line_sync(cmd, &output, NULL, NULL, error);
40         g_free(cmd);
41
42         lines = g_strsplit(output, "\n", 0);
43         g_free(output);
44         if (!lines)
45                 return false;
46
47         for (i = 0; lines[i]; i++) {
48                 DBG("lines[%02d]: %s\n", i, lines[i]);
49                 if (g_strcmp0(lines[i], rule) == 0)
50                         break;
51         }
52
53         if (!lines[i])
54                 ret = false;
55
56         g_strfreev(lines);
57         return ret;
58 }
59
60 static void assert_rule_exists(const char *table_name, const char *rule)
61 {
62         if (g_strcmp0(IPTABLES_SAVE, "") == 0) {
63                 DBG("iptables-save is missing, no assertion possible");
64                 return;
65         }
66
67         g_assert(assert_rule(table_name, rule));
68 }
69
70 static void assert_rule_not_exists(const char *table_name, const char *rule)
71 {
72         if (g_strcmp0(IPTABLES_SAVE, "") == 0) {
73                 DBG("iptables-save is missing, no assertion possible");
74                 return;
75         }
76
77         g_assert(!assert_rule(table_name, rule));
78 }
79
80 static void test_iptables_chain0(void)
81 {
82         int err;
83
84         err = __connman_iptables_new_chain("filter", "foo");
85         g_assert(err == 0);
86
87         err = __connman_iptables_commit("filter");
88         g_assert(err == 0);
89
90         assert_rule_exists("filter", ":foo - [0:0]");
91
92         err = __connman_iptables_delete_chain("filter", "foo");
93         g_assert(err == 0);
94
95         err = __connman_iptables_commit("filter");
96         g_assert(err == 0);
97
98         assert_rule_not_exists("filter", ":foo - [0:0]");
99 }
100
101 static void test_iptables_chain1(void)
102 {
103         int err;
104
105         err = __connman_iptables_new_chain("filter", "foo");
106         g_assert(err == 0);
107
108         err = __connman_iptables_commit("filter");
109         g_assert(err == 0);
110
111         err = __connman_iptables_flush_chain("filter", "foo");
112         g_assert(err == 0);
113
114         err = __connman_iptables_commit("filter");
115         g_assert(err == 0);
116
117         err = __connman_iptables_delete_chain("filter", "foo");
118         g_assert(err == 0);
119
120         err = __connman_iptables_commit("filter");
121         g_assert(err == 0);
122 }
123
124 static void test_iptables_chain2(void)
125 {
126         int err;
127
128         err = __connman_iptables_change_policy("filter", "INPUT", "DROP");
129         g_assert(err == 0);
130
131         err = __connman_iptables_commit("filter");
132         g_assert(err == 0);
133
134         err = __connman_iptables_change_policy("filter", "INPUT", "ACCEPT");
135         g_assert(err == 0);
136
137         err = __connman_iptables_commit("filter");
138         g_assert(err == 0);
139 }
140
141 static void test_iptables_chain3(void)
142 {
143         int err;
144
145         err = __connman_iptables_new_chain("filter", "user-chain-0");
146         g_assert(err == 0);
147
148         err = __connman_iptables_commit("filter");
149         g_assert(err == 0);
150
151         assert_rule_exists("filter", ":user-chain-0 - [0:0]");
152
153         err = __connman_iptables_new_chain("filter", "user-chain-1");
154         g_assert(err == 0);
155
156         err = __connman_iptables_commit("filter");
157         g_assert(err == 0);
158
159         assert_rule_exists("filter", ":user-chain-0 - [0:0]");
160         assert_rule_exists("filter", ":user-chain-1 - [0:0]");
161
162         err = __connman_iptables_delete_chain("filter", "user-chain-1");
163         g_assert(err == 0);
164
165         err = __connman_iptables_commit("filter");
166         g_assert(err == 0);
167
168         assert_rule_exists("filter", ":user-chain-0 - [0:0]");
169         assert_rule_not_exists("filter", ":user-chain-1 - [0:0]");
170
171         err = __connman_iptables_delete_chain("filter", "user-chain-0");
172         g_assert(err == 0);
173
174         err = __connman_iptables_commit("filter");
175         g_assert(err == 0);
176
177         assert_rule_not_exists("filter", ":user-chain-0 - [0:0]");
178 }
179
180 static void test_iptables_rule0(void)
181 {
182         int err;
183
184         /* Test simple appending and removing a rule */
185
186         err = __connman_iptables_append("filter", "INPUT",
187                                         "-m mark --mark 1 -j LOG");
188         g_assert(err == 0);
189
190         err = __connman_iptables_commit("filter");
191         g_assert(err == 0);
192
193         assert_rule_exists("filter",
194                                 "-A INPUT -m mark --mark 0x1 -j LOG");
195
196         err = __connman_iptables_delete("filter", "INPUT",
197                                         "-m mark --mark 1 -j LOG");
198         g_assert(err == 0);
199
200         err = __connman_iptables_commit("filter");
201         g_assert(err == 0);
202
203         assert_rule_not_exists("filter",
204                                 "-A INPUT -m mark --mark 0x1 -j LOG");
205 }
206
207 static void test_iptables_rule1(void)
208 {
209         int err;
210
211         /* Test if we can do NAT stuff */
212
213         err = __connman_iptables_append("nat", "POSTROUTING",
214                                 "-s 10.10.1.0/24 -o eth0 -j MASQUERADE");
215
216         err = __connman_iptables_commit("nat");
217         g_assert(err == 0);
218
219         assert_rule_exists("nat",
220                 "-A POSTROUTING -s 10.10.1.0/24 -o eth0 -j MASQUERADE");
221
222         err = __connman_iptables_delete("nat", "POSTROUTING",
223                                 "-s 10.10.1.0/24 -o eth0 -j MASQUERADE");
224
225         err = __connman_iptables_commit("nat");
226         g_assert(err == 0);
227
228         assert_rule_not_exists("nat",
229                 "-A POSTROUTING -s 10.10.1.0/24 -o eth0 -j MASQUERADE");
230 }
231
232 static void test_iptables_rule2(void)
233 {
234         int err;
235
236         /* Test if the right rule is removed */
237
238         err = __connman_iptables_append("filter", "INPUT",
239                                         "-m mark --mark 1 -j LOG");
240         g_assert(err == 0);
241
242         err = __connman_iptables_commit("filter");
243         g_assert(err == 0);
244
245         assert_rule_exists("filter",
246                                 "-A INPUT -m mark --mark 0x1 -j LOG");
247
248         err = __connman_iptables_append("filter", "INPUT",
249                                         "-m mark --mark 2 -j LOG");
250         g_assert(err == 0);
251
252         err = __connman_iptables_commit("filter");
253         g_assert(err == 0);
254
255         assert_rule_exists("filter",
256                                 "-A INPUT -m mark --mark 0x1 -j LOG");
257         assert_rule_exists("filter",
258                                 "-A INPUT -m mark --mark 0x2 -j LOG");
259
260         err = __connman_iptables_delete("filter", "INPUT",
261                                         "-m mark --mark 2 -j LOG");
262         g_assert(err == 0);
263
264         err = __connman_iptables_commit("filter");
265         g_assert(err == 0);
266
267         assert_rule_exists("filter",
268                                 "-A INPUT -m mark --mark 0x1 -j LOG");
269         assert_rule_not_exists("filter",
270                                 "-A INPUT -m mark --mark 0x2 -j LOG");
271
272         err = __connman_iptables_delete("filter", "INPUT",
273                                         "-m mark --mark 1 -j LOG");
274         g_assert(err == 0);
275
276         err = __connman_iptables_commit("filter");
277         g_assert(err == 0);
278
279         assert_rule_not_exists("filter",
280                                 "-A INPUT -m mark --mark 0x1 -j LOG");
281 }
282
283 static void test_iptables_target0(void)
284 {
285         int err;
286
287         /* Test if 'fallthrough' targets work */
288
289         err = __connman_iptables_append("filter", "INPUT",
290                                         "-m mark --mark 1");
291         g_assert(err == 0);
292
293         err = __connman_iptables_append("filter", "INPUT",
294                                         "-m mark --mark 2");
295         g_assert(err == 0);
296
297         err = __connman_iptables_commit("filter");
298         g_assert(err == 0);
299
300         assert_rule_exists("filter", "-A INPUT -m mark --mark 0x1");
301         assert_rule_exists("filter", "-A INPUT -m mark --mark 0x2");
302
303         err = __connman_iptables_delete("filter", "INPUT",
304                                         "-m mark --mark 1");
305         g_assert(err == 0);
306
307         err = __connman_iptables_commit("filter");
308         g_assert(err == 0);
309
310         err = __connman_iptables_delete("filter", "INPUT",
311                                         "-m mark --mark 2");
312         g_assert(err == 0);
313
314         err = __connman_iptables_commit("filter");
315         g_assert(err == 0);
316
317         assert_rule_not_exists("filter", "-A INPUT -m mark --mark 0x1");
318         assert_rule_not_exists("filter", "-A INPUT -m mark --mark 0x2");
319 }
320
321 struct connman_notifier *nat_notifier;
322
323 struct connman_service {
324         char *dummy;
325 };
326
327 char *connman_service_get_interface(struct connman_service *service)
328 {
329         return "eth0";
330 }
331
332 int connman_notifier_register(struct connman_notifier *notifier)
333 {
334         nat_notifier = notifier;
335
336         return 0;
337 }
338
339 void connman_notifier_unregister(struct connman_notifier *notifier)
340 {
341         nat_notifier = NULL;
342 }
343
344 static void test_nat_basic0(void)
345 {
346         int err;
347
348         err = __connman_nat_enable("bridge", "192.168.2.1", 24);
349         g_assert(err == 0);
350
351         /* test that table is empty */
352         err = __connman_iptables_append("nat", "POSTROUTING",
353                                         "-s 192.168.2.1/24 -o eth0 -j MASQUERADE");
354         g_assert(err == 0);
355
356         err = __connman_iptables_commit("nat");
357         g_assert(err == 0);
358
359         assert_rule_exists("nat",
360                 "-A POSTROUTING -s 192.168.2.0/24 -o eth0 -j MASQUERADE");
361
362         err = __connman_iptables_delete("nat", "POSTROUTING",
363                                         "-s 192.168.2.1/24 -o eth0 -j MASQUERADE");
364         g_assert(err == 0);
365
366         err = __connman_iptables_commit("nat");
367         g_assert(err == 0);
368
369         assert_rule_not_exists("nat",
370                 "-A POSTROUTING -s 192.168.2.0/24 -o eth0 -j MASQUERADE");
371
372         __connman_nat_disable("bridge");
373 }
374
375 static void test_nat_basic1(void)
376 {
377         struct connman_service *service;
378         int err;
379
380         service = g_try_new0(struct connman_service, 1);
381         g_assert(service);
382
383         nat_notifier->default_changed(service);
384
385         err = __connman_nat_enable("bridge", "192.168.2.1", 24);
386         g_assert(err == 0);
387
388         /* test that table is not empty */
389         err = __connman_iptables_append("nat", "POSTROUTING",
390                                         "-s 192.168.2.1/24 -o eth0 -j MASQUERADE");
391         g_assert(err == 0);
392
393         err = __connman_iptables_commit("nat");
394         g_assert(err == 0);
395
396         __connman_nat_disable("bridge");
397
398         /* test that table is empty again */
399         err = __connman_iptables_delete("nat", "POSTROUTING",
400                                         "-s 192.168.2.1/24 -o eth0 -j MASQUERADE");
401         g_assert(err == 0);
402
403         err = __connman_iptables_commit("nat");
404         g_assert(err == 0);
405
406         g_free(service);
407 }
408
409 static gchar *option_debug = NULL;
410
411 static bool parse_debug(const char *key, const char *value,
412                                         gpointer user_data, GError **error)
413 {
414         if (value)
415                 option_debug = g_strdup(value);
416         else
417                 option_debug = g_strdup("*");
418
419         return true;
420 }
421
422 static GOptionEntry options[] = {
423         { "debug", 'd', G_OPTION_FLAG_OPTIONAL_ARG,
424                                 G_OPTION_ARG_CALLBACK, parse_debug,
425                                 "Specify debug options to enable", "DEBUG" },
426         { NULL },
427 };
428
429 int main(int argc, char *argv[])
430 {
431         GOptionContext *context;
432         GError *error = NULL;
433         int err;
434
435         g_test_init(&argc, &argv, NULL);
436
437         context = g_option_context_new(NULL);
438         g_option_context_add_main_entries(context, options, NULL);
439
440         if (!g_option_context_parse(context, &argc, &argv, &error)) {
441                 if (error) {
442                         g_printerr("%s\n", error->message);
443                         g_error_free(error);
444                 } else
445                         g_printerr("An unknown error occurred\n");
446                 return 1;
447         }
448
449         g_option_context_free(context);
450
451         __connman_log_init(argv[0], option_debug, false, false,
452                         "Unit Tests Connection Manager", VERSION);
453
454         __connman_iptables_init();
455         __connman_nat_init();
456
457         g_test_add_func("/iptables/chain0", test_iptables_chain0);
458         g_test_add_func("/iptables/chain1", test_iptables_chain1);
459         g_test_add_func("/iptables/chain2", test_iptables_chain2);
460         g_test_add_func("/iptables/chain3", test_iptables_chain3);
461         g_test_add_func("/iptables/rule0",  test_iptables_rule0);
462         g_test_add_func("/iptables/rule1",  test_iptables_rule1);
463         g_test_add_func("/iptables/rule2",  test_iptables_rule2);
464         g_test_add_func("/iptables/target0", test_iptables_target0);
465         g_test_add_func("/nat/basic0", test_nat_basic0);
466         g_test_add_func("/nat/basic1", test_nat_basic1);
467
468         err = g_test_run();
469
470         __connman_nat_cleanup();
471         __connman_iptables_cleanup();
472
473         g_free(option_debug);
474
475         return err;
476 }