1 /* 2 * Copyright (c) 2005 Reyk Floeter <reyk@openbsd.org> 3 * 4 * Permission to use, copy, modify, and distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 #include "includes.h" 18 19 #include <sys/types.h> 20 #include <sys/ioctl.h> 21 22 #include <netinet/in.h> 23 #include <arpa/inet.h> 24 #include <netinet/ip.h> 25 26 #include <errno.h> 27 #include <fcntl.h> 28 #include <stdarg.h> 29 #include <string.h> 30 #include <unistd.h> 31 32 #include "openbsd-compat/sys-queue.h" 33 #include "log.h" 34 #include "misc.h" 35 #include "sshbuf.h" 36 #include "channels.h" 37 #include "ssherr.h" 38 39 /* 40 * This file contains various portability code for network support, 41 * including tun/tap forwarding and routing domains. 42 */ 43 44 /* 45 * This is the portable version of the SSH tunnel forwarding, it 46 * uses some preprocessor definitions for various platform-specific 47 * settings. 48 * 49 * SSH_TUN_LINUX Use the (newer) Linux tun/tap device 50 * SSH_TUN_FREEBSD Use the FreeBSD tun/tap device 51 * SSH_TUN_COMPAT_AF Translate the OpenBSD address family 52 * SSH_TUN_PREPEND_AF Prepend/remove the address family 53 */ 54 55 /* 56 * System-specific tunnel open function 57 */ 58 59 #ifdef SSH_TUN_FREEBSD 60 #include <sys/socket.h> 61 #include <net/if.h> 62 63 #ifdef HAVE_NET_IF_TUN_H 64 #include <net/if_tun.h> 65 #endif 66 #ifdef __DragonFly__ 67 #include <net/tun/if_tun.h> 68 #endif 69 70 int 71 sys_tun_open(int tun, int mode, char **ifname) 72 { 73 struct ifreq ifr; 74 char name[100]; 75 int fd = -1, sock, flag; 76 const char *tunbase = "tun"; 77 78 if (ifname != NULL) 79 *ifname = NULL; 80 81 if (mode == SSH_TUNMODE_ETHERNET) { 82 #ifdef SSH_TUN_NO_L2 83 debug("%s: no layer 2 tunnelling support", __func__); 84 return (-1); 85 #else 86 tunbase = "tap"; 87 #endif 88 } 89 90 /* Open the tunnel device */ 91 if (tun <= SSH_TUNID_MAX) { 92 snprintf(name, sizeof(name), "/dev/%s%d", tunbase, tun); 93 fd = open(name, O_RDWR); 94 } else if (tun == SSH_TUNID_ANY) { 95 for (tun = 100; tun >= 0; tun--) { 96 snprintf(name, sizeof(name), "/dev/%s%d", 97 tunbase, tun); 98 if ((fd = open(name, O_RDWR)) >= 0) 99 break; 100 } 101 } else { 102 debug("%s: invalid tunnel %u\n", __func__, tun); 103 return (-1); 104 } 105 106 if (fd < 0) { 107 debug("%s: %s open failed: %s", __func__, name, 108 strerror(errno)); 109 return (-1); 110 } 111 112 /* Turn on tunnel headers */ 113 flag = 1; 114 #if defined(TUNSIFHEAD) && !defined(SSH_TUN_PREPEND_AF) 115 if (mode != SSH_TUNMODE_ETHERNET && 116 ioctl(fd, TUNSIFHEAD, &flag) == -1) { 117 debug("%s: ioctl(%d, TUNSIFHEAD, 1): %s", __func__, fd, 118 strerror(errno)); 119 close(fd); 120 } 121 #endif 122 123 debug("%s: %s mode %d fd %d", __func__, name, mode, fd); 124 125 /* Set the tunnel device operation mode */ 126 snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d", tunbase, tun); 127 if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) 128 goto failed; 129 130 if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1) 131 goto failed; 132 if ((ifr.ifr_flags & IFF_UP) == 0) { 133 ifr.ifr_flags |= IFF_UP; 134 if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1) 135 goto failed; 136 } 137 138 if (ifname != NULL && (*ifname = strdup(ifr.ifr_name)) == NULL) 139 goto failed; 140 141 close(sock); 142 return (fd); 143 144 failed: 145 if (fd >= 0) 146 close(fd); 147 if (sock >= 0) 148 close(sock); 149 debug("%s: failed to set %s mode %d: %s", __func__, name, 150 mode, strerror(errno)); 151 return (-1); 152 } 153 #endif /* SSH_TUN_FREEBSD */ 154