From 8245100eaffc8d0fd0e75afd747cc598ec8ab0b8 Mon Sep 17 00:00:00 2001 From: Gregor Riepl Date: Tue, 20 Jul 2010 22:43:21 +0200 Subject: [PATCH] Initial checkin of tethering script and C implementation with hardcoded paths --- .gitignore | 2 + Makefile | 27 +++++ main.c | 309 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ tethering.sh | 67 +++++++++++++ 4 files changed, 405 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 main.c create mode 100644 tethering.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0001171 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.o +maemo-tethering diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d60af75 --- /dev/null +++ b/Makefile @@ -0,0 +1,27 @@ +MAD = mad +CC = gcc +CFLAGS = -Wall -O2 -D_GNU_SOURCE +INCLUDES = -I/usr/include/dbus-1.0 -I/usr/lib/dbus-1.0/include +LIBS = -ldbus-1 -lpthread +SSH_ADDRESS = developer@192.168.253.254 +SSH_SCP = scp +SSH_SSH = ssh +SSH_PATH = /home/developer + +maemo-tethering: main.o + $(MAD) $(CC) $(LDLFAGS) $(LIBS) -o $@ $^ + +%PHONY: copy run clean + +copy: maemo-tethering + $(SSH_SCP) $^ $(SSH_ADDRESS):$(SSH_PATH) + +run: copy + $(SSH_SSH) $(SSH_ADDRESS) $(SSH_PATH)/maemo-tethering + +clean: + rm -f *.o maemo-tethering + +%.o: %.c + $(MAD) $(CC) $(CFLAGS) $(INCLUDES) -o $@ -c $^ + diff --git a/main.c b/main.c new file mode 100644 index 0000000..b3bb6c4 --- /dev/null +++ b/main.c @@ -0,0 +1,309 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include + +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; +} diff --git a/tethering.sh b/tethering.sh new file mode 100644 index 0000000..bf40abc --- /dev/null +++ b/tethering.sh @@ -0,0 +1,67 @@ +#!/bin/sh +# +# /usr/bin/tethering.sh +# +# Enable tethering on USB network and Bluetooth PAN. +# +# Note that the INETDEV must be up and running when this script is +# started, or forwarding will not be enabled. +# Having tethering on multiple devices concurrently is possible, +# but forwarding will be disabled once the first device disconnetcs. +# A better check is necessary. +# +# Put this into /etc/dbus-scripts/tethering : +# /usr/bin/tethering.sh * * org.freedesktop.Hal.Manager DeviceAdded +# /usr/bin/tethering.sh * * org.freedesktop.Hal.Manager DeviceRemoved +# +# dbus-scripts doesn't give us the event path, so we have to use a more +# convoluted method of getting the network interface. +# + +EVENT="$4" +UDI="$5" +HALDEV="$(echo $UDI | sed 's#.*/\([0-9a-zA-Z_]*\)#\1#')" +LOG="/tmp/tethering.log" +INETDEV="gprs0" +RUNFILE="/var/run/tethering.$HALDEV.pid" +IFACEFILE="/var/run/tethering.$HALDEV.iface" + +if [ "$EVENT" = "DeviceAdded" ]; then + IFACE=$(hal-get-property --udi $UDI --key net.interface) + case $IFACE in + bnep0 ) + IF_ADDRESS=192.168.254.254 + IF_RANGE=192.168.254.1,192.168.254.254 + ;; + usb0 ) + IF_ADDRESS=192.168.253.254 + IF_RANGE=192.168.253.1,192.168.253.254 + ;; + * ) + exit 0 + ;; + esac + + echo "$(date) Enabling tethering on interface $IFACE" >> $LOG + echo "$IFACE" > $IFACEFILE + ifconfig "$IFACE" "$IF_ADDRESS" + /sbin/modprobe ipt_MASQUERADE + /usr/sbin/iptables -t nat -A POSTROUTING -o $INETDEV -j MASQUERADE + start-stop-daemon -S -p "$RUNFILE" -m -b -x /usr/sbin/dnsmasq -- -k -I lo -i "$IFACE" -a $IF_ADDRESS -z -F $IF_RANGE,3600 + echo 1 > /proc/sys/net/ipv4/conf/$IFACE/forwarding + echo 1 > /proc/sys/net/ipv4/conf/$INETDEV/forwarding +fi + +if [ "$EVENT" = "DeviceRemoved" ]; then + if [ ! -f "$IFACEFILE" ]; then + exit 0 + fi + IFACE="$(cat $IFACEFILE)" + rm "$IFACEFILE" + echo "$(date) Disabling tethering on device $IFACE" >> $LOG + echo 0 > /proc/sys/net/ipv4/conf/$INETDEV/forwarding + start-stop-daemon -K -p "$RUNFILE" -x /usr/sbin/dnsmasq + /usr/sbin/iptables -t nat -D POSTROUTING -o $INETDEV -j MASQUERADE +fi + +exit 0 -- 1.7.9.5