12c0338ffSzrj /*
22c0338ffSzrj * Copyright (c) 2005 Reyk Floeter <reyk@openbsd.org>
32c0338ffSzrj *
42c0338ffSzrj * Permission to use, copy, modify, and distribute this software for any
52c0338ffSzrj * purpose with or without fee is hereby granted, provided that the above
62c0338ffSzrj * copyright notice and this permission notice appear in all copies.
72c0338ffSzrj *
82c0338ffSzrj * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
92c0338ffSzrj * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
102c0338ffSzrj * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
112c0338ffSzrj * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
122c0338ffSzrj * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
132c0338ffSzrj * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
142c0338ffSzrj * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
152c0338ffSzrj */
162c0338ffSzrj
172c0338ffSzrj #include "includes.h"
182c0338ffSzrj
192c0338ffSzrj #include <sys/types.h>
202c0338ffSzrj #include <sys/ioctl.h>
212c0338ffSzrj
222c0338ffSzrj #include <netinet/in.h>
232c0338ffSzrj #include <arpa/inet.h>
242c0338ffSzrj #include <netinet/ip.h>
252c0338ffSzrj
262c0338ffSzrj #include <errno.h>
272c0338ffSzrj #include <fcntl.h>
282c0338ffSzrj #include <stdarg.h>
29*2c81fb9cSAntonio Huete Jimenez #include <stdio.h>
302c0338ffSzrj #include <string.h>
312c0338ffSzrj #include <unistd.h>
322c0338ffSzrj
332c0338ffSzrj #include "openbsd-compat/sys-queue.h"
342c0338ffSzrj #include "log.h"
352c0338ffSzrj #include "misc.h"
362c0338ffSzrj #include "sshbuf.h"
372c0338ffSzrj #include "channels.h"
382c0338ffSzrj #include "ssherr.h"
392c0338ffSzrj
402c0338ffSzrj /*
412c0338ffSzrj * This file contains various portability code for network support,
422c0338ffSzrj * including tun/tap forwarding and routing domains.
432c0338ffSzrj */
442c0338ffSzrj
45bc9cc675SDaniel Fojt #if defined(SYS_RDOMAIN_LINUX) || defined(SSH_TUN_LINUX)
46bc9cc675SDaniel Fojt #include <linux/if.h>
47bc9cc675SDaniel Fojt #endif
48bc9cc675SDaniel Fojt
49bc9cc675SDaniel Fojt #if defined(SYS_RDOMAIN_LINUX)
50bc9cc675SDaniel Fojt char *
sys_get_rdomain(int fd)51bc9cc675SDaniel Fojt sys_get_rdomain(int fd)
52bc9cc675SDaniel Fojt {
53bc9cc675SDaniel Fojt char dev[IFNAMSIZ + 1];
54bc9cc675SDaniel Fojt socklen_t len = sizeof(dev) - 1;
55bc9cc675SDaniel Fojt
56bc9cc675SDaniel Fojt if (getsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, dev, &len) == -1) {
57bc9cc675SDaniel Fojt error("%s: cannot determine VRF for fd=%d : %s",
58bc9cc675SDaniel Fojt __func__, fd, strerror(errno));
59bc9cc675SDaniel Fojt return NULL;
60bc9cc675SDaniel Fojt }
61bc9cc675SDaniel Fojt dev[len] = '\0';
62bc9cc675SDaniel Fojt return strdup(dev);
63bc9cc675SDaniel Fojt }
64bc9cc675SDaniel Fojt
65bc9cc675SDaniel Fojt int
sys_set_rdomain(int fd,const char * name)66bc9cc675SDaniel Fojt sys_set_rdomain(int fd, const char *name)
67bc9cc675SDaniel Fojt {
68bc9cc675SDaniel Fojt if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
69bc9cc675SDaniel Fojt name, strlen(name)) == -1) {
70bc9cc675SDaniel Fojt error("%s: setsockopt(%d, SO_BINDTODEVICE, %s): %s",
71bc9cc675SDaniel Fojt __func__, fd, name, strerror(errno));
72bc9cc675SDaniel Fojt return -1;
73bc9cc675SDaniel Fojt }
74bc9cc675SDaniel Fojt return 0;
75bc9cc675SDaniel Fojt }
76bc9cc675SDaniel Fojt
77bc9cc675SDaniel Fojt int
sys_valid_rdomain(const char * name)78bc9cc675SDaniel Fojt sys_valid_rdomain(const char *name)
79bc9cc675SDaniel Fojt {
80bc9cc675SDaniel Fojt int fd;
81bc9cc675SDaniel Fojt
82bc9cc675SDaniel Fojt /*
83bc9cc675SDaniel Fojt * This is a pretty crappy way to test. It would be better to
84bc9cc675SDaniel Fojt * check whether "name" represents a VRF device, but apparently
85bc9cc675SDaniel Fojt * that requires an rtnetlink transaction.
86bc9cc675SDaniel Fojt */
87bc9cc675SDaniel Fojt if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
88bc9cc675SDaniel Fojt return 0;
89bc9cc675SDaniel Fojt if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
90bc9cc675SDaniel Fojt name, strlen(name)) == -1) {
91bc9cc675SDaniel Fojt close(fd);
92bc9cc675SDaniel Fojt return 0;
93bc9cc675SDaniel Fojt }
94bc9cc675SDaniel Fojt close(fd);
95bc9cc675SDaniel Fojt return 1;
96bc9cc675SDaniel Fojt }
97bc9cc675SDaniel Fojt #elif defined(SYS_RDOMAIN_XXX)
98bc9cc675SDaniel Fojt /* XXX examples */
99bc9cc675SDaniel Fojt char *
sys_get_rdomain(int fd)100bc9cc675SDaniel Fojt sys_get_rdomain(int fd)
101bc9cc675SDaniel Fojt {
102bc9cc675SDaniel Fojt return NULL;
103bc9cc675SDaniel Fojt }
104bc9cc675SDaniel Fojt
105bc9cc675SDaniel Fojt int
sys_set_rdomain(int fd,const char * name)106bc9cc675SDaniel Fojt sys_set_rdomain(int fd, const char *name)
107bc9cc675SDaniel Fojt {
108bc9cc675SDaniel Fojt return -1;
109bc9cc675SDaniel Fojt }
110bc9cc675SDaniel Fojt
111bc9cc675SDaniel Fojt int
valid_rdomain(const char * name)112bc9cc675SDaniel Fojt valid_rdomain(const char *name)
113bc9cc675SDaniel Fojt {
114bc9cc675SDaniel Fojt return 0;
115bc9cc675SDaniel Fojt }
116bc9cc675SDaniel Fojt
117bc9cc675SDaniel Fojt void
sys_set_process_rdomain(const char * name)118bc9cc675SDaniel Fojt sys_set_process_rdomain(const char *name)
119bc9cc675SDaniel Fojt {
120bc9cc675SDaniel Fojt fatal("%s: not supported", __func__);
121bc9cc675SDaniel Fojt }
122bc9cc675SDaniel Fojt #endif /* defined(SYS_RDOMAIN_XXX) */
123bc9cc675SDaniel Fojt
1242c0338ffSzrj /*
1252c0338ffSzrj * This is the portable version of the SSH tunnel forwarding, it
1262c0338ffSzrj * uses some preprocessor definitions for various platform-specific
1272c0338ffSzrj * settings.
1282c0338ffSzrj *
1292c0338ffSzrj * SSH_TUN_LINUX Use the (newer) Linux tun/tap device
1302c0338ffSzrj * SSH_TUN_FREEBSD Use the FreeBSD tun/tap device
1312c0338ffSzrj * SSH_TUN_COMPAT_AF Translate the OpenBSD address family
1322c0338ffSzrj * SSH_TUN_PREPEND_AF Prepend/remove the address family
1332c0338ffSzrj */
1342c0338ffSzrj
1352c0338ffSzrj /*
1362c0338ffSzrj * System-specific tunnel open function
1372c0338ffSzrj */
1382c0338ffSzrj
139bc9cc675SDaniel Fojt #if defined(SSH_TUN_LINUX)
140bc9cc675SDaniel Fojt #include <linux/if_tun.h>
141bc9cc675SDaniel Fojt #define TUN_CTRL_DEV "/dev/net/tun"
142bc9cc675SDaniel Fojt
143bc9cc675SDaniel Fojt int
sys_tun_open(int tun,int mode,char ** ifname)144bc9cc675SDaniel Fojt sys_tun_open(int tun, int mode, char **ifname)
145bc9cc675SDaniel Fojt {
146bc9cc675SDaniel Fojt struct ifreq ifr;
147bc9cc675SDaniel Fojt int fd = -1;
148bc9cc675SDaniel Fojt const char *name = NULL;
149bc9cc675SDaniel Fojt
150bc9cc675SDaniel Fojt if (ifname != NULL)
151bc9cc675SDaniel Fojt *ifname = NULL;
152bc9cc675SDaniel Fojt if ((fd = open(TUN_CTRL_DEV, O_RDWR)) == -1) {
153bc9cc675SDaniel Fojt debug("%s: failed to open tunnel control device \"%s\": %s",
154bc9cc675SDaniel Fojt __func__, TUN_CTRL_DEV, strerror(errno));
155bc9cc675SDaniel Fojt return (-1);
156bc9cc675SDaniel Fojt }
157bc9cc675SDaniel Fojt
158bc9cc675SDaniel Fojt bzero(&ifr, sizeof(ifr));
159bc9cc675SDaniel Fojt
160bc9cc675SDaniel Fojt if (mode == SSH_TUNMODE_ETHERNET) {
161bc9cc675SDaniel Fojt ifr.ifr_flags = IFF_TAP;
162bc9cc675SDaniel Fojt name = "tap%d";
163bc9cc675SDaniel Fojt } else {
164bc9cc675SDaniel Fojt ifr.ifr_flags = IFF_TUN;
165bc9cc675SDaniel Fojt name = "tun%d";
166bc9cc675SDaniel Fojt }
167bc9cc675SDaniel Fojt ifr.ifr_flags |= IFF_NO_PI;
168bc9cc675SDaniel Fojt
169bc9cc675SDaniel Fojt if (tun != SSH_TUNID_ANY) {
170bc9cc675SDaniel Fojt if (tun > SSH_TUNID_MAX) {
171bc9cc675SDaniel Fojt debug("%s: invalid tunnel id %x: %s", __func__,
172bc9cc675SDaniel Fojt tun, strerror(errno));
173bc9cc675SDaniel Fojt goto failed;
174bc9cc675SDaniel Fojt }
175bc9cc675SDaniel Fojt snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), name, tun);
176bc9cc675SDaniel Fojt }
177bc9cc675SDaniel Fojt
178bc9cc675SDaniel Fojt if (ioctl(fd, TUNSETIFF, &ifr) == -1) {
179bc9cc675SDaniel Fojt debug("%s: failed to configure tunnel (mode %d): %s", __func__,
180bc9cc675SDaniel Fojt mode, strerror(errno));
181bc9cc675SDaniel Fojt goto failed;
182bc9cc675SDaniel Fojt }
183bc9cc675SDaniel Fojt
184bc9cc675SDaniel Fojt if (tun == SSH_TUNID_ANY)
185bc9cc675SDaniel Fojt debug("%s: tunnel mode %d fd %d", __func__, mode, fd);
186bc9cc675SDaniel Fojt else
187bc9cc675SDaniel Fojt debug("%s: %s mode %d fd %d", __func__, ifr.ifr_name, mode, fd);
188bc9cc675SDaniel Fojt
189bc9cc675SDaniel Fojt if (ifname != NULL && (*ifname = strdup(ifr.ifr_name)) == NULL)
190bc9cc675SDaniel Fojt goto failed;
191bc9cc675SDaniel Fojt
192bc9cc675SDaniel Fojt return (fd);
193bc9cc675SDaniel Fojt
194bc9cc675SDaniel Fojt failed:
195bc9cc675SDaniel Fojt close(fd);
196bc9cc675SDaniel Fojt return (-1);
197bc9cc675SDaniel Fojt }
198bc9cc675SDaniel Fojt #endif /* SSH_TUN_LINUX */
199bc9cc675SDaniel Fojt
2002c0338ffSzrj #ifdef SSH_TUN_FREEBSD
2012c0338ffSzrj #include <sys/socket.h>
2022c0338ffSzrj #include <net/if.h>
2032c0338ffSzrj
2042c0338ffSzrj #ifdef HAVE_NET_IF_TUN_H
2052c0338ffSzrj #include <net/if_tun.h>
2062c0338ffSzrj #endif
2072c0338ffSzrj
2082c0338ffSzrj int
sys_tun_open(int tun,int mode,char ** ifname)2092c0338ffSzrj sys_tun_open(int tun, int mode, char **ifname)
2102c0338ffSzrj {
2112c0338ffSzrj struct ifreq ifr;
2122c0338ffSzrj char name[100];
213*2c81fb9cSAntonio Huete Jimenez int fd = -1, sock;
2142c0338ffSzrj const char *tunbase = "tun";
215*2c81fb9cSAntonio Huete Jimenez #if defined(TUNSIFHEAD) && !defined(SSH_TUN_PREPEND_AF)
216*2c81fb9cSAntonio Huete Jimenez int flag;
217*2c81fb9cSAntonio Huete Jimenez #endif
2182c0338ffSzrj
2192c0338ffSzrj if (ifname != NULL)
2202c0338ffSzrj *ifname = NULL;
2212c0338ffSzrj
2222c0338ffSzrj if (mode == SSH_TUNMODE_ETHERNET) {
2232c0338ffSzrj #ifdef SSH_TUN_NO_L2
2242c0338ffSzrj debug("%s: no layer 2 tunnelling support", __func__);
2252c0338ffSzrj return (-1);
2262c0338ffSzrj #else
2272c0338ffSzrj tunbase = "tap";
2282c0338ffSzrj #endif
2292c0338ffSzrj }
2302c0338ffSzrj
2312c0338ffSzrj /* Open the tunnel device */
2322c0338ffSzrj if (tun <= SSH_TUNID_MAX) {
2332c0338ffSzrj snprintf(name, sizeof(name), "/dev/%s%d", tunbase, tun);
2342c0338ffSzrj fd = open(name, O_RDWR);
2352c0338ffSzrj } else if (tun == SSH_TUNID_ANY) {
2362c0338ffSzrj for (tun = 100; tun >= 0; tun--) {
2372c0338ffSzrj snprintf(name, sizeof(name), "/dev/%s%d",
2382c0338ffSzrj tunbase, tun);
2392c0338ffSzrj if ((fd = open(name, O_RDWR)) >= 0)
2402c0338ffSzrj break;
2412c0338ffSzrj }
2422c0338ffSzrj } else {
2432c0338ffSzrj debug("%s: invalid tunnel %u\n", __func__, tun);
2442c0338ffSzrj return (-1);
2452c0338ffSzrj }
2462c0338ffSzrj
2472c0338ffSzrj if (fd < 0) {
2482c0338ffSzrj debug("%s: %s open failed: %s", __func__, name,
2492c0338ffSzrj strerror(errno));
2502c0338ffSzrj return (-1);
2512c0338ffSzrj }
2522c0338ffSzrj
2532c0338ffSzrj /* Turn on tunnel headers */
2542c0338ffSzrj #if defined(TUNSIFHEAD) && !defined(SSH_TUN_PREPEND_AF)
255*2c81fb9cSAntonio Huete Jimenez flag = 1;
2562c0338ffSzrj if (mode != SSH_TUNMODE_ETHERNET &&
2572c0338ffSzrj ioctl(fd, TUNSIFHEAD, &flag) == -1) {
2582c0338ffSzrj debug("%s: ioctl(%d, TUNSIFHEAD, 1): %s", __func__, fd,
2592c0338ffSzrj strerror(errno));
2602c0338ffSzrj close(fd);
2612c0338ffSzrj }
2622c0338ffSzrj #endif
2632c0338ffSzrj
2642c0338ffSzrj debug("%s: %s mode %d fd %d", __func__, name, mode, fd);
2652c0338ffSzrj
2662c0338ffSzrj /* Set the tunnel device operation mode */
2672c0338ffSzrj snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d", tunbase, tun);
2682c0338ffSzrj if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
2692c0338ffSzrj goto failed;
2702c0338ffSzrj
2712c0338ffSzrj if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1)
2722c0338ffSzrj goto failed;
2732c0338ffSzrj if ((ifr.ifr_flags & IFF_UP) == 0) {
2742c0338ffSzrj ifr.ifr_flags |= IFF_UP;
2752c0338ffSzrj if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1)
2762c0338ffSzrj goto failed;
2772c0338ffSzrj }
2782c0338ffSzrj
2792c0338ffSzrj if (ifname != NULL && (*ifname = strdup(ifr.ifr_name)) == NULL)
2802c0338ffSzrj goto failed;
2812c0338ffSzrj
2822c0338ffSzrj close(sock);
2832c0338ffSzrj return (fd);
2842c0338ffSzrj
2852c0338ffSzrj failed:
2862c0338ffSzrj if (fd >= 0)
2872c0338ffSzrj close(fd);
2882c0338ffSzrj if (sock >= 0)
2892c0338ffSzrj close(sock);
2902c0338ffSzrj debug("%s: failed to set %s mode %d: %s", __func__, name,
2912c0338ffSzrj mode, strerror(errno));
2922c0338ffSzrj return (-1);
2932c0338ffSzrj }
2942c0338ffSzrj #endif /* SSH_TUN_FREEBSD */
295bc9cc675SDaniel Fojt
296bc9cc675SDaniel Fojt /*
297bc9cc675SDaniel Fojt * System-specific channel filters
298bc9cc675SDaniel Fojt */
299bc9cc675SDaniel Fojt
300bc9cc675SDaniel Fojt #if defined(SSH_TUN_FILTER)
301bc9cc675SDaniel Fojt /*
302bc9cc675SDaniel Fojt * The tunnel forwarding protocol prepends the address family of forwarded
303bc9cc675SDaniel Fojt * IP packets using OpenBSD's numbers.
304bc9cc675SDaniel Fojt */
305bc9cc675SDaniel Fojt #define OPENBSD_AF_INET 2
306bc9cc675SDaniel Fojt #define OPENBSD_AF_INET6 24
307bc9cc675SDaniel Fojt
308bc9cc675SDaniel Fojt int
sys_tun_infilter(struct ssh * ssh,struct Channel * c,char * buf,int _len)309bc9cc675SDaniel Fojt sys_tun_infilter(struct ssh *ssh, struct Channel *c, char *buf, int _len)
310bc9cc675SDaniel Fojt {
311bc9cc675SDaniel Fojt int r;
312bc9cc675SDaniel Fojt size_t len;
313bc9cc675SDaniel Fojt char *ptr = buf;
314bc9cc675SDaniel Fojt #if defined(SSH_TUN_PREPEND_AF)
315bc9cc675SDaniel Fojt char rbuf[CHAN_RBUF];
316bc9cc675SDaniel Fojt struct ip iph;
317bc9cc675SDaniel Fojt #endif
318bc9cc675SDaniel Fojt #if defined(SSH_TUN_PREPEND_AF) || defined(SSH_TUN_COMPAT_AF)
319bc9cc675SDaniel Fojt u_int32_t af;
320bc9cc675SDaniel Fojt #endif
321bc9cc675SDaniel Fojt
322bc9cc675SDaniel Fojt /* XXX update channel input filter API to use unsigned length */
323bc9cc675SDaniel Fojt if (_len < 0)
324bc9cc675SDaniel Fojt return -1;
325bc9cc675SDaniel Fojt len = _len;
326bc9cc675SDaniel Fojt
327bc9cc675SDaniel Fojt #if defined(SSH_TUN_PREPEND_AF)
328bc9cc675SDaniel Fojt if (len <= sizeof(iph) || len > sizeof(rbuf) - 4)
329bc9cc675SDaniel Fojt return -1;
330bc9cc675SDaniel Fojt /* Determine address family from packet IP header. */
331bc9cc675SDaniel Fojt memcpy(&iph, buf, sizeof(iph));
332bc9cc675SDaniel Fojt af = iph.ip_v == 6 ? OPENBSD_AF_INET6 : OPENBSD_AF_INET;
333bc9cc675SDaniel Fojt /* Prepend address family to packet using OpenBSD constants */
334bc9cc675SDaniel Fojt memcpy(rbuf + 4, buf, len);
335bc9cc675SDaniel Fojt len += 4;
336bc9cc675SDaniel Fojt POKE_U32(rbuf, af);
337bc9cc675SDaniel Fojt ptr = rbuf;
338bc9cc675SDaniel Fojt #elif defined(SSH_TUN_COMPAT_AF)
339bc9cc675SDaniel Fojt /* Convert existing address family header to OpenBSD value */
340bc9cc675SDaniel Fojt if (len <= 4)
341bc9cc675SDaniel Fojt return -1;
342bc9cc675SDaniel Fojt af = PEEK_U32(buf);
343bc9cc675SDaniel Fojt /* Put it back */
344bc9cc675SDaniel Fojt POKE_U32(buf, af == AF_INET6 ? OPENBSD_AF_INET6 : OPENBSD_AF_INET);
345bc9cc675SDaniel Fojt #endif
346bc9cc675SDaniel Fojt
347bc9cc675SDaniel Fojt if ((r = sshbuf_put_string(c->input, ptr, len)) != 0)
348bc9cc675SDaniel Fojt fatal("%s: buffer error: %s", __func__, ssh_err(r));
349bc9cc675SDaniel Fojt return (0);
350bc9cc675SDaniel Fojt }
351bc9cc675SDaniel Fojt
352bc9cc675SDaniel Fojt u_char *
sys_tun_outfilter(struct ssh * ssh,struct Channel * c,u_char ** data,size_t * dlen)353bc9cc675SDaniel Fojt sys_tun_outfilter(struct ssh *ssh, struct Channel *c,
354bc9cc675SDaniel Fojt u_char **data, size_t *dlen)
355bc9cc675SDaniel Fojt {
356bc9cc675SDaniel Fojt u_char *buf;
357bc9cc675SDaniel Fojt u_int32_t af;
358bc9cc675SDaniel Fojt int r;
359bc9cc675SDaniel Fojt
360bc9cc675SDaniel Fojt /* XXX new API is incompatible with this signature. */
361bc9cc675SDaniel Fojt if ((r = sshbuf_get_string(c->output, data, dlen)) != 0)
362bc9cc675SDaniel Fojt fatal("%s: buffer error: %s", __func__, ssh_err(r));
363bc9cc675SDaniel Fojt if (*dlen < sizeof(af))
364bc9cc675SDaniel Fojt return (NULL);
365bc9cc675SDaniel Fojt buf = *data;
366bc9cc675SDaniel Fojt
367bc9cc675SDaniel Fojt #if defined(SSH_TUN_PREPEND_AF)
368bc9cc675SDaniel Fojt /* skip address family */
369bc9cc675SDaniel Fojt *dlen -= sizeof(af);
370bc9cc675SDaniel Fojt buf = *data + sizeof(af);
371bc9cc675SDaniel Fojt #elif defined(SSH_TUN_COMPAT_AF)
372bc9cc675SDaniel Fojt /* translate address family */
373bc9cc675SDaniel Fojt af = (PEEK_U32(buf) == OPENBSD_AF_INET6) ? AF_INET6 : AF_INET;
374bc9cc675SDaniel Fojt POKE_U32(buf, af);
375bc9cc675SDaniel Fojt #endif
376bc9cc675SDaniel Fojt return (buf);
377bc9cc675SDaniel Fojt }
378bc9cc675SDaniel Fojt #endif /* SSH_TUN_FILTER */
379