5 * Copyright (C) 2007-2012 Intel Corporation. All rights reserved.
6 * Copyright (C) 2012-2014 BMW Car IT GmbH.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
32 static char *default_interface;
33 static GHashTable *nat_hash;
37 unsigned char prefixlen;
38 struct firewall_context *fw;
43 static int enable_ip_forward(bool enable)
47 f = fopen("/proc/sys/net/ipv4/ip_forward", "r+");
61 static int enable_nat(struct connman_nat *nat)
66 g_free(nat->interface);
67 nat->interface = g_strdup(default_interface);
72 /* Enable masquerading */
73 cmd = g_strdup_printf("-s %s/%d -o %s -j MASQUERADE",
78 err = __connman_firewall_add_rule(nat->fw, "nat",
84 return __connman_firewall_enable(nat->fw);
87 static void disable_nat(struct connman_nat *nat)
92 /* Disable masquerading */
93 __connman_firewall_disable(nat->fw);
96 int __connman_nat_enable(const char *name, const char *address,
97 unsigned char prefixlen)
99 struct connman_nat *nat;
102 if (g_hash_table_size(nat_hash) == 0) {
103 err = enable_ip_forward(true);
108 nat = g_try_new0(struct connman_nat, 1);
112 nat->fw = __connman_firewall_create();
116 nat->address = g_strdup(address);
117 nat->prefixlen = prefixlen;
119 g_hash_table_replace(nat_hash, g_strdup(name), nat);
121 return enable_nat(nat);
126 __connman_firewall_destroy(nat->fw);
130 if (g_hash_table_size(nat_hash) == 0)
131 enable_ip_forward(false);
136 void __connman_nat_disable(const char *name)
138 struct connman_nat *nat;
140 nat = g_hash_table_lookup(nat_hash, name);
146 g_hash_table_remove(nat_hash, name);
148 if (g_hash_table_size(nat_hash) == 0)
149 enable_ip_forward(false);
152 static void update_default_interface(struct connman_service *service)
159 interface = connman_service_get_interface(service);
161 DBG("interface %s", interface);
163 g_free(default_interface);
164 default_interface = interface;
166 g_hash_table_iter_init(&iter, nat_hash);
168 while (g_hash_table_iter_next(&iter, &key, &value)) {
169 const char *name = key;
170 struct connman_nat *nat = value;
173 err = enable_nat(nat);
175 DBG("Failed to enable nat for %s", name);
179 static void shutdown_nat(gpointer key, gpointer value, gpointer user_data)
181 const char *name = key;
183 __connman_nat_disable(name);
186 static void cleanup_nat(gpointer data)
188 struct connman_nat *nat = data;
190 __connman_firewall_destroy(nat->fw);
191 g_free(nat->address);
192 g_free(nat->interface);
196 static struct connman_notifier nat_notifier = {
198 .default_changed = update_default_interface,
201 int __connman_nat_init(void)
207 err = connman_notifier_register(&nat_notifier);
211 nat_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
212 g_free, cleanup_nat);
217 void __connman_nat_cleanup(void)
221 g_hash_table_foreach(nat_hash, shutdown_nat, NULL);
222 g_hash_table_destroy(nat_hash);
225 connman_notifier_unregister(&nat_notifier);