147dd1d1bSDag-Erling Smørgrav /*
247dd1d1bSDag-Erling Smørgrav * Copyright (c) 2005 Reyk Floeter <reyk@openbsd.org>
347dd1d1bSDag-Erling Smørgrav *
447dd1d1bSDag-Erling Smørgrav * Permission to use, copy, modify, and distribute this software for any
547dd1d1bSDag-Erling Smørgrav * purpose with or without fee is hereby granted, provided that the above
647dd1d1bSDag-Erling Smørgrav * copyright notice and this permission notice appear in all copies.
747dd1d1bSDag-Erling Smørgrav *
847dd1d1bSDag-Erling Smørgrav * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
947dd1d1bSDag-Erling Smørgrav * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1047dd1d1bSDag-Erling Smørgrav * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1147dd1d1bSDag-Erling Smørgrav * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1247dd1d1bSDag-Erling Smørgrav * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1347dd1d1bSDag-Erling Smørgrav * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1447dd1d1bSDag-Erling Smørgrav * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1547dd1d1bSDag-Erling Smørgrav */
1647dd1d1bSDag-Erling Smørgrav
1747dd1d1bSDag-Erling Smørgrav #include "includes.h"
1847dd1d1bSDag-Erling Smørgrav
1947dd1d1bSDag-Erling Smørgrav #include <sys/types.h>
2047dd1d1bSDag-Erling Smørgrav #include <sys/ioctl.h>
2147dd1d1bSDag-Erling Smørgrav
2247dd1d1bSDag-Erling Smørgrav #include <netinet/in.h>
2347dd1d1bSDag-Erling Smørgrav #include <arpa/inet.h>
2447dd1d1bSDag-Erling Smørgrav #include <netinet/ip.h>
2547dd1d1bSDag-Erling Smørgrav
2647dd1d1bSDag-Erling Smørgrav #include <errno.h>
2747dd1d1bSDag-Erling Smørgrav #include <fcntl.h>
2847dd1d1bSDag-Erling Smørgrav #include <stdarg.h>
29*19261079SEd Maste #include <stdio.h>
3047dd1d1bSDag-Erling Smørgrav #include <string.h>
3147dd1d1bSDag-Erling Smørgrav #include <unistd.h>
3247dd1d1bSDag-Erling Smørgrav
3347dd1d1bSDag-Erling Smørgrav #include "openbsd-compat/sys-queue.h"
3447dd1d1bSDag-Erling Smørgrav #include "log.h"
3547dd1d1bSDag-Erling Smørgrav #include "misc.h"
3647dd1d1bSDag-Erling Smørgrav #include "sshbuf.h"
3747dd1d1bSDag-Erling Smørgrav #include "channels.h"
3847dd1d1bSDag-Erling Smørgrav #include "ssherr.h"
3947dd1d1bSDag-Erling Smørgrav
4047dd1d1bSDag-Erling Smørgrav /*
4147dd1d1bSDag-Erling Smørgrav * This file contains various portability code for network support,
4247dd1d1bSDag-Erling Smørgrav * including tun/tap forwarding and routing domains.
4347dd1d1bSDag-Erling Smørgrav */
4447dd1d1bSDag-Erling Smørgrav
4547dd1d1bSDag-Erling Smørgrav #if defined(SYS_RDOMAIN_LINUX) || defined(SSH_TUN_LINUX)
4647dd1d1bSDag-Erling Smørgrav #include <linux/if.h>
4747dd1d1bSDag-Erling Smørgrav #endif
4847dd1d1bSDag-Erling Smørgrav
4947dd1d1bSDag-Erling Smørgrav #if defined(SYS_RDOMAIN_LINUX)
5047dd1d1bSDag-Erling Smørgrav char *
sys_get_rdomain(int fd)5147dd1d1bSDag-Erling Smørgrav sys_get_rdomain(int fd)
5247dd1d1bSDag-Erling Smørgrav {
5347dd1d1bSDag-Erling Smørgrav char dev[IFNAMSIZ + 1];
5447dd1d1bSDag-Erling Smørgrav socklen_t len = sizeof(dev) - 1;
5547dd1d1bSDag-Erling Smørgrav
5647dd1d1bSDag-Erling Smørgrav if (getsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, dev, &len) == -1) {
5747dd1d1bSDag-Erling Smørgrav error("%s: cannot determine VRF for fd=%d : %s",
5847dd1d1bSDag-Erling Smørgrav __func__, fd, strerror(errno));
5947dd1d1bSDag-Erling Smørgrav return NULL;
6047dd1d1bSDag-Erling Smørgrav }
6147dd1d1bSDag-Erling Smørgrav dev[len] = '\0';
6247dd1d1bSDag-Erling Smørgrav return strdup(dev);
6347dd1d1bSDag-Erling Smørgrav }
6447dd1d1bSDag-Erling Smørgrav
6547dd1d1bSDag-Erling Smørgrav int
sys_set_rdomain(int fd,const char * name)6647dd1d1bSDag-Erling Smørgrav sys_set_rdomain(int fd, const char *name)
6747dd1d1bSDag-Erling Smørgrav {
6847dd1d1bSDag-Erling Smørgrav if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
6947dd1d1bSDag-Erling Smørgrav name, strlen(name)) == -1) {
7047dd1d1bSDag-Erling Smørgrav error("%s: setsockopt(%d, SO_BINDTODEVICE, %s): %s",
7147dd1d1bSDag-Erling Smørgrav __func__, fd, name, strerror(errno));
7247dd1d1bSDag-Erling Smørgrav return -1;
7347dd1d1bSDag-Erling Smørgrav }
7447dd1d1bSDag-Erling Smørgrav return 0;
7547dd1d1bSDag-Erling Smørgrav }
7647dd1d1bSDag-Erling Smørgrav
7747dd1d1bSDag-Erling Smørgrav int
sys_valid_rdomain(const char * name)7847dd1d1bSDag-Erling Smørgrav sys_valid_rdomain(const char *name)
7947dd1d1bSDag-Erling Smørgrav {
8047dd1d1bSDag-Erling Smørgrav int fd;
8147dd1d1bSDag-Erling Smørgrav
8247dd1d1bSDag-Erling Smørgrav /*
8347dd1d1bSDag-Erling Smørgrav * This is a pretty crappy way to test. It would be better to
8447dd1d1bSDag-Erling Smørgrav * check whether "name" represents a VRF device, but apparently
8547dd1d1bSDag-Erling Smørgrav * that requires an rtnetlink transaction.
8647dd1d1bSDag-Erling Smørgrav */
8747dd1d1bSDag-Erling Smørgrav if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
8847dd1d1bSDag-Erling Smørgrav return 0;
8947dd1d1bSDag-Erling Smørgrav if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
9047dd1d1bSDag-Erling Smørgrav name, strlen(name)) == -1) {
9147dd1d1bSDag-Erling Smørgrav close(fd);
9247dd1d1bSDag-Erling Smørgrav return 0;
9347dd1d1bSDag-Erling Smørgrav }
9447dd1d1bSDag-Erling Smørgrav close(fd);
9547dd1d1bSDag-Erling Smørgrav return 1;
9647dd1d1bSDag-Erling Smørgrav }
9747dd1d1bSDag-Erling Smørgrav #elif defined(SYS_RDOMAIN_XXX)
9847dd1d1bSDag-Erling Smørgrav /* XXX examples */
9947dd1d1bSDag-Erling Smørgrav char *
sys_get_rdomain(int fd)10047dd1d1bSDag-Erling Smørgrav sys_get_rdomain(int fd)
10147dd1d1bSDag-Erling Smørgrav {
10247dd1d1bSDag-Erling Smørgrav return NULL;
10347dd1d1bSDag-Erling Smørgrav }
10447dd1d1bSDag-Erling Smørgrav
10547dd1d1bSDag-Erling Smørgrav int
sys_set_rdomain(int fd,const char * name)10647dd1d1bSDag-Erling Smørgrav sys_set_rdomain(int fd, const char *name)
10747dd1d1bSDag-Erling Smørgrav {
10847dd1d1bSDag-Erling Smørgrav return -1;
10947dd1d1bSDag-Erling Smørgrav }
11047dd1d1bSDag-Erling Smørgrav
11147dd1d1bSDag-Erling Smørgrav int
valid_rdomain(const char * name)11247dd1d1bSDag-Erling Smørgrav valid_rdomain(const char *name)
11347dd1d1bSDag-Erling Smørgrav {
11447dd1d1bSDag-Erling Smørgrav return 0;
11547dd1d1bSDag-Erling Smørgrav }
11647dd1d1bSDag-Erling Smørgrav
11747dd1d1bSDag-Erling Smørgrav void
sys_set_process_rdomain(const char * name)11847dd1d1bSDag-Erling Smørgrav sys_set_process_rdomain(const char *name)
11947dd1d1bSDag-Erling Smørgrav {
12047dd1d1bSDag-Erling Smørgrav fatal("%s: not supported", __func__);
12147dd1d1bSDag-Erling Smørgrav }
12247dd1d1bSDag-Erling Smørgrav #endif /* defined(SYS_RDOMAIN_XXX) */
12347dd1d1bSDag-Erling Smørgrav
12447dd1d1bSDag-Erling Smørgrav /*
12547dd1d1bSDag-Erling Smørgrav * This is the portable version of the SSH tunnel forwarding, it
12647dd1d1bSDag-Erling Smørgrav * uses some preprocessor definitions for various platform-specific
12747dd1d1bSDag-Erling Smørgrav * settings.
12847dd1d1bSDag-Erling Smørgrav *
12947dd1d1bSDag-Erling Smørgrav * SSH_TUN_LINUX Use the (newer) Linux tun/tap device
13047dd1d1bSDag-Erling Smørgrav * SSH_TUN_FREEBSD Use the FreeBSD tun/tap device
13147dd1d1bSDag-Erling Smørgrav * SSH_TUN_COMPAT_AF Translate the OpenBSD address family
13247dd1d1bSDag-Erling Smørgrav * SSH_TUN_PREPEND_AF Prepend/remove the address family
13347dd1d1bSDag-Erling Smørgrav */
13447dd1d1bSDag-Erling Smørgrav
13547dd1d1bSDag-Erling Smørgrav /*
13647dd1d1bSDag-Erling Smørgrav * System-specific tunnel open function
13747dd1d1bSDag-Erling Smørgrav */
13847dd1d1bSDag-Erling Smørgrav
13947dd1d1bSDag-Erling Smørgrav #if defined(SSH_TUN_LINUX)
14047dd1d1bSDag-Erling Smørgrav #include <linux/if_tun.h>
141*19261079SEd Maste #define TUN_CTRL_DEV "/dev/net/tun"
14247dd1d1bSDag-Erling Smørgrav
14347dd1d1bSDag-Erling Smørgrav int
sys_tun_open(int tun,int mode,char ** ifname)14447dd1d1bSDag-Erling Smørgrav sys_tun_open(int tun, int mode, char **ifname)
14547dd1d1bSDag-Erling Smørgrav {
14647dd1d1bSDag-Erling Smørgrav struct ifreq ifr;
14747dd1d1bSDag-Erling Smørgrav int fd = -1;
14847dd1d1bSDag-Erling Smørgrav const char *name = NULL;
14947dd1d1bSDag-Erling Smørgrav
15047dd1d1bSDag-Erling Smørgrav if (ifname != NULL)
15147dd1d1bSDag-Erling Smørgrav *ifname = NULL;
152*19261079SEd Maste if ((fd = open(TUN_CTRL_DEV, O_RDWR)) == -1) {
153*19261079SEd Maste debug("%s: failed to open tunnel control device \"%s\": %s",
154*19261079SEd Maste __func__, TUN_CTRL_DEV, strerror(errno));
15547dd1d1bSDag-Erling Smørgrav return (-1);
15647dd1d1bSDag-Erling Smørgrav }
15747dd1d1bSDag-Erling Smørgrav
15847dd1d1bSDag-Erling Smørgrav bzero(&ifr, sizeof(ifr));
15947dd1d1bSDag-Erling Smørgrav
16047dd1d1bSDag-Erling Smørgrav if (mode == SSH_TUNMODE_ETHERNET) {
16147dd1d1bSDag-Erling Smørgrav ifr.ifr_flags = IFF_TAP;
16247dd1d1bSDag-Erling Smørgrav name = "tap%d";
16347dd1d1bSDag-Erling Smørgrav } else {
16447dd1d1bSDag-Erling Smørgrav ifr.ifr_flags = IFF_TUN;
16547dd1d1bSDag-Erling Smørgrav name = "tun%d";
16647dd1d1bSDag-Erling Smørgrav }
16747dd1d1bSDag-Erling Smørgrav ifr.ifr_flags |= IFF_NO_PI;
16847dd1d1bSDag-Erling Smørgrav
16947dd1d1bSDag-Erling Smørgrav if (tun != SSH_TUNID_ANY) {
17047dd1d1bSDag-Erling Smørgrav if (tun > SSH_TUNID_MAX) {
17147dd1d1bSDag-Erling Smørgrav debug("%s: invalid tunnel id %x: %s", __func__,
17247dd1d1bSDag-Erling Smørgrav tun, strerror(errno));
17347dd1d1bSDag-Erling Smørgrav goto failed;
17447dd1d1bSDag-Erling Smørgrav }
17547dd1d1bSDag-Erling Smørgrav snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), name, tun);
17647dd1d1bSDag-Erling Smørgrav }
17747dd1d1bSDag-Erling Smørgrav
17847dd1d1bSDag-Erling Smørgrav if (ioctl(fd, TUNSETIFF, &ifr) == -1) {
17947dd1d1bSDag-Erling Smørgrav debug("%s: failed to configure tunnel (mode %d): %s", __func__,
18047dd1d1bSDag-Erling Smørgrav mode, strerror(errno));
18147dd1d1bSDag-Erling Smørgrav goto failed;
18247dd1d1bSDag-Erling Smørgrav }
18347dd1d1bSDag-Erling Smørgrav
18447dd1d1bSDag-Erling Smørgrav if (tun == SSH_TUNID_ANY)
18547dd1d1bSDag-Erling Smørgrav debug("%s: tunnel mode %d fd %d", __func__, mode, fd);
18647dd1d1bSDag-Erling Smørgrav else
18747dd1d1bSDag-Erling Smørgrav debug("%s: %s mode %d fd %d", __func__, ifr.ifr_name, mode, fd);
18847dd1d1bSDag-Erling Smørgrav
189f2a2dfa7SDag-Erling Smørgrav if (ifname != NULL && (*ifname = strdup(ifr.ifr_name)) == NULL)
19047dd1d1bSDag-Erling Smørgrav goto failed;
19147dd1d1bSDag-Erling Smørgrav
19247dd1d1bSDag-Erling Smørgrav return (fd);
19347dd1d1bSDag-Erling Smørgrav
19447dd1d1bSDag-Erling Smørgrav failed:
19547dd1d1bSDag-Erling Smørgrav close(fd);
19647dd1d1bSDag-Erling Smørgrav return (-1);
19747dd1d1bSDag-Erling Smørgrav }
19847dd1d1bSDag-Erling Smørgrav #endif /* SSH_TUN_LINUX */
19947dd1d1bSDag-Erling Smørgrav
20047dd1d1bSDag-Erling Smørgrav #ifdef SSH_TUN_FREEBSD
20147dd1d1bSDag-Erling Smørgrav #include <sys/socket.h>
20247dd1d1bSDag-Erling Smørgrav #include <net/if.h>
20347dd1d1bSDag-Erling Smørgrav
20447dd1d1bSDag-Erling Smørgrav #ifdef HAVE_NET_IF_TUN_H
20547dd1d1bSDag-Erling Smørgrav #include <net/if_tun.h>
20647dd1d1bSDag-Erling Smørgrav #endif
20747dd1d1bSDag-Erling Smørgrav
20847dd1d1bSDag-Erling Smørgrav int
sys_tun_open(int tun,int mode,char ** ifname)20947dd1d1bSDag-Erling Smørgrav sys_tun_open(int tun, int mode, char **ifname)
21047dd1d1bSDag-Erling Smørgrav {
21147dd1d1bSDag-Erling Smørgrav struct ifreq ifr;
21247dd1d1bSDag-Erling Smørgrav char name[100];
213*19261079SEd Maste int fd = -1, sock;
21447dd1d1bSDag-Erling Smørgrav const char *tunbase = "tun";
215*19261079SEd Maste #if defined(TUNSIFHEAD) && !defined(SSH_TUN_PREPEND_AF)
216*19261079SEd Maste int flag;
217*19261079SEd Maste #endif
21847dd1d1bSDag-Erling Smørgrav
21947dd1d1bSDag-Erling Smørgrav if (ifname != NULL)
22047dd1d1bSDag-Erling Smørgrav *ifname = NULL;
22147dd1d1bSDag-Erling Smørgrav
22247dd1d1bSDag-Erling Smørgrav if (mode == SSH_TUNMODE_ETHERNET) {
22347dd1d1bSDag-Erling Smørgrav #ifdef SSH_TUN_NO_L2
22447dd1d1bSDag-Erling Smørgrav debug("%s: no layer 2 tunnelling support", __func__);
22547dd1d1bSDag-Erling Smørgrav return (-1);
22647dd1d1bSDag-Erling Smørgrav #else
22747dd1d1bSDag-Erling Smørgrav tunbase = "tap";
22847dd1d1bSDag-Erling Smørgrav #endif
22947dd1d1bSDag-Erling Smørgrav }
23047dd1d1bSDag-Erling Smørgrav
23147dd1d1bSDag-Erling Smørgrav /* Open the tunnel device */
23247dd1d1bSDag-Erling Smørgrav if (tun <= SSH_TUNID_MAX) {
23347dd1d1bSDag-Erling Smørgrav snprintf(name, sizeof(name), "/dev/%s%d", tunbase, tun);
23447dd1d1bSDag-Erling Smørgrav fd = open(name, O_RDWR);
23547dd1d1bSDag-Erling Smørgrav } else if (tun == SSH_TUNID_ANY) {
23647dd1d1bSDag-Erling Smørgrav for (tun = 100; tun >= 0; tun--) {
23747dd1d1bSDag-Erling Smørgrav snprintf(name, sizeof(name), "/dev/%s%d",
23847dd1d1bSDag-Erling Smørgrav tunbase, tun);
23947dd1d1bSDag-Erling Smørgrav if ((fd = open(name, O_RDWR)) >= 0)
24047dd1d1bSDag-Erling Smørgrav break;
24147dd1d1bSDag-Erling Smørgrav }
24247dd1d1bSDag-Erling Smørgrav } else {
24347dd1d1bSDag-Erling Smørgrav debug("%s: invalid tunnel %u\n", __func__, tun);
24447dd1d1bSDag-Erling Smørgrav return (-1);
24547dd1d1bSDag-Erling Smørgrav }
24647dd1d1bSDag-Erling Smørgrav
24747dd1d1bSDag-Erling Smørgrav if (fd < 0) {
24847dd1d1bSDag-Erling Smørgrav debug("%s: %s open failed: %s", __func__, name,
24947dd1d1bSDag-Erling Smørgrav strerror(errno));
25047dd1d1bSDag-Erling Smørgrav return (-1);
25147dd1d1bSDag-Erling Smørgrav }
25247dd1d1bSDag-Erling Smørgrav
25347dd1d1bSDag-Erling Smørgrav /* Turn on tunnel headers */
25447dd1d1bSDag-Erling Smørgrav #if defined(TUNSIFHEAD) && !defined(SSH_TUN_PREPEND_AF)
255*19261079SEd Maste flag = 1;
25647dd1d1bSDag-Erling Smørgrav if (mode != SSH_TUNMODE_ETHERNET &&
25747dd1d1bSDag-Erling Smørgrav ioctl(fd, TUNSIFHEAD, &flag) == -1) {
25847dd1d1bSDag-Erling Smørgrav debug("%s: ioctl(%d, TUNSIFHEAD, 1): %s", __func__, fd,
25947dd1d1bSDag-Erling Smørgrav strerror(errno));
26047dd1d1bSDag-Erling Smørgrav close(fd);
26147dd1d1bSDag-Erling Smørgrav }
26247dd1d1bSDag-Erling Smørgrav #endif
26347dd1d1bSDag-Erling Smørgrav
26447dd1d1bSDag-Erling Smørgrav debug("%s: %s mode %d fd %d", __func__, name, mode, fd);
26547dd1d1bSDag-Erling Smørgrav
26647dd1d1bSDag-Erling Smørgrav /* Set the tunnel device operation mode */
26747dd1d1bSDag-Erling Smørgrav snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d", tunbase, tun);
26847dd1d1bSDag-Erling Smørgrav if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
26947dd1d1bSDag-Erling Smørgrav goto failed;
27047dd1d1bSDag-Erling Smørgrav
27147dd1d1bSDag-Erling Smørgrav if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1)
27247dd1d1bSDag-Erling Smørgrav goto failed;
27347dd1d1bSDag-Erling Smørgrav if ((ifr.ifr_flags & IFF_UP) == 0) {
27447dd1d1bSDag-Erling Smørgrav ifr.ifr_flags |= IFF_UP;
27547dd1d1bSDag-Erling Smørgrav if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1)
27647dd1d1bSDag-Erling Smørgrav goto failed;
27747dd1d1bSDag-Erling Smørgrav }
27847dd1d1bSDag-Erling Smørgrav
279f2a2dfa7SDag-Erling Smørgrav if (ifname != NULL && (*ifname = strdup(ifr.ifr_name)) == NULL)
28047dd1d1bSDag-Erling Smørgrav goto failed;
28147dd1d1bSDag-Erling Smørgrav
28247dd1d1bSDag-Erling Smørgrav close(sock);
28347dd1d1bSDag-Erling Smørgrav return (fd);
28447dd1d1bSDag-Erling Smørgrav
28547dd1d1bSDag-Erling Smørgrav failed:
28647dd1d1bSDag-Erling Smørgrav if (fd >= 0)
28747dd1d1bSDag-Erling Smørgrav close(fd);
28847dd1d1bSDag-Erling Smørgrav if (sock >= 0)
28947dd1d1bSDag-Erling Smørgrav close(sock);
29047dd1d1bSDag-Erling Smørgrav debug("%s: failed to set %s mode %d: %s", __func__, name,
29147dd1d1bSDag-Erling Smørgrav mode, strerror(errno));
29247dd1d1bSDag-Erling Smørgrav return (-1);
29347dd1d1bSDag-Erling Smørgrav }
29447dd1d1bSDag-Erling Smørgrav #endif /* SSH_TUN_FREEBSD */
29547dd1d1bSDag-Erling Smørgrav
29647dd1d1bSDag-Erling Smørgrav /*
29747dd1d1bSDag-Erling Smørgrav * System-specific channel filters
29847dd1d1bSDag-Erling Smørgrav */
29947dd1d1bSDag-Erling Smørgrav
30047dd1d1bSDag-Erling Smørgrav #if defined(SSH_TUN_FILTER)
30147dd1d1bSDag-Erling Smørgrav /*
30247dd1d1bSDag-Erling Smørgrav * The tunnel forwarding protocol prepends the address family of forwarded
30347dd1d1bSDag-Erling Smørgrav * IP packets using OpenBSD's numbers.
30447dd1d1bSDag-Erling Smørgrav */
30547dd1d1bSDag-Erling Smørgrav #define OPENBSD_AF_INET 2
30647dd1d1bSDag-Erling Smørgrav #define OPENBSD_AF_INET6 24
30747dd1d1bSDag-Erling Smørgrav
30847dd1d1bSDag-Erling Smørgrav int
sys_tun_infilter(struct ssh * ssh,struct Channel * c,char * buf,int _len)30947dd1d1bSDag-Erling Smørgrav sys_tun_infilter(struct ssh *ssh, struct Channel *c, char *buf, int _len)
31047dd1d1bSDag-Erling Smørgrav {
31147dd1d1bSDag-Erling Smørgrav int r;
31247dd1d1bSDag-Erling Smørgrav size_t len;
31347dd1d1bSDag-Erling Smørgrav char *ptr = buf;
31447dd1d1bSDag-Erling Smørgrav #if defined(SSH_TUN_PREPEND_AF)
31547dd1d1bSDag-Erling Smørgrav char rbuf[CHAN_RBUF];
31647dd1d1bSDag-Erling Smørgrav struct ip iph;
31747dd1d1bSDag-Erling Smørgrav #endif
31847dd1d1bSDag-Erling Smørgrav #if defined(SSH_TUN_PREPEND_AF) || defined(SSH_TUN_COMPAT_AF)
31947dd1d1bSDag-Erling Smørgrav u_int32_t af;
32047dd1d1bSDag-Erling Smørgrav #endif
32147dd1d1bSDag-Erling Smørgrav
32247dd1d1bSDag-Erling Smørgrav /* XXX update channel input filter API to use unsigned length */
32347dd1d1bSDag-Erling Smørgrav if (_len < 0)
32447dd1d1bSDag-Erling Smørgrav return -1;
32547dd1d1bSDag-Erling Smørgrav len = _len;
32647dd1d1bSDag-Erling Smørgrav
32747dd1d1bSDag-Erling Smørgrav #if defined(SSH_TUN_PREPEND_AF)
32847dd1d1bSDag-Erling Smørgrav if (len <= sizeof(iph) || len > sizeof(rbuf) - 4)
32947dd1d1bSDag-Erling Smørgrav return -1;
33047dd1d1bSDag-Erling Smørgrav /* Determine address family from packet IP header. */
33147dd1d1bSDag-Erling Smørgrav memcpy(&iph, buf, sizeof(iph));
33247dd1d1bSDag-Erling Smørgrav af = iph.ip_v == 6 ? OPENBSD_AF_INET6 : OPENBSD_AF_INET;
33347dd1d1bSDag-Erling Smørgrav /* Prepend address family to packet using OpenBSD constants */
33447dd1d1bSDag-Erling Smørgrav memcpy(rbuf + 4, buf, len);
33547dd1d1bSDag-Erling Smørgrav len += 4;
33647dd1d1bSDag-Erling Smørgrav POKE_U32(rbuf, af);
33747dd1d1bSDag-Erling Smørgrav ptr = rbuf;
33847dd1d1bSDag-Erling Smørgrav #elif defined(SSH_TUN_COMPAT_AF)
33947dd1d1bSDag-Erling Smørgrav /* Convert existing address family header to OpenBSD value */
34047dd1d1bSDag-Erling Smørgrav if (len <= 4)
34147dd1d1bSDag-Erling Smørgrav return -1;
34247dd1d1bSDag-Erling Smørgrav af = PEEK_U32(buf);
34347dd1d1bSDag-Erling Smørgrav /* Put it back */
34447dd1d1bSDag-Erling Smørgrav POKE_U32(buf, af == AF_INET6 ? OPENBSD_AF_INET6 : OPENBSD_AF_INET);
34547dd1d1bSDag-Erling Smørgrav #endif
34647dd1d1bSDag-Erling Smørgrav
34747dd1d1bSDag-Erling Smørgrav if ((r = sshbuf_put_string(c->input, ptr, len)) != 0)
34847dd1d1bSDag-Erling Smørgrav fatal("%s: buffer error: %s", __func__, ssh_err(r));
34947dd1d1bSDag-Erling Smørgrav return (0);
35047dd1d1bSDag-Erling Smørgrav }
35147dd1d1bSDag-Erling Smørgrav
35247dd1d1bSDag-Erling Smørgrav u_char *
sys_tun_outfilter(struct ssh * ssh,struct Channel * c,u_char ** data,size_t * dlen)35347dd1d1bSDag-Erling Smørgrav sys_tun_outfilter(struct ssh *ssh, struct Channel *c,
35447dd1d1bSDag-Erling Smørgrav u_char **data, size_t *dlen)
35547dd1d1bSDag-Erling Smørgrav {
35647dd1d1bSDag-Erling Smørgrav u_char *buf;
35747dd1d1bSDag-Erling Smørgrav u_int32_t af;
35847dd1d1bSDag-Erling Smørgrav int r;
35947dd1d1bSDag-Erling Smørgrav
36047dd1d1bSDag-Erling Smørgrav /* XXX new API is incompatible with this signature. */
36147dd1d1bSDag-Erling Smørgrav if ((r = sshbuf_get_string(c->output, data, dlen)) != 0)
36247dd1d1bSDag-Erling Smørgrav fatal("%s: buffer error: %s", __func__, ssh_err(r));
36347dd1d1bSDag-Erling Smørgrav if (*dlen < sizeof(af))
36447dd1d1bSDag-Erling Smørgrav return (NULL);
36547dd1d1bSDag-Erling Smørgrav buf = *data;
36647dd1d1bSDag-Erling Smørgrav
36747dd1d1bSDag-Erling Smørgrav #if defined(SSH_TUN_PREPEND_AF)
36847dd1d1bSDag-Erling Smørgrav /* skip address family */
36947dd1d1bSDag-Erling Smørgrav *dlen -= sizeof(af);
37047dd1d1bSDag-Erling Smørgrav buf = *data + sizeof(af);
37147dd1d1bSDag-Erling Smørgrav #elif defined(SSH_TUN_COMPAT_AF)
37247dd1d1bSDag-Erling Smørgrav /* translate address family */
37347dd1d1bSDag-Erling Smørgrav af = (PEEK_U32(buf) == OPENBSD_AF_INET6) ? AF_INET6 : AF_INET;
37447dd1d1bSDag-Erling Smørgrav POKE_U32(buf, af);
37547dd1d1bSDag-Erling Smørgrav #endif
37647dd1d1bSDag-Erling Smørgrav return (buf);
37747dd1d1bSDag-Erling Smørgrav }
37847dd1d1bSDag-Erling Smørgrav #endif /* SSH_TUN_FILTER */
379