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
28 #include <sys/types.h>
35 static char *default_interface;
36 static GHashTable *nat_hash;
40 unsigned char prefixlen;
41 struct firewall_context *fw;
46 static int enable_ip_forward(bool enable)
48 static char value = 0;
51 if ((f = open("/proc/sys/net/ipv4/ip_forward", O_CLOEXEC | O_RDWR)) < 0)
55 if (read(f, &value, sizeof(value)) < 0)
58 if (lseek(f, 0, SEEK_SET) < 0)
65 if (write (f, &allow, sizeof(allow)) < 0)
73 if (write(f, &deny, sizeof(deny)) < 0)
84 static int enable_nat(struct connman_nat *nat)
86 g_free(nat->interface);
87 nat->interface = g_strdup(default_interface);
92 return __connman_firewall_enable_nat(nat->fw, nat->address,
93 nat->prefixlen, nat->interface);
96 static void disable_nat(struct connman_nat *nat)
101 __connman_firewall_disable_nat(nat->fw);
104 int __connman_nat_enable(const char *name, const char *address,
105 unsigned char prefixlen)
107 struct connman_nat *nat;
110 if (g_hash_table_size(nat_hash) == 0) {
111 err = enable_ip_forward(true);
116 nat = g_try_new0(struct connman_nat, 1);
120 nat->fw = __connman_firewall_create();
124 nat->address = g_strdup(address);
125 nat->prefixlen = prefixlen;
127 g_hash_table_replace(nat_hash, g_strdup(name), nat);
129 return enable_nat(nat);
134 __connman_firewall_destroy(nat->fw);
138 if (g_hash_table_size(nat_hash) == 0)
139 enable_ip_forward(false);
144 void __connman_nat_disable(const char *name)
146 struct connman_nat *nat;
148 nat = g_hash_table_lookup(nat_hash, name);
154 g_hash_table_remove(nat_hash, name);
156 if (g_hash_table_size(nat_hash) == 0)
157 enable_ip_forward(false);
160 static void update_default_interface(struct connman_service *service)
167 interface = connman_service_get_interface(service);
169 DBG("interface %s", interface);
171 g_free(default_interface);
172 default_interface = interface;
174 g_hash_table_iter_init(&iter, nat_hash);
176 while (g_hash_table_iter_next(&iter, &key, &value)) {
177 const char *name = key;
178 struct connman_nat *nat = value;
181 err = enable_nat(nat);
183 DBG("Failed to enable nat for %s", name);
187 static void shutdown_nat(gpointer key, gpointer value, gpointer user_data)
189 const char *name = key;
191 __connman_nat_disable(name);
194 static void cleanup_nat(gpointer data)
196 struct connman_nat *nat = data;
198 __connman_firewall_destroy(nat->fw);
199 g_free(nat->address);
200 g_free(nat->interface);
204 static struct connman_notifier nat_notifier = {
206 .default_changed = update_default_interface,
209 int __connman_nat_init(void)
215 err = connman_notifier_register(&nat_notifier);
219 nat_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
220 g_free, cleanup_nat);
225 void __connman_nat_cleanup(void)
229 g_hash_table_foreach(nat_hash, shutdown_nat, NULL);
230 g_hash_table_destroy(nat_hash);
233 connman_notifier_unregister(&nat_notifier);