Projects/Software/TunTapIO/tuntap.c

/**********************************************************************
 * ttio - tun/tap to stdin/out proxy                                  *
 * Written by: Ivo Smits                              *
 * Compile using: gcc tuntap.c -o ttio                                *
 * Based on PigeonWare (http://www.blug.linux.no/rfc1149/)            *
 * Many thanks to:                                                    *
 * - http://www.blug.linux.no/rfc1149/ (must-see!)                   *
 * - http://linux.about.com/od/commands/l/blcmdl2_select.htm         *
 * Many thanks to:                                                    *
 * - http://www.blug.linux.no/rfc1149/ (must-see!)                   *
 * - http://linux.about.com/od/commands/l/blcmdl2_select.htm         *

#include 
 * 1) include 
 * 2) include 
 * 3) include 
 * 4) include 
 * 5) ifndef HAVE_NETINET_IN_H
 * 1) endif


 * 1) include 
 * 2) include 
 * 3) include 
 * 4) include 


 * 1) include 
 * 2) include 

const char* TunTapDev = "/dev/net/tun";

// The main program, this is where all the magic happens int main(int argc, char** argv) { int DumpStats = 1; int IncludePLen = 1;

//Parse command line arguments if (argc > 1) { if (strcmp(argv[1], "-h") == 0) { fprintf(stderr, "ttio - tun/tap to stdio proxy\n"); fprintf(stderr, "Usage: %s INTF [-tap|-tun] [CLEN] [-pi]\n", argv[0]); fprintf(stderr, " INTF:  the name of the network interface\n"); fprintf(stderr, " -tap:  tap style ethernet tunnel (default)\n"); fprintf(stderr, " -tun:  point-to-point IP tunnel\n"); fprintf(stderr, " CLEN:  capture size (should be the same as the mtu, default: %d)\n", ETH_FRAME_LEN); fprintf(stderr, " -pi:   include packet information\n"); fprintf(stderr, "Note that the arguments should be in exactly THIS order.\n"); fprintf(stderr, "Report bugs to \n"); exit(0); }	} else { //Application won't run without arguments fprintf(stderr, "Try: %s -h\n", argv[0]); exit(1); }

struct ifreq ifr; //Clear the ifreq structure memset(&ifr, 0, sizeof(ifr));

char dev[IFNAMSIZ] = "tap1";	//Interface name //Copy the interface name from the commandline strcpy(dev, argv[1]); strcpy(ifr.ifr_name, dev);

//Initial capture length int CaptureLen = ETH_FRAME_LEN;

{		//Default to TAP interface, change only if --tun option is detected short ifrflags = IFF_TAP; if (argc > 2 && strcmp(argv[2], "-tun") == 0) { ifrflags = IFF_TUN; CaptureLen = ETH_DATA_LEN; }		//Different capture length? if (argc > 3) CaptureLen = atoi(argv[3]); if (CaptureLen < 1) { fprintf(stderr, "Capture length %d invalid!\n", CaptureLen); exit(1); }		fprintf(stderr, "Max packet length: %d\n", CaptureLen); //Include packet info in output? if (!(argc > 4 && strcmp(argv[4], "-pi") == 0)) ifrflags = ifrflags | IFF_NO_PI; //Set ifr flags ifr.ifr_flags = ifrflags; }

#warning "Make sure that dbuf can hold all the captured data" register int Ret; //Return value int TunFD; //Tun/tap stream

//Try to open the tun/tap device file, exit on failure fprintf(stderr, "Opening %s\n", TunTapDev); if ((TunFD = open(TunTapDev, O_RDWR)) < 0) { fprintf(stderr, "Failed to open %s: %d\n", TunTapDev, TunFD); exit(2); }

//Request the interface and set its flags fprintf(stderr, "Requesting device: %s\n", dev); if (ioctl(TunFD, TUNSETIFF, (void *)&ifr) < 0 ) { fprintf(stderr, "ioctl for device name failed!\n"); close(TunFD); exit(3); }

//Just to make sure..? #warning "Do we really need to read the interface name back from the ifr structure?" strcpy(dev, ifr.ifr_name); fprintf(stderr, "Tunnel interface: %s\n", dev);

#warning "Set the interfaces mtu to CaptureLength (-2 if Packet Info flag)" //Run the setup script {		char syscmd[256]; sprintf(syscmd, "./setup.sh %s", dev); fprintf(stderr, "Execute: %s\n", syscmd); system(syscmd); }

fprintf(stderr, "Proxy ready for action!\n");

fd_set fdsRead, fdsWrite; //FileDescriptor sets for select unsigned char RBuf[CaptureLen], WBuf[CaptureLen]; //Data buffers int RBufLen = 0, WBufLen = 0; //Packet length int PLen; //Start an infinite loop while (1) { if (WBufLen < 0 || RBufLen < 0) { fprintf(stderr, "WBufLen < 0 or RBufLen < 0 :|\n"); exit(2); }

FD_ZERO(&fdsRead);			//Clear FD set if (RBufLen == 0) FD_SET(TunFD, &fdsRead);	//Add tunnel device file if (WBufLen == 0) FD_SET(0, &fdsRead);		//Add stdin

FD_ZERO(&fdsWrite);			//Clear FD set if (WBufLen > 0) FD_SET(TunFD, &fdsWrite);	//Add tunnel device file if (RBufLen > 0) FD_SET(1, &fdsWrite);		//Add stdout

if (select(TunFD + 1, &fdsRead, &fdsWrite, NULL, NULL) < 0) { if (errno == EAGAIN || errno == EINTR) { continue; //Retry select } else { fprintf(stderr, "An unhandled error occured in select: %d", errno); exit(5); }		}

//Read from tun/tap device file if (FD_ISSET(TunFD, &fdsRead) && RBufLen == 0) { RBufLen = read(TunFD, RBuf, CaptureLen); if (RBufLen == 0) { fprintf(stderr, "End of file on %s\n", TunTapDev); exit(0); } else if (RBufLen < 0) { fprintf(stderr, "Some error occured while reading from %s: %d\n", TunTapDev, RBufLen); exit(4); }			if (DumpStats != 0) fprintf(stderr, "R: %d\n", RBufLen); }		//Write to tun/tap device file if (FD_ISSET(TunFD, &fdsWrite) && WBufLen > 0) { write(TunFD, WBuf, WBufLen); if (DumpStats != 0) fprintf(stderr, "W: %d\n", WBufLen); WBufLen = 0; }

//Read from stdin (FD 0) if (FD_ISSET(0, &fdsRead) && WBufLen == 0) { if (IncludePLen == 1) { WBufLen = read(0, &PLen, 4); }			if (IncludePLen == 0 || PLen > CaptureLen) { PLen = CaptureLen; }			if (IncludePLen == 0 || WBufLen > 0) { WBufLen = read(0, WBuf, PLen); }			if (WBufLen == 0) { fprintf(stderr, "End of file on stdin\n"); exit(0); } else if (WBufLen < 0) { fprintf(stderr, "Some error occured while reading stdin: %d\n", WBufLen); exit(4); }		}		//Write to stdout (FD 1) if (FD_ISSET(1, &fdsWrite) && RBufLen > 0) { if (IncludePLen == 1) write(1, &RBufLen, 4); write(1, RBuf, RBufLen); RBufLen = 0; }	} }