Projects/Software/TunTapIO/tuntap.c: Difference between revisions
Jump to navigation
Jump to search
(Nieuwe pagina aangemaakt met '<pre> /********************************************************************** * ttio - tun/tap to stdin/out proxy * * Written by: Ivo...') |
m (1 revision imported) |
(No difference)
|
Latest revision as of 15:49, 9 November 2022
/********************************************************************** * ttio - tun/tap to stdin/out proxy * * Written by: Ivo Smits <Ivo@UFO-Net.nl> * * * * 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 * * * **********************************************************************/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #ifndef HAVE_NETINET_IN_H #include <netinet/in.h> #endif #include <sys/ioctl.h> #include <linux/if.h> #include <linux/if_tun.h> #include <linux/if_ether.h> #include <errno.h> #include <dirent.h> 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 <Ivo@UFO-Net.nl>\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; } } }