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 void flush_nat(void)
64 err = __connman_iptables_command("-t nat -F POSTROUTING");
66 DBG("Flushing the nat table failed");
71 __connman_iptables_commit("nat");
74 static int enable_nat(struct connman_nat *nat)
78 g_free(nat->interface);
79 nat->interface = g_strdup(default_interface);
81 if (nat->interface == NULL)
84 /* Enable masquerading */
85 err = __connman_iptables_command("-t nat -A POSTROUTING "
86 "-s %s/%d -o %s -j MASQUERADE",
93 return __connman_iptables_commit("nat");
96 static void disable_nat(struct connman_nat *nat)
100 if (nat->interface == NULL)
103 /* Disable masquerading */
104 err = __connman_iptables_command("-t nat -D POSTROUTING "
105 "-s %s/%d -o %s -j MASQUERADE",
112 __connman_iptables_commit("nat");
115 int __connman_nat_enable(const char *name, const char *address,
116 unsigned char prefixlen)
118 struct connman_nat *nat;
121 if (g_hash_table_size(nat_hash) == 0) {
122 err = enable_ip_forward(TRUE);
127 nat = g_try_new0(struct connman_nat, 1);
129 if (g_hash_table_size(nat_hash) == 0)
130 enable_ip_forward(FALSE);
135 nat->address = g_strdup(address);
136 nat->prefixlen = prefixlen;
138 g_hash_table_replace(nat_hash, g_strdup(name), nat);
140 return enable_nat(nat);
143 void __connman_nat_disable(const char *name)
145 struct connman_nat *nat;
147 nat = g_hash_table_lookup(nat_hash, name);
153 g_hash_table_remove(nat_hash, name);
155 if (g_hash_table_size(nat_hash) == 0)
156 enable_ip_forward(FALSE);
159 static void update_default_interface(struct connman_service *service)
166 interface = connman_service_get_interface(service);
168 DBG("interface %s", interface);
170 g_free(default_interface);
171 default_interface = interface;
173 g_hash_table_iter_init(&iter, nat_hash);
175 while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
176 const char *name = key;
177 struct connman_nat *nat = value;
180 err = enable_nat(nat);
182 DBG("Failed to enable nat for %s", name);
186 static void shutdown_nat(gpointer key, gpointer value, gpointer user_data)
188 const char *name = key;
190 __connman_nat_disable(name);
193 static void cleanup_nat(gpointer data)
195 struct connman_nat *nat = data;
197 g_free(nat->address);
198 g_free(nat->interface);
201 static struct connman_notifier nat_notifier = {
203 .default_changed = update_default_interface,
206 int __connman_nat_init(void)
212 err = connman_notifier_register(&nat_notifier);
216 nat_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
217 g_free, cleanup_nat);
224 void __connman_nat_cleanup(void)
228 g_hash_table_foreach(nat_hash, shutdown_nat, NULL);
229 g_hash_table_destroy(nat_hash);
234 connman_notifier_unregister(&nat_notifier);