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