summaryrefslogtreecommitdiff
path: root/openbsd-compat/port-tun.c
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2006-01-01 19:47:05 +1100
committerDamien Miller <djm@mindrot.org>2006-01-01 19:47:05 +1100
commit2dcddbfaf6b68bd58b5b1422ebeef7767c0c2633 (patch)
tree8c044d00a3185cea6a500c32508df1161b048c29 /openbsd-compat/port-tun.c
parentc4bcc917519e55f449044e558228a2e11b80740c (diff)
- (djm) [Makefile.in configure.ac includes.h misc.c]
[openbsd-compat/port-tun.c openbsd-compat/port-tun.h] Add support for tunnel forwarding for FreeBSD and NetBSD. NetBSD's support is limited to IPv4 tunnels only, and most versions don't support the tap(4) device at all.
Diffstat (limited to 'openbsd-compat/port-tun.c')
-rw-r--r--openbsd-compat/port-tun.c98
1 files changed, 97 insertions, 1 deletions
diff --git a/openbsd-compat/port-tun.c b/openbsd-compat/port-tun.c
index 479b46b7a..00a0442b1 100644
--- a/openbsd-compat/port-tun.c
+++ b/openbsd-compat/port-tun.c
@@ -89,6 +89,88 @@ sys_tun_open(int tun, int mode)
89} 89}
90#endif /* SSH_TUN_LINUX */ 90#endif /* SSH_TUN_LINUX */
91 91
92#ifdef SSH_TUN_FREEBSD
93#include <sys/socket.h>
94#include <net/if.h>
95#include <net/if_tun.h>
96
97int
98sys_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
92/* 174/*
93 * System-specific channel filters 175 * System-specific channel filters
94 */ 176 */
@@ -102,16 +184,29 @@ sys_tun_infilter(struct Channel *c, char *buf, int len)
102{ 184{
103#if defined(SSH_TUN_PREPEND_AF) 185#if defined(SSH_TUN_PREPEND_AF)
104 char rbuf[CHAN_RBUF]; 186 char rbuf[CHAN_RBUF];
187 struct ip *iph;
105#endif 188#endif
106 u_int32_t *af; 189 u_int32_t *af;
107 char *ptr = buf; 190 char *ptr = buf;
108 191
109#if defined(SSH_TUN_PREPEND_AF) 192#if defined(SSH_TUN_PREPEND_AF)
110 if (len > (int)(sizeof(rbuf) - sizeof(*af))) 193 if (len <= 0 || len > (int)(sizeof(rbuf) - sizeof(*af)))
111 return (-1); 194 return (-1);
112 ptr = (char *)&rbuf[0]; 195 ptr = (char *)&rbuf[0];
113 bcopy(buf, ptr + sizeof(u_int32_t), len); 196 bcopy(buf, ptr + sizeof(u_int32_t), len);
114 len += sizeof(u_int32_t); 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 }
115#endif 210#endif
116 211
117#if defined(SSH_TUN_COMPAT_AF) 212#if defined(SSH_TUN_COMPAT_AF)
@@ -124,6 +219,7 @@ sys_tun_infilter(struct Channel *c, char *buf, int len)
124 else 219 else
125 *af = htonl(OPENBSD_AF_INET); 220 *af = htonl(OPENBSD_AF_INET);
126#endif 221#endif
222
127 buffer_put_string(&c->input, ptr, len); 223 buffer_put_string(&c->input, ptr, len);
128 return (0); 224 return (0);
129} 225}