]> andersk Git - openssh.git/blame - openbsd-compat/port-tun.c
- (dtucker) [auth.c openbsd-compat/port-aix.c] Bug #1207: always call
[openssh.git] / openbsd-compat / port-tun.c
CommitLineData
e914f53a 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
22bbb3e6 19#include <sys/types.h>
3e9b2b1b 20#include <sys/ioctl.h>
f9d5c000 21#include <netinet/in.h>
3e9b2b1b 22#include <netinet/ip.h>
23
fec71b2f 24#include <errno.h>
22bbb3e6 25#include <fcntl.h>
f2265d5d 26#include <stdarg.h>
28cb0a43 27#include <string.h>
28#include <unistd.h>
22bbb3e6 29
e914f53a 30#include "log.h"
31#include "misc.h"
693a35d3 32#include "buffer.h"
00a017bd 33#include "channels.h"
e914f53a 34
35/*
36 * This is the portable version of the SSH tunnel forwarding, it
37 * uses some preprocessor definitions for various platform-specific
38 * settings.
39 *
40 * SSH_TUN_LINUX Use the (newer) Linux tun/tap device
e02505e2 41 * SSH_TUN_FREEBSD Use the FreeBSD tun/tap device
e914f53a 42 * SSH_TUN_COMPAT_AF Translate the OpenBSD address family
43 * SSH_TUN_PREPEND_AF Prepend/remove the address family
44 */
45
46/*
47 * System-specific tunnel open function
48 */
49
50#if defined(SSH_TUN_LINUX)
3aef38da 51#include <linux/if.h>
e914f53a 52#include <linux/if_tun.h>
53
54int
55sys_tun_open(int tun, int mode)
56{
57 struct ifreq ifr;
58 int fd = -1;
59 const char *name = NULL;
60
61 if ((fd = open("/dev/net/tun", O_RDWR)) == -1) {
62 debug("%s: failed to open tunnel control interface: %s",
63 __func__, strerror(errno));
64 return (-1);
65 }
66
67 bzero(&ifr, sizeof(ifr));
68
69 if (mode == SSH_TUNMODE_ETHERNET) {
70 ifr.ifr_flags = IFF_TAP;
71 name = "tap%d";
72 } else {
73 ifr.ifr_flags = IFF_TUN;
74 name = "tun%d";
75 }
76 ifr.ifr_flags |= IFF_NO_PI;
77
78 if (tun != SSH_TUNID_ANY) {
79 if (tun > SSH_TUNID_MAX) {
80 debug("%s: invalid tunnel id %x: %s", __func__,
81 tun, strerror(errno));
82 goto failed;
83 }
84 snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), name, tun);
85 }
86
87 if (ioctl(fd, TUNSETIFF, &ifr) == -1) {
88 debug("%s: failed to configure tunnel (mode %d): %s", __func__,
89 mode, strerror(errno));
90 goto failed;
91 }
92
93 if (tun == SSH_TUNID_ANY)
94 debug("%s: tunnel mode %d fd %d", __func__, mode, fd);
95 else
96 debug("%s: %s mode %d fd %d", __func__, ifr.ifr_name, mode, fd);
97
98 return (fd);
99
100 failed:
101 close(fd);
102 return (-1);
103}
104#endif /* SSH_TUN_LINUX */
105
0f6cb079 106#ifdef SSH_TUN_FREEBSD
107#include <sys/socket.h>
108#include <net/if.h>
e02505e2 109
110#ifdef HAVE_NET_IF_TUN_H
0f6cb079 111#include <net/if_tun.h>
e02505e2 112#endif
0f6cb079 113
114int
115sys_tun_open(int tun, int mode)
116{
117 struct ifreq ifr;
118 char name[100];
119 int fd = -1, sock, flag;
120 const char *tunbase = "tun";
121
122 if (mode == SSH_TUNMODE_ETHERNET) {
123#ifdef SSH_TUN_NO_L2
124 debug("%s: no layer 2 tunnelling support", __func__);
125 return (-1);
126#else
127 tunbase = "tap";
128#endif
129 }
130
131 /* Open the tunnel device */
132 if (tun <= SSH_TUNID_MAX) {
133 snprintf(name, sizeof(name), "/dev/%s%d", tunbase, tun);
134 fd = open(name, O_RDWR);
135 } else if (tun == SSH_TUNID_ANY) {
136 for (tun = 100; tun >= 0; tun--) {
137 snprintf(name, sizeof(name), "/dev/%s%d",
138 tunbase, tun);
139 if ((fd = open(name, O_RDWR)) >= 0)
140 break;
141 }
142 } else {
143 debug("%s: invalid tunnel %u\n", __func__, tun);
144 return (-1);
145 }
146
147 if (fd < 0) {
148 debug("%s: %s open failed: %s", __func__, name,
149 strerror(errno));
150 return (-1);
151 }
152
153 /* Turn on tunnel headers */
154 flag = 1;
155#if defined(TUNSIFHEAD) && !defined(SSH_TUN_PREPEND_AF)
156 if (mode != SSH_TUNMODE_ETHERNET &&
157 ioctl(fd, TUNSIFHEAD, &flag) == -1) {
158 debug("%s: ioctl(%d, TUNSIFHEAD, 1): %s", __func__, fd,
159 strerror(errno));
160 close(fd);
161 }
162#endif
163
164 debug("%s: %s mode %d fd %d", __func__, name, mode, fd);
165
166 /* Set the tunnel device operation mode */
167 snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d", tunbase, tun);
168 if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
169 goto failed;
170
171 if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1)
172 goto failed;
173 ifr.ifr_flags |= IFF_UP;
174 if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1)
175 goto failed;
176
177 close(sock);
178 return (fd);
179
180 failed:
181 if (fd >= 0)
182 close(fd);
183 if (sock >= 0)
184 close(sock);
185 debug("%s: failed to set %s mode %d: %s", __func__, name,
186 mode, strerror(errno));
187 return (-1);
188}
189#endif /* SSH_TUN_FREEBSD */
190
e914f53a 191/*
192 * System-specific channel filters
193 */
194
195#if defined(SSH_TUN_FILTER)
196#define OPENBSD_AF_INET 2
197#define OPENBSD_AF_INET6 24
198
199int
200sys_tun_infilter(struct Channel *c, char *buf, int len)
201{
202#if defined(SSH_TUN_PREPEND_AF)
203 char rbuf[CHAN_RBUF];
0f6cb079 204 struct ip *iph;
e914f53a 205#endif
206 u_int32_t *af;
207 char *ptr = buf;
208
209#if defined(SSH_TUN_PREPEND_AF)
0f6cb079 210 if (len <= 0 || len > (int)(sizeof(rbuf) - sizeof(*af)))
e914f53a 211 return (-1);
212 ptr = (char *)&rbuf[0];
213 bcopy(buf, ptr + sizeof(u_int32_t), len);
214 len += sizeof(u_int32_t);
0f6cb079 215 af = (u_int32_t *)ptr;
216
217 iph = (struct ip *)(ptr + sizeof(u_int32_t));
218 switch (iph->ip_v) {
219 case 6:
220 *af = AF_INET6;
221 break;
222 case 4:
223 default:
224 *af = AF_INET;
225 break;
226 }
e914f53a 227#endif
228
229#if defined(SSH_TUN_COMPAT_AF)
230 if (len < (int)sizeof(u_int32_t))
231 return (-1);
232
233 af = (u_int32_t *)ptr;
234 if (*af == htonl(AF_INET6))
235 *af = htonl(OPENBSD_AF_INET6);
236 else
237 *af = htonl(OPENBSD_AF_INET);
238#endif
0f6cb079 239
e914f53a 240 buffer_put_string(&c->input, ptr, len);
241 return (0);
242}
243
244u_char *
245sys_tun_outfilter(struct Channel *c, u_char **data, u_int *dlen)
246{
247 u_char *buf;
248 u_int32_t *af;
249
250 *data = buffer_get_string(&c->output, dlen);
251 if (*dlen < sizeof(*af))
252 return (NULL);
253 buf = *data;
254
255#if defined(SSH_TUN_PREPEND_AF)
256 *dlen -= sizeof(u_int32_t);
257 buf = *data + sizeof(u_int32_t);
258#elif defined(SSH_TUN_COMPAT_AF)
259 af = ntohl(*(u_int32_t *)buf);
260 if (*af == OPENBSD_AF_INET6)
261 *af = htonl(AF_INET6);
262 else
263 *af = htonl(AF_INET);
264#endif
265
266 return (buf);
267}
268#endif /* SSH_TUN_FILTER */
This page took 1.100703 seconds and 5 git commands to generate.