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;
}
}
}