--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <sys/wait.h>
+#include <dbus/dbus.h>
+//#include <hal/libhal.h>
+
+static const char *INETDEV = "gprs0";
+static const char *DEVICES[] = {
+ "bnep0",
+ "usb0",
+ NULL
+};
+static const char *ADDRESSES[] = {
+ "192.168.253.254",
+ "192.168.254.254",
+ NULL
+};
+static const char *STARTADDRESSES[] = {
+ "192.168.253.1",
+ "192.168.254.1",
+ NULL
+};
+static const char *ENDADDRESSES[] = {
+ "192.168.253.254",
+ "192.168.254.254",
+ NULL
+};
+
+static int running;
+static unsigned int active;
+
+static void sigIntHandler(int sig) {
+ fprintf(stderr, "SIGINIT received, exiting\n");
+ running = 0;
+}
+
+/*static void deviceAdded(LibHalContext *ctx, const char *udi) {
+ DBusError err;
+ dbus_error_init(&err);
+ char *device = libhal_device_get_property_string(ctx, udi, "net.interface", &err);
+ if (!device) {
+ if (dbus_error_is_set(&err)) {
+ fprintf(stderr, "Error %s occured: %s\n", err.name, err.message);
+ dbus_error_free(&err);
+ }
+ }
+ printf("Device %s added.\n", device);
+}
+
+static void deviceRemoved(LibHalContext *ctx, const char *udi) {
+ DBusError err;
+ dbus_error_init(&err);
+ char *device = libhal_device_get_property_string(ctx, udi, "net.interface", &err);
+ if (!device) {
+ if (dbus_error_is_set(&err)) {
+ fprintf(stderr, "Error %s occured: %s\n", err.name, err.message);
+ dbus_error_free(&err);
+ }
+ }
+ printf("Device %s removed.\n", device);
+}*/
+
+static int launch(const char *args[]) {
+ pid_t pid = fork();
+ if (pid == 0) {
+ if (execv(args[0], (char **const) args) == -1) {
+ fprintf(stderr, "Error launching external process %s: %s\n", args[0], strerror(errno));
+ exit(1);
+ }
+ } else if (pid == -1) {
+ fprintf(stderr, "Can't fork external process %s: %s\n", args[0], strerror(errno));
+ return -1;
+ } else {
+ int status = 0;
+ if (waitpid(pid, &status, 0) == -1) {
+ perror("Error waiting for child process completion");
+ return -1;
+ }
+ if (WIFEXITED(status)) {
+ if (WEXITSTATUS(status) != 0) {
+ fprintf(stderr, "Child process returned error: %d\n", WEXITSTATUS(status));
+ return -1;
+ }
+ } else if (WIFSIGNALED(status)) {
+ fprintf(stderr, "Child process killed by signal: %d\n", WTERMSIG(status));
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static void added(const char *device, const char *inetdev, const char *address, const char *startaddress, const char *endaddress) {
+ printf("Got org.kernel.kevent.add on %s\n", device);
+ const char *ifconfig[] = { "/sbin/ifconfig", device, address, "up", NULL };
+ launch(ifconfig);
+ const char *modprobe[] = { "/sbin/modprobe", "ipt_MASQUERADE", NULL };
+ launch(modprobe);
+ const char *iptables[] = { "/usr/sbin/iptables", "-t", "nat", "-A", "POSTROUTING", "-o", inetdev, "-j", "MASQUERADE", NULL };
+ launch(iptables);
+ char *runfile = NULL;
+ asprintf(&runfile, "/var/run/tethering.%s.pid", device);
+ char *range = NULL;
+ asprintf(&range, "%s-%s,3600", startaddress, endaddress);
+ const char *dnsmasq[] = { "/sbin/start-stop-daemon", "-S", "-p", runfile, "-m", "-b", "-x", "/usr/sbin/dnsmasq", "--", "-k", "-I", "lo", "-i", device, "-a", address, "-z", "-F", range, NULL };
+ launch(dnsmasq);
+ free(range);
+ free(runfile);
+ char *forwsysctl = NULL;
+ asprintf(&forwsysctl, "/proc/sys/net/ipv4/conf/%s/forwarding", device);
+ int fd = open(forwsysctl, O_WRONLY, 0666);
+ if (fd < 0) {
+ perror("Can't enable forwarding on PAN device");
+ } else {
+ if (write(fd, "0", 1) == -1) {
+ perror("Can't enable forwarding on PAN device");
+ }
+ close(fd);
+ }
+ free(forwsysctl);
+ asprintf(&forwsysctl, "/proc/sys/net/ipv4/conf/%s/forwarding", inetdev);
+ fd = open(forwsysctl, O_WRONLY, 0666);
+ if (fd < 0) {
+ perror("Can't enable forwarding on WAN device");
+ } else {
+ if (write(fd, "0", 1) == -1) {
+ perror("Can't enable forwarding on WAN device");
+ }
+ close(fd);
+ }
+ free(forwsysctl);
+ active++;
+}
+
+static void removed(const char *device, const char *inetdev) {
+ printf("Got org.kernel.kevent.remove on %s\n", device);
+ char *runfile = NULL;
+ asprintf(&runfile, "/var/run/tethering.%s.pid", device);
+ const char *dnsmasq[] = { "/sbin/start-stop-daemon", "-K", "-p", runfile, "-x", "/usr/sbin/dnsmasq", NULL };
+ launch(dnsmasq);
+ free(runfile);
+ const char *iptables[] = { "/usr/sbin/iptables", "-t", "nat", "-D", "POSTROUTING", "-o", inetdev, "-j", "MASQUERADE", NULL };
+ launch(iptables);
+ if (active > 0) active--;
+ if (active == 0) {
+ char *forwsysctl = NULL;
+ asprintf(&forwsysctl, "/proc/sys/net/ipv4/conf/%s/forwarding", inetdev);
+ int fd = open(forwsysctl, O_WRONLY, 0666);
+ if (fd < 0) {
+ perror("Can't disable forwarding on WAN device");
+ } else {
+ if (write(fd, "0", 1) == -1) {
+ perror("Can't disable forwarding on WAN device");
+ }
+ close(fd);
+ }
+ free(forwsysctl);
+ }
+}
+
+static int finddev(const char* device, const char *devices[]) {
+ int i;
+ for (i = 0; devices[i]; i++) {
+ if (strcmp(device, devices[i]) == 0) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+int main(int argc, const char *argv[]) {
+ running = 1;
+ active = 0;
+ signal(SIGINT, sigIntHandler);
+
+ DBusError err;
+ dbus_error_init(&err);
+ DBusConnection *conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
+ if (dbus_error_is_set(&err)) {
+ fprintf(stderr, "Error %s occured: %s\n", err.name, err.message);
+ dbus_error_free(&err);
+ }
+ if (!conn) {
+ return 1;
+ }
+ /*LibHalContext *ctx = libhal_ctx_new();
+ if (!ctx) {
+ fprintf(stderr, "Error occured: Can't create HAL context.\n");
+ return 2;
+ }
+ if (!libhal_ctx_set_dbus_connection(ctx, conn)) {
+ fprintf(stderr, "Error occured: Can't assign DBUS connection to HAL context.\n");
+ return 3;
+ }
+ if (!libhal_ctx_set_device_added(ctx, deviceAdded)) {
+ fprintf(stderr, "Error occured: Can't set device added message handler.\n");
+ return 4;
+ }
+ if (!libhal_ctx_set_device_removed(ctx, deviceRemoved)) {
+ fprintf(stderr, "Error occured: Can't set device removed message handler.\n");
+ return 4;
+ }
+ if (!libhal_ctx_init(ctx, &err)) {
+ if (dbus_error_is_set(&err)) {
+ fprintf(stderr, "Error %s occured: %s\n", err.name, err.message);
+ dbus_error_free(&err);
+ }
+ return 5;
+ }
+ dbus_bool_t nodisc = TRUE;
+ while (running && nodisc) {
+ nodisc = dbus_connection_read_write_dispatch(conn, 500);
+ }*/
+ //dbus_bus_add_match(conn, "type='signal',interface='org.freedesktop.Hal.Manager',member='DeviceAdded'", NULL);
+ //dbus_bus_add_match(conn, "type='signal',interface='org.freedesktop.Hal.Manager',member='DeviceRemoved'", NULL);
+ //dbus_bus_add_match(conn, "type='signal',interface='org.kernel.kevent',path='/org/kernel/class/net/bnep0'", NULL);
+ //dbus_bus_add_match(conn, "type='signal',interface='org.kernel.kevent',path='/org/kernel/class/net/usb0'", NULL);
+ int i;
+ for (i = 0; DEVICES[i]; i++) {
+ char *filter = NULL;
+ if (!asprintf(&filter, "type='signal',interface='org.kernel.kevent',path='/org/kernel/class/net/%s'", DEVICES[i])) {
+ perror("Can't construct filter rule");
+ } else {
+ dbus_bus_add_match(conn, filter, NULL);
+ }
+ }
+ dbus_connection_flush(conn);
+ while (running) {
+ dbus_connection_read_write(conn, 500);
+ DBusMessage* msg = dbus_connection_pop_message(conn);
+ if (msg) {
+ /*if (dbus_message_is_signal(msg, "org.freedesktop.Hal.Manager", "DeviceAdded")) {
+ DBusMessageIter args;
+ if (!dbus_message_iter_init(msg, &args)) {
+ fprintf(stderr, "Message has no arguments!\n");
+ } else if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_STRING) {
+ fprintf(stderr, "Argument is not a string!\n");
+ } else {
+ char *sigvalue = NULL;
+ dbus_message_iter_get_basic(&args, &sigvalue);
+ fprintf(stderr, "Got DeviceAdded with value %s\n", sigvalue);
+ }
+ } else if (dbus_message_is_signal(msg, "org.freedesktop.Hal.Manager", "DeviceRemoved")) {
+ DBusMessageIter args;
+ if (!dbus_message_iter_init(msg, &args)) {
+ fprintf(stderr, "Message has no arguments!\n");
+ } else if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_STRING) {
+ fprintf(stderr, "Argument is not a string!\n");
+ } else {
+ char *sigvalue = NULL;
+ dbus_message_iter_get_basic(&args, &sigvalue);
+ fprintf(stderr, "Got DeviceRemoved with value %s\n", sigvalue);
+ }
+ } else */
+ if (dbus_message_is_signal(msg, "org.kernel.kevent", "add")) {
+ char **path = NULL;
+ if (!dbus_message_get_path_decomposed(msg, &path)) {
+ fprintf(stderr, "Can't get add message path!\n");
+ } else {
+ unsigned int last;
+ for (last = 0; path[last] && last <= 6; last++);
+ if (last == 0 || last > 6) {
+ fprintf(stderr, "Add message has no path or path too long!\n");
+ } else {
+ int index = finddev(path[last - 1], DEVICES);
+ if (index >= 0) {
+
+ added(DEVICES[index], INETDEV, ADDRESSES[index], STARTADDRESSES[index], ENDADDRESSES[index]);
+ }
+ }
+ dbus_free_string_array(path);
+ }
+ } else if (dbus_message_is_signal(msg, "org.kernel.kevent", "remove")) {
+ char **path = NULL;
+ if (!dbus_message_get_path_decomposed(msg, &path)) {
+ fprintf(stderr, "Can't get remove message path!\n");
+ } else {
+ unsigned int last;
+ for (last = 0; path[last] && last <= 6; last++);
+ if (last == 0 || last > 6) {
+ fprintf(stderr, "Remove message has no path or path too long!\n");
+ } else {
+ int index = finddev(path[last - 1], DEVICES);
+ if (index >= 0) {
+ removed(DEVICES[index], INETDEV);
+ }
+ }
+ dbus_free_string_array(path);
+ }
+ }
+ dbus_message_unref(msg);
+ }
+ }
+ /*if (!libhal_ctx_shutdown(ctx, &err)) {
+ if (dbus_error_is_set(&err)) {
+ fprintf(stderr, "Error %s occured: %s\n", err.name, err.message);
+ dbus_error_free(&err);
+ }
+ }
+ libhal_ctx_free(ctx);*/
+ dbus_connection_unref(conn);
+ return 0;
+}