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