b9066fbb |
1 | /* -*-c-*- |
2 | * |
3 | * $Id$ |
4 | * |
5 | * Tunnel packets via SLIP |
6 | * |
7 | * (c) 2005 Straylight/Edgeware |
8 | */ |
9 | |
10 | /*----- Licensing notice --------------------------------------------------* |
11 | * |
12 | * This file is part of Trivial IP Encryption (TrIPE). |
13 | * |
14 | * TrIPE is free software; you can redistribute it and/or modify |
15 | * it under the terms of the GNU General Public License as published by |
16 | * the Free Software Foundation; either version 2 of the License, or |
17 | * (at your option) any later version. |
18 | * |
19 | * TrIPE is distributed in the hope that it will be useful, |
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
22 | * GNU General Public License for more details. |
23 | * |
24 | * You should have received a copy of the GNU General Public License |
25 | * along with TrIPE; if not, write to the Free Software Foundation, |
26 | * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
27 | */ |
28 | |
29 | /*----- Header files ------------------------------------------------------*/ |
30 | |
31 | #include "tripe.h" |
32 | |
33 | /*----- Static variables --------------------------------------------------*/ |
34 | |
35 | static slipif *slipifs; /* List of available interfaces */ |
98fdb08d |
36 | static const char *slipcmd; /* Script to make new interfaces */ |
b9066fbb |
37 | |
38 | /*----- Main code ---------------------------------------------------------*/ |
39 | |
40 | #if TUN_TYPE != TUN_SLIP |
41 | # error "Tunnel type mismatch: fix the Makefile" |
42 | #endif |
43 | |
44 | #define SL_END 0xc0 |
45 | #define SL_ESC 0xdb |
46 | #define SL_ESCEND 0xdc |
47 | #define SL_ESCESC 0xdd |
48 | |
49 | /* --- @t_read@ --- * |
50 | * |
51 | * Arguments: @int fd@ = file descriptor to read |
52 | * @unsigned mode@ = what's happened |
53 | * @void *v@ = pointer to tunnel block |
54 | * |
55 | * Returns: --- |
56 | * |
57 | * Use: Reads data from the tunnel. |
58 | */ |
59 | |
60 | static void t_read(int fd, unsigned mode, void *v) |
61 | { |
62 | tunnel *t = v; |
63 | ssize_t n; |
64 | const octet *p, *l, *ll; |
65 | octet *q; |
66 | unsigned st; |
67 | octet o; |
68 | buf b; |
69 | |
70 | /* --- Read the input data --- */ |
71 | |
72 | n = read(fd, buf_t, sizeof(buf_t)); |
73 | if (n < 0) { |
74 | if (errno == EINTR || |
98fdb08d |
75 | #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN |
b9066fbb |
76 | errno == EWOULDBLOCK || |
77 | #endif |
78 | errno == EAGAIN) |
79 | return; |
80 | a_warn("TUN %s read-error -- %s", t->sl->name, strerror(errno)); |
81 | return; |
82 | } |
83 | if (!n) { |
84 | a_warn("TUN %s slip eof", t->sl->name); |
85 | t->st = SLIPST_EOF; |
86 | sel_rmfile(&t->f); |
87 | return; |
88 | } |
89 | IF_TRACING(T_TUNNEL, { |
90 | trace_block(T_PACKET, "tunnel: SLIP-encapsulated data", |
91 | buf_t, n); |
92 | }) |
93 | |
94 | /* --- Decapsulate the packet --- */ |
95 | |
96 | for (p = buf_t, l = p + n, st = t->st, |
97 | q = t->buf + t->n, ll = t->buf + sizeof(t->buf); |
98 | p < l; |
99 | p++) { |
100 | o = *p; |
101 | switch (o) { |
102 | case SL_END: |
103 | if (st & SLIPST_BAD) |
104 | ; |
105 | else if (st & SLIPST_ESC) |
106 | a_warn("TUN %s slip escape-end", t->sl->name); |
107 | else if (q == t->buf) { |
108 | T( trace(T_TUNNEL, "tunnel: empty packet"); ) |
109 | } else { |
110 | IF_TRACING(T_TUNNEL, { |
111 | trace(T_TUNNEL, "tunnel: packet arrived"); |
112 | trace_block(T_PACKET, "tunnel: packet contents", |
113 | t->buf, q - t->buf); |
114 | }) |
115 | buf_init(&b, t->buf, q - t->buf); |
116 | p_tun(t->p, &b); |
117 | } |
118 | q = t->buf; |
119 | st &= ~(SLIPST_ESC | SLIPST_BAD); |
120 | break; |
121 | case SL_ESC: |
122 | if ((st & SLIPST_ESC) && !(st & SLIPST_BAD)) { |
123 | a_warn("TUN %s slip bad-escape", t->sl->name); |
124 | st |= SLIPST_BAD; |
125 | } else |
126 | st |= SLIPST_ESC; |
127 | break; |
128 | case SL_ESCEND: |
129 | if (st & SLIPST_ESC) |
130 | o = SL_END; |
131 | goto emit; |
132 | case SL_ESCESC: |
133 | if (st & SLIPST_ESC) |
134 | o = SL_ESC; |
135 | goto emit; |
136 | default: |
137 | if ((st & SLIPST_ESC) && !(st & SLIPST_BAD)) { |
138 | a_warn("TUN %s slip bad-escape", t->sl->name); |
139 | st |= SLIPST_BAD; |
140 | } |
141 | emit: |
142 | if (!(st & SLIPST_BAD)) { |
143 | if (q < ll) |
144 | *q++ = o; |
145 | else { |
146 | a_warn("TUN %s slip overflow", t->sl->name); |
147 | st |= SLIPST_BAD; |
148 | } |
149 | } |
150 | st &= ~SLIPST_ESC; |
151 | break; |
152 | } |
153 | } |
154 | |
155 | t->n = q - t->buf; |
156 | t->st = st; |
157 | } |
158 | |
159 | /* --- @tun_init@ --- * |
160 | * |
161 | * Arguments: --- |
162 | * |
163 | * Returns: --- |
164 | * |
165 | * Use: Initializes the tunneling system. Maybe this will require |
166 | * opening file descriptors or something. |
167 | */ |
168 | |
169 | void tun_init(void) |
170 | { |
171 | char *p, *q; |
172 | dstr d = DSTR_INIT; |
173 | slipif *sl, **tail = &slipifs; |
174 | unsigned long uli, ulo; |
175 | size_t n; |
176 | |
b9066fbb |
177 | if ((p = getenv("TRIPE_SLIPIF")) == 0) |
178 | die(1, "no slip interfaces listed: set TRIPE_SLIPIF"); |
98fdb08d |
179 | |
180 | /* --- Build the list of available interfaces --- */ |
181 | |
b9066fbb |
182 | dstr_puts(&d, p); |
183 | |
184 | p = d.buf; |
185 | for (;;) { |
98fdb08d |
186 | if (*p == '/' || *p == '.') { |
187 | slipcmd = p; |
188 | T( trace(T_TUNNEL, "tunnel: declared slip command `%s'", slipcmd); ) |
189 | break; |
190 | } |
b9066fbb |
191 | uli = strtoul(p, &q, 0); |
192 | if (uli > INT_MAX || q == p) |
193 | goto whine; |
194 | if (*q != ',') |
195 | ulo = uli; |
196 | else { |
197 | p = q + 1; |
198 | ulo = strtoul(p, &q, 0); |
199 | if (ulo > INT_MAX || q == p) |
200 | goto whine; |
201 | } |
202 | if (*q != '=' || (n = strcspn(q + 1, ":")) == 0) |
203 | goto whine; |
204 | sl = CREATE(slipif); |
205 | sl->next = 0; |
206 | sl->ifd = uli; |
98fdb08d |
207 | fdflags(sl->ifd, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC); |
208 | fdflags(sl->ofd, O_NONBLOCK, 0, FD_CLOEXEC, FD_CLOEXEC); |
b9066fbb |
209 | sl->ofd = ulo; |
210 | sl->name = xmalloc(n + 1); |
98fdb08d |
211 | sl->kid = -1; |
b9066fbb |
212 | sl->f = 0; |
213 | memcpy(sl->name, q + 1, n); |
214 | sl->name[n] = 0; |
215 | *tail = sl; |
216 | tail = &sl->next; |
217 | T( trace(T_TUNNEL, "tunnel: declared slipif %d,%d=%s", |
218 | sl->ifd, sl->ofd, sl->name); ) |
219 | p = q + n + 1; |
220 | if (!*p) |
221 | break; |
222 | p++; |
223 | } |
224 | return; |
225 | |
226 | whine: |
227 | die(1, "bad slip interface list"); |
228 | } |
229 | |
230 | /* --- @tun_create@ --- * |
231 | * |
232 | * Arguments: @tunnel *t@ = pointer to tunnel block |
233 | * @peer *p@ = pointer to peer block |
234 | * |
235 | * Returns: Zero if it worked, nonzero on failure. |
236 | * |
237 | * Use: Initializes a new tunnel. |
238 | */ |
239 | |
240 | int tun_create(tunnel *t, peer *p) |
241 | { |
98fdb08d |
242 | slipif *sl = 0; |
243 | int pin[2] = { -1, -1 }, pout[2] = { -1, -1 }; |
244 | pid_t kid = -1; |
245 | dstr d = DSTR_INIT; |
246 | unsigned char ch; |
b9066fbb |
247 | static const char end[] = { SL_END, SL_END }; |
248 | |
98fdb08d |
249 | /* --- Try to find a spare static interface --- */ |
250 | |
b9066fbb |
251 | for (sl = slipifs; sl; sl = sl->next) { |
98fdb08d |
252 | if (!(sl->f & SLIPIFF_INUSE)) { |
253 | T( trace(T_TUNNEL, "tunnel: %s using static slipif %s", |
254 | p_name(p), sl->name); ) |
b9066fbb |
255 | goto found; |
98fdb08d |
256 | } |
b9066fbb |
257 | } |
98fdb08d |
258 | |
259 | /* --- If no dynamic interfaces are available, give up --- */ |
260 | |
261 | if (!slipcmd) { |
262 | a_warn("TUN %s slip no-slip-interfaces", p_name(p)); |
263 | goto fail; |
264 | } |
265 | |
266 | /* --- Fork off a child process to create a dynamic SLIP interface --- */ |
267 | |
268 | if (pipe(pin) || pipe(pout)) { |
269 | a_warn("TUN %s slip pipe-error -- %s", p_name(p), strerror(errno)); |
270 | goto fail; |
271 | } |
272 | if ((kid = fork()) < 0) { |
273 | a_warn("TUN %s slip fork-error -- %s", p_name(p), strerror(errno)); |
274 | goto fail; |
275 | } |
276 | if (!kid) { |
277 | close(pin[1]); |
278 | close(pout[0]); |
279 | dup2(pin[0], STDIN_FILENO); |
280 | dup2(pout[1], STDOUT_FILENO); |
281 | execlp(slipcmd, slipcmd, p_name(p), (char *)0); |
282 | _exit(127); |
283 | } |
284 | |
285 | /* --- Read the interface name --- */ |
286 | |
287 | sl = CREATE(slipif); |
288 | close(pin[0]); pin[0] = -1; |
289 | close(pout[1]); pout[1] = -1; |
290 | for (;;) { |
291 | errno = EIO; |
292 | if (read(pout[0], &ch, 1) != 1 || ch == SL_END) { |
293 | a_warn("TUN %s slip read-ifname-failed -- %s", |
294 | p_name(p), strerror(errno)); |
295 | goto fail; |
296 | } |
297 | if (ch == '\n') |
298 | break; |
299 | DPUTC(&d, (char)ch); |
300 | } |
301 | DPUTZ(&d); |
302 | sl->name = xstrdup(d.buf); |
303 | sl->ifd = pout[0]; |
304 | sl->ofd = pin[1]; |
305 | sl->kid = kid; |
306 | sl->next = 0; |
307 | sl->f = SLIPIFF_DYNAMIC; |
308 | T( trace(T_TUNNEL, "tunnel: %s using dynamic slipif %s", |
309 | p_name(p), sl->name); ) |
310 | fdflags(pout[0], O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC); |
311 | fdflags(pin[1], O_NONBLOCK, 0, FD_CLOEXEC, FD_CLOEXEC); |
312 | |
313 | /* --- Set up the new tunnel --- */ |
b9066fbb |
314 | |
315 | found: |
316 | t->p = p; |
317 | t->sl = sl; |
318 | t->st = 0; |
319 | t->n = 0; |
320 | sl->f |= SLIPIFF_INUSE; |
321 | sel_initfile(&sel, &t->f, sl->ifd, SEL_READ, t_read, t); |
322 | sel_addfile(&t->f); |
323 | write(sl->ofd, end, sizeof(end)); |
98fdb08d |
324 | dstr_destroy(&d); |
b9066fbb |
325 | return (0); |
98fdb08d |
326 | |
327 | /* --- Tidy up after a failure --- */ |
328 | |
329 | fail: |
330 | #define CLOSE(fd) do if (fd != -1) close(fd); while (0) |
331 | CLOSE(pin[0]); CLOSE(pout[0]); |
332 | CLOSE(pin[1]); CLOSE(pout[1]); |
333 | #undef CLOSE |
334 | if (kid != -1) kill(kid, SIGTERM); |
335 | if (sl && (sl->f & SLIPIFF_DYNAMIC)) DESTROY(sl); |
336 | dstr_destroy(&d); |
337 | return (-1); |
b9066fbb |
338 | } |
339 | |
340 | /* --- @tun_ifname@ --- * |
341 | * |
342 | * Arguments: @tunnel *t@ = pointer to tunnel block |
343 | * |
344 | * Returns: A pointer to the tunnel's interface name. |
345 | */ |
346 | |
98fdb08d |
347 | const char *tun_ifname(tunnel *t) { return (t->sl->name); } |
b9066fbb |
348 | |
349 | /* --- @tun_inject@ --- * |
350 | * |
351 | * Arguments: @tunnel *t@ = pointer to tunnel block |
352 | * @buf *b@ = buffer to send |
353 | * |
354 | * Returns: --- |
355 | * |
356 | * Use: Injects a packet into the local network stack. |
357 | */ |
358 | |
359 | void tun_inject(tunnel *t, buf *b) |
360 | { |
361 | octet buf[PKBUFSZ * 2 + 2]; |
362 | const octet *p, *l; |
363 | octet *q; |
364 | |
365 | IF_TRACING(T_TUNNEL, { |
366 | trace(T_TUNNEL, "tunnel: inject decrypted packet"); |
367 | trace_block(T_PACKET, "tunnel: packet contents", BBASE(b), BLEN(b)); |
368 | }) |
369 | |
370 | q = buf; |
371 | *q++ = SL_END; |
372 | for (p = BBASE(b), l = BCUR(b); p < l; p++) { |
373 | switch (*p) { |
374 | case SL_END: *q++ = SL_ESC; *q++ = SL_ESCEND; break; |
375 | case SL_ESC: *q++ = SL_ESC; *q++ = SL_ESCESC; break; |
376 | default: *q++ = *p; break; |
377 | } |
378 | } |
379 | *q++ = SL_END; |
380 | IF_TRACING(T_TUNNEL, { |
381 | trace_block(T_PACKET, "tunnel: SLIP-encapsulated contents", |
382 | buf, q - buf); |
383 | }) |
384 | write(t->sl->ofd, buf, q - buf); |
385 | } |
386 | |
387 | /* --- @tun_destroy@ --- * |
388 | * |
389 | * Arguments: @tunnel *t@ = pointer to tunnel block |
390 | * |
391 | * Returns: --- |
392 | * |
393 | * Use: Destroys a tunnel. |
394 | */ |
395 | |
396 | void tun_destroy(tunnel *t) |
397 | { |
98fdb08d |
398 | slipif *sl = t->sl; |
399 | |
b9066fbb |
400 | /* --- If it reported EOF, leave it out-of-action --- */ |
401 | |
402 | if (!(t->st & SLIPST_EOF)) { |
403 | sel_rmfile(&t->f); |
98fdb08d |
404 | sl->f &= ~SLIPIFF_INUSE; |
405 | } |
406 | if (sl && (sl->f & SLIPIFF_DYNAMIC)) { |
407 | T( trace(T_TUNNEL, "tunnel: releasing dynamic slipif %s", sl->name); ) |
408 | close(sl->ofd); |
409 | close(sl->ifd); |
410 | kill(sl->kid, SIGTERM); |
411 | xfree(sl->name); |
412 | DESTROY(sl); |
b9066fbb |
413 | } |
414 | } |
415 | |
416 | /*----- That's all, folks -------------------------------------------------*/ |