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 | |
42da2a58 |
31 | #define TUN_INTERNALS |
32 | |
b9066fbb |
33 | #include "tripe.h" |
34 | |
42da2a58 |
35 | /*----- Data structures ---------------------------------------------------*/ |
36 | |
37 | typedef struct slipif { |
38 | struct slipif *next; /* Next one in the list */ |
39 | int ifd, ofd; /* File descriptors to talk on */ |
40 | char *name; /* Interface name */ |
41 | pid_t kid; /* Child process id */ |
42 | unsigned f; /* Various flags */ |
43 | # define F_INUSE 1u /* Interface is in use */ |
44 | # define F_DYNAMIC 2u /* Interface found dynamically */ |
45 | } slipif; |
46 | |
47 | struct tunnel { |
48 | const tunnel_ops *ops; /* Pointer to operations */ |
49 | slipif *sl; /* My interface record */ |
50 | sel_file f; /* Selector for SLIP tty */ |
51 | struct peer *p; /* Pointer to my peer */ |
52 | unsigned st; /* Current parser state */ |
53 | # define ST_ESC 1u /* Last saw an escape character */ |
54 | # define ST_BAD 2u /* This packet is malformed */ |
55 | # define ST_EOF 4u /* File descriptor reported EOF */ |
56 | size_t n; /* Number of bytes used in buffer */ |
57 | octet buf[PKBUFSZ]; /* Buffer for incoming data */ |
58 | }; |
59 | |
b9066fbb |
60 | /*----- Static variables --------------------------------------------------*/ |
61 | |
62 | static slipif *slipifs; /* List of available interfaces */ |
98fdb08d |
63 | static const char *slipcmd; /* Script to make new interfaces */ |
b9066fbb |
64 | |
65 | /*----- Main code ---------------------------------------------------------*/ |
66 | |
b9066fbb |
67 | #define SL_END 0xc0 |
68 | #define SL_ESC 0xdb |
69 | #define SL_ESCEND 0xdc |
70 | #define SL_ESCESC 0xdd |
71 | |
72 | /* --- @t_read@ --- * |
73 | * |
74 | * Arguments: @int fd@ = file descriptor to read |
75 | * @unsigned mode@ = what's happened |
76 | * @void *v@ = pointer to tunnel block |
77 | * |
78 | * Returns: --- |
79 | * |
80 | * Use: Reads data from the tunnel. |
81 | */ |
82 | |
83 | static void t_read(int fd, unsigned mode, void *v) |
84 | { |
85 | tunnel *t = v; |
86 | ssize_t n; |
87 | const octet *p, *l, *ll; |
88 | octet *q; |
89 | unsigned st; |
90 | octet o; |
91 | buf b; |
92 | |
93 | /* --- Read the input data --- */ |
94 | |
95 | n = read(fd, buf_t, sizeof(buf_t)); |
96 | if (n < 0) { |
97 | if (errno == EINTR || |
98fdb08d |
98 | #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN |
b9066fbb |
99 | errno == EWOULDBLOCK || |
100 | #endif |
101 | errno == EAGAIN) |
102 | return; |
f43df819 |
103 | a_warn("TUN", "%s", t->sl->name, "read-error", "?ERRNO", A_END); |
b9066fbb |
104 | return; |
105 | } |
106 | if (!n) { |
f43df819 |
107 | a_warn("TUN", "%s", t->sl->name, "slip", "eof", A_END); |
42da2a58 |
108 | t->st = ST_EOF; |
b9066fbb |
109 | sel_rmfile(&t->f); |
110 | return; |
111 | } |
112 | IF_TRACING(T_TUNNEL, { |
060ca767 |
113 | trace_block(T_PACKET, "tun-slip: SLIP-encapsulated data", |
b9066fbb |
114 | buf_t, n); |
115 | }) |
116 | |
117 | /* --- Decapsulate the packet --- */ |
118 | |
119 | for (p = buf_t, l = p + n, st = t->st, |
120 | q = t->buf + t->n, ll = t->buf + sizeof(t->buf); |
121 | p < l; |
122 | p++) { |
123 | o = *p; |
124 | switch (o) { |
125 | case SL_END: |
42da2a58 |
126 | if (st & ST_BAD) |
b9066fbb |
127 | ; |
42da2a58 |
128 | else if (st & ST_ESC) |
f43df819 |
129 | a_warn("TUN", "%s", t->sl->name, "slip", "escape-end", A_END); |
b9066fbb |
130 | else if (q == t->buf) { |
060ca767 |
131 | T( trace(T_TUNNEL, "tun-slip: empty packet"); ) |
b9066fbb |
132 | } else { |
133 | IF_TRACING(T_TUNNEL, { |
060ca767 |
134 | trace(T_TUNNEL, "tun-slip: packet arrived"); |
135 | trace_block(T_PACKET, "tun-slip: packet contents", |
b9066fbb |
136 | t->buf, q - t->buf); |
137 | }) |
138 | buf_init(&b, t->buf, q - t->buf); |
139 | p_tun(t->p, &b); |
140 | } |
141 | q = t->buf; |
42da2a58 |
142 | st &= ~(ST_ESC | ST_BAD); |
b9066fbb |
143 | break; |
144 | case SL_ESC: |
42da2a58 |
145 | if ((st & ST_ESC) && !(st & ST_BAD)) { |
f43df819 |
146 | a_warn("TUN", "%s", t->sl->name, "slip", "bad-escape", A_END); |
42da2a58 |
147 | st |= ST_BAD; |
b9066fbb |
148 | } else |
42da2a58 |
149 | st |= ST_ESC; |
b9066fbb |
150 | break; |
151 | case SL_ESCEND: |
42da2a58 |
152 | if (st & ST_ESC) |
b9066fbb |
153 | o = SL_END; |
154 | goto emit; |
155 | case SL_ESCESC: |
42da2a58 |
156 | if (st & ST_ESC) |
b9066fbb |
157 | o = SL_ESC; |
158 | goto emit; |
159 | default: |
42da2a58 |
160 | if ((st & ST_ESC) && !(st & ST_BAD)) { |
f43df819 |
161 | a_warn("TUN", "%s", t->sl->name, "slip", "bad-escape", A_END); |
42da2a58 |
162 | st |= ST_BAD; |
b9066fbb |
163 | } |
164 | emit: |
42da2a58 |
165 | if (!(st & ST_BAD)) { |
b9066fbb |
166 | if (q < ll) |
167 | *q++ = o; |
168 | else { |
f43df819 |
169 | a_warn("TUN", "%s", t->sl->name, "slip", "overflow", A_END); |
42da2a58 |
170 | st |= ST_BAD; |
b9066fbb |
171 | } |
172 | } |
42da2a58 |
173 | st &= ~ST_ESC; |
b9066fbb |
174 | break; |
175 | } |
176 | } |
177 | |
178 | t->n = q - t->buf; |
179 | t->st = st; |
180 | } |
181 | |
42da2a58 |
182 | /* --- @t_init@ --- * |
b9066fbb |
183 | * |
184 | * Arguments: --- |
185 | * |
186 | * Returns: --- |
187 | * |
188 | * Use: Initializes the tunneling system. Maybe this will require |
189 | * opening file descriptors or something. |
190 | */ |
191 | |
42da2a58 |
192 | static void t_init(void) |
b9066fbb |
193 | { |
194 | char *p, *q; |
195 | dstr d = DSTR_INIT; |
196 | slipif *sl, **tail = &slipifs; |
197 | unsigned long uli, ulo; |
198 | size_t n; |
199 | |
b9066fbb |
200 | if ((p = getenv("TRIPE_SLIPIF")) == 0) |
42da2a58 |
201 | return; |
98fdb08d |
202 | |
203 | /* --- Build the list of available interfaces --- */ |
204 | |
b9066fbb |
205 | dstr_puts(&d, p); |
206 | |
207 | p = d.buf; |
208 | for (;;) { |
98fdb08d |
209 | if (*p == '/' || *p == '.') { |
210 | slipcmd = p; |
060ca767 |
211 | T( trace(T_TUNNEL, "tun-slip: declared slip command `%s'", slipcmd); ) |
98fdb08d |
212 | break; |
213 | } |
b9066fbb |
214 | uli = strtoul(p, &q, 0); |
215 | if (uli > INT_MAX || q == p) |
216 | goto whine; |
217 | if (*q != ',') |
218 | ulo = uli; |
219 | else { |
220 | p = q + 1; |
221 | ulo = strtoul(p, &q, 0); |
222 | if (ulo > INT_MAX || q == p) |
223 | goto whine; |
224 | } |
225 | if (*q != '=' || (n = strcspn(q + 1, ":")) == 0) |
226 | goto whine; |
227 | sl = CREATE(slipif); |
228 | sl->next = 0; |
229 | sl->ifd = uli; |
98fdb08d |
230 | fdflags(sl->ifd, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC); |
231 | fdflags(sl->ofd, O_NONBLOCK, 0, FD_CLOEXEC, FD_CLOEXEC); |
b9066fbb |
232 | sl->ofd = ulo; |
233 | sl->name = xmalloc(n + 1); |
98fdb08d |
234 | sl->kid = -1; |
b9066fbb |
235 | sl->f = 0; |
236 | memcpy(sl->name, q + 1, n); |
237 | sl->name[n] = 0; |
238 | *tail = sl; |
239 | tail = &sl->next; |
060ca767 |
240 | T( trace(T_TUNNEL, "tun-slip: declared slipif %d,%d=%s", |
b9066fbb |
241 | sl->ifd, sl->ofd, sl->name); ) |
242 | p = q + n + 1; |
243 | if (!*p) |
244 | break; |
245 | p++; |
246 | } |
247 | return; |
248 | |
249 | whine: |
42da2a58 |
250 | moan("bad slip interface list"); |
b9066fbb |
251 | } |
252 | |
42da2a58 |
253 | /* --- @t_create@ --- * |
b9066fbb |
254 | * |
42da2a58 |
255 | * Arguments: @peer *p@ = pointer to peer block |
b9066fbb |
256 | * |
42da2a58 |
257 | * Returns: A tunnel block if it worked, or null on failure. |
b9066fbb |
258 | * |
259 | * Use: Initializes a new tunnel. |
260 | */ |
261 | |
42da2a58 |
262 | static tunnel *t_create(peer *p) |
b9066fbb |
263 | { |
98fdb08d |
264 | slipif *sl = 0; |
265 | int pin[2] = { -1, -1 }, pout[2] = { -1, -1 }; |
266 | pid_t kid = -1; |
267 | dstr d = DSTR_INIT; |
268 | unsigned char ch; |
42da2a58 |
269 | tunnel *t; |
b9066fbb |
270 | static const char end[] = { SL_END, SL_END }; |
271 | |
98fdb08d |
272 | /* --- Try to find a spare static interface --- */ |
273 | |
b9066fbb |
274 | for (sl = slipifs; sl; sl = sl->next) { |
42da2a58 |
275 | if (!(sl->f & F_INUSE)) { |
060ca767 |
276 | T( trace(T_TUNNEL, "tun-slip: %s using static slipif %s", |
98fdb08d |
277 | p_name(p), sl->name); ) |
b9066fbb |
278 | goto found; |
98fdb08d |
279 | } |
b9066fbb |
280 | } |
98fdb08d |
281 | |
282 | /* --- If no dynamic interfaces are available, give up --- */ |
283 | |
284 | if (!slipcmd) { |
f43df819 |
285 | a_warn("TUN", "-", "slip", "no-slip-interfaces", A_END); |
98fdb08d |
286 | goto fail; |
287 | } |
288 | |
289 | /* --- Fork off a child process to create a dynamic SLIP interface --- */ |
290 | |
291 | if (pipe(pin) || pipe(pout)) { |
f43df819 |
292 | a_warn("TUN", "-", "slip", "pipe-error", "?ERRNO", A_END); |
98fdb08d |
293 | goto fail; |
294 | } |
295 | if ((kid = fork()) < 0) { |
f43df819 |
296 | a_warn("TUN", "-", "slip", "fork-error", "?ERRNO", A_END); |
98fdb08d |
297 | goto fail; |
298 | } |
299 | if (!kid) { |
300 | close(pin[1]); |
301 | close(pout[0]); |
302 | dup2(pin[0], STDIN_FILENO); |
303 | dup2(pout[1], STDOUT_FILENO); |
304 | execlp(slipcmd, slipcmd, p_name(p), (char *)0); |
305 | _exit(127); |
306 | } |
307 | |
308 | /* --- Read the interface name --- */ |
309 | |
310 | sl = CREATE(slipif); |
311 | close(pin[0]); pin[0] = -1; |
312 | close(pout[1]); pout[1] = -1; |
313 | for (;;) { |
314 | errno = EIO; |
315 | if (read(pout[0], &ch, 1) != 1 || ch == SL_END) { |
f43df819 |
316 | a_warn("TUN", "-", "slip", "read-ifname-failed", "?ERRNO", A_END); |
98fdb08d |
317 | goto fail; |
318 | } |
319 | if (ch == '\n') |
320 | break; |
321 | DPUTC(&d, (char)ch); |
322 | } |
323 | DPUTZ(&d); |
324 | sl->name = xstrdup(d.buf); |
325 | sl->ifd = pout[0]; |
326 | sl->ofd = pin[1]; |
327 | sl->kid = kid; |
328 | sl->next = 0; |
42da2a58 |
329 | sl->f = F_DYNAMIC; |
060ca767 |
330 | T( trace(T_TUNNEL, "tun-slip: %s using dynamic slipif %s", |
98fdb08d |
331 | p_name(p), sl->name); ) |
332 | fdflags(pout[0], O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC); |
333 | fdflags(pin[1], O_NONBLOCK, 0, FD_CLOEXEC, FD_CLOEXEC); |
334 | |
335 | /* --- Set up the new tunnel --- */ |
b9066fbb |
336 | |
337 | found: |
42da2a58 |
338 | t = CREATE(tunnel); |
339 | t->ops = &tun_slip; |
b9066fbb |
340 | t->p = p; |
341 | t->sl = sl; |
342 | t->st = 0; |
343 | t->n = 0; |
42da2a58 |
344 | sl->f |= F_INUSE; |
b9066fbb |
345 | sel_initfile(&sel, &t->f, sl->ifd, SEL_READ, t_read, t); |
346 | sel_addfile(&t->f); |
347 | write(sl->ofd, end, sizeof(end)); |
98fdb08d |
348 | dstr_destroy(&d); |
42da2a58 |
349 | return (t); |
98fdb08d |
350 | |
351 | /* --- Tidy up after a failure --- */ |
352 | |
353 | fail: |
354 | #define CLOSE(fd) do if (fd != -1) close(fd); while (0) |
355 | CLOSE(pin[0]); CLOSE(pout[0]); |
356 | CLOSE(pin[1]); CLOSE(pout[1]); |
357 | #undef CLOSE |
358 | if (kid != -1) kill(kid, SIGTERM); |
42da2a58 |
359 | if (sl && (sl->f & F_DYNAMIC)) DESTROY(sl); |
98fdb08d |
360 | dstr_destroy(&d); |
42da2a58 |
361 | return (0); |
b9066fbb |
362 | } |
363 | |
42da2a58 |
364 | /* --- @t_ifname@ --- * |
b9066fbb |
365 | * |
366 | * Arguments: @tunnel *t@ = pointer to tunnel block |
367 | * |
368 | * Returns: A pointer to the tunnel's interface name. |
369 | */ |
370 | |
42da2a58 |
371 | static const char *t_ifname(tunnel *t) { return (t->sl->name); } |
b9066fbb |
372 | |
42da2a58 |
373 | /* --- @t_inject@ --- * |
b9066fbb |
374 | * |
375 | * Arguments: @tunnel *t@ = pointer to tunnel block |
376 | * @buf *b@ = buffer to send |
377 | * |
378 | * Returns: --- |
379 | * |
380 | * Use: Injects a packet into the local network stack. |
381 | */ |
382 | |
42da2a58 |
383 | static void t_inject(tunnel *t, buf *b) |
b9066fbb |
384 | { |
385 | octet buf[PKBUFSZ * 2 + 2]; |
386 | const octet *p, *l; |
387 | octet *q; |
388 | |
389 | IF_TRACING(T_TUNNEL, { |
060ca767 |
390 | trace(T_TUNNEL, "tun-slip: inject decrypted packet"); |
391 | trace_block(T_PACKET, "tun-slip: packet contents", BBASE(b), BLEN(b)); |
b9066fbb |
392 | }) |
393 | |
394 | q = buf; |
395 | *q++ = SL_END; |
396 | for (p = BBASE(b), l = BCUR(b); p < l; p++) { |
397 | switch (*p) { |
398 | case SL_END: *q++ = SL_ESC; *q++ = SL_ESCEND; break; |
399 | case SL_ESC: *q++ = SL_ESC; *q++ = SL_ESCESC; break; |
400 | default: *q++ = *p; break; |
401 | } |
402 | } |
403 | *q++ = SL_END; |
404 | IF_TRACING(T_TUNNEL, { |
060ca767 |
405 | trace_block(T_PACKET, "tun-slip: SLIP-encapsulated contents", |
b9066fbb |
406 | buf, q - buf); |
407 | }) |
408 | write(t->sl->ofd, buf, q - buf); |
409 | } |
410 | |
42da2a58 |
411 | /* --- @t_destroy@ --- * |
b9066fbb |
412 | * |
413 | * Arguments: @tunnel *t@ = pointer to tunnel block |
414 | * |
415 | * Returns: --- |
416 | * |
417 | * Use: Destroys a tunnel. |
418 | */ |
419 | |
42da2a58 |
420 | static void t_destroy(tunnel *t) |
b9066fbb |
421 | { |
98fdb08d |
422 | slipif *sl = t->sl; |
423 | |
b9066fbb |
424 | /* --- If it reported EOF, leave it out-of-action --- */ |
425 | |
42da2a58 |
426 | if (!(t->st & ST_EOF)) { |
b9066fbb |
427 | sel_rmfile(&t->f); |
42da2a58 |
428 | sl->f &= ~F_INUSE; |
98fdb08d |
429 | } |
42da2a58 |
430 | if (sl && (sl->f & F_DYNAMIC)) { |
060ca767 |
431 | T( trace(T_TUNNEL, "tun-slip: releasing dynamic slipif %s", sl->name); ) |
98fdb08d |
432 | close(sl->ofd); |
433 | close(sl->ifd); |
434 | kill(sl->kid, SIGTERM); |
435 | xfree(sl->name); |
436 | DESTROY(sl); |
b9066fbb |
437 | } |
42da2a58 |
438 | DESTROY(t); |
b9066fbb |
439 | } |
440 | |
42da2a58 |
441 | const tunnel_ops tun_slip = { |
442 | "slip", |
443 | t_init, |
444 | t_create, |
445 | t_ifname, |
446 | t_inject, |
447 | t_destroy |
448 | }; |
449 | |
b9066fbb |
450 | /*----- That's all, folks -------------------------------------------------*/ |