diff options
author | Damien Miller <djm@mindrot.org> | 2006-01-01 19:47:05 +1100 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2006-01-01 19:47:05 +1100 |
commit | 2dcddbfaf6b68bd58b5b1422ebeef7767c0c2633 (patch) | |
tree | 8c044d00a3185cea6a500c32508df1161b048c29 /openbsd-compat/port-tun.c | |
parent | c4bcc917519e55f449044e558228a2e11b80740c (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.c | 98 |
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 | |||
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 | |||
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 | } |