5 * Copyright (C) 2007-2012 Intel Corporation. All rights reserved.
6 * Copyright (C) 2012 BMW Car IT GmbH. All rights reserved.
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;
42 static int enable_ip_forward(connman_bool_t enable)
46 f = fopen("/proc/sys/net/ipv4/ip_forward", "r+");
60 static int enable_nat(struct connman_nat *nat)
65 g_free(nat->interface);
66 nat->interface = g_strdup(default_interface);
68 if (nat->interface == NULL)
71 /* Enable masquerading */
72 cmd = g_strdup_printf("-s %s/%d -o %s -j MASQUERADE",
76 err = __connman_iptables_append("nat", "POSTROUTING", cmd);
81 return __connman_iptables_commit("nat");
84 static void disable_nat(struct connman_nat *nat)
89 if (nat->interface == NULL)
92 /* Disable masquerading */
93 cmd = g_strdup_printf("-s %s/%d -o %s -j MASQUERADE",
97 err = __connman_iptables_delete("nat", "POSTROUTING", cmd);
102 __connman_iptables_commit("nat");
105 int __connman_nat_enable(const char *name, const char *address,
106 unsigned char prefixlen)
108 struct connman_nat *nat;
111 if (g_hash_table_size(nat_hash) == 0) {
112 err = enable_ip_forward(TRUE);
117 nat = g_try_new0(struct connman_nat, 1);
119 if (g_hash_table_size(nat_hash) == 0)
120 enable_ip_forward(FALSE);
125 nat->address = g_strdup(address);
126 nat->prefixlen = prefixlen;
128 g_hash_table_replace(nat_hash, g_strdup(name), nat);
130 return enable_nat(nat);
133 void __connman_nat_disable(const char *name)
135 struct connman_nat *nat;
137 nat = g_hash_table_lookup(nat_hash, name);
143 g_hash_table_remove(nat_hash, name);
145 if (g_hash_table_size(nat_hash) == 0)
146 enable_ip_forward(FALSE);
149 static void update_default_interface(struct connman_service *service)
156 interface = connman_service_get_interface(service);
158 DBG("interface %s", interface);
160 g_free(default_interface);
161 default_interface = interface;
163 g_hash_table_iter_init(&iter, nat_hash);
165 while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
166 const char *name = key;
167 struct connman_nat *nat = value;
170 err = enable_nat(nat);
172 DBG("Failed to enable nat for %s", name);
176 static void shutdown_nat(gpointer key, gpointer value, gpointer user_data)
178 const char *name = key;
180 __connman_nat_disable(name);
183 static void cleanup_nat(gpointer data)
185 struct connman_nat *nat = data;
187 g_free(nat->address);
188 g_free(nat->interface);
192 static struct connman_notifier nat_notifier = {
194 .default_changed = update_default_interface,
197 int __connman_nat_init(void)
203 err = connman_notifier_register(&nat_notifier);
207 nat_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
208 g_free, cleanup_nat);
213 void __connman_nat_cleanup(void)
217 g_hash_table_foreach(nat_hash, shutdown_nat, NULL);
218 g_hash_table_destroy(nat_hash);
221 connman_notifier_unregister(&nat_notifier);