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