From d9febee503e39231d98847e32156c800d0b096af Mon Sep 17 00:00:00 2001 From: Urban Wallasch Date: Sun, 21 Apr 2019 11:33:47 +0200 Subject: [PATCH] * Initial commit. --- fbind/.gitignore | 1 + fbind/Makefile | 35 +++++++++ fbind/fbind | 15 ++++ fbind/fbind.c | 186 +++++++++++++++++++++++++++++++++++++++++++ fbind/fbind32 | 1 + fbind/fbind64 | 1 + nns.sh | 200 +++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 439 insertions(+) create mode 100644 fbind/.gitignore create mode 100644 fbind/Makefile create mode 100755 fbind/fbind create mode 100644 fbind/fbind.c create mode 120000 fbind/fbind32 create mode 120000 fbind/fbind64 create mode 100755 nns.sh diff --git a/fbind/.gitignore b/fbind/.gitignore new file mode 100644 index 0000000..140f8cf --- /dev/null +++ b/fbind/.gitignore @@ -0,0 +1 @@ +*.so diff --git a/fbind/Makefile b/fbind/Makefile new file mode 100644 index 0000000..8f1aa6f --- /dev/null +++ b/fbind/Makefile @@ -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 index 0000000..f7ab880 --- /dev/null +++ b/fbind/fbind @@ -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 index 0000000..7f687bc --- /dev/null +++ b/fbind/fbind.c @@ -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 +#include +#include +#include +#include +#include +#include +#include + +#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 index 0000000..402eea8 --- /dev/null +++ b/fbind/fbind32 @@ -0,0 +1 @@ +fbind \ No newline at end of file diff --git a/fbind/fbind64 b/fbind/fbind64 new file mode 120000 index 0000000..402eea8 --- /dev/null +++ b/fbind/fbind64 @@ -0,0 +1 @@ +fbind \ No newline at end of file diff --git a/nns.sh b/nns.sh new file mode 100755 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 -- 2.30.2