diff options
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 | } |