147dd1d1bSDag-Erling Smørgrav /* 247dd1d1bSDag-Erling Smørgrav * Copyright (c) 2005 Reyk Floeter <reyk@openbsd.org> 347dd1d1bSDag-Erling Smørgrav * 447dd1d1bSDag-Erling Smørgrav * Permission to use, copy, modify, and distribute this software for any 547dd1d1bSDag-Erling Smørgrav * purpose with or without fee is hereby granted, provided that the above 647dd1d1bSDag-Erling Smørgrav * copyright notice and this permission notice appear in all copies. 747dd1d1bSDag-Erling Smørgrav * 847dd1d1bSDag-Erling Smørgrav * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 947dd1d1bSDag-Erling Smørgrav * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1047dd1d1bSDag-Erling Smørgrav * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1147dd1d1bSDag-Erling Smørgrav * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1247dd1d1bSDag-Erling Smørgrav * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1347dd1d1bSDag-Erling Smørgrav * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1447dd1d1bSDag-Erling Smørgrav * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1547dd1d1bSDag-Erling Smørgrav */ 1647dd1d1bSDag-Erling Smørgrav 1747dd1d1bSDag-Erling Smørgrav #include "includes.h" 1847dd1d1bSDag-Erling Smørgrav 1947dd1d1bSDag-Erling Smørgrav #include <sys/types.h> 2047dd1d1bSDag-Erling Smørgrav #include <sys/ioctl.h> 2147dd1d1bSDag-Erling Smørgrav 2247dd1d1bSDag-Erling Smørgrav #include <netinet/in.h> 2347dd1d1bSDag-Erling Smørgrav #include <arpa/inet.h> 2447dd1d1bSDag-Erling Smørgrav #include <netinet/ip.h> 2547dd1d1bSDag-Erling Smørgrav 2647dd1d1bSDag-Erling Smørgrav #include <errno.h> 2747dd1d1bSDag-Erling Smørgrav #include <fcntl.h> 2847dd1d1bSDag-Erling Smørgrav #include <stdarg.h> 2947dd1d1bSDag-Erling Smørgrav #include <string.h> 3047dd1d1bSDag-Erling Smørgrav #include <unistd.h> 3147dd1d1bSDag-Erling Smørgrav 3247dd1d1bSDag-Erling Smørgrav #include "openbsd-compat/sys-queue.h" 3347dd1d1bSDag-Erling Smørgrav #include "log.h" 3447dd1d1bSDag-Erling Smørgrav #include "misc.h" 3547dd1d1bSDag-Erling Smørgrav #include "sshbuf.h" 3647dd1d1bSDag-Erling Smørgrav #include "channels.h" 3747dd1d1bSDag-Erling Smørgrav #include "ssherr.h" 3847dd1d1bSDag-Erling Smørgrav 3947dd1d1bSDag-Erling Smørgrav /* 4047dd1d1bSDag-Erling Smørgrav * This file contains various portability code for network support, 4147dd1d1bSDag-Erling Smørgrav * including tun/tap forwarding and routing domains. 4247dd1d1bSDag-Erling Smørgrav */ 4347dd1d1bSDag-Erling Smørgrav 4447dd1d1bSDag-Erling Smørgrav #if defined(SYS_RDOMAIN_LINUX) || defined(SSH_TUN_LINUX) 4547dd1d1bSDag-Erling Smørgrav #include <linux/if.h> 4647dd1d1bSDag-Erling Smørgrav #endif 4747dd1d1bSDag-Erling Smørgrav 4847dd1d1bSDag-Erling Smørgrav #if defined(SYS_RDOMAIN_LINUX) 4947dd1d1bSDag-Erling Smørgrav char * 5047dd1d1bSDag-Erling Smørgrav sys_get_rdomain(int fd) 5147dd1d1bSDag-Erling Smørgrav { 5247dd1d1bSDag-Erling Smørgrav char dev[IFNAMSIZ + 1]; 5347dd1d1bSDag-Erling Smørgrav socklen_t len = sizeof(dev) - 1; 5447dd1d1bSDag-Erling Smørgrav 5547dd1d1bSDag-Erling Smørgrav if (getsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, dev, &len) == -1) { 5647dd1d1bSDag-Erling Smørgrav error("%s: cannot determine VRF for fd=%d : %s", 5747dd1d1bSDag-Erling Smørgrav __func__, fd, strerror(errno)); 5847dd1d1bSDag-Erling Smørgrav return NULL; 5947dd1d1bSDag-Erling Smørgrav } 6047dd1d1bSDag-Erling Smørgrav dev[len] = '\0'; 6147dd1d1bSDag-Erling Smørgrav return strdup(dev); 6247dd1d1bSDag-Erling Smørgrav } 6347dd1d1bSDag-Erling Smørgrav 6447dd1d1bSDag-Erling Smørgrav int 6547dd1d1bSDag-Erling Smørgrav sys_set_rdomain(int fd, const char *name) 6647dd1d1bSDag-Erling Smørgrav { 6747dd1d1bSDag-Erling Smørgrav if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, 6847dd1d1bSDag-Erling Smørgrav name, strlen(name)) == -1) { 6947dd1d1bSDag-Erling Smørgrav error("%s: setsockopt(%d, SO_BINDTODEVICE, %s): %s", 7047dd1d1bSDag-Erling Smørgrav __func__, fd, name, strerror(errno)); 7147dd1d1bSDag-Erling Smørgrav return -1; 7247dd1d1bSDag-Erling Smørgrav } 7347dd1d1bSDag-Erling Smørgrav return 0; 7447dd1d1bSDag-Erling Smørgrav } 7547dd1d1bSDag-Erling Smørgrav 7647dd1d1bSDag-Erling Smørgrav int 7747dd1d1bSDag-Erling Smørgrav sys_valid_rdomain(const char *name) 7847dd1d1bSDag-Erling Smørgrav { 7947dd1d1bSDag-Erling Smørgrav int fd; 8047dd1d1bSDag-Erling Smørgrav 8147dd1d1bSDag-Erling Smørgrav /* 8247dd1d1bSDag-Erling Smørgrav * This is a pretty crappy way to test. It would be better to 8347dd1d1bSDag-Erling Smørgrav * check whether "name" represents a VRF device, but apparently 8447dd1d1bSDag-Erling Smørgrav * that requires an rtnetlink transaction. 8547dd1d1bSDag-Erling Smørgrav */ 8647dd1d1bSDag-Erling Smørgrav if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) 8747dd1d1bSDag-Erling Smørgrav return 0; 8847dd1d1bSDag-Erling Smørgrav if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, 8947dd1d1bSDag-Erling Smørgrav name, strlen(name)) == -1) { 9047dd1d1bSDag-Erling Smørgrav close(fd); 9147dd1d1bSDag-Erling Smørgrav return 0; 9247dd1d1bSDag-Erling Smørgrav } 9347dd1d1bSDag-Erling Smørgrav close(fd); 9447dd1d1bSDag-Erling Smørgrav return 1; 9547dd1d1bSDag-Erling Smørgrav } 9647dd1d1bSDag-Erling Smørgrav #elif defined(SYS_RDOMAIN_XXX) 9747dd1d1bSDag-Erling Smørgrav /* XXX examples */ 9847dd1d1bSDag-Erling Smørgrav char * 9947dd1d1bSDag-Erling Smørgrav sys_get_rdomain(int fd) 10047dd1d1bSDag-Erling Smørgrav { 10147dd1d1bSDag-Erling Smørgrav return NULL; 10247dd1d1bSDag-Erling Smørgrav } 10347dd1d1bSDag-Erling Smørgrav 10447dd1d1bSDag-Erling Smørgrav int 10547dd1d1bSDag-Erling Smørgrav sys_set_rdomain(int fd, const char *name) 10647dd1d1bSDag-Erling Smørgrav { 10747dd1d1bSDag-Erling Smørgrav return -1; 10847dd1d1bSDag-Erling Smørgrav } 10947dd1d1bSDag-Erling Smørgrav 11047dd1d1bSDag-Erling Smørgrav int 11147dd1d1bSDag-Erling Smørgrav valid_rdomain(const char *name) 11247dd1d1bSDag-Erling Smørgrav { 11347dd1d1bSDag-Erling Smørgrav return 0; 11447dd1d1bSDag-Erling Smørgrav } 11547dd1d1bSDag-Erling Smørgrav 11647dd1d1bSDag-Erling Smørgrav void 11747dd1d1bSDag-Erling Smørgrav sys_set_process_rdomain(const char *name) 11847dd1d1bSDag-Erling Smørgrav { 11947dd1d1bSDag-Erling Smørgrav fatal("%s: not supported", __func__); 12047dd1d1bSDag-Erling Smørgrav } 12147dd1d1bSDag-Erling Smørgrav #endif /* defined(SYS_RDOMAIN_XXX) */ 12247dd1d1bSDag-Erling Smørgrav 12347dd1d1bSDag-Erling Smørgrav /* 12447dd1d1bSDag-Erling Smørgrav * This is the portable version of the SSH tunnel forwarding, it 12547dd1d1bSDag-Erling Smørgrav * uses some preprocessor definitions for various platform-specific 12647dd1d1bSDag-Erling Smørgrav * settings. 12747dd1d1bSDag-Erling Smørgrav * 12847dd1d1bSDag-Erling Smørgrav * SSH_TUN_LINUX Use the (newer) Linux tun/tap device 12947dd1d1bSDag-Erling Smørgrav * SSH_TUN_FREEBSD Use the FreeBSD tun/tap device 13047dd1d1bSDag-Erling Smørgrav * SSH_TUN_COMPAT_AF Translate the OpenBSD address family 13147dd1d1bSDag-Erling Smørgrav * SSH_TUN_PREPEND_AF Prepend/remove the address family 13247dd1d1bSDag-Erling Smørgrav */ 13347dd1d1bSDag-Erling Smørgrav 13447dd1d1bSDag-Erling Smørgrav /* 13547dd1d1bSDag-Erling Smørgrav * System-specific tunnel open function 13647dd1d1bSDag-Erling Smørgrav */ 13747dd1d1bSDag-Erling Smørgrav 13847dd1d1bSDag-Erling Smørgrav #if defined(SSH_TUN_LINUX) 13947dd1d1bSDag-Erling Smørgrav #include <linux/if_tun.h> 14047dd1d1bSDag-Erling Smørgrav 14147dd1d1bSDag-Erling Smørgrav int 14247dd1d1bSDag-Erling Smørgrav sys_tun_open(int tun, int mode, char **ifname) 14347dd1d1bSDag-Erling Smørgrav { 14447dd1d1bSDag-Erling Smørgrav struct ifreq ifr; 14547dd1d1bSDag-Erling Smørgrav int fd = -1; 14647dd1d1bSDag-Erling Smørgrav const char *name = NULL; 14747dd1d1bSDag-Erling Smørgrav 14847dd1d1bSDag-Erling Smørgrav if (ifname != NULL) 14947dd1d1bSDag-Erling Smørgrav *ifname = NULL; 15047dd1d1bSDag-Erling Smørgrav 15147dd1d1bSDag-Erling Smørgrav if ((fd = open("/dev/net/tun", O_RDWR)) == -1) { 15247dd1d1bSDag-Erling Smørgrav debug("%s: failed to open tunnel control interface: %s", 15347dd1d1bSDag-Erling Smørgrav __func__, strerror(errno)); 15447dd1d1bSDag-Erling Smørgrav return (-1); 15547dd1d1bSDag-Erling Smørgrav } 15647dd1d1bSDag-Erling Smørgrav 15747dd1d1bSDag-Erling Smørgrav bzero(&ifr, sizeof(ifr)); 15847dd1d1bSDag-Erling Smørgrav 15947dd1d1bSDag-Erling Smørgrav if (mode == SSH_TUNMODE_ETHERNET) { 16047dd1d1bSDag-Erling Smørgrav ifr.ifr_flags = IFF_TAP; 16147dd1d1bSDag-Erling Smørgrav name = "tap%d"; 16247dd1d1bSDag-Erling Smørgrav } else { 16347dd1d1bSDag-Erling Smørgrav ifr.ifr_flags = IFF_TUN; 16447dd1d1bSDag-Erling Smørgrav name = "tun%d"; 16547dd1d1bSDag-Erling Smørgrav } 16647dd1d1bSDag-Erling Smørgrav ifr.ifr_flags |= IFF_NO_PI; 16747dd1d1bSDag-Erling Smørgrav 16847dd1d1bSDag-Erling Smørgrav if (tun != SSH_TUNID_ANY) { 16947dd1d1bSDag-Erling Smørgrav if (tun > SSH_TUNID_MAX) { 17047dd1d1bSDag-Erling Smørgrav debug("%s: invalid tunnel id %x: %s", __func__, 17147dd1d1bSDag-Erling Smørgrav tun, strerror(errno)); 17247dd1d1bSDag-Erling Smørgrav goto failed; 17347dd1d1bSDag-Erling Smørgrav } 17447dd1d1bSDag-Erling Smørgrav snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), name, tun); 17547dd1d1bSDag-Erling Smørgrav } 17647dd1d1bSDag-Erling Smørgrav 17747dd1d1bSDag-Erling Smørgrav if (ioctl(fd, TUNSETIFF, &ifr) == -1) { 17847dd1d1bSDag-Erling Smørgrav debug("%s: failed to configure tunnel (mode %d): %s", __func__, 17947dd1d1bSDag-Erling Smørgrav mode, strerror(errno)); 18047dd1d1bSDag-Erling Smørgrav goto failed; 18147dd1d1bSDag-Erling Smørgrav } 18247dd1d1bSDag-Erling Smørgrav 18347dd1d1bSDag-Erling Smørgrav if (tun == SSH_TUNID_ANY) 18447dd1d1bSDag-Erling Smørgrav debug("%s: tunnel mode %d fd %d", __func__, mode, fd); 18547dd1d1bSDag-Erling Smørgrav else 18647dd1d1bSDag-Erling Smørgrav debug("%s: %s mode %d fd %d", __func__, ifr.ifr_name, mode, fd); 18747dd1d1bSDag-Erling Smørgrav 188*f2a2dfa7SDag-Erling Smørgrav if (ifname != NULL && (*ifname = strdup(ifr.ifr_name)) == NULL) 18947dd1d1bSDag-Erling Smørgrav goto failed; 19047dd1d1bSDag-Erling Smørgrav 19147dd1d1bSDag-Erling Smørgrav return (fd); 19247dd1d1bSDag-Erling Smørgrav 19347dd1d1bSDag-Erling Smørgrav failed: 19447dd1d1bSDag-Erling Smørgrav close(fd); 19547dd1d1bSDag-Erling Smørgrav return (-1); 19647dd1d1bSDag-Erling Smørgrav } 19747dd1d1bSDag-Erling Smørgrav #endif /* SSH_TUN_LINUX */ 19847dd1d1bSDag-Erling Smørgrav 19947dd1d1bSDag-Erling Smørgrav #ifdef SSH_TUN_FREEBSD 20047dd1d1bSDag-Erling Smørgrav #include <sys/socket.h> 20147dd1d1bSDag-Erling Smørgrav #include <net/if.h> 20247dd1d1bSDag-Erling Smørgrav 20347dd1d1bSDag-Erling Smørgrav #ifdef HAVE_NET_IF_TUN_H 20447dd1d1bSDag-Erling Smørgrav #include <net/if_tun.h> 20547dd1d1bSDag-Erling Smørgrav #endif 20647dd1d1bSDag-Erling Smørgrav 20747dd1d1bSDag-Erling Smørgrav int 20847dd1d1bSDag-Erling Smørgrav sys_tun_open(int tun, int mode, char **ifname) 20947dd1d1bSDag-Erling Smørgrav { 21047dd1d1bSDag-Erling Smørgrav struct ifreq ifr; 21147dd1d1bSDag-Erling Smørgrav char name[100]; 21247dd1d1bSDag-Erling Smørgrav int fd = -1, sock, flag; 21347dd1d1bSDag-Erling Smørgrav const char *tunbase = "tun"; 21447dd1d1bSDag-Erling Smørgrav 21547dd1d1bSDag-Erling Smørgrav if (ifname != NULL) 21647dd1d1bSDag-Erling Smørgrav *ifname = NULL; 21747dd1d1bSDag-Erling Smørgrav 21847dd1d1bSDag-Erling Smørgrav if (mode == SSH_TUNMODE_ETHERNET) { 21947dd1d1bSDag-Erling Smørgrav #ifdef SSH_TUN_NO_L2 22047dd1d1bSDag-Erling Smørgrav debug("%s: no layer 2 tunnelling support", __func__); 22147dd1d1bSDag-Erling Smørgrav return (-1); 22247dd1d1bSDag-Erling Smørgrav #else 22347dd1d1bSDag-Erling Smørgrav tunbase = "tap"; 22447dd1d1bSDag-Erling Smørgrav #endif 22547dd1d1bSDag-Erling Smørgrav } 22647dd1d1bSDag-Erling Smørgrav 22747dd1d1bSDag-Erling Smørgrav /* Open the tunnel device */ 22847dd1d1bSDag-Erling Smørgrav if (tun <= SSH_TUNID_MAX) { 22947dd1d1bSDag-Erling Smørgrav snprintf(name, sizeof(name), "/dev/%s%d", tunbase, tun); 23047dd1d1bSDag-Erling Smørgrav fd = open(name, O_RDWR); 23147dd1d1bSDag-Erling Smørgrav } else if (tun == SSH_TUNID_ANY) { 23247dd1d1bSDag-Erling Smørgrav for (tun = 100; tun >= 0; tun--) { 23347dd1d1bSDag-Erling Smørgrav snprintf(name, sizeof(name), "/dev/%s%d", 23447dd1d1bSDag-Erling Smørgrav tunbase, tun); 23547dd1d1bSDag-Erling Smørgrav if ((fd = open(name, O_RDWR)) >= 0) 23647dd1d1bSDag-Erling Smørgrav break; 23747dd1d1bSDag-Erling Smørgrav } 23847dd1d1bSDag-Erling Smørgrav } else { 23947dd1d1bSDag-Erling Smørgrav debug("%s: invalid tunnel %u\n", __func__, tun); 24047dd1d1bSDag-Erling Smørgrav return (-1); 24147dd1d1bSDag-Erling Smørgrav } 24247dd1d1bSDag-Erling Smørgrav 24347dd1d1bSDag-Erling Smørgrav if (fd < 0) { 24447dd1d1bSDag-Erling Smørgrav debug("%s: %s open failed: %s", __func__, name, 24547dd1d1bSDag-Erling Smørgrav strerror(errno)); 24647dd1d1bSDag-Erling Smørgrav return (-1); 24747dd1d1bSDag-Erling Smørgrav } 24847dd1d1bSDag-Erling Smørgrav 24947dd1d1bSDag-Erling Smørgrav /* Turn on tunnel headers */ 25047dd1d1bSDag-Erling Smørgrav flag = 1; 25147dd1d1bSDag-Erling Smørgrav #if defined(TUNSIFHEAD) && !defined(SSH_TUN_PREPEND_AF) 25247dd1d1bSDag-Erling Smørgrav if (mode != SSH_TUNMODE_ETHERNET && 25347dd1d1bSDag-Erling Smørgrav ioctl(fd, TUNSIFHEAD, &flag) == -1) { 25447dd1d1bSDag-Erling Smørgrav debug("%s: ioctl(%d, TUNSIFHEAD, 1): %s", __func__, fd, 25547dd1d1bSDag-Erling Smørgrav strerror(errno)); 25647dd1d1bSDag-Erling Smørgrav close(fd); 25747dd1d1bSDag-Erling Smørgrav } 25847dd1d1bSDag-Erling Smørgrav #endif 25947dd1d1bSDag-Erling Smørgrav 26047dd1d1bSDag-Erling Smørgrav debug("%s: %s mode %d fd %d", __func__, name, mode, fd); 26147dd1d1bSDag-Erling Smørgrav 26247dd1d1bSDag-Erling Smørgrav /* Set the tunnel device operation mode */ 26347dd1d1bSDag-Erling Smørgrav snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d", tunbase, tun); 26447dd1d1bSDag-Erling Smørgrav if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) 26547dd1d1bSDag-Erling Smørgrav goto failed; 26647dd1d1bSDag-Erling Smørgrav 26747dd1d1bSDag-Erling Smørgrav if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1) 26847dd1d1bSDag-Erling Smørgrav goto failed; 26947dd1d1bSDag-Erling Smørgrav if ((ifr.ifr_flags & IFF_UP) == 0) { 27047dd1d1bSDag-Erling Smørgrav ifr.ifr_flags |= IFF_UP; 27147dd1d1bSDag-Erling Smørgrav if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1) 27247dd1d1bSDag-Erling Smørgrav goto failed; 27347dd1d1bSDag-Erling Smørgrav } 27447dd1d1bSDag-Erling Smørgrav 275*f2a2dfa7SDag-Erling Smørgrav if (ifname != NULL && (*ifname = strdup(ifr.ifr_name)) == NULL) 27647dd1d1bSDag-Erling Smørgrav goto failed; 27747dd1d1bSDag-Erling Smørgrav 27847dd1d1bSDag-Erling Smørgrav close(sock); 27947dd1d1bSDag-Erling Smørgrav return (fd); 28047dd1d1bSDag-Erling Smørgrav 28147dd1d1bSDag-Erling Smørgrav failed: 28247dd1d1bSDag-Erling Smørgrav if (fd >= 0) 28347dd1d1bSDag-Erling Smørgrav close(fd); 28447dd1d1bSDag-Erling Smørgrav if (sock >= 0) 28547dd1d1bSDag-Erling Smørgrav close(sock); 28647dd1d1bSDag-Erling Smørgrav debug("%s: failed to set %s mode %d: %s", __func__, name, 28747dd1d1bSDag-Erling Smørgrav mode, strerror(errno)); 28847dd1d1bSDag-Erling Smørgrav return (-1); 28947dd1d1bSDag-Erling Smørgrav } 29047dd1d1bSDag-Erling Smørgrav #endif /* SSH_TUN_FREEBSD */ 29147dd1d1bSDag-Erling Smørgrav 29247dd1d1bSDag-Erling Smørgrav /* 29347dd1d1bSDag-Erling Smørgrav * System-specific channel filters 29447dd1d1bSDag-Erling Smørgrav */ 29547dd1d1bSDag-Erling Smørgrav 29647dd1d1bSDag-Erling Smørgrav #if defined(SSH_TUN_FILTER) 29747dd1d1bSDag-Erling Smørgrav /* 29847dd1d1bSDag-Erling Smørgrav * The tunnel forwarding protocol prepends the address family of forwarded 29947dd1d1bSDag-Erling Smørgrav * IP packets using OpenBSD's numbers. 30047dd1d1bSDag-Erling Smørgrav */ 30147dd1d1bSDag-Erling Smørgrav #define OPENBSD_AF_INET 2 30247dd1d1bSDag-Erling Smørgrav #define OPENBSD_AF_INET6 24 30347dd1d1bSDag-Erling Smørgrav 30447dd1d1bSDag-Erling Smørgrav int 30547dd1d1bSDag-Erling Smørgrav sys_tun_infilter(struct ssh *ssh, struct Channel *c, char *buf, int _len) 30647dd1d1bSDag-Erling Smørgrav { 30747dd1d1bSDag-Erling Smørgrav int r; 30847dd1d1bSDag-Erling Smørgrav size_t len; 30947dd1d1bSDag-Erling Smørgrav char *ptr = buf; 31047dd1d1bSDag-Erling Smørgrav #if defined(SSH_TUN_PREPEND_AF) 31147dd1d1bSDag-Erling Smørgrav char rbuf[CHAN_RBUF]; 31247dd1d1bSDag-Erling Smørgrav struct ip iph; 31347dd1d1bSDag-Erling Smørgrav #endif 31447dd1d1bSDag-Erling Smørgrav #if defined(SSH_TUN_PREPEND_AF) || defined(SSH_TUN_COMPAT_AF) 31547dd1d1bSDag-Erling Smørgrav u_int32_t af; 31647dd1d1bSDag-Erling Smørgrav #endif 31747dd1d1bSDag-Erling Smørgrav 31847dd1d1bSDag-Erling Smørgrav /* XXX update channel input filter API to use unsigned length */ 31947dd1d1bSDag-Erling Smørgrav if (_len < 0) 32047dd1d1bSDag-Erling Smørgrav return -1; 32147dd1d1bSDag-Erling Smørgrav len = _len; 32247dd1d1bSDag-Erling Smørgrav 32347dd1d1bSDag-Erling Smørgrav #if defined(SSH_TUN_PREPEND_AF) 32447dd1d1bSDag-Erling Smørgrav if (len <= sizeof(iph) || len > sizeof(rbuf) - 4) 32547dd1d1bSDag-Erling Smørgrav return -1; 32647dd1d1bSDag-Erling Smørgrav /* Determine address family from packet IP header. */ 32747dd1d1bSDag-Erling Smørgrav memcpy(&iph, buf, sizeof(iph)); 32847dd1d1bSDag-Erling Smørgrav af = iph.ip_v == 6 ? OPENBSD_AF_INET6 : OPENBSD_AF_INET; 32947dd1d1bSDag-Erling Smørgrav /* Prepend address family to packet using OpenBSD constants */ 33047dd1d1bSDag-Erling Smørgrav memcpy(rbuf + 4, buf, len); 33147dd1d1bSDag-Erling Smørgrav len += 4; 33247dd1d1bSDag-Erling Smørgrav POKE_U32(rbuf, af); 33347dd1d1bSDag-Erling Smørgrav ptr = rbuf; 33447dd1d1bSDag-Erling Smørgrav #elif defined(SSH_TUN_COMPAT_AF) 33547dd1d1bSDag-Erling Smørgrav /* Convert existing address family header to OpenBSD value */ 33647dd1d1bSDag-Erling Smørgrav if (len <= 4) 33747dd1d1bSDag-Erling Smørgrav return -1; 33847dd1d1bSDag-Erling Smørgrav af = PEEK_U32(buf); 33947dd1d1bSDag-Erling Smørgrav /* Put it back */ 34047dd1d1bSDag-Erling Smørgrav POKE_U32(buf, af == AF_INET6 ? OPENBSD_AF_INET6 : OPENBSD_AF_INET); 34147dd1d1bSDag-Erling Smørgrav #endif 34247dd1d1bSDag-Erling Smørgrav 34347dd1d1bSDag-Erling Smørgrav if ((r = sshbuf_put_string(c->input, ptr, len)) != 0) 34447dd1d1bSDag-Erling Smørgrav fatal("%s: buffer error: %s", __func__, ssh_err(r)); 34547dd1d1bSDag-Erling Smørgrav return (0); 34647dd1d1bSDag-Erling Smørgrav } 34747dd1d1bSDag-Erling Smørgrav 34847dd1d1bSDag-Erling Smørgrav u_char * 34947dd1d1bSDag-Erling Smørgrav sys_tun_outfilter(struct ssh *ssh, struct Channel *c, 35047dd1d1bSDag-Erling Smørgrav u_char **data, size_t *dlen) 35147dd1d1bSDag-Erling Smørgrav { 35247dd1d1bSDag-Erling Smørgrav u_char *buf; 35347dd1d1bSDag-Erling Smørgrav u_int32_t af; 35447dd1d1bSDag-Erling Smørgrav int r; 35547dd1d1bSDag-Erling Smørgrav 35647dd1d1bSDag-Erling Smørgrav /* XXX new API is incompatible with this signature. */ 35747dd1d1bSDag-Erling Smørgrav if ((r = sshbuf_get_string(c->output, data, dlen)) != 0) 35847dd1d1bSDag-Erling Smørgrav fatal("%s: buffer error: %s", __func__, ssh_err(r)); 35947dd1d1bSDag-Erling Smørgrav if (*dlen < sizeof(af)) 36047dd1d1bSDag-Erling Smørgrav return (NULL); 36147dd1d1bSDag-Erling Smørgrav buf = *data; 36247dd1d1bSDag-Erling Smørgrav 36347dd1d1bSDag-Erling Smørgrav #if defined(SSH_TUN_PREPEND_AF) 36447dd1d1bSDag-Erling Smørgrav /* skip address family */ 36547dd1d1bSDag-Erling Smørgrav *dlen -= sizeof(af); 36647dd1d1bSDag-Erling Smørgrav buf = *data + sizeof(af); 36747dd1d1bSDag-Erling Smørgrav #elif defined(SSH_TUN_COMPAT_AF) 36847dd1d1bSDag-Erling Smørgrav /* translate address family */ 36947dd1d1bSDag-Erling Smørgrav af = (PEEK_U32(buf) == OPENBSD_AF_INET6) ? AF_INET6 : AF_INET; 37047dd1d1bSDag-Erling Smørgrav POKE_U32(buf, af); 37147dd1d1bSDag-Erling Smørgrav #endif 37247dd1d1bSDag-Erling Smørgrav return (buf); 37347dd1d1bSDag-Erling Smørgrav } 37447dd1d1bSDag-Erling Smørgrav #endif /* SSH_TUN_FILTER */ 375