* Connection Manager
*
* Copyright (C) 2007-2012 Intel Corporation. All rights reserved.
- * Copyright (C) 2012 BMW Car IT GmbH. All rights reserved.
+ * Copyright (C) 2012-2014 BMW Car IT GmbH.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
#endif
#include <errno.h>
-#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
#include "connman.h"
struct connman_nat {
char *address;
unsigned char prefixlen;
+ struct firewall_context *fw;
char *interface;
};
-static int enable_ip_forward(connman_bool_t enable)
+static int enable_ip_forward(bool enable)
{
- FILE *f;
+ static char value = 0;
+ int f, err = 0;
- f = fopen("/proc/sys/net/ipv4/ip_forward", "r+");
- if (f == NULL)
+ if ((f = open("/proc/sys/net/ipv4/ip_forward", O_CLOEXEC | O_RDWR)) < 0)
return -errno;
- if (enable == TRUE)
- fprintf(f, "1");
- else
- fprintf(f, "0");
+ if (!value) {
+ if (read(f, &value, sizeof(value)) < 0)
+ value = 0;
- fclose(f);
+ if (lseek(f, 0, SEEK_SET) < 0) {
+ close(f);
+ return -errno;
+ }
+ }
- return 0;
-}
+ if (enable) {
+ char allow = '1';
-static void flush_nat(void)
-{
- int err;
+ if (write (f, &allow, sizeof(allow)) < 0)
+ err = -errno;
+ } else {
+ char deny = '0';
- err = __connman_iptables_command("-t nat -F POSTROUTING");
- if (err < 0) {
- DBG("Flushing the nat table failed");
+ if (value)
+ deny = value;
- return;
+ if (write(f, &deny, sizeof(deny)) < 0)
+ err = -errno;
+
+ value = 0;
}
- __connman_iptables_commit("nat");
+ close(f);
+
+ return err;
}
static int enable_nat(struct connman_nat *nat)
{
- int err;
-
g_free(nat->interface);
nat->interface = g_strdup(default_interface);
- if (nat->interface == NULL)
+ if (!nat->interface)
return 0;
- /* Enable masquerading */
- err = __connman_iptables_command("-t nat -A POSTROUTING "
- "-s %s/%d -o %s -j MASQUERADE",
- nat->address,
- nat->prefixlen,
- nat->interface);
- if (err < 0)
- return err;
-
- return __connman_iptables_commit("nat");
+ return __connman_firewall_enable_nat(nat->fw, nat->address,
+ nat->prefixlen, nat->interface);
}
static void disable_nat(struct connman_nat *nat)
{
- int err;
-
- if (nat->interface == NULL)
+ if (!nat->interface)
return;
- /* Disable masquerading */
- err = __connman_iptables_command("-t nat -D POSTROUTING "
- "-s %s/%d -o %s -j MASQUERADE",
- nat->address,
- nat->prefixlen,
- nat->interface);
- if (err < 0)
- return;
-
- __connman_iptables_commit("nat");
+ __connman_firewall_disable_nat(nat->fw);
}
int __connman_nat_enable(const char *name, const char *address,
int err;
if (g_hash_table_size(nat_hash) == 0) {
- err = enable_ip_forward(TRUE);
+ err = enable_ip_forward(true);
if (err < 0)
return err;
}
nat = g_try_new0(struct connman_nat, 1);
- if (nat == NULL) {
- if (g_hash_table_size(nat_hash) == 0)
- enable_ip_forward(FALSE);
+ if (!nat)
+ goto err;
- return -ENOMEM;
- }
+ nat->fw = __connman_firewall_create();
+ if (!nat->fw)
+ goto err;
nat->address = g_strdup(address);
nat->prefixlen = prefixlen;
g_hash_table_replace(nat_hash, g_strdup(name), nat);
return enable_nat(nat);
+
+err:
+ if (nat) {
+ if (nat->fw)
+ __connman_firewall_destroy(nat->fw);
+ g_free(nat);
+ }
+
+ if (g_hash_table_size(nat_hash) == 0)
+ enable_ip_forward(false);
+
+ return -ENOMEM;
}
void __connman_nat_disable(const char *name)
struct connman_nat *nat;
nat = g_hash_table_lookup(nat_hash, name);
- if (nat == NULL)
+ if (!nat)
return;
disable_nat(nat);
g_hash_table_remove(nat_hash, name);
if (g_hash_table_size(nat_hash) == 0)
- enable_ip_forward(FALSE);
+ enable_ip_forward(false);
}
static void update_default_interface(struct connman_service *service)
g_hash_table_iter_init(&iter, nat_hash);
- while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
const char *name = key;
struct connman_nat *nat = value;
{
struct connman_nat *nat = data;
+ __connman_firewall_destroy(nat->fw);
g_free(nat->address);
g_free(nat->interface);
g_free(nat);
}
-static struct connman_notifier nat_notifier = {
+static const struct connman_notifier nat_notifier = {
.name = "nat",
.default_changed = update_default_interface,
};
nat_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
g_free, cleanup_nat);
- flush_nat();
-
return 0;
}
g_hash_table_destroy(nat_hash);
nat_hash = NULL;
- flush_nat();
-
connman_notifier_unregister(&nat_notifier);
}