From deed9c099fb16dc0a736a39e347f89928a389a5b Mon Sep 17 00:00:00 2001 From: phk Date: Sat, 11 Apr 1998 19:33:06 +0000 Subject: [PATCH] Program which implements "nos" alias "ka9q" alias "IP-IP" tunnels. PR: 1154 Reviewed by: phk Manpage by: phk Submitted by: Nickolay N. Dudorov nnd@itfs.nsk.su --- sbin/noc-tun/Makefile | 6 + sbin/noc-tun/nos-tun.8 | 73 +++++++++ sbin/noc-tun/nos-tun.c | 345 +++++++++++++++++++++++++++++++++++++++++ sbin/nos-tun/Makefile | 6 + sbin/nos-tun/nos-tun.8 | 73 +++++++++ sbin/nos-tun/nos-tun.c | 345 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 848 insertions(+) create mode 100644 sbin/noc-tun/Makefile create mode 100644 sbin/noc-tun/nos-tun.8 create mode 100644 sbin/noc-tun/nos-tun.c create mode 100644 sbin/nos-tun/Makefile create mode 100644 sbin/nos-tun/nos-tun.8 create mode 100644 sbin/nos-tun/nos-tun.c diff --git a/sbin/noc-tun/Makefile b/sbin/noc-tun/Makefile new file mode 100644 index 00000000000..bd74d7b208d --- /dev/null +++ b/sbin/noc-tun/Makefile @@ -0,0 +1,6 @@ + +PROG=nos-tun +MAN8=nos-tun.8 + +.include + diff --git a/sbin/noc-tun/nos-tun.8 b/sbin/noc-tun/nos-tun.8 new file mode 100644 index 00000000000..f3af572196c --- /dev/null +++ b/sbin/noc-tun/nos-tun.8 @@ -0,0 +1,73 @@ +.\" +.\" ---------------------------------------------------------------------------- +.\" "THE BEER-WARE LICENSE" (Revision 42): +.\" wrote this file. As long as you retain this notice you +.\" can do whatever you want with this stuff. If we meet some day, and you think +.\" this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp +.\" ---------------------------------------------------------------------------- +.\" +.\" $Id$ +.\" +.Dd April 11, 1998 +.Dt NOS-TUN 8 +.Os FreeBSD 3.0 +.Sh NAME +.Nm nos-tun +.Nd Implement ``nos'' or ``ka9q'' style IP over IP tunnel +.Sh SYNOPSIS +.Nm nos-tun +.Fl t +.Ar tunnel +.Fl s +.Ar source +.Fl d +.Ar destination +.Ar target +.Sh DESCRIPTION +.Nm +is used to establish an +.Em nos +style tunnel, (also known as +.Em ka9q +or +.Em IP-IP +tunnel) using a +.Xr tun 4 +kernel interface. +.Pp +.Ar tunnel +is the name of the tunnel device +.Dq /dev/tun0 +for example. +.Pp +.Ar source +and +.Ar destination +are the addresses used on the tunnel device. +If you configure the tunnel against a cisco router, use a netmask of +.Dq 255.255.255.252 +on the cisco. This is because the tunnel is a point-to-point interface +in the FreeBSD end, a concept cisco doesn't really implement. +.Pp +.Ar target +is the address of the remote tunnel device, this must match the source +address set on the remote end. +.Sh EXAMPLES +This end, a FreeBSD box on address 192.168.59.34: +.Bd -literal -offset indent 4m +nos-tun -t /dev/tun0 -s 192.168.61.1 -d 192.168.61.2 192.168.56.45 +.Ed +.Pp +Remote cisco on address 192.168.56.45: +.Bd -literal -offset indent 4m +interface tunnel 0 +ip address 192.168.61.2 255.255.255.252 +tunnel mode nos +tunnel destination 192.168.59.34 +tunnel source 192.168.56.45 +.Ed +.Sh BUGS +We don't allow for setting our source address for multihomed machines. +.Sh AUTHOR +Nickolay N. Dudorov wrote the program, +Poul-Henning Kamp wrote the man-page. diff --git a/sbin/noc-tun/nos-tun.c b/sbin/noc-tun/nos-tun.c new file mode 100644 index 00000000000..7847d5e7f4d --- /dev/null +++ b/sbin/noc-tun/nos-tun.c @@ -0,0 +1,345 @@ +/* + * Copyright (c) 1996, Nickolay Dudorov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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 AUTHOR 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 AUTHOR 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. + * + */ + +/* + * 'nos_tun' program configure tunN interface as a point-to-point + * connection with two "pseudo"-addresses between this host and + * 'target'. + * + * It uses Ip-over-Ip incapsulation ( protocol number 94 - IPIP) + * (known as NOS-incapsulation in CISCO-routers' terminology). + * + * 'nos_tun' can works with itself and CISCO-routers. + * (It may also work with Linux 'nos_tun's, but + * I have no Linux system here to test with). + * + * BUGS (or features ?): + * - you must specify ONE of the target host's addresses + * ( nos_tun sends and accepts packets only to/from this + * address ) + * - there can be only ONE tunnel between two hosts, + * more precisely - between given host and (one of) + * target hosts' address(es) + * (and why do you want more ?) + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* Tunnel interface configuration stuff */ +static struct ifaliasreq ifra; +static struct ifreq ifrq; + +/* Global descriptors */ +int net; /* socket descriptor */ +int tun; /* tunnel descriptor */ + +int Set_address(char *addr, struct sockaddr_in *sin) +{ + struct hostent *hp; + + bzero((char *)sin, sizeof(struct sockaddr)); + sin->sin_family = AF_INET; + if((sin->sin_addr.s_addr = inet_addr(addr)) == (u_long)-1) { + hp = gethostbyname(addr); + if (!hp) { + syslog(LOG_ERR,"Unknown host %s\n", addr); + return 1; + } + sin->sin_family = hp->h_addrtype; + bcopy(hp->h_addr, (caddr_t)&sin->sin_addr, hp->h_length); + } + return 0; +} + +int tun_open(char *devname, struct sockaddr *ouraddr, char *theiraddr) +{ + int s; + struct sockaddr_in *sin; + + /* Open tun device */ + tun = open (devname, O_RDWR); + if (tun < 0) { + syslog(LOG_ERR,"Can't open %s - %m",devname); + return(1); + } + + /* + * At first, name the interface. + */ + bzero((char *)&ifra, sizeof(ifra)); + bzero((char *)&ifrq, sizeof(ifrq)); + + strncpy(ifrq.ifr_name, devname+5, IFNAMSIZ); + strncpy(ifra.ifra_name, devname+5, IFNAMSIZ); + + s = socket(AF_INET, SOCK_DGRAM, 0); + if (s < 0) { + syslog(LOG_ERR,"Can't open socket - %M"); + goto tunc_return; + } + + /* + * Delete (previous) adresses for interface + * + * !!!! + * On FreeBSD this ioctl returns error + * when tunN have no addresses, so - log and ignore it. + * + */ + if (ioctl(s, SIOCDIFADDR, &ifra) < 0) { + syslog(LOG_ERR,"SIOCDIFADDR - %m"); + } + + /* + * Set interface address + */ + sin = (struct sockaddr_in *)&(ifra.ifra_addr); + bcopy(ouraddr, sin, sizeof(struct sockaddr_in)); + sin->sin_len = sizeof(*sin); + + /* + * Set destination address + */ + sin = (struct sockaddr_in *)&(ifra.ifra_broadaddr); + if(Set_address(theiraddr,sin)) { + syslog(LOG_ERR,"Bad destination address:%s\n",theiraddr); + goto stunc_return; + } + sin->sin_len = sizeof(*sin); + + if (ioctl(s, SIOCAIFADDR, &ifra) < 0) { + syslog(LOG_ERR,"Can't set interface address - %m"); + goto stunc_return; + } + + /* + * Now, bring up the interface. + */ + if (ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) { + syslog(LOG_ERR,"Can't get interface flags - %m"); + goto stunc_return; + } + + ifrq.ifr_flags |= IFF_UP; + if (!(ioctl(s, SIOCSIFFLAGS, &ifrq) < 0)) { + close(s); + return(0); + } + syslog(LOG_ERR,"Can't set interface UP - %m"); +stunc_return: + close(s); +tunc_return: + close(tun); + return(1); +} + +void Finish(int signum) +{ + int s; + + syslog(LOG_INFO,"Exiting"); + + close(net); + + s = socket(AF_INET, SOCK_DGRAM, 0); + if (s < 0) { + syslog(LOG_ERR,"Can't open socket - %m"); + goto closing_tun; + } + + /* + * Shut down interface. + */ + if (ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) { + syslog(LOG_ERR,"Can't get interface flags - %m"); + goto closing_fds; + } + + ifrq.ifr_flags &= ~(IFF_UP|IFF_RUNNING); + if (ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) { + syslog(LOG_ERR,"Can't set interface DOWN - %m"); + goto closing_fds; + } + + /* + * Delete adresses for interface + */ + bzero(&ifra.ifra_addr, sizeof(ifra.ifra_addr)); + bzero(&ifra.ifra_broadaddr, sizeof(ifra.ifra_addr)); + bzero(&ifra.ifra_mask, sizeof(ifra.ifra_addr)); + if (ioctl(s, SIOCDIFADDR, &ifra) < 0) { + syslog(LOG_ERR,"Can't delete interface's addresses - %m"); + } +closing_fds: + close(s); +closing_tun: + close(tun); + closelog(); + exit(signum); +} + +int main (int argc, char **argv) +{ + int c, len, ipoff; + + char *devname = NULL; + char *point_to = NULL; + char *to_point = NULL; + char *target; + + struct sockaddr t_laddr; /* Source address of tunnel */ + struct sockaddr whereto; /* Destination of tunnel */ + struct sockaddr_in *to; + + char buf[0x2000]; /* Packets buffer */ + struct ip *ip = (struct ip *)buf; + + fd_set rfds, wfds, efds; /* File descriptors for select() */ + int nfds; /* Return from select() */ + + + while ((c = getopt(argc, argv, "d:s:t:")) != EOF) { + switch (c) { + case 'd': + to_point = optarg; + break; + case 's': + point_to = optarg; + break; + case 't': + devname = optarg; + break; + } + } + argc -= optind; + argv += optind; + + if (argc != 1 || (devname == NULL) || + (point_to == NULL) || (to_point == NULL)) { + fprintf(stderr, + "Usage: nos_tun -t -s -d \n"); + exit(1); + } + + target = *argv; + + /* Establish logging through 'syslog' */ + openlog("nos_tun", LOG_PID, LOG_DAEMON); + + if(Set_address(point_to, (struct sockaddr_in *)&t_laddr)) { + closelog(); + exit(2); + } + + if(tun_open(devname, &t_laddr, to_point)) { + closelog(); + exit(3); + } + + to = (struct sockaddr_in *)&whereto; + if(Set_address(target, to)) + Finish(4); + + if ((net = socket(AF_INET, SOCK_RAW, 94)) < 0) { + syslog(LOG_ERR,"Can't open socket - %m"); + Finish(5); + } + + if (connect(net,&whereto,sizeof(struct sockaddr_in)) < 0 ) { + syslog(LOG_ERR,"Can't connect to target - %m"); + close(net); + Finish(6); + } + + /* Demonize it */ + daemon(0,0); + + /* Install signal handlers */ + (void)signal(SIGHUP,Finish); + (void)signal(SIGINT,Finish); + (void)signal(SIGTERM,Finish); + + for (;;) { + /* Set file descriptors for select() */ + FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); + FD_SET(tun,&rfds); FD_SET(net,&rfds); + + nfds = select(net+10,&rfds,&wfds,&efds,NULL); + if(nfds < 0) { + syslog(LOG_ERR,"Interrupted select"); + close(net); + Finish(7); + } + if(nfds == 0) { /* Impossible ? */ + syslog(LOG_ERR,"Timeout in select"); + close(net); + Finish(8); + } + + + if(FD_ISSET(net,&rfds)) { + /* Read from socket ... */ + len = read(net, buf, sizeof(buf)); + /* Check if this is "our" packet */ + if((ip->ip_src).s_addr == (to->sin_addr).s_addr) { + /* ... skip encapsulation headers ... */ + ipoff = (ip->ip_hl << 2); + /* ... and write to tun-device */ + write(tun,buf+ipoff,len-ipoff); + } + } + + if(FD_ISSET(tun,&rfds)) { + /* Read from tun ... */ + len = read(tun, buf, sizeof(buf)); + /* ... and send to network */ + if(send(net, buf, len,0) <= 0) { + syslog(LOG_ERR,"Can't send - %m"); + } + } + } +} + diff --git a/sbin/nos-tun/Makefile b/sbin/nos-tun/Makefile new file mode 100644 index 00000000000..bd74d7b208d --- /dev/null +++ b/sbin/nos-tun/Makefile @@ -0,0 +1,6 @@ + +PROG=nos-tun +MAN8=nos-tun.8 + +.include + diff --git a/sbin/nos-tun/nos-tun.8 b/sbin/nos-tun/nos-tun.8 new file mode 100644 index 00000000000..f3af572196c --- /dev/null +++ b/sbin/nos-tun/nos-tun.8 @@ -0,0 +1,73 @@ +.\" +.\" ---------------------------------------------------------------------------- +.\" "THE BEER-WARE LICENSE" (Revision 42): +.\" wrote this file. As long as you retain this notice you +.\" can do whatever you want with this stuff. If we meet some day, and you think +.\" this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp +.\" ---------------------------------------------------------------------------- +.\" +.\" $Id$ +.\" +.Dd April 11, 1998 +.Dt NOS-TUN 8 +.Os FreeBSD 3.0 +.Sh NAME +.Nm nos-tun +.Nd Implement ``nos'' or ``ka9q'' style IP over IP tunnel +.Sh SYNOPSIS +.Nm nos-tun +.Fl t +.Ar tunnel +.Fl s +.Ar source +.Fl d +.Ar destination +.Ar target +.Sh DESCRIPTION +.Nm +is used to establish an +.Em nos +style tunnel, (also known as +.Em ka9q +or +.Em IP-IP +tunnel) using a +.Xr tun 4 +kernel interface. +.Pp +.Ar tunnel +is the name of the tunnel device +.Dq /dev/tun0 +for example. +.Pp +.Ar source +and +.Ar destination +are the addresses used on the tunnel device. +If you configure the tunnel against a cisco router, use a netmask of +.Dq 255.255.255.252 +on the cisco. This is because the tunnel is a point-to-point interface +in the FreeBSD end, a concept cisco doesn't really implement. +.Pp +.Ar target +is the address of the remote tunnel device, this must match the source +address set on the remote end. +.Sh EXAMPLES +This end, a FreeBSD box on address 192.168.59.34: +.Bd -literal -offset indent 4m +nos-tun -t /dev/tun0 -s 192.168.61.1 -d 192.168.61.2 192.168.56.45 +.Ed +.Pp +Remote cisco on address 192.168.56.45: +.Bd -literal -offset indent 4m +interface tunnel 0 +ip address 192.168.61.2 255.255.255.252 +tunnel mode nos +tunnel destination 192.168.59.34 +tunnel source 192.168.56.45 +.Ed +.Sh BUGS +We don't allow for setting our source address for multihomed machines. +.Sh AUTHOR +Nickolay N. Dudorov wrote the program, +Poul-Henning Kamp wrote the man-page. diff --git a/sbin/nos-tun/nos-tun.c b/sbin/nos-tun/nos-tun.c new file mode 100644 index 00000000000..7847d5e7f4d --- /dev/null +++ b/sbin/nos-tun/nos-tun.c @@ -0,0 +1,345 @@ +/* + * Copyright (c) 1996, Nickolay Dudorov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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 AUTHOR 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 AUTHOR 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. + * + */ + +/* + * 'nos_tun' program configure tunN interface as a point-to-point + * connection with two "pseudo"-addresses between this host and + * 'target'. + * + * It uses Ip-over-Ip incapsulation ( protocol number 94 - IPIP) + * (known as NOS-incapsulation in CISCO-routers' terminology). + * + * 'nos_tun' can works with itself and CISCO-routers. + * (It may also work with Linux 'nos_tun's, but + * I have no Linux system here to test with). + * + * BUGS (or features ?): + * - you must specify ONE of the target host's addresses + * ( nos_tun sends and accepts packets only to/from this + * address ) + * - there can be only ONE tunnel between two hosts, + * more precisely - between given host and (one of) + * target hosts' address(es) + * (and why do you want more ?) + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* Tunnel interface configuration stuff */ +static struct ifaliasreq ifra; +static struct ifreq ifrq; + +/* Global descriptors */ +int net; /* socket descriptor */ +int tun; /* tunnel descriptor */ + +int Set_address(char *addr, struct sockaddr_in *sin) +{ + struct hostent *hp; + + bzero((char *)sin, sizeof(struct sockaddr)); + sin->sin_family = AF_INET; + if((sin->sin_addr.s_addr = inet_addr(addr)) == (u_long)-1) { + hp = gethostbyname(addr); + if (!hp) { + syslog(LOG_ERR,"Unknown host %s\n", addr); + return 1; + } + sin->sin_family = hp->h_addrtype; + bcopy(hp->h_addr, (caddr_t)&sin->sin_addr, hp->h_length); + } + return 0; +} + +int tun_open(char *devname, struct sockaddr *ouraddr, char *theiraddr) +{ + int s; + struct sockaddr_in *sin; + + /* Open tun device */ + tun = open (devname, O_RDWR); + if (tun < 0) { + syslog(LOG_ERR,"Can't open %s - %m",devname); + return(1); + } + + /* + * At first, name the interface. + */ + bzero((char *)&ifra, sizeof(ifra)); + bzero((char *)&ifrq, sizeof(ifrq)); + + strncpy(ifrq.ifr_name, devname+5, IFNAMSIZ); + strncpy(ifra.ifra_name, devname+5, IFNAMSIZ); + + s = socket(AF_INET, SOCK_DGRAM, 0); + if (s < 0) { + syslog(LOG_ERR,"Can't open socket - %M"); + goto tunc_return; + } + + /* + * Delete (previous) adresses for interface + * + * !!!! + * On FreeBSD this ioctl returns error + * when tunN have no addresses, so - log and ignore it. + * + */ + if (ioctl(s, SIOCDIFADDR, &ifra) < 0) { + syslog(LOG_ERR,"SIOCDIFADDR - %m"); + } + + /* + * Set interface address + */ + sin = (struct sockaddr_in *)&(ifra.ifra_addr); + bcopy(ouraddr, sin, sizeof(struct sockaddr_in)); + sin->sin_len = sizeof(*sin); + + /* + * Set destination address + */ + sin = (struct sockaddr_in *)&(ifra.ifra_broadaddr); + if(Set_address(theiraddr,sin)) { + syslog(LOG_ERR,"Bad destination address:%s\n",theiraddr); + goto stunc_return; + } + sin->sin_len = sizeof(*sin); + + if (ioctl(s, SIOCAIFADDR, &ifra) < 0) { + syslog(LOG_ERR,"Can't set interface address - %m"); + goto stunc_return; + } + + /* + * Now, bring up the interface. + */ + if (ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) { + syslog(LOG_ERR,"Can't get interface flags - %m"); + goto stunc_return; + } + + ifrq.ifr_flags |= IFF_UP; + if (!(ioctl(s, SIOCSIFFLAGS, &ifrq) < 0)) { + close(s); + return(0); + } + syslog(LOG_ERR,"Can't set interface UP - %m"); +stunc_return: + close(s); +tunc_return: + close(tun); + return(1); +} + +void Finish(int signum) +{ + int s; + + syslog(LOG_INFO,"Exiting"); + + close(net); + + s = socket(AF_INET, SOCK_DGRAM, 0); + if (s < 0) { + syslog(LOG_ERR,"Can't open socket - %m"); + goto closing_tun; + } + + /* + * Shut down interface. + */ + if (ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) { + syslog(LOG_ERR,"Can't get interface flags - %m"); + goto closing_fds; + } + + ifrq.ifr_flags &= ~(IFF_UP|IFF_RUNNING); + if (ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) { + syslog(LOG_ERR,"Can't set interface DOWN - %m"); + goto closing_fds; + } + + /* + * Delete adresses for interface + */ + bzero(&ifra.ifra_addr, sizeof(ifra.ifra_addr)); + bzero(&ifra.ifra_broadaddr, sizeof(ifra.ifra_addr)); + bzero(&ifra.ifra_mask, sizeof(ifra.ifra_addr)); + if (ioctl(s, SIOCDIFADDR, &ifra) < 0) { + syslog(LOG_ERR,"Can't delete interface's addresses - %m"); + } +closing_fds: + close(s); +closing_tun: + close(tun); + closelog(); + exit(signum); +} + +int main (int argc, char **argv) +{ + int c, len, ipoff; + + char *devname = NULL; + char *point_to = NULL; + char *to_point = NULL; + char *target; + + struct sockaddr t_laddr; /* Source address of tunnel */ + struct sockaddr whereto; /* Destination of tunnel */ + struct sockaddr_in *to; + + char buf[0x2000]; /* Packets buffer */ + struct ip *ip = (struct ip *)buf; + + fd_set rfds, wfds, efds; /* File descriptors for select() */ + int nfds; /* Return from select() */ + + + while ((c = getopt(argc, argv, "d:s:t:")) != EOF) { + switch (c) { + case 'd': + to_point = optarg; + break; + case 's': + point_to = optarg; + break; + case 't': + devname = optarg; + break; + } + } + argc -= optind; + argv += optind; + + if (argc != 1 || (devname == NULL) || + (point_to == NULL) || (to_point == NULL)) { + fprintf(stderr, + "Usage: nos_tun -t -s -d \n"); + exit(1); + } + + target = *argv; + + /* Establish logging through 'syslog' */ + openlog("nos_tun", LOG_PID, LOG_DAEMON); + + if(Set_address(point_to, (struct sockaddr_in *)&t_laddr)) { + closelog(); + exit(2); + } + + if(tun_open(devname, &t_laddr, to_point)) { + closelog(); + exit(3); + } + + to = (struct sockaddr_in *)&whereto; + if(Set_address(target, to)) + Finish(4); + + if ((net = socket(AF_INET, SOCK_RAW, 94)) < 0) { + syslog(LOG_ERR,"Can't open socket - %m"); + Finish(5); + } + + if (connect(net,&whereto,sizeof(struct sockaddr_in)) < 0 ) { + syslog(LOG_ERR,"Can't connect to target - %m"); + close(net); + Finish(6); + } + + /* Demonize it */ + daemon(0,0); + + /* Install signal handlers */ + (void)signal(SIGHUP,Finish); + (void)signal(SIGINT,Finish); + (void)signal(SIGTERM,Finish); + + for (;;) { + /* Set file descriptors for select() */ + FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); + FD_SET(tun,&rfds); FD_SET(net,&rfds); + + nfds = select(net+10,&rfds,&wfds,&efds,NULL); + if(nfds < 0) { + syslog(LOG_ERR,"Interrupted select"); + close(net); + Finish(7); + } + if(nfds == 0) { /* Impossible ? */ + syslog(LOG_ERR,"Timeout in select"); + close(net); + Finish(8); + } + + + if(FD_ISSET(net,&rfds)) { + /* Read from socket ... */ + len = read(net, buf, sizeof(buf)); + /* Check if this is "our" packet */ + if((ip->ip_src).s_addr == (to->sin_addr).s_addr) { + /* ... skip encapsulation headers ... */ + ipoff = (ip->ip_hl << 2); + /* ... and write to tun-device */ + write(tun,buf+ipoff,len-ipoff); + } + } + + if(FD_ISSET(tun,&rfds)) { + /* Read from tun ... */ + len = read(tun, buf, sizeof(buf)); + /* ... and send to network */ + if(send(net, buf, len,0) <= 0) { + syslog(LOG_ERR,"Can't send - %m"); + } + } + } +} + -- 2.45.2