1 /*
2  * Copyright (c) 2005 Reyk Floeter <reyk@openbsd.org>
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 #include "includes.h"
18 
19 #include <sys/types.h>
20 #include <sys/ioctl.h>
21 
22 #include <netinet/in.h>
23 #include <arpa/inet.h>
24 #include <netinet/ip.h>
25 
26 #include <errno.h>
27 #include <fcntl.h>
28 #include <stdarg.h>
29 #include <string.h>
30 #include <unistd.h>
31 
32 #include "openbsd-compat/sys-queue.h"
33 #include "log.h"
34 #include "misc.h"
35 #include "sshbuf.h"
36 #include "channels.h"
37 #include "ssherr.h"
38 
39 /*
40  * This file contains various portability code for network support,
41  * including tun/tap forwarding and routing domains.
42  */
43 
44 /*
45  * This is the portable version of the SSH tunnel forwarding, it
46  * uses some preprocessor definitions for various platform-specific
47  * settings.
48  *
49  * SSH_TUN_LINUX	Use the (newer) Linux tun/tap device
50  * SSH_TUN_FREEBSD	Use the FreeBSD tun/tap device
51  * SSH_TUN_COMPAT_AF	Translate the OpenBSD address family
52  * SSH_TUN_PREPEND_AF	Prepend/remove the address family
53  */
54 
55 /*
56  * System-specific tunnel open function
57  */
58 
59 #ifdef SSH_TUN_FREEBSD
60 #include <sys/socket.h>
61 #include <net/if.h>
62 
63 #ifdef HAVE_NET_IF_TUN_H
64 #include <net/if_tun.h>
65 #endif
66 #ifdef __DragonFly__
67 #include <net/tun/if_tun.h>
68 #endif
69 
70 int
71 sys_tun_open(int tun, int mode, char **ifname)
72 {
73 	struct ifreq ifr;
74 	char name[100];
75 	int fd = -1, sock, flag;
76 	const char *tunbase = "tun";
77 
78 	if (ifname != NULL)
79 		*ifname = NULL;
80 
81 	if (mode == SSH_TUNMODE_ETHERNET) {
82 #ifdef SSH_TUN_NO_L2
83 		debug("%s: no layer 2 tunnelling support", __func__);
84 		return (-1);
85 #else
86 		tunbase = "tap";
87 #endif
88 	}
89 
90 	/* Open the tunnel device */
91 	if (tun <= SSH_TUNID_MAX) {
92 		snprintf(name, sizeof(name), "/dev/%s%d", tunbase, tun);
93 		fd = open(name, O_RDWR);
94 	} else if (tun == SSH_TUNID_ANY) {
95 		for (tun = 100; tun >= 0; tun--) {
96 			snprintf(name, sizeof(name), "/dev/%s%d",
97 			    tunbase, tun);
98 			if ((fd = open(name, O_RDWR)) >= 0)
99 				break;
100 		}
101 	} else {
102 		debug("%s: invalid tunnel %u\n", __func__, tun);
103 		return (-1);
104 	}
105 
106 	if (fd < 0) {
107 		debug("%s: %s open failed: %s", __func__, name,
108 		    strerror(errno));
109 		return (-1);
110 	}
111 
112 	/* Turn on tunnel headers */
113 	flag = 1;
114 #if defined(TUNSIFHEAD) && !defined(SSH_TUN_PREPEND_AF)
115 	if (mode != SSH_TUNMODE_ETHERNET &&
116 	    ioctl(fd, TUNSIFHEAD, &flag) == -1) {
117 		debug("%s: ioctl(%d, TUNSIFHEAD, 1): %s", __func__, fd,
118 		    strerror(errno));
119 		close(fd);
120 	}
121 #endif
122 
123 	debug("%s: %s mode %d fd %d", __func__, name, mode, fd);
124 
125 	/* Set the tunnel device operation mode */
126 	snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d", tunbase, tun);
127 	if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
128 		goto failed;
129 
130 	if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1)
131 		goto failed;
132 	if ((ifr.ifr_flags & IFF_UP) == 0) {
133 		ifr.ifr_flags |= IFF_UP;
134 		if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1)
135 			goto failed;
136 	}
137 
138 	if (ifname != NULL && (*ifname = strdup(ifr.ifr_name)) == NULL)
139 		goto failed;
140 
141 	close(sock);
142 	return (fd);
143 
144  failed:
145 	if (fd >= 0)
146 		close(fd);
147 	if (sock >= 0)
148 		close(sock);
149 	debug("%s: failed to set %s mode %d: %s", __func__, name,
150 	    mode, strerror(errno));
151 	return (-1);
152 }
153 #endif /* SSH_TUN_FREEBSD */
154