* Initial commit.
authorUrban Wallasch <urban.wallasch@freenet.de>
Sun, 21 Apr 2019 09:33:47 +0000 (11:33 +0200)
committerUrban Wallasch <urban.wallasch@freenet.de>
Sun, 21 Apr 2019 09:33:47 +0000 (11:33 +0200)
fbind/.gitignore [new file with mode: 0644]
fbind/Makefile [new file with mode: 0644]
fbind/fbind [new file with mode: 0755]
fbind/fbind.c [new file with mode: 0644]
fbind/fbind32 [new symlink]
fbind/fbind64 [new symlink]
nns.sh [new file with mode: 0755]

diff --git a/fbind/.gitignore b/fbind/.gitignore
new file mode 100644 (file)
index 0000000..140f8cf
--- /dev/null
@@ -0,0 +1 @@
+*.so
diff --git a/fbind/Makefile b/fbind/Makefile
new file mode 100644 (file)
index 0000000..8f1aa6f
--- /dev/null
@@ -0,0 +1,35 @@
+
+CC      ?= gcc
+CFLAGS  := -Wall -Wextra -nostartfiles -fpic -shared fbind.c -ldl -D_GNU_SOURCE
+CFLAGSD := $(CFLAGS) -DDEBUG
+
+STRIP   := strip
+RM      := rm -f
+
+SRC   := $(wildcard *.c)
+SO    := fbind32.so fbind32d.so fbind64.so fbind64d.so
+SELF  := $(lastword $(MAKEFILE_LIST))
+
+
+.PHONY: all clean distclean
+
+all: $(SO)
+
+fbind32.so: $(SRC) $(SELF)
+       $(CC) -m32 -o $@ $(CFLAGS)
+       strip $@
+
+fbind32d.so: $(SRC) $(SELF)
+       $(CC) -m32 -o $@ $(CFLAGSD)
+
+fbind64.so: $(SRC) $(SELF)
+       $(CC) -m64 -o $@ $(CFLAGS)
+       strip $@
+
+fbind64d.so: $(SRC) $(SELF)
+       $(CC) -m64 -o $@ $(CFLAGSD)
+
+clean:
+       $(RM) $(SO)
+
+distclean: clean
diff --git a/fbind/fbind b/fbind/fbind
new file mode 100755 (executable)
index 0000000..f7ab880
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/bash
+if [ $# -lt 2 ] ; then
+    echo "Usage: fbind address command [command_args]"
+    exit 1
+fi
+
+SO="fbind64dbg.so"
+if [ "$(basename "$0")" == "bind32" ] ; then
+    SO="fbind32dbg.so"
+fi
+PFX=$(dirname $(realpath "$0"))
+ADR="$1"
+shift
+
+BIND_ADDR="$ADR" LD_PRELOAD="$PFX/$SO" $*
diff --git a/fbind/fbind.c b/fbind/fbind.c
new file mode 100644 (file)
index 0000000..7f687bc
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+   Copyright (C) 2000  Daniel Ryde
+   Small amendment by Daniel Lange, 2010
+   Changes (C) 2019 by volpol and irrwahn:
+    * added sendto() and sendmsg()
+    * do not pollute global namespace
+    * proper debug output
+    * fixed several minor issues
+    * renamed to fbind to avoid name clashes
+    * added call script and Makefile
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+*/
+
+/*
+   LD_PRELOAD library to make bind and connect to use a virtual
+   IP address as localaddress. Specified via the enviroment
+   variable BIND_ADDR.
+
+   Compile on Linux with:
+   gcc -nostartfiles -fpic -shared bind.c -o bind.so -ldl -D_GNU_SOURCE
+
+
+   Example in bash to make inetd only listen to the localhost
+   lo interface, thus disabling remote connections and only
+   enable to/from localhost:
+
+   BIND_ADDR="127.0.0.1" LD_PRELOAD=./bind.so /sbin/inetd
+
+
+   Example in bash to use your virtual IP as your outgoing
+   sourceaddress for ircII:
+
+   BIND_ADDR="your-virt-ip" LD_PRELOAD=./bind.so ircII
+
+   Note that you have to set up your servers virtual IP first.
+
+
+   This program was made by Daniel Ryde
+   email: daniel@ryde.net
+   web:   http://www.ryde.net/
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <dlfcn.h>
+#include <errno.h>
+
+#ifdef DEBUG
+  #define DBGPRINT(...)    fprintf(stderr, "[bind.so] "__VA_ARGS__)
+#else
+  #define DBGPRINT(...)
+#endif
+
+int (*real_bind)(int, const struct sockaddr *, socklen_t);
+int (*real_connect)(int, const struct sockaddr *, socklen_t);
+int (*real_sendto)(int, const void *, size_t, int, const struct sockaddr *, socklen_t);
+int (*real_sendmsg)(int, const struct msghdr *, int);
+
+static char *bind_addr_env;
+static unsigned long int bind_addr_saddr;
+static unsigned long int inaddr_any_saddr;
+static struct sockaddr_in local_sockaddr_in[] = { 0 };
+
+void _init(void) {
+    const char *err;
+
+    real_bind = dlsym(RTLD_NEXT, "bind");
+    if ((err = dlerror()) != NULL) {
+        fprintf(stderr, "dlsym(bind): %s\n", err);
+        exit(EXIT_FAILURE);
+    }
+
+    real_connect = dlsym(RTLD_NEXT, "connect");
+    if ((err = dlerror()) != NULL) {
+        fprintf(stderr, "dlsym(connect): %s\n", err);
+        exit(EXIT_FAILURE);
+    }
+
+    real_sendto = dlsym(RTLD_NEXT, "sendto");
+    if ((err = dlerror()) != NULL) {
+        fprintf(stderr, "dlsym(sendto): %s\n", err);
+        exit(EXIT_FAILURE);
+    }
+
+    real_sendmsg = dlsym(RTLD_NEXT, "sendmsg");
+    if ((err = dlerror()) != NULL) {
+        fprintf(stderr, "dlsym(sendmsg): %s\n", err);
+        exit(EXIT_FAILURE);
+    }
+
+    inaddr_any_saddr = htonl(INADDR_ANY);
+    if (NULL != (bind_addr_env = getenv("BIND_ADDR"))) {
+        DBGPRINT("_init: bind_addr_env='%s'\n", bind_addr_env);
+        bind_addr_saddr = inet_addr(bind_addr_env);
+        local_sockaddr_in->sin_family = AF_INET;
+        local_sockaddr_in->sin_addr.s_addr = bind_addr_saddr;
+        local_sockaddr_in->sin_port = htons(0);
+        DBGPRINT("_init: %s:%d\n", inet_ntoa(local_sockaddr_in->sin_addr), ntohs(local_sockaddr_in->sin_port));
+    }
+}
+
+int bind(int fd, const struct sockaddr *sk, socklen_t sl) {
+    static struct sockaddr_in *lsk_in;
+
+    lsk_in = (struct sockaddr_in *)sk;
+    if ((lsk_in->sin_family == AF_INET)
+        && (lsk_in->sin_addr.s_addr == inaddr_any_saddr)
+        && (bind_addr_env)) {
+        lsk_in->sin_addr.s_addr = bind_addr_saddr;
+        DBGPRINT("[*] bind(INADDR_ANY): %d %s:%d\n", fd, inet_ntoa(lsk_in->sin_addr), ntohs(lsk_in->sin_port));
+    } else {
+        DBGPRINT("[-] bind: %d %s:%d\n", fd, inet_ntoa(lsk_in->sin_addr), ntohs(lsk_in->sin_port));
+    }
+    return real_bind(fd, sk, sl);
+}
+
+int connect(int fd, const struct sockaddr *sk, socklen_t sl) {
+    static struct sockaddr_in *rsk_in;
+
+    rsk_in = (struct sockaddr_in *)sk;
+    if ((rsk_in->sin_family == AF_INET) && bind_addr_env) {
+        real_bind(fd, (struct sockaddr *)local_sockaddr_in, sizeof (struct sockaddr));
+        DBGPRINT("[*] connect: %d %s:%d (bound to %s:%d)\n",
+                fd, inet_ntoa(rsk_in->sin_addr), ntohs(rsk_in->sin_port),
+                inet_ntoa(local_sockaddr_in->sin_addr), ntohs(local_sockaddr_in->sin_port));
+    } else {
+        DBGPRINT("[-] connect: %d %s:%d\n", fd, inet_ntoa(rsk_in->sin_addr), ntohs(rsk_in->sin_port));
+    }
+    return real_connect(fd, sk, sl);
+}
+
+ssize_t sendto(int fd, const void *buf, size_t l, int flags, const struct sockaddr *sa, socklen_t sal) {
+    static struct sockaddr_in *rsk_in;
+
+    rsk_in = (struct sockaddr_in *)sa;
+    if ((rsk_in->sin_family == AF_INET) && bind_addr_env) {
+        real_bind(fd, (struct sockaddr *)local_sockaddr_in, sizeof (struct sockaddr));
+        DBGPRINT("[*] sendto: %d %s:%d (bound to %s:%d)\n",
+                fd, inet_ntoa(rsk_in->sin_addr),ntohs(rsk_in->sin_port),
+                inet_ntoa(local_sockaddr_in->sin_addr),ntohs(local_sockaddr_in->sin_port));
+    } else {
+        DBGPRINT("[-] sendto: %d %s:%d\n", fd, inet_ntoa(rsk_in->sin_addr),ntohs(rsk_in->sin_port));
+    }
+    return real_sendto(fd, buf, l, flags, sa, sal);
+}
+
+ssize_t sendmsg(int fd, const struct msghdr *msg, int flags) {
+    struct sockaddr_storage _local;
+    struct sockaddr_in *local = (struct sockaddr_in*) &_local;
+    socklen_t s_local = sizeof(_local);
+
+    if ( 0 == getsockname(fd, (struct sockaddr *)&_local, &s_local)
+      && s_local == sizeof (struct sockaddr_in) && local->sin_family == AF_INET) {
+#ifdef DEBUG
+        struct sockaddr_in *haddr;
+        haddr = (struct sockaddr_in *)(msg->msg_name);
+        char *destaddr = inet_ntoa(haddr->sin_addr);
+        int destport = ntohs(haddr->sin_port);
+#endif
+        if ( local->sin_addr.s_addr == INADDR_ANY && bind_addr_env) {
+            real_bind(fd, (struct sockaddr *)local_sockaddr_in, sizeof (struct sockaddr));
+            DBGPRINT("[*] sendmsg: %d %s:%d (bound to %s:%d)\n",
+                    fd, destaddr, destport,
+                    inet_ntoa(local_sockaddr_in->sin_addr),ntohs(local_sockaddr_in->sin_port));
+        } else {
+            DBGPRINT("[-] sendmsg: %d %s:%d\n", fd, destaddr, destport);
+        }
+    }
+    else {
+        DBGPRINT("[-] sendmsg: %d\n", fd);
+    }
+    return real_sendmsg(fd, msg, flags);
+}
diff --git a/fbind/fbind32 b/fbind/fbind32
new file mode 120000 (symlink)
index 0000000..402eea8
--- /dev/null
@@ -0,0 +1 @@
+fbind
\ No newline at end of file
diff --git a/fbind/fbind64 b/fbind/fbind64
new file mode 120000 (symlink)
index 0000000..402eea8
--- /dev/null
@@ -0,0 +1 @@
+fbind
\ No newline at end of file
diff --git a/nns.sh b/nns.sh
new file mode 100755 (executable)
index 0000000..22e9926
--- /dev/null
+++ b/nns.sh
@@ -0,0 +1,200 @@
+#!/bin/bash
+#
+# This script will setup a network namespace with a macvlan
+# which obtains its IP address via dhclient from the LAN on which the host is
+# placed
+#
+
+set -x
+
+# It will open an xterm window in the new network namespace; if anything
+# else is required, change the statement below.
+
+export XTERM1=xterm
+
+# The script will temporarily activate ip forwarding for you. If you
+# do not wish to retain this feature, you will have to issue, at the
+# end of this session, the command
+# echo 0 > /proc/sys/net/ipv4/ip_forward
+# yourself.
+
+###############################################################################
+
+BASE_IF=vpn_tap1
+VETH_HOST=veth_host
+VETH_GUEST=veth_guest
+
+export WHEREIS=/usr/bin/whereis
+
+# First of all, check that the script is run by root:
+
+[ "root" != "$USER" ] && exec sudo -E $0 "$@"
+
+if [ $# != 2 ]; then
+    echo "Usage $0 name action"
+    echo "where name is the network namespace name,"
+    echo " and action is one of start| stop| reload."
+    exit 1
+fi
+
+# Do we have all it takes?
+
+IERROR1=0
+IERROR2=0
+IERROR3=0
+
+export IP=$($WHEREIS -b ip | /usr/bin/awk '{print $2}')
+export IPTABLES=$($WHEREIS -b iptables | /usr/bin/awk '{print $2}')
+export XTERM=$($WHEREIS -b $XTERM1 | /usr/bin/awk '{print $2}')
+
+if [ "x$IP" = "x" ] ; then
+    echo "please install the iproute2 package"
+    IERROR1=1
+fi
+
+if [ "x$IPTABLES" = "x" ] ; then
+    echo "please install the iptables package"
+    IERROR2=1
+fi
+
+if [ "x$XTERM" = "x" ] ; then
+    echo "please install the xterm package"
+    IERROR3=1
+fi
+
+if [[ $IERROR1 == 0 && $IERROR2 == 0 && $IERROR3 == 0 ]]
+then
+    :
+else
+    exit 1
+fi
+
+
+prelim() {
+
+# Perform some preliminary setup. First, clear the proposed
+# namespace name of blank characters; then create a directory
+# for logging info, and a pid file in it; lastly, enable IPv4
+# forwarding.
+
+    VAR=$1
+    export NNSNAME=${VAR//[[:space:]]}
+
+    export OUTDIR=/var/log/newns/$NNSNAME
+
+    if [ ! -d $OUTDIR ]; then
+        /bin/mkdir -p $OUTDIR
+    fi
+    export PID=$OUTDIR/pid$NNSNAME
+
+    echo 1 > /proc/sys/net/ipv4/ip_forward
+
+}
+
+start_nns() {
+
+# Check whether a namespace with the same name already exists.
+
+    $IP netns list | /bin/grep $1 2> /dev/null
+    if [ $? == 0 ]; then
+        echo "Network namespace $1 already exists,"
+        echo "please choose another name"
+        exit 1
+    fi
+
+# Here we take care of DNS
+
+    /bin/mkdir -p /etc/netns/$1
+    echo "nameserver 8.8.8.8" > /etc/netns/$1/resolv.conf
+    echo "nameserver 8.8.4.4" >> /etc/netns/$1/resolv.conf
+
+# The following creates the new namespace, and the veth interface
+
+    $IP netns add $1
+    ip link add $VETH_HOST type veth peer name $VETH_GUEST
+    brctl addbr br0
+    brctl addif br0 $BASE_IF
+    brctl addif br0 $VETH_HOST
+    ifconfig $VETH_HOST up
+    ifconfig br0 192.168.30.3 up
+# This assigns the macvlan interface, mac$1, to the new
+# namespace, asks for an IP address via a call to dhclient,
+# brings up this and the (essential) lo interface,
+# creates a new terminal in the new namespace and
+# stores its pid for the purpose of tearing it cleanly, later.
+
+#    $IP link set mac$1 netns $1
+    $IP link set $VETH_GUEST netns $1
+#    $IP netns exec $1 /sbin/dhclient -pf /var/run/dhclient_$1.pid -v mac$1 1> /dev/null 2>&1
+    $IP netns exec $1 /sbin/dhclient -pf /var/run/dhclient_$1.pid -v $VETH_GUEST 1> /dev/null 2>&1
+    $IP netns exec $1 $IP link set dev lo up
+    $IP netns exec $1 su -p -c $XTERM $SUDO_USER &
+    $IP netns exec $1 echo "$!" > $PID
+    iptables -t nat -A POSTROUTING --source 192.168.30.0/24 --jump MASQUERADE
+    $IP netns exec $1 /sbin/route add default gw 192.168.30.3
+
+}
+
+stop_nns() {
+
+# Check that the namespace to be torn down really exists
+
+    $IP netns list | /bin/grep $1 2>&1 1> /dev/null
+    if [ ! $? == 0 ]; then
+        echo "Network namespace $1 does not exist,"
+        echo "please choose another name"
+        exit 1
+    fi
+
+# This kills the terminal in the separate namespace and
+# removes the file and the directory where it is stored.
+
+    /bin/kill -TERM $(cat $PID) 2> /dev/null 1> /dev/null
+    /bin/kill -TERM $(cat /var/run/dhclient_$1.pid) 2> /dev/null 1> /dev/null
+    /bin/rm $PID
+    /bin/rmdir $OUTDIR
+
+    ifconfig br0 down
+    brctl delif br0 $BASE_IF
+    brctl delif br0 $VETH_HOST
+    brctl delbr br0
+
+    $IP netns exec $1 $IP link del $VETH_GUEST
+    $IP netns del $1
+    $IP link del $VETH_HOST
+    iptables -t nat -D POSTROUTING --source 192.168.30.0/24 --jump MASQUERADE
+
+# This deletes the file and direcotory connected with the DNSes.
+
+    /bin/rm /etc/netns/$1/resolv.conf
+    /bin/rmdir /etc/netns/$1
+
+}
+
+
+case $2 in
+    start)
+        prelim "$1"
+        start_nns $NNSNAME
+        ;;
+    stop)
+        prelim "$1"
+        stop_nns $NNSNAME
+        ;;
+    reload)
+        prelim "$1"
+        stop_nns $NNSNAME
+        prelim "$1"
+        start_nns $NNSNAME
+        ;;
+    *)
+# This removes the absolute path from the command name
+
+        NAME1=$0
+        NAMESHORT=${NAME1##*/}
+
+        echo "Usage:" $NAMESHORT "name action,"
+        echo "where name is the name of the network namespace,"
+        echo "and action is one of start|stop|reload"
+        ;;
+esac