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) {
67 if (write (f, &allow, sizeof(allow)) < 0)
75 if (write(f, &deny, sizeof(deny)) < 0)
86 static int enable_nat(struct connman_nat *nat)
88 g_free(nat->interface);
89 nat->interface = g_strdup(default_interface);
94 return __connman_firewall_enable_nat(nat->fw, nat->address,
95 nat->prefixlen, nat->interface);
98 static void disable_nat(struct connman_nat *nat)
103 __connman_firewall_disable_nat(nat->fw);
106 int __connman_nat_enable(const char *name, const char *address,
107 unsigned char prefixlen)
109 struct connman_nat *nat;
112 if (g_hash_table_size(nat_hash) == 0) {
113 err = enable_ip_forward(true);
118 nat = g_try_new0(struct connman_nat, 1);
122 nat->fw = __connman_firewall_create();
126 nat->address = g_strdup(address);
127 nat->prefixlen = prefixlen;
129 g_hash_table_replace(nat_hash, g_strdup(name), nat);
131 return enable_nat(nat);
136 __connman_firewall_destroy(nat->fw);
140 if (g_hash_table_size(nat_hash) == 0)
141 enable_ip_forward(false);
146 void __connman_nat_disable(const char *name)
148 struct connman_nat *nat;
150 nat = g_hash_table_lookup(nat_hash, name);
156 g_hash_table_remove(nat_hash, name);
158 if (g_hash_table_size(nat_hash) == 0)
159 enable_ip_forward(false);
162 static void update_default_interface(struct connman_service *service)
169 interface = connman_service_get_interface(service);
171 DBG("interface %s", interface);
173 g_free(default_interface);
174 default_interface = interface;
176 g_hash_table_iter_init(&iter, nat_hash);
178 while (g_hash_table_iter_next(&iter, &key, &value)) {
179 const char *name = key;
180 struct connman_nat *nat = value;
183 err = enable_nat(nat);
185 DBG("Failed to enable nat for %s", name);
189 static void shutdown_nat(gpointer key, gpointer value, gpointer user_data)
191 const char *name = key;
193 __connman_nat_disable(name);
196 static void cleanup_nat(gpointer data)
198 struct connman_nat *nat = data;
200 __connman_firewall_destroy(nat->fw);
201 g_free(nat->address);
202 g_free(nat->interface);
206 static const struct connman_notifier nat_notifier = {
208 .default_changed = update_default_interface,
211 int __connman_nat_init(void)
217 err = connman_notifier_register(&nat_notifier);
221 nat_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
222 g_free, cleanup_nat);
227 void __connman_nat_cleanup(void)
231 g_hash_table_foreach(nat_hash, shutdown_nat, NULL);
232 g_hash_table_destroy(nat_hash);
235 connman_notifier_unregister(&nat_notifier);