]> andersk Git - openssh.git/blob - openbsd-compat/port-tun.c
- (dtucker) [openbsd-compat/port-irix.c] Add errno.h, found by Iain Morgan.
[openssh.git] / openbsd-compat / port-tun.c
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 #include <netinet/in.h>
22 #include <netinet/ip.h>
23
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <stdarg.h>
27 #include <string.h>
28 #include <unistd.h>
29
30 #include "log.h"
31 #include "misc.h"
32 #include "buffer.h"
33 #include "channels.h"
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
41  * SSH_TUN_FREEBSD      Use the FreeBSD tun/tap device
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)
51 #include <linux/if.h>
52 #include <linux/if_tun.h>
53
54 int
55 sys_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
106 #ifdef SSH_TUN_FREEBSD
107 #include <sys/socket.h>
108 #include <net/if.h>
109
110 #ifdef HAVE_NET_IF_TUN_H
111 #include <net/if_tun.h>
112 #endif
113
114 int
115 sys_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
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
199 int
200 sys_tun_infilter(struct Channel *c, char *buf, int len)
201 {
202 #if defined(SSH_TUN_PREPEND_AF)
203         char rbuf[CHAN_RBUF];
204         struct ip *iph;
205 #endif
206         u_int32_t *af;
207         char *ptr = buf;
208
209 #if defined(SSH_TUN_PREPEND_AF)
210         if (len <= 0 || len > (int)(sizeof(rbuf) - sizeof(*af)))
211                 return (-1);
212         ptr = (char *)&rbuf[0];
213         bcopy(buf, ptr + sizeof(u_int32_t), len);
214         len += sizeof(u_int32_t);
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         }
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
239
240         buffer_put_string(&c->input, ptr, len);
241         return (0);
242 }
243
244 u_char *
245 sys_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 0.128405 seconds and 5 git commands to generate.