From e914f53ae82f35cba59b29370ceabbe8d1446f12 Mon Sep 17 00:00:00 2001 From: djm Date: Sat, 31 Dec 2005 05:33:36 +0000 Subject: [PATCH] - (djm) [openbsd-compat/port-tun.c openbsd-compat/port-tun.h configure.ac] [serverloop.c ssh.c openbsd-compat/Makefile.in] [openbsd-compat/openbsd-compat.h] Implement tun(4) forwarding compatability support for Linux, diff from reyk@ --- ChangeLog | 4 + configure.ac | 3 + openbsd-compat/Makefile.in | 2 +- openbsd-compat/openbsd-compat.h | 1 + openbsd-compat/port-tun.c | 155 ++++++++++++++++++++++++++++++++ openbsd-compat/port-tun.h | 33 +++++++ serverloop.c | 5 ++ ssh.c | 5 ++ 8 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 openbsd-compat/port-tun.c create mode 100644 openbsd-compat/port-tun.h diff --git a/ChangeLog b/ChangeLog index f07c518b..82d5c049 100644 --- a/ChangeLog +++ b/ChangeLog @@ -16,6 +16,10 @@ - stevesk@cvs.openbsd.org 2005/12/31 01:38:45 [ssh.1] document -MM; ok djm@ + - (djm) [openbsd-compat/port-tun.c openbsd-compat/port-tun.h configure.ac] + [serverloop.c ssh.c openbsd-compat/Makefile.in] + [openbsd-compat/openbsd-compat.h] Implement tun(4) forwarding + compatability support for Linux, diff from reyk@ 20051229 - (tim) [buildpkg.sh.in] grep for $SSHDUID instead of $SSHDGID on /etc/passwd diff --git a/configure.ac b/configure.ac index 9cd5344f..82ea4ff4 100644 --- a/configure.ac +++ b/configure.ac @@ -326,6 +326,9 @@ main() { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16)) [Define if cmsg_type is not passed correctly]) ;; esac + AC_DEFINE(SSH_TUN_LINUX, 1, [Open tunnel devices the Linux tun/tap way]) + AC_DEFINE(SSH_TUN_COMPAT_AF, 1, [Use tunnel device compatibility to OpenBSD]) + AC_DEFINE(SSH_TUN_PREPEND_AF, 1, [Prepend the address family to IP tunnel traffic]) ;; mips-sony-bsd|mips-sony-newsos4) AC_DEFINE(NEED_SETPRGP, 1, [Need setpgrp to acquire controlling tty]) diff --git a/openbsd-compat/Makefile.in b/openbsd-compat/Makefile.in index f605e73a..f164c6b7 100644 --- a/openbsd-compat/Makefile.in +++ b/openbsd-compat/Makefile.in @@ -20,7 +20,7 @@ OPENBSD=base64.o basename.o bindresvport.o daemon.o dirname.o getcwd.o getgroupl COMPAT=bsd-arc4random.o bsd-asprintf.o bsd-closefrom.o bsd-cray.o bsd-cygwin_util.o bsd-getpeereid.o bsd-misc.o bsd-nextstep.o bsd-openpty.o bsd-snprintf.o bsd-waitpid.o fake-rfc2553.o openssl-compat.o xmmap.o xcrypt.o -PORTS=port-irix.o port-aix.o port-uw.o +PORTS=port-irix.o port-aix.o port-uw.o port-tun.o .c.o: $(CC) $(CFLAGS) $(CPPFLAGS) -c $< diff --git a/openbsd-compat/openbsd-compat.h b/openbsd-compat/openbsd-compat.h index 00c907c5..2428528c 100644 --- a/openbsd-compat/openbsd-compat.h +++ b/openbsd-compat/openbsd-compat.h @@ -186,5 +186,6 @@ char *shadow_pw(struct passwd *pw); #include "port-irix.h" #include "port-aix.h" #include "port-uw.h" +#include "port-tun.h" #endif /* _OPENBSD_COMPAT_H */ diff --git a/openbsd-compat/port-tun.c b/openbsd-compat/port-tun.c new file mode 100644 index 00000000..479b46b7 --- /dev/null +++ b/openbsd-compat/port-tun.c @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2005 Reyk Floeter + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "includes.h" + +#include "log.h" +#include "misc.h" +#include "bufaux.h" + +/* + * This is the portable version of the SSH tunnel forwarding, it + * uses some preprocessor definitions for various platform-specific + * settings. + * + * SSH_TUN_LINUX Use the (newer) Linux tun/tap device + * SSH_TUN_COMPAT_AF Translate the OpenBSD address family + * SSH_TUN_PREPEND_AF Prepend/remove the address family + */ + +/* + * System-specific tunnel open function + */ + +#if defined(SSH_TUN_LINUX) +#include + +int +sys_tun_open(int tun, int mode) +{ + struct ifreq ifr; + int fd = -1; + const char *name = NULL; + + if ((fd = open("/dev/net/tun", O_RDWR)) == -1) { + debug("%s: failed to open tunnel control interface: %s", + __func__, strerror(errno)); + return (-1); + } + + bzero(&ifr, sizeof(ifr)); + + if (mode == SSH_TUNMODE_ETHERNET) { + ifr.ifr_flags = IFF_TAP; + name = "tap%d"; + } else { + ifr.ifr_flags = IFF_TUN; + name = "tun%d"; + } + ifr.ifr_flags |= IFF_NO_PI; + + if (tun != SSH_TUNID_ANY) { + if (tun > SSH_TUNID_MAX) { + debug("%s: invalid tunnel id %x: %s", __func__, + tun, strerror(errno)); + goto failed; + } + snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), name, tun); + } + + if (ioctl(fd, TUNSETIFF, &ifr) == -1) { + debug("%s: failed to configure tunnel (mode %d): %s", __func__, + mode, strerror(errno)); + goto failed; + } + + if (tun == SSH_TUNID_ANY) + debug("%s: tunnel mode %d fd %d", __func__, mode, fd); + else + debug("%s: %s mode %d fd %d", __func__, ifr.ifr_name, mode, fd); + + return (fd); + + failed: + close(fd); + return (-1); +} +#endif /* SSH_TUN_LINUX */ + +/* + * System-specific channel filters + */ + +#if defined(SSH_TUN_FILTER) +#define OPENBSD_AF_INET 2 +#define OPENBSD_AF_INET6 24 + +int +sys_tun_infilter(struct Channel *c, char *buf, int len) +{ +#if defined(SSH_TUN_PREPEND_AF) + char rbuf[CHAN_RBUF]; +#endif + u_int32_t *af; + char *ptr = buf; + +#if defined(SSH_TUN_PREPEND_AF) + if (len > (int)(sizeof(rbuf) - sizeof(*af))) + return (-1); + ptr = (char *)&rbuf[0]; + bcopy(buf, ptr + sizeof(u_int32_t), len); + len += sizeof(u_int32_t); +#endif + +#if defined(SSH_TUN_COMPAT_AF) + if (len < (int)sizeof(u_int32_t)) + return (-1); + + af = (u_int32_t *)ptr; + if (*af == htonl(AF_INET6)) + *af = htonl(OPENBSD_AF_INET6); + else + *af = htonl(OPENBSD_AF_INET); +#endif + buffer_put_string(&c->input, ptr, len); + return (0); +} + +u_char * +sys_tun_outfilter(struct Channel *c, u_char **data, u_int *dlen) +{ + u_char *buf; + u_int32_t *af; + + *data = buffer_get_string(&c->output, dlen); + if (*dlen < sizeof(*af)) + return (NULL); + buf = *data; + +#if defined(SSH_TUN_PREPEND_AF) + *dlen -= sizeof(u_int32_t); + buf = *data + sizeof(u_int32_t); +#elif defined(SSH_TUN_COMPAT_AF) + af = ntohl(*(u_int32_t *)buf); + if (*af == OPENBSD_AF_INET6) + *af = htonl(AF_INET6); + else + *af = htonl(AF_INET); +#endif + + return (buf); +} +#endif /* SSH_TUN_FILTER */ diff --git a/openbsd-compat/port-tun.h b/openbsd-compat/port-tun.h new file mode 100644 index 00000000..942610c6 --- /dev/null +++ b/openbsd-compat/port-tun.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2005 Reyk Floeter + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _PORT_TUN_H +#define _PORT_TUN_H + +#include "channels.h" + +#if defined(SSH_TUN_LINUX) +# define CUSTOM_SYS_TUN_OPEN +int sys_tun_open(int, int); +#endif + +#if defined(SSH_TUN_COMPAT_AF) || defined(SSH_TUN_PREPEND_AF) +# define SSH_TUN_FILTER +int sys_tun_infilter(struct Channel *, char *, int); +u_char *sys_tun_outfilter(struct Channel *, u_char **, u_int *); +#endif + +#endif diff --git a/serverloop.c b/serverloop.c index a575ce0d..3d8e7cfb 100644 --- a/serverloop.c +++ b/serverloop.c @@ -947,6 +947,11 @@ server_request_tun(void) c = channel_new("tun", SSH_CHANNEL_OPEN, sock, sock, -1, CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1); c->datagram = 1; +#if defined(SSH_TUN_FILTER) + if (mode == SSH_TUNMODE_POINTOPOINT) + channel_register_filter(c->self, sys_tun_infilter, + sys_tun_outfilter); +#endif done: if (c == NULL) diff --git a/ssh.c b/ssh.c index cdfc9163..3940dabf 100644 --- a/ssh.c +++ b/ssh.c @@ -1079,6 +1079,11 @@ ssh_session2_setup(int id, void *arg) CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1); c->datagram = 1; +#if defined(SSH_TUN_FILTER) + if (options.tun_open == SSH_TUNMODE_POINTOPOINT) + channel_register_filter(c->self, sys_tun_infilter, + sys_tun_outfilter); +#endif packet_start(SSH2_MSG_CHANNEL_OPEN); packet_put_cstring("tun@openssh.com"); packet_put_int(c->self); -- 2.45.1