summaryrefslogtreecommitdiff
path: root/openbsd-compat
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2017-07-21 14:38:16 +1000
committerDamien Miller <djm@mindrot.org>2017-07-28 13:22:47 +1000
commitc78e6eec78c88acf8d51db90ae05a3e39458603d (patch)
tree02c84858f139b6475a08182ae79d161bda5e0b93 /openbsd-compat
parent2985d4062ebf4204bbd373456a810d558698f9f5 (diff)
fix problems in tunnel forwarding portability code
This fixes a few problems in the tun forwarding code, mostly to do with host/network byte order confusion. Based on a report and patch by stepe AT centaurus.uberspace.de; bz#2735; ok dtucker@
Diffstat (limited to 'openbsd-compat')
-rw-r--r--openbsd-compat/port-tun.c83
1 files changed, 41 insertions, 42 deletions
diff --git a/openbsd-compat/port-tun.c b/openbsd-compat/port-tun.c
index a444adf1d..a7a5d949a 100644
--- a/openbsd-compat/port-tun.c
+++ b/openbsd-compat/port-tun.c
@@ -199,49 +199,50 @@ sys_tun_open(int tun, int mode)
199 */ 199 */
200 200
201#if defined(SSH_TUN_FILTER) 201#if defined(SSH_TUN_FILTER)
202/*
203 * The tunnel forwarding protocol prepends the address family of forwarded
204 * IP packets using OpenBSD's numbers.
205 */
202#define OPENBSD_AF_INET 2 206#define OPENBSD_AF_INET 2
203#define OPENBSD_AF_INET6 24 207#define OPENBSD_AF_INET6 24
204 208
205int 209int
206sys_tun_infilter(struct Channel *c, char *buf, int len) 210sys_tun_infilter(struct Channel *c, char *buf, int _len)
207{ 211{
212 int r;
213 size_t len;
214 char *ptr = buf;
208#if defined(SSH_TUN_PREPEND_AF) 215#if defined(SSH_TUN_PREPEND_AF)
209 char rbuf[CHAN_RBUF]; 216 char rbuf[CHAN_RBUF];
210 struct ip *iph; 217 struct ip iph;
211#endif 218#endif
212 u_int32_t *af; 219#if defined(SSH_TUN_PREPEND_AF) || defined(SSH_TUN_COMPAT_AF)
213 char *ptr = buf; 220 u_int32_t af;
214 int r;
215
216#if defined(SSH_TUN_PREPEND_AF)
217 if (len <= 0 || len > (int)(sizeof(rbuf) - sizeof(*af)))
218 return (-1);
219 ptr = (char *)&rbuf[0];
220 bcopy(buf, ptr + sizeof(u_int32_t), len);
221 len += sizeof(u_int32_t);
222 af = (u_int32_t *)ptr;
223
224 iph = (struct ip *)(ptr + sizeof(u_int32_t));
225 switch (iph->ip_v) {
226 case 6:
227 *af = AF_INET6;
228 break;
229 case 4:
230 default:
231 *af = AF_INET;
232 break;
233 }
234#endif 221#endif
235 222
236#if defined(SSH_TUN_COMPAT_AF) 223 /* XXX update channel input filter API to use unsigned length */
237 if (len < (int)sizeof(u_int32_t)) 224 if (_len < 0)
238 return (-1); 225 return -1;
226 len = _len;
239 227
240 af = (u_int32_t *)ptr; 228#if defined(SSH_TUN_PREPEND_AF)
241 if (*af == htonl(AF_INET6)) 229 if (len <= sizeof(iph) || len > sizeof(rbuf) - 4)
242 *af = htonl(OPENBSD_AF_INET6); 230 return -1;
243 else 231 /* Determine address family from packet IP header. */
244 *af = htonl(OPENBSD_AF_INET); 232 memcpy(&iph, buf, sizeof(iph));
233 af = iph.ip_v == 6 ? OPENBSD_AF_INET6 : OPENBSD_AF_INET;
234 /* Prepend address family to packet using OpenBSD constants */
235 memcpy(rbuf + 4, buf, len);
236 len += 4;
237 POKE_U32(rbuf, af);
238 ptr = rbuf;
239#elif defined(SSH_TUN_COMPAT_AF)
240 /* Convert existing address family header to OpenBSD value */
241 if (len <= 4)
242 return -1;
243 af = PEEK_U32(buf);
244 /* Put it back */
245 POKE_U32(buf, af == AF_INET6 ? OPENBSD_AF_INET6 : OPENBSD_AF_INET);
245#endif 246#endif
246 247
247 if ((r = sshbuf_put_string(&c->input, ptr, len)) != 0) 248 if ((r = sshbuf_put_string(&c->input, ptr, len)) != 0)
@@ -253,7 +254,7 @@ u_char *
253sys_tun_outfilter(struct Channel *c, u_char **data, u_int *dlen) 254sys_tun_outfilter(struct Channel *c, u_char **data, u_int *dlen)
254{ 255{
255 u_char *buf; 256 u_char *buf;
256 u_int32_t *af; 257 u_int32_t af;
257 int r; 258 int r;
258 size_t xxx_dlen; 259 size_t xxx_dlen;
259 260
@@ -262,21 +263,19 @@ sys_tun_outfilter(struct Channel *c, u_char **data, u_int *dlen)
262 fatal("%s: buffer error: %s", __func__, ssh_err(r)); 263 fatal("%s: buffer error: %s", __func__, ssh_err(r));
263 if (dlen != NULL) 264 if (dlen != NULL)
264 *dlen = xxx_dlen; 265 *dlen = xxx_dlen;
265 if (*dlen < sizeof(*af)) 266 if (*dlen < sizeof(af))
266 return (NULL); 267 return (NULL);
267 buf = *data; 268 buf = *data;
268 269
269#if defined(SSH_TUN_PREPEND_AF) 270#if defined(SSH_TUN_PREPEND_AF)
270 *dlen -= sizeof(u_int32_t); 271 /* skip address family */
271 buf = *data + sizeof(u_int32_t); 272 *dlen -= sizeof(af);
273 buf = *data + sizeof(af);
272#elif defined(SSH_TUN_COMPAT_AF) 274#elif defined(SSH_TUN_COMPAT_AF)
273 af = ntohl(*(u_int32_t *)buf); 275 /* translate address family */
274 if (*af == OPENBSD_AF_INET6) 276 af = (PEEK_U32(buf) == OPENBSD_AF_INET6) ? AF_INET6 : AF_INET;
275 *af = htonl(AF_INET6); 277 POKE_U32(buf, af);
276 else
277 *af = htonl(AF_INET);
278#endif 278#endif
279
280 return (buf); 279 return (buf);
281} 280}
282#endif /* SSH_TUN_FILTER */ 281#endif /* SSH_TUN_FILTER */