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)
64 g_free(nat->interface);
65 nat->interface = g_strdup(default_interface);
67 if (nat->interface == NULL)
70 /* Enable masquerading */
71 err = __connman_iptables_command("-t nat -A POSTROUTING "
72 "-s %s/%d -o %s -j MASQUERADE",
79 return __connman_iptables_commit("nat");
82 static void disable_nat(struct connman_nat *nat)
86 if (nat->interface == NULL)
89 /* Disable masquerading */
90 err = __connman_iptables_command("-t nat -D POSTROUTING "
91 "-s %s/%d -o %s -j MASQUERADE",
98 __connman_iptables_commit("nat");
101 int __connman_nat_enable(const char *name, const char *address,
102 unsigned char prefixlen)
104 struct connman_nat *nat;
107 if (g_hash_table_size(nat_hash) == 0) {
108 err = enable_ip_forward(TRUE);
113 nat = g_try_new0(struct connman_nat, 1);
115 if (g_hash_table_size(nat_hash) == 0)
116 enable_ip_forward(FALSE);
121 nat->address = g_strdup(address);
122 nat->prefixlen = prefixlen;
124 g_hash_table_replace(nat_hash, g_strdup(name), nat);
126 return enable_nat(nat);
129 void __connman_nat_disable(const char *name)
131 struct connman_nat *nat;
133 nat = g_hash_table_lookup(nat_hash, name);
139 g_hash_table_remove(nat_hash, name);
141 if (g_hash_table_size(nat_hash) == 0)
142 enable_ip_forward(FALSE);
145 static void update_default_interface(struct connman_service *service)
152 interface = connman_service_get_interface(service);
154 DBG("interface %s", interface);
156 g_free(default_interface);
157 default_interface = interface;
159 g_hash_table_iter_init(&iter, nat_hash);
161 while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
162 const char *name = key;
163 struct connman_nat *nat = value;
166 err = enable_nat(nat);
168 DBG("Failed to enable nat for %s", name);
172 static void shutdown_nat(gpointer key, gpointer value, gpointer user_data)
174 const char *name = key;
176 __connman_nat_disable(name);
179 static void cleanup_nat(gpointer data)
181 struct connman_nat *nat = data;
183 g_free(nat->address);
184 g_free(nat->interface);
188 static struct connman_notifier nat_notifier = {
190 .default_changed = update_default_interface,
193 int __connman_nat_init(void)
199 err = connman_notifier_register(&nat_notifier);
203 nat_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
204 g_free, cleanup_nat);
209 void __connman_nat_cleanup(void)
213 g_hash_table_foreach(nat_hash, shutdown_nat, NULL);
214 g_hash_table_destroy(nat_hash);
217 connman_notifier_unregister(&nat_notifier);