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