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