1157016Sdes/* 2157016Sdes * Copyright (c) 2005 Reyk Floeter <reyk@openbsd.org> 3157016Sdes * 4157016Sdes * Permission to use, copy, modify, and distribute this software for any 5157016Sdes * purpose with or without fee is hereby granted, provided that the above 6157016Sdes * copyright notice and this permission notice appear in all copies. 7157016Sdes * 8157016Sdes * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9157016Sdes * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10157016Sdes * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11157016Sdes * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12157016Sdes * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13157016Sdes * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14157016Sdes * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15157016Sdes */ 16157016Sdes 17157016Sdes#include "includes.h" 18157016Sdes 19162852Sdes#include <sys/types.h> 20162852Sdes#include <sys/ioctl.h> 21162852Sdes 22162852Sdes#include <netinet/in.h> 23162852Sdes#include <arpa/inet.h> 24162852Sdes#include <netinet/ip.h> 25162852Sdes 26162852Sdes#include <errno.h> 27162852Sdes#include <fcntl.h> 28162852Sdes#include <stdarg.h> 29162852Sdes#include <string.h> 30162852Sdes#include <unistd.h> 31162852Sdes 32181111Sdes#include "openbsd-compat/sys-queue.h" 33157016Sdes#include "log.h" 34157016Sdes#include "misc.h" 35162852Sdes#include "buffer.h" 36162852Sdes#include "channels.h" 37157016Sdes 38157016Sdes/* 39157016Sdes * This is the portable version of the SSH tunnel forwarding, it 40157016Sdes * uses some preprocessor definitions for various platform-specific 41157016Sdes * settings. 42157016Sdes * 43157016Sdes * SSH_TUN_LINUX Use the (newer) Linux tun/tap device 44162852Sdes * SSH_TUN_FREEBSD Use the FreeBSD tun/tap device 45157016Sdes * SSH_TUN_COMPAT_AF Translate the OpenBSD address family 46157016Sdes * SSH_TUN_PREPEND_AF Prepend/remove the address family 47157016Sdes */ 48157016Sdes 49157016Sdes/* 50157016Sdes * System-specific tunnel open function 51157016Sdes */ 52157016Sdes 53157016Sdes#if defined(SSH_TUN_LINUX) 54157016Sdes#include <linux/if.h> 55157016Sdes#include <linux/if_tun.h> 56157016Sdes 57157016Sdesint 58157016Sdessys_tun_open(int tun, int mode) 59157016Sdes{ 60157016Sdes struct ifreq ifr; 61157016Sdes int fd = -1; 62157016Sdes const char *name = NULL; 63157016Sdes 64157016Sdes if ((fd = open("/dev/net/tun", O_RDWR)) == -1) { 65157016Sdes debug("%s: failed to open tunnel control interface: %s", 66157016Sdes __func__, strerror(errno)); 67157016Sdes return (-1); 68157016Sdes } 69157016Sdes 70157016Sdes bzero(&ifr, sizeof(ifr)); 71157016Sdes 72157016Sdes if (mode == SSH_TUNMODE_ETHERNET) { 73157016Sdes ifr.ifr_flags = IFF_TAP; 74157016Sdes name = "tap%d"; 75157016Sdes } else { 76157016Sdes ifr.ifr_flags = IFF_TUN; 77157016Sdes name = "tun%d"; 78157016Sdes } 79157016Sdes ifr.ifr_flags |= IFF_NO_PI; 80157016Sdes 81157016Sdes if (tun != SSH_TUNID_ANY) { 82157016Sdes if (tun > SSH_TUNID_MAX) { 83157016Sdes debug("%s: invalid tunnel id %x: %s", __func__, 84157016Sdes tun, strerror(errno)); 85157016Sdes goto failed; 86157016Sdes } 87157016Sdes snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), name, tun); 88157016Sdes } 89157016Sdes 90157016Sdes if (ioctl(fd, TUNSETIFF, &ifr) == -1) { 91157016Sdes debug("%s: failed to configure tunnel (mode %d): %s", __func__, 92157016Sdes mode, strerror(errno)); 93157016Sdes goto failed; 94157016Sdes } 95157016Sdes 96157016Sdes if (tun == SSH_TUNID_ANY) 97157016Sdes debug("%s: tunnel mode %d fd %d", __func__, mode, fd); 98157016Sdes else 99157016Sdes debug("%s: %s mode %d fd %d", __func__, ifr.ifr_name, mode, fd); 100157016Sdes 101157016Sdes return (fd); 102157016Sdes 103157016Sdes failed: 104157016Sdes close(fd); 105157016Sdes return (-1); 106157016Sdes} 107157016Sdes#endif /* SSH_TUN_LINUX */ 108157016Sdes 109157016Sdes#ifdef SSH_TUN_FREEBSD 110157016Sdes#include <sys/socket.h> 111157016Sdes#include <net/if.h> 112162852Sdes 113162852Sdes#ifdef HAVE_NET_IF_TUN_H 114157016Sdes#include <net/if_tun.h> 115162852Sdes#endif 116157016Sdes 117157016Sdesint 118157016Sdessys_tun_open(int tun, int mode) 119157016Sdes{ 120157016Sdes struct ifreq ifr; 121157016Sdes char name[100]; 122157016Sdes int fd = -1, sock, flag; 123157016Sdes const char *tunbase = "tun"; 124157016Sdes 125157016Sdes if (mode == SSH_TUNMODE_ETHERNET) { 126157016Sdes#ifdef SSH_TUN_NO_L2 127157016Sdes debug("%s: no layer 2 tunnelling support", __func__); 128157016Sdes return (-1); 129157016Sdes#else 130157016Sdes tunbase = "tap"; 131157016Sdes#endif 132157016Sdes } 133157016Sdes 134157016Sdes /* Open the tunnel device */ 135157016Sdes if (tun <= SSH_TUNID_MAX) { 136157016Sdes snprintf(name, sizeof(name), "/dev/%s%d", tunbase, tun); 137157016Sdes fd = open(name, O_RDWR); 138157016Sdes } else if (tun == SSH_TUNID_ANY) { 139157016Sdes for (tun = 100; tun >= 0; tun--) { 140157016Sdes snprintf(name, sizeof(name), "/dev/%s%d", 141157016Sdes tunbase, tun); 142157016Sdes if ((fd = open(name, O_RDWR)) >= 0) 143157016Sdes break; 144157016Sdes } 145157016Sdes } else { 146157016Sdes debug("%s: invalid tunnel %u\n", __func__, tun); 147157016Sdes return (-1); 148157016Sdes } 149157016Sdes 150157016Sdes if (fd < 0) { 151157016Sdes debug("%s: %s open failed: %s", __func__, name, 152157016Sdes strerror(errno)); 153157016Sdes return (-1); 154157016Sdes } 155157016Sdes 156157016Sdes /* Turn on tunnel headers */ 157157016Sdes flag = 1; 158157016Sdes#if defined(TUNSIFHEAD) && !defined(SSH_TUN_PREPEND_AF) 159157016Sdes if (mode != SSH_TUNMODE_ETHERNET && 160157016Sdes ioctl(fd, TUNSIFHEAD, &flag) == -1) { 161157016Sdes debug("%s: ioctl(%d, TUNSIFHEAD, 1): %s", __func__, fd, 162157016Sdes strerror(errno)); 163157016Sdes close(fd); 164157016Sdes } 165157016Sdes#endif 166157016Sdes 167157016Sdes debug("%s: %s mode %d fd %d", __func__, name, mode, fd); 168157016Sdes 169157016Sdes /* Set the tunnel device operation mode */ 170157016Sdes snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d", tunbase, tun); 171157016Sdes if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) 172157016Sdes goto failed; 173157016Sdes 174157016Sdes if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1) 175157016Sdes goto failed; 176215116Sdes if ((ifr.ifr_flags & IFF_UP) == 0) { 177215116Sdes ifr.ifr_flags |= IFF_UP; 178215116Sdes if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1) 179215116Sdes goto failed; 180215116Sdes } 181157016Sdes 182157016Sdes close(sock); 183157016Sdes return (fd); 184157016Sdes 185157016Sdes failed: 186157016Sdes if (fd >= 0) 187157016Sdes close(fd); 188157016Sdes if (sock >= 0) 189157016Sdes close(sock); 190157016Sdes debug("%s: failed to set %s mode %d: %s", __func__, name, 191157016Sdes mode, strerror(errno)); 192157016Sdes return (-1); 193157016Sdes} 194157016Sdes#endif /* SSH_TUN_FREEBSD */ 195157016Sdes 196157016Sdes/* 197157016Sdes * System-specific channel filters 198157016Sdes */ 199157016Sdes 200157016Sdes#if defined(SSH_TUN_FILTER) 201157016Sdes#define OPENBSD_AF_INET 2 202157016Sdes#define OPENBSD_AF_INET6 24 203157016Sdes 204157016Sdesint 205157016Sdessys_tun_infilter(struct Channel *c, char *buf, int len) 206157016Sdes{ 207157016Sdes#if defined(SSH_TUN_PREPEND_AF) 208157016Sdes char rbuf[CHAN_RBUF]; 209157016Sdes struct ip *iph; 210157016Sdes#endif 211157016Sdes u_int32_t *af; 212157016Sdes char *ptr = buf; 213157016Sdes 214157016Sdes#if defined(SSH_TUN_PREPEND_AF) 215157016Sdes if (len <= 0 || len > (int)(sizeof(rbuf) - sizeof(*af))) 216157016Sdes return (-1); 217157016Sdes ptr = (char *)&rbuf[0]; 218157016Sdes bcopy(buf, ptr + sizeof(u_int32_t), len); 219157016Sdes len += sizeof(u_int32_t); 220157016Sdes af = (u_int32_t *)ptr; 221157016Sdes 222157016Sdes iph = (struct ip *)(ptr + sizeof(u_int32_t)); 223157016Sdes switch (iph->ip_v) { 224157016Sdes case 6: 225157016Sdes *af = AF_INET6; 226157016Sdes break; 227157016Sdes case 4: 228157016Sdes default: 229157016Sdes *af = AF_INET; 230157016Sdes break; 231157016Sdes } 232157016Sdes#endif 233157016Sdes 234157016Sdes#if defined(SSH_TUN_COMPAT_AF) 235157016Sdes if (len < (int)sizeof(u_int32_t)) 236157016Sdes return (-1); 237157016Sdes 238157016Sdes af = (u_int32_t *)ptr; 239157016Sdes if (*af == htonl(AF_INET6)) 240157016Sdes *af = htonl(OPENBSD_AF_INET6); 241157016Sdes else 242157016Sdes *af = htonl(OPENBSD_AF_INET); 243157016Sdes#endif 244157016Sdes 245157016Sdes buffer_put_string(&c->input, ptr, len); 246157016Sdes return (0); 247157016Sdes} 248157016Sdes 249157016Sdesu_char * 250157016Sdessys_tun_outfilter(struct Channel *c, u_char **data, u_int *dlen) 251157016Sdes{ 252157016Sdes u_char *buf; 253157016Sdes u_int32_t *af; 254157016Sdes 255157016Sdes *data = buffer_get_string(&c->output, dlen); 256157016Sdes if (*dlen < sizeof(*af)) 257157016Sdes return (NULL); 258157016Sdes buf = *data; 259157016Sdes 260157016Sdes#if defined(SSH_TUN_PREPEND_AF) 261157016Sdes *dlen -= sizeof(u_int32_t); 262157016Sdes buf = *data + sizeof(u_int32_t); 263157016Sdes#elif defined(SSH_TUN_COMPAT_AF) 264157016Sdes af = ntohl(*(u_int32_t *)buf); 265157016Sdes if (*af == OPENBSD_AF_INET6) 266157016Sdes *af = htonl(AF_INET6); 267157016Sdes else 268157016Sdes *af = htonl(AF_INET); 269157016Sdes#endif 270157016Sdes 271157016Sdes return (buf); 272157016Sdes} 273157016Sdes#endif /* SSH_TUN_FILTER */ 274