1*47dd1d1bSDag-Erling Smørgrav /* 2*47dd1d1bSDag-Erling Smørgrav * Copyright (c) 2005 Reyk Floeter <reyk@openbsd.org> 3*47dd1d1bSDag-Erling Smørgrav * 4*47dd1d1bSDag-Erling Smørgrav * Permission to use, copy, modify, and distribute this software for any 5*47dd1d1bSDag-Erling Smørgrav * purpose with or without fee is hereby granted, provided that the above 6*47dd1d1bSDag-Erling Smørgrav * copyright notice and this permission notice appear in all copies. 7*47dd1d1bSDag-Erling Smørgrav * 8*47dd1d1bSDag-Erling Smørgrav * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9*47dd1d1bSDag-Erling Smørgrav * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10*47dd1d1bSDag-Erling Smørgrav * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11*47dd1d1bSDag-Erling Smørgrav * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12*47dd1d1bSDag-Erling Smørgrav * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13*47dd1d1bSDag-Erling Smørgrav * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14*47dd1d1bSDag-Erling Smørgrav * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15*47dd1d1bSDag-Erling Smørgrav */ 16*47dd1d1bSDag-Erling Smørgrav 17*47dd1d1bSDag-Erling Smørgrav #include "includes.h" 18*47dd1d1bSDag-Erling Smørgrav 19*47dd1d1bSDag-Erling Smørgrav #include <sys/types.h> 20*47dd1d1bSDag-Erling Smørgrav #include <sys/ioctl.h> 21*47dd1d1bSDag-Erling Smørgrav 22*47dd1d1bSDag-Erling Smørgrav #include <netinet/in.h> 23*47dd1d1bSDag-Erling Smørgrav #include <arpa/inet.h> 24*47dd1d1bSDag-Erling Smørgrav #include <netinet/ip.h> 25*47dd1d1bSDag-Erling Smørgrav 26*47dd1d1bSDag-Erling Smørgrav #include <errno.h> 27*47dd1d1bSDag-Erling Smørgrav #include <fcntl.h> 28*47dd1d1bSDag-Erling Smørgrav #include <stdarg.h> 29*47dd1d1bSDag-Erling Smørgrav #include <string.h> 30*47dd1d1bSDag-Erling Smørgrav #include <unistd.h> 31*47dd1d1bSDag-Erling Smørgrav 32*47dd1d1bSDag-Erling Smørgrav #include "openbsd-compat/sys-queue.h" 33*47dd1d1bSDag-Erling Smørgrav #include "log.h" 34*47dd1d1bSDag-Erling Smørgrav #include "misc.h" 35*47dd1d1bSDag-Erling Smørgrav #include "sshbuf.h" 36*47dd1d1bSDag-Erling Smørgrav #include "channels.h" 37*47dd1d1bSDag-Erling Smørgrav #include "ssherr.h" 38*47dd1d1bSDag-Erling Smørgrav 39*47dd1d1bSDag-Erling Smørgrav /* 40*47dd1d1bSDag-Erling Smørgrav * This file contains various portability code for network support, 41*47dd1d1bSDag-Erling Smørgrav * including tun/tap forwarding and routing domains. 42*47dd1d1bSDag-Erling Smørgrav */ 43*47dd1d1bSDag-Erling Smørgrav 44*47dd1d1bSDag-Erling Smørgrav #if defined(SYS_RDOMAIN_LINUX) || defined(SSH_TUN_LINUX) 45*47dd1d1bSDag-Erling Smørgrav #include <linux/if.h> 46*47dd1d1bSDag-Erling Smørgrav #endif 47*47dd1d1bSDag-Erling Smørgrav 48*47dd1d1bSDag-Erling Smørgrav #if defined(SYS_RDOMAIN_LINUX) 49*47dd1d1bSDag-Erling Smørgrav char * 50*47dd1d1bSDag-Erling Smørgrav sys_get_rdomain(int fd) 51*47dd1d1bSDag-Erling Smørgrav { 52*47dd1d1bSDag-Erling Smørgrav char dev[IFNAMSIZ + 1]; 53*47dd1d1bSDag-Erling Smørgrav socklen_t len = sizeof(dev) - 1; 54*47dd1d1bSDag-Erling Smørgrav 55*47dd1d1bSDag-Erling Smørgrav if (getsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, dev, &len) == -1) { 56*47dd1d1bSDag-Erling Smørgrav error("%s: cannot determine VRF for fd=%d : %s", 57*47dd1d1bSDag-Erling Smørgrav __func__, fd, strerror(errno)); 58*47dd1d1bSDag-Erling Smørgrav return NULL; 59*47dd1d1bSDag-Erling Smørgrav } 60*47dd1d1bSDag-Erling Smørgrav dev[len] = '\0'; 61*47dd1d1bSDag-Erling Smørgrav return strdup(dev); 62*47dd1d1bSDag-Erling Smørgrav } 63*47dd1d1bSDag-Erling Smørgrav 64*47dd1d1bSDag-Erling Smørgrav int 65*47dd1d1bSDag-Erling Smørgrav sys_set_rdomain(int fd, const char *name) 66*47dd1d1bSDag-Erling Smørgrav { 67*47dd1d1bSDag-Erling Smørgrav if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, 68*47dd1d1bSDag-Erling Smørgrav name, strlen(name)) == -1) { 69*47dd1d1bSDag-Erling Smørgrav error("%s: setsockopt(%d, SO_BINDTODEVICE, %s): %s", 70*47dd1d1bSDag-Erling Smørgrav __func__, fd, name, strerror(errno)); 71*47dd1d1bSDag-Erling Smørgrav return -1; 72*47dd1d1bSDag-Erling Smørgrav } 73*47dd1d1bSDag-Erling Smørgrav return 0; 74*47dd1d1bSDag-Erling Smørgrav } 75*47dd1d1bSDag-Erling Smørgrav 76*47dd1d1bSDag-Erling Smørgrav int 77*47dd1d1bSDag-Erling Smørgrav sys_valid_rdomain(const char *name) 78*47dd1d1bSDag-Erling Smørgrav { 79*47dd1d1bSDag-Erling Smørgrav int fd; 80*47dd1d1bSDag-Erling Smørgrav 81*47dd1d1bSDag-Erling Smørgrav /* 82*47dd1d1bSDag-Erling Smørgrav * This is a pretty crappy way to test. It would be better to 83*47dd1d1bSDag-Erling Smørgrav * check whether "name" represents a VRF device, but apparently 84*47dd1d1bSDag-Erling Smørgrav * that requires an rtnetlink transaction. 85*47dd1d1bSDag-Erling Smørgrav */ 86*47dd1d1bSDag-Erling Smørgrav if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) 87*47dd1d1bSDag-Erling Smørgrav return 0; 88*47dd1d1bSDag-Erling Smørgrav if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, 89*47dd1d1bSDag-Erling Smørgrav name, strlen(name)) == -1) { 90*47dd1d1bSDag-Erling Smørgrav close(fd); 91*47dd1d1bSDag-Erling Smørgrav return 0; 92*47dd1d1bSDag-Erling Smørgrav } 93*47dd1d1bSDag-Erling Smørgrav close(fd); 94*47dd1d1bSDag-Erling Smørgrav return 1; 95*47dd1d1bSDag-Erling Smørgrav } 96*47dd1d1bSDag-Erling Smørgrav #elif defined(SYS_RDOMAIN_XXX) 97*47dd1d1bSDag-Erling Smørgrav /* XXX examples */ 98*47dd1d1bSDag-Erling Smørgrav char * 99*47dd1d1bSDag-Erling Smørgrav sys_get_rdomain(int fd) 100*47dd1d1bSDag-Erling Smørgrav { 101*47dd1d1bSDag-Erling Smørgrav return NULL; 102*47dd1d1bSDag-Erling Smørgrav } 103*47dd1d1bSDag-Erling Smørgrav 104*47dd1d1bSDag-Erling Smørgrav int 105*47dd1d1bSDag-Erling Smørgrav sys_set_rdomain(int fd, const char *name) 106*47dd1d1bSDag-Erling Smørgrav { 107*47dd1d1bSDag-Erling Smørgrav return -1; 108*47dd1d1bSDag-Erling Smørgrav } 109*47dd1d1bSDag-Erling Smørgrav 110*47dd1d1bSDag-Erling Smørgrav int 111*47dd1d1bSDag-Erling Smørgrav valid_rdomain(const char *name) 112*47dd1d1bSDag-Erling Smørgrav { 113*47dd1d1bSDag-Erling Smørgrav return 0; 114*47dd1d1bSDag-Erling Smørgrav } 115*47dd1d1bSDag-Erling Smørgrav 116*47dd1d1bSDag-Erling Smørgrav void 117*47dd1d1bSDag-Erling Smørgrav sys_set_process_rdomain(const char *name) 118*47dd1d1bSDag-Erling Smørgrav { 119*47dd1d1bSDag-Erling Smørgrav fatal("%s: not supported", __func__); 120*47dd1d1bSDag-Erling Smørgrav } 121*47dd1d1bSDag-Erling Smørgrav #endif /* defined(SYS_RDOMAIN_XXX) */ 122*47dd1d1bSDag-Erling Smørgrav 123*47dd1d1bSDag-Erling Smørgrav /* 124*47dd1d1bSDag-Erling Smørgrav * This is the portable version of the SSH tunnel forwarding, it 125*47dd1d1bSDag-Erling Smørgrav * uses some preprocessor definitions for various platform-specific 126*47dd1d1bSDag-Erling Smørgrav * settings. 127*47dd1d1bSDag-Erling Smørgrav * 128*47dd1d1bSDag-Erling Smørgrav * SSH_TUN_LINUX Use the (newer) Linux tun/tap device 129*47dd1d1bSDag-Erling Smørgrav * SSH_TUN_FREEBSD Use the FreeBSD tun/tap device 130*47dd1d1bSDag-Erling Smørgrav * SSH_TUN_COMPAT_AF Translate the OpenBSD address family 131*47dd1d1bSDag-Erling Smørgrav * SSH_TUN_PREPEND_AF Prepend/remove the address family 132*47dd1d1bSDag-Erling Smørgrav */ 133*47dd1d1bSDag-Erling Smørgrav 134*47dd1d1bSDag-Erling Smørgrav /* 135*47dd1d1bSDag-Erling Smørgrav * System-specific tunnel open function 136*47dd1d1bSDag-Erling Smørgrav */ 137*47dd1d1bSDag-Erling Smørgrav 138*47dd1d1bSDag-Erling Smørgrav #if defined(SSH_TUN_LINUX) 139*47dd1d1bSDag-Erling Smørgrav #include <linux/if_tun.h> 140*47dd1d1bSDag-Erling Smørgrav 141*47dd1d1bSDag-Erling Smørgrav int 142*47dd1d1bSDag-Erling Smørgrav sys_tun_open(int tun, int mode, char **ifname) 143*47dd1d1bSDag-Erling Smørgrav { 144*47dd1d1bSDag-Erling Smørgrav struct ifreq ifr; 145*47dd1d1bSDag-Erling Smørgrav int fd = -1; 146*47dd1d1bSDag-Erling Smørgrav const char *name = NULL; 147*47dd1d1bSDag-Erling Smørgrav 148*47dd1d1bSDag-Erling Smørgrav if (ifname != NULL) 149*47dd1d1bSDag-Erling Smørgrav *ifname = NULL; 150*47dd1d1bSDag-Erling Smørgrav 151*47dd1d1bSDag-Erling Smørgrav if ((fd = open("/dev/net/tun", O_RDWR)) == -1) { 152*47dd1d1bSDag-Erling Smørgrav debug("%s: failed to open tunnel control interface: %s", 153*47dd1d1bSDag-Erling Smørgrav __func__, strerror(errno)); 154*47dd1d1bSDag-Erling Smørgrav return (-1); 155*47dd1d1bSDag-Erling Smørgrav } 156*47dd1d1bSDag-Erling Smørgrav 157*47dd1d1bSDag-Erling Smørgrav bzero(&ifr, sizeof(ifr)); 158*47dd1d1bSDag-Erling Smørgrav 159*47dd1d1bSDag-Erling Smørgrav if (mode == SSH_TUNMODE_ETHERNET) { 160*47dd1d1bSDag-Erling Smørgrav ifr.ifr_flags = IFF_TAP; 161*47dd1d1bSDag-Erling Smørgrav name = "tap%d"; 162*47dd1d1bSDag-Erling Smørgrav } else { 163*47dd1d1bSDag-Erling Smørgrav ifr.ifr_flags = IFF_TUN; 164*47dd1d1bSDag-Erling Smørgrav name = "tun%d"; 165*47dd1d1bSDag-Erling Smørgrav } 166*47dd1d1bSDag-Erling Smørgrav ifr.ifr_flags |= IFF_NO_PI; 167*47dd1d1bSDag-Erling Smørgrav 168*47dd1d1bSDag-Erling Smørgrav if (tun != SSH_TUNID_ANY) { 169*47dd1d1bSDag-Erling Smørgrav if (tun > SSH_TUNID_MAX) { 170*47dd1d1bSDag-Erling Smørgrav debug("%s: invalid tunnel id %x: %s", __func__, 171*47dd1d1bSDag-Erling Smørgrav tun, strerror(errno)); 172*47dd1d1bSDag-Erling Smørgrav goto failed; 173*47dd1d1bSDag-Erling Smørgrav } 174*47dd1d1bSDag-Erling Smørgrav snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), name, tun); 175*47dd1d1bSDag-Erling Smørgrav } 176*47dd1d1bSDag-Erling Smørgrav 177*47dd1d1bSDag-Erling Smørgrav if (ioctl(fd, TUNSETIFF, &ifr) == -1) { 178*47dd1d1bSDag-Erling Smørgrav debug("%s: failed to configure tunnel (mode %d): %s", __func__, 179*47dd1d1bSDag-Erling Smørgrav mode, strerror(errno)); 180*47dd1d1bSDag-Erling Smørgrav goto failed; 181*47dd1d1bSDag-Erling Smørgrav } 182*47dd1d1bSDag-Erling Smørgrav 183*47dd1d1bSDag-Erling Smørgrav if (tun == SSH_TUNID_ANY) 184*47dd1d1bSDag-Erling Smørgrav debug("%s: tunnel mode %d fd %d", __func__, mode, fd); 185*47dd1d1bSDag-Erling Smørgrav else 186*47dd1d1bSDag-Erling Smørgrav debug("%s: %s mode %d fd %d", __func__, ifr.ifr_name, mode, fd); 187*47dd1d1bSDag-Erling Smørgrav 188*47dd1d1bSDag-Erling Smørgrav if (ifname != NULL && (*ifname = strdup(ifr.ifr_name))) 189*47dd1d1bSDag-Erling Smørgrav goto failed; 190*47dd1d1bSDag-Erling Smørgrav 191*47dd1d1bSDag-Erling Smørgrav return (fd); 192*47dd1d1bSDag-Erling Smørgrav 193*47dd1d1bSDag-Erling Smørgrav failed: 194*47dd1d1bSDag-Erling Smørgrav close(fd); 195*47dd1d1bSDag-Erling Smørgrav return (-1); 196*47dd1d1bSDag-Erling Smørgrav } 197*47dd1d1bSDag-Erling Smørgrav #endif /* SSH_TUN_LINUX */ 198*47dd1d1bSDag-Erling Smørgrav 199*47dd1d1bSDag-Erling Smørgrav #ifdef SSH_TUN_FREEBSD 200*47dd1d1bSDag-Erling Smørgrav #include <sys/socket.h> 201*47dd1d1bSDag-Erling Smørgrav #include <net/if.h> 202*47dd1d1bSDag-Erling Smørgrav 203*47dd1d1bSDag-Erling Smørgrav #ifdef HAVE_NET_IF_TUN_H 204*47dd1d1bSDag-Erling Smørgrav #include <net/if_tun.h> 205*47dd1d1bSDag-Erling Smørgrav #endif 206*47dd1d1bSDag-Erling Smørgrav 207*47dd1d1bSDag-Erling Smørgrav int 208*47dd1d1bSDag-Erling Smørgrav sys_tun_open(int tun, int mode, char **ifname) 209*47dd1d1bSDag-Erling Smørgrav { 210*47dd1d1bSDag-Erling Smørgrav struct ifreq ifr; 211*47dd1d1bSDag-Erling Smørgrav char name[100]; 212*47dd1d1bSDag-Erling Smørgrav int fd = -1, sock, flag; 213*47dd1d1bSDag-Erling Smørgrav const char *tunbase = "tun"; 214*47dd1d1bSDag-Erling Smørgrav 215*47dd1d1bSDag-Erling Smørgrav if (ifname != NULL) 216*47dd1d1bSDag-Erling Smørgrav *ifname = NULL; 217*47dd1d1bSDag-Erling Smørgrav 218*47dd1d1bSDag-Erling Smørgrav if (mode == SSH_TUNMODE_ETHERNET) { 219*47dd1d1bSDag-Erling Smørgrav #ifdef SSH_TUN_NO_L2 220*47dd1d1bSDag-Erling Smørgrav debug("%s: no layer 2 tunnelling support", __func__); 221*47dd1d1bSDag-Erling Smørgrav return (-1); 222*47dd1d1bSDag-Erling Smørgrav #else 223*47dd1d1bSDag-Erling Smørgrav tunbase = "tap"; 224*47dd1d1bSDag-Erling Smørgrav #endif 225*47dd1d1bSDag-Erling Smørgrav } 226*47dd1d1bSDag-Erling Smørgrav 227*47dd1d1bSDag-Erling Smørgrav /* Open the tunnel device */ 228*47dd1d1bSDag-Erling Smørgrav if (tun <= SSH_TUNID_MAX) { 229*47dd1d1bSDag-Erling Smørgrav snprintf(name, sizeof(name), "/dev/%s%d", tunbase, tun); 230*47dd1d1bSDag-Erling Smørgrav fd = open(name, O_RDWR); 231*47dd1d1bSDag-Erling Smørgrav } else if (tun == SSH_TUNID_ANY) { 232*47dd1d1bSDag-Erling Smørgrav for (tun = 100; tun >= 0; tun--) { 233*47dd1d1bSDag-Erling Smørgrav snprintf(name, sizeof(name), "/dev/%s%d", 234*47dd1d1bSDag-Erling Smørgrav tunbase, tun); 235*47dd1d1bSDag-Erling Smørgrav if ((fd = open(name, O_RDWR)) >= 0) 236*47dd1d1bSDag-Erling Smørgrav break; 237*47dd1d1bSDag-Erling Smørgrav } 238*47dd1d1bSDag-Erling Smørgrav } else { 239*47dd1d1bSDag-Erling Smørgrav debug("%s: invalid tunnel %u\n", __func__, tun); 240*47dd1d1bSDag-Erling Smørgrav return (-1); 241*47dd1d1bSDag-Erling Smørgrav } 242*47dd1d1bSDag-Erling Smørgrav 243*47dd1d1bSDag-Erling Smørgrav if (fd < 0) { 244*47dd1d1bSDag-Erling Smørgrav debug("%s: %s open failed: %s", __func__, name, 245*47dd1d1bSDag-Erling Smørgrav strerror(errno)); 246*47dd1d1bSDag-Erling Smørgrav return (-1); 247*47dd1d1bSDag-Erling Smørgrav } 248*47dd1d1bSDag-Erling Smørgrav 249*47dd1d1bSDag-Erling Smørgrav /* Turn on tunnel headers */ 250*47dd1d1bSDag-Erling Smørgrav flag = 1; 251*47dd1d1bSDag-Erling Smørgrav #if defined(TUNSIFHEAD) && !defined(SSH_TUN_PREPEND_AF) 252*47dd1d1bSDag-Erling Smørgrav if (mode != SSH_TUNMODE_ETHERNET && 253*47dd1d1bSDag-Erling Smørgrav ioctl(fd, TUNSIFHEAD, &flag) == -1) { 254*47dd1d1bSDag-Erling Smørgrav debug("%s: ioctl(%d, TUNSIFHEAD, 1): %s", __func__, fd, 255*47dd1d1bSDag-Erling Smørgrav strerror(errno)); 256*47dd1d1bSDag-Erling Smørgrav close(fd); 257*47dd1d1bSDag-Erling Smørgrav } 258*47dd1d1bSDag-Erling Smørgrav #endif 259*47dd1d1bSDag-Erling Smørgrav 260*47dd1d1bSDag-Erling Smørgrav debug("%s: %s mode %d fd %d", __func__, name, mode, fd); 261*47dd1d1bSDag-Erling Smørgrav 262*47dd1d1bSDag-Erling Smørgrav /* Set the tunnel device operation mode */ 263*47dd1d1bSDag-Erling Smørgrav snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d", tunbase, tun); 264*47dd1d1bSDag-Erling Smørgrav if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) 265*47dd1d1bSDag-Erling Smørgrav goto failed; 266*47dd1d1bSDag-Erling Smørgrav 267*47dd1d1bSDag-Erling Smørgrav if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1) 268*47dd1d1bSDag-Erling Smørgrav goto failed; 269*47dd1d1bSDag-Erling Smørgrav if ((ifr.ifr_flags & IFF_UP) == 0) { 270*47dd1d1bSDag-Erling Smørgrav ifr.ifr_flags |= IFF_UP; 271*47dd1d1bSDag-Erling Smørgrav if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1) 272*47dd1d1bSDag-Erling Smørgrav goto failed; 273*47dd1d1bSDag-Erling Smørgrav } 274*47dd1d1bSDag-Erling Smørgrav 275*47dd1d1bSDag-Erling Smørgrav if (ifname != NULL && (*ifname = strdup(ifr.ifr_name))) 276*47dd1d1bSDag-Erling Smørgrav goto failed; 277*47dd1d1bSDag-Erling Smørgrav 278*47dd1d1bSDag-Erling Smørgrav close(sock); 279*47dd1d1bSDag-Erling Smørgrav return (fd); 280*47dd1d1bSDag-Erling Smørgrav 281*47dd1d1bSDag-Erling Smørgrav failed: 282*47dd1d1bSDag-Erling Smørgrav if (fd >= 0) 283*47dd1d1bSDag-Erling Smørgrav close(fd); 284*47dd1d1bSDag-Erling Smørgrav if (sock >= 0) 285*47dd1d1bSDag-Erling Smørgrav close(sock); 286*47dd1d1bSDag-Erling Smørgrav debug("%s: failed to set %s mode %d: %s", __func__, name, 287*47dd1d1bSDag-Erling Smørgrav mode, strerror(errno)); 288*47dd1d1bSDag-Erling Smørgrav return (-1); 289*47dd1d1bSDag-Erling Smørgrav } 290*47dd1d1bSDag-Erling Smørgrav #endif /* SSH_TUN_FREEBSD */ 291*47dd1d1bSDag-Erling Smørgrav 292*47dd1d1bSDag-Erling Smørgrav /* 293*47dd1d1bSDag-Erling Smørgrav * System-specific channel filters 294*47dd1d1bSDag-Erling Smørgrav */ 295*47dd1d1bSDag-Erling Smørgrav 296*47dd1d1bSDag-Erling Smørgrav #if defined(SSH_TUN_FILTER) 297*47dd1d1bSDag-Erling Smørgrav /* 298*47dd1d1bSDag-Erling Smørgrav * The tunnel forwarding protocol prepends the address family of forwarded 299*47dd1d1bSDag-Erling Smørgrav * IP packets using OpenBSD's numbers. 300*47dd1d1bSDag-Erling Smørgrav */ 301*47dd1d1bSDag-Erling Smørgrav #define OPENBSD_AF_INET 2 302*47dd1d1bSDag-Erling Smørgrav #define OPENBSD_AF_INET6 24 303*47dd1d1bSDag-Erling Smørgrav 304*47dd1d1bSDag-Erling Smørgrav int 305*47dd1d1bSDag-Erling Smørgrav sys_tun_infilter(struct ssh *ssh, struct Channel *c, char *buf, int _len) 306*47dd1d1bSDag-Erling Smørgrav { 307*47dd1d1bSDag-Erling Smørgrav int r; 308*47dd1d1bSDag-Erling Smørgrav size_t len; 309*47dd1d1bSDag-Erling Smørgrav char *ptr = buf; 310*47dd1d1bSDag-Erling Smørgrav #if defined(SSH_TUN_PREPEND_AF) 311*47dd1d1bSDag-Erling Smørgrav char rbuf[CHAN_RBUF]; 312*47dd1d1bSDag-Erling Smørgrav struct ip iph; 313*47dd1d1bSDag-Erling Smørgrav #endif 314*47dd1d1bSDag-Erling Smørgrav #if defined(SSH_TUN_PREPEND_AF) || defined(SSH_TUN_COMPAT_AF) 315*47dd1d1bSDag-Erling Smørgrav u_int32_t af; 316*47dd1d1bSDag-Erling Smørgrav #endif 317*47dd1d1bSDag-Erling Smørgrav 318*47dd1d1bSDag-Erling Smørgrav /* XXX update channel input filter API to use unsigned length */ 319*47dd1d1bSDag-Erling Smørgrav if (_len < 0) 320*47dd1d1bSDag-Erling Smørgrav return -1; 321*47dd1d1bSDag-Erling Smørgrav len = _len; 322*47dd1d1bSDag-Erling Smørgrav 323*47dd1d1bSDag-Erling Smørgrav #if defined(SSH_TUN_PREPEND_AF) 324*47dd1d1bSDag-Erling Smørgrav if (len <= sizeof(iph) || len > sizeof(rbuf) - 4) 325*47dd1d1bSDag-Erling Smørgrav return -1; 326*47dd1d1bSDag-Erling Smørgrav /* Determine address family from packet IP header. */ 327*47dd1d1bSDag-Erling Smørgrav memcpy(&iph, buf, sizeof(iph)); 328*47dd1d1bSDag-Erling Smørgrav af = iph.ip_v == 6 ? OPENBSD_AF_INET6 : OPENBSD_AF_INET; 329*47dd1d1bSDag-Erling Smørgrav /* Prepend address family to packet using OpenBSD constants */ 330*47dd1d1bSDag-Erling Smørgrav memcpy(rbuf + 4, buf, len); 331*47dd1d1bSDag-Erling Smørgrav len += 4; 332*47dd1d1bSDag-Erling Smørgrav POKE_U32(rbuf, af); 333*47dd1d1bSDag-Erling Smørgrav ptr = rbuf; 334*47dd1d1bSDag-Erling Smørgrav #elif defined(SSH_TUN_COMPAT_AF) 335*47dd1d1bSDag-Erling Smørgrav /* Convert existing address family header to OpenBSD value */ 336*47dd1d1bSDag-Erling Smørgrav if (len <= 4) 337*47dd1d1bSDag-Erling Smørgrav return -1; 338*47dd1d1bSDag-Erling Smørgrav af = PEEK_U32(buf); 339*47dd1d1bSDag-Erling Smørgrav /* Put it back */ 340*47dd1d1bSDag-Erling Smørgrav POKE_U32(buf, af == AF_INET6 ? OPENBSD_AF_INET6 : OPENBSD_AF_INET); 341*47dd1d1bSDag-Erling Smørgrav #endif 342*47dd1d1bSDag-Erling Smørgrav 343*47dd1d1bSDag-Erling Smørgrav if ((r = sshbuf_put_string(c->input, ptr, len)) != 0) 344*47dd1d1bSDag-Erling Smørgrav fatal("%s: buffer error: %s", __func__, ssh_err(r)); 345*47dd1d1bSDag-Erling Smørgrav return (0); 346*47dd1d1bSDag-Erling Smørgrav } 347*47dd1d1bSDag-Erling Smørgrav 348*47dd1d1bSDag-Erling Smørgrav u_char * 349*47dd1d1bSDag-Erling Smørgrav sys_tun_outfilter(struct ssh *ssh, struct Channel *c, 350*47dd1d1bSDag-Erling Smørgrav u_char **data, size_t *dlen) 351*47dd1d1bSDag-Erling Smørgrav { 352*47dd1d1bSDag-Erling Smørgrav u_char *buf; 353*47dd1d1bSDag-Erling Smørgrav u_int32_t af; 354*47dd1d1bSDag-Erling Smørgrav int r; 355*47dd1d1bSDag-Erling Smørgrav 356*47dd1d1bSDag-Erling Smørgrav /* XXX new API is incompatible with this signature. */ 357*47dd1d1bSDag-Erling Smørgrav if ((r = sshbuf_get_string(c->output, data, dlen)) != 0) 358*47dd1d1bSDag-Erling Smørgrav fatal("%s: buffer error: %s", __func__, ssh_err(r)); 359*47dd1d1bSDag-Erling Smørgrav if (*dlen < sizeof(af)) 360*47dd1d1bSDag-Erling Smørgrav return (NULL); 361*47dd1d1bSDag-Erling Smørgrav buf = *data; 362*47dd1d1bSDag-Erling Smørgrav 363*47dd1d1bSDag-Erling Smørgrav #if defined(SSH_TUN_PREPEND_AF) 364*47dd1d1bSDag-Erling Smørgrav /* skip address family */ 365*47dd1d1bSDag-Erling Smørgrav *dlen -= sizeof(af); 366*47dd1d1bSDag-Erling Smørgrav buf = *data + sizeof(af); 367*47dd1d1bSDag-Erling Smørgrav #elif defined(SSH_TUN_COMPAT_AF) 368*47dd1d1bSDag-Erling Smørgrav /* translate address family */ 369*47dd1d1bSDag-Erling Smørgrav af = (PEEK_U32(buf) == OPENBSD_AF_INET6) ? AF_INET6 : AF_INET; 370*47dd1d1bSDag-Erling Smørgrav POKE_U32(buf, af); 371*47dd1d1bSDag-Erling Smørgrav #endif 372*47dd1d1bSDag-Erling Smørgrav return (buf); 373*47dd1d1bSDag-Erling Smørgrav } 374*47dd1d1bSDag-Erling Smørgrav #endif /* SSH_TUN_FILTER */ 375