Commits

Ivan Vučica committed 345b593

Added Mac OS X support

  • Participants
  • Parent commits 52c1351

Comments (0)

Files changed (3)

-OBJECTS=tapper.o
+TAPPER_OBJECTS=tapper.o
+TAPPER_OSX_OBJECTS=tapper-macosx.o
 
 all: tapper
 
-tapper: $(OBJECTS)
-	$(CC) $(OBJECTS) -o tapper
+tapper: $(TAPPER_OBJECTS)
+	$(CC) $(TAPPER_OBJECTS) -o tapper
 
+tapper-macosx: $(TAPPER_OSX_OBJECTS)
+	$(CC) $(TAPPER_OSX_OBJECTS) -o tapper-macosx
 
+

File tapper-macosx.c

+/*
+TAPPER-MACOSX - sample code for work with tap devices on mac os x
+
+Copyright (c) 2011, 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>
+#include <sys/socket.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)
+{
+	int fd;
+
+	srand(time(NULL));
+	/* On Mac OS X, tuntap driver does not provide dynamic creation of
+	   devices. We'll just try using /dev/tapXX, where XX is random. */
+	sprintf(newdev, "/dev/tap%d", rand() % 16);
+	fd = open(newdev, O_RDWR);
+	if(fd<0)
+		err(ERR_OPEN_ERR, "open()");
+
+	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", strrchr(devname, '/')+1,
+		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;
+}
+

File testrun-macosx.sh

+sudo ./twinpipe.sh ./tapper-macosx "nc -l -p 1234" &
+sleep 1
+sudo ./twinpipe.sh "nc localhost 1234" ./tapper-macosx