Commits

Ivan Vučica committed 52c1351

Tapper as originally released on October 25th 2009

Comments (0)

Files changed (6)

+OBJECTS=tapper.o
+
+all: tapper
+
+tapper: $(OBJECTS)
+	$(CC) $(OBJECTS) -o tapper
+
+
+TAPPER - sample code for work with tap devices on linux
+
+Copyright (c) 2009, Ivan Vucica, http://ivan.vucica.net/
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+   copyright notice, this list of conditions and the following
+   disclaimer in the documentation and/or other materials
+   provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+THE POSSIBILITY OF SUCH DAMAGE.
+
+-
+ Purpose
+
+Providing simple code for creating a tap device, outputting onto stdout the
+network traffic generated by kernel for the tap device, and writing into
+tap device the traffic from stdin for processing by the kernel.
+
+That is: a two way tunnel between stdio and tap network device.
+
+-
+ Requirements
+
+Not sure. You obviously need tun driver for networking (to be able to
+create tap device) -- if you don't have /dev/net/tun something's wrong.
+
+Otherwise, this was made in the era of 2.6.30 kernels on a 2.6.26 kernel,
+and with eglibc 2.9 installed (debian release of eglibc 2.9-12).
+
+-
+ Files
+
+tapper files:
+* tapper.c - provides the tap device
+* README - this file
+* Makefile - builds tapper
+* testrun.sh - shows how to use twinpipe and netcat to tunnel traffic
+  in a simple way
+
+nontapper files:
+* TINYFREELICENSE - does not apply to tapper. license of twinpipe.sh
+* twinpipe.sh - runs two processes and interconnects them via pipes.
+
+twinpipe was obtained from this URL:
+ http://bisqwit.iki.fi/source/twinpipe.html
+
+-
+ Alternative tutorial with extra info
+
+This is neat and simple code, but perhaps not best and definitely with 
+much room for improvement and cleanup. So here's another nice article:
+ http://linuxgazette.net/149/melinte.html 
+and another one:
+ http://waldner.netsons.org/d2-tuntap.php
+license for twinpipe.sh
+
+ * No warranty. You are free to modify this source and to
+ * distribute the modified sources, as long as you keep the
+ * existing copyright messages intact and as long as you
+ * remember to add your own copyright markings.
+ * You are not allowed to distribute the program or modified versions
+ * of the program without including the source code (or a reference to
+ * the publicly available source) and this notice with it.
+/*
+TAPPER - sample code for work with tap devices on linux
+
+Copyright (c) 2009, Ivan Vucica, http://ivan.vucica.net/
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without 
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above 
+   copyright notice, this list of conditions and the following 
+   disclaimer in the documentation and/or other materials 
+   provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 
+THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+
+
+
+#include <stdio.h>
+#include <unistd.h>
+/*
+This works in C and C++ but not in ANSI C;
+docs on net say mixing linux/ and libc headers
+should not really be done.
+
+#include <linux/if_tun.h>
+#include <net/if.h>
+
+Instead, to get gcc -ansi compat, we do this:
+*/
+#include <sys/socket.h>
+#include <linux/if.h>
+#include <linux/if_tun.h>
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/select.h>
+#include <err.h>
+
+#define ERR_CANT_TAP 1
+#define ERR_OPEN_ERR 2
+#define ERR_READ_ERR 3
+#define ERR_WRITE_ERR 4
+
+#define UIP_DRIPADDR0 10
+#define UIP_DRIPADDR1 0
+#define UIP_DRIPADDR2 2
+#define UIP_DRIPADDR3 2
+
+int primary_fd; /* a copy of the filedescriptor for tap device */
+
+/* following function creates a tap device */
+int createTap(char *newdev)
+{
+	struct ifreq ifr;
+	int fd=open("/dev/net/tun", O_RDWR); /* open the tap device */
+
+	if(fd<0) /* handle error */
+		err(ERR_CANT_TAP, "Could not create a TAP device");
+
+	memset(&ifr, 0, sizeof(ifr)); /* initialize the structure specifying data about net device */
+	ifr.ifr_flags=IFF_TAP|IFF_NO_PI ; /* we want a tap device, not a tun device, and we won't include tuntap driver's headers */
+
+	if((ioctl(fd, TUNSETIFF, (void*)&ifr))<0) /* tell our device what we want it to do */
+	{
+		close(fd); /* if we failed close and abort */
+		err(ERR_CANT_TAP, "Could not create a TAP device because of ioctl()");
+	}
+	strcpy(newdev, ifr.ifr_name); /* return the generated device name */
+	return fd;
+	
+}
+
+/* when we exit we want to clean up */
+void atex()
+{
+	close(primary_fd); /* close the tap network device */
+}
+int main()
+{
+	int fd; /* file descriptor of the tap device; shorthand for primary_fd */
+	char devname[25]={0}; /* initialize device name (where we'll pick up the generated dev name) 
+				to zeros so it doesn't look like we're sending a device name in*/
+	char buf[255]; /* buffer for receiving stuff */
+	primary_fd=createTap(devname); /* let's create a tap device */
+
+	srand(time(NULL)+devname[3]); /* we want our ip address to depend on time, and on last
+					symbol in device name. dev name is always a three-letter 'tap'
+					+ number, and let's just presume it's a single digit num */
+	snprintf(buf, sizeof(buf), "ifconfig %s inet %d.%d.%d.%d", devname,
+		UIP_DRIPADDR0, UIP_DRIPADDR1, UIP_DRIPADDR2, rand()%254+1);/*UIP_DRIPADDR3);*/
+	system(buf); /* configure ip address */
+
+	fd=primary_fd; /* store into our shorthand */
+	if (fd<0) /* error with creating tap? tough luck, let's bail out */
+		err(ERR_OPEN_ERR, "open()");
+	
+	atexit(atex); /* when the loop is aborted, cleanup */
+	while(1)
+	{
+		int readies, i;
+
+		/*
+		since we're trying to create a twoway tunnel between stdio and the tap device
+		we need to do monitoring via select(). we simply don't know which one will
+		send us data first.
+		*/
+		fd_set fds;
+		FD_ZERO(&fds); /* init set of file descriptors */
+		FD_SET(fd,&fds); /* add tap device to set */
+		FD_SET(0,&fds); /* add stdin to set */
+
+		readies=select(fd+1, &fds, NULL, NULL, NULL); /* monitor the set. the first param is
+							max fd we monitor +1 (as usual with select()).
+							here that's fd. */
+		if(readies<=0) err(readies, "Not ready"); /* we passed a timeoutless select() with 0
+							active fds? ouch. */
+		for(i=0;i<2;i++)
+		{
+			/* some arcane magic to make the loop simple. i was lazy to cut paste code.
+			basically first the fd_int is stdin (0) and fd_oth is our tap device (fd).
+			then the fd_int is tap device (fd) and fd_oth is the stdout (1). */
+			int fd_int=i*fd;
+			int fd_oth=abs(fd-i*fd);
+			if(!fd_oth) fd_oth=1;
+			
+			/* is the currently monitored fd_int (first stdin, then tap) actually
+			   the one causing select() to unblock? */
+			if(FD_ISSET(fd_int, &fds))
+			{
+				/* yay! that one has somethign to say. let's read as much as
+				   possible for our buffer. num of actually read bytes is
+				   stored in ret, unless it's -1 which is error */
+				int ret = read(fd_int, buf, 255);
+				if (!ret) 
+				{
+					warnx("read(): nothing to read");
+					continue;
+				}
+				if (ret < 0) err(ERR_READ_ERR, "read(%d)", fd_int);
+		
+				/* write ret bytes into fd_oth; that's all the bytes we read */
+				if(write(fd_oth, buf, ret)<0) 
+					err(ERR_WRITE_ERR, "write(%d)", fd_oth);
+			}
+		}
+	}
+	
+	/* never happens */
+	return 0;
+}
+
+sudo ./twinpipe.sh ./tapper "nc -l -p 1234" &
+sleep 1
+sudo ./twinpipe.sh "nc localhost 1234" ./tapper
+#!/bin/sh
+
+VERSION=1.0.3
+
+cmd1=""
+cmd2=""
+
+help=0
+error=0
+cmdnum=0
+delfirst=1
+for opt; do
+  case "$opt" in
+    --help | -help | -h)
+      help=1
+      ;;
+    -d)
+      delfirst=0
+      ;;
+    -*)
+      echo "$0: Invalid option \`$opt\'" >&2
+      error=1
+      ;;
+    *)
+      if test $cmdnum = 2; then
+        echo "$0: Can't twinlink more than two processes." >&2
+        error=1
+      else
+        if test $cmdnum = 1; then
+          cmd2="$opt"
+          cmdnum=2
+        else
+          cmd1="$opt"
+          cmdnum=1
+        fi
+      fi
+      ;;
+  esac
+done
+
+if test ! $cmdnum = 2 -a $help = 0; then
+  echo "$0: You must specify two commands." >&2
+  error=1
+fi
+
+if test $help = 1; then
+  cat<<EOF
+$0 v$VERSION - Copyright (C) 1992,2002 Bisqwit (http://iki.fi/bisqwit/)
+The sourcecode of this program is available at the author's pages.
+
+Usage: $0 [-d] <command1> <command2>
+
+This program runs command1 and command2 simultaneously,
+so that command1's output is piped to command2 and
+command2's output is piped to command1.
+
+$0 creates a temporary fifo in /tmp directory, and
+deletes it as soon as possible, unless you use -d switch, in which
+case the fifo is deleted after both the processes have terminated.
+
+Demonstration of usage (not a demonstration of applicability):
+  $0 'echo a;head -n 1 >&2' 'echo b;echo c'
+
+For an example of applicability, you could use this program to create
+ppp tunnels via ssh, for example, linking the two ppp programs together.
+EOF
+else
+  if test $error = 0; then
+    uniqid="$$`date +%S%M%H%d%m%Y`"
+
+    fifo=/tmp/twinpipe.pipe."$uniqid"
+
+    if mkfifo "$fifo"; then
+      sh -c "$cmd1" < "$fifo" | \
+      sh -c "$cmd2" > "$fifo" &
+      if test $delfirst = 1; then rm -f "$fifo"; fi
+      wait
+      if test $delfirst = 0; then rm -f "$fifo"; fi
+    else
+      echo "$0: mkfifo failed for \`$fifo\'" >&2
+    fi
+  fi
+fi