summaryrefslogtreecommitdiffstats
path: root/sbin/nos-tun
diff options
context:
space:
mode:
authorphk <phk@FreeBSD.org>1998-04-11 19:33:06 +0000
committerphk <phk@FreeBSD.org>1998-04-11 19:33:06 +0000
commitdeed9c099fb16dc0a736a39e347f89928a389a5b (patch)
tree4e8e7de81b90b9d3814eba721bd0f224a205e14a /sbin/nos-tun
parent87312aadccbc33e70fd10dadb1258ffd51aac8d8 (diff)
downloadFreeBSD-src-deed9c099fb16dc0a736a39e347f89928a389a5b.zip
FreeBSD-src-deed9c099fb16dc0a736a39e347f89928a389a5b.tar.gz
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
Diffstat (limited to 'sbin/nos-tun')
-rw-r--r--sbin/nos-tun/Makefile6
-rw-r--r--sbin/nos-tun/nos-tun.873
-rw-r--r--sbin/nos-tun/nos-tun.c345
3 files changed, 424 insertions, 0 deletions
diff --git a/sbin/nos-tun/Makefile b/sbin/nos-tun/Makefile
new file mode 100644
index 0000000..bd74d7b
--- /dev/null
+++ b/sbin/nos-tun/Makefile
@@ -0,0 +1,6 @@
+
+PROG=nos-tun
+MAN8=nos-tun.8
+
+.include <bsd.prog.mk>
+
diff --git a/sbin/nos-tun/nos-tun.8 b/sbin/nos-tun/nos-tun.8
new file mode 100644
index 0000000..f3af572
--- /dev/null
+++ b/sbin/nos-tun/nos-tun.8
@@ -0,0 +1,73 @@
+.\"
+.\" ----------------------------------------------------------------------------
+.\" "THE BEER-WARE LICENSE" (Revision 42):
+.\" <phk@FreeBSD.org> 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 <nnd@itfs.nsk.su> wrote the program,
+Poul-Henning Kamp <phk@FreeBSD.org> 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 0000000..7847d5e
--- /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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <syslog.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/signal.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <net/if.h>
+#include <arpa/inet.h>
+
+
+/* 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 <tun_name> -s <source_addr> -d <dest_addr> <target_addr>\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");
+ }
+ }
+ }
+}
+
OpenPOWER on IntegriCloud