chiark / gitweb /
1d1bd14b1ae69a691bb0506d5113b5a2bace3db4
[tripe] / tun-slip.c
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 */
36
37 /*----- Main code ---------------------------------------------------------*/
38
39 #if TUN_TYPE != TUN_SLIP
40 #  error "Tunnel type mismatch: fix the Makefile"
41 #endif
42
43 #define SL_END 0xc0
44 #define SL_ESC 0xdb
45 #define SL_ESCEND 0xdc
46 #define SL_ESCESC 0xdd
47
48 /* --- @t_read@ --- *
49  *
50  * Arguments:   @int fd@ = file descriptor to read
51  *              @unsigned mode@ = what's happened
52  *              @void *v@ = pointer to tunnel block
53  *
54  * Returns:     ---
55  *
56  * Use:         Reads data from the tunnel.
57  */
58
59 static void t_read(int fd, unsigned mode, void *v)
60 {
61   tunnel *t = v;
62   ssize_t n;
63   const octet *p, *l, *ll;
64   octet *q;
65   unsigned st;
66   octet o;
67   buf b;
68
69   /* --- Read the input data --- */
70
71   n = read(fd, buf_t, sizeof(buf_t));
72   if (n < 0) {
73     if (errno == EINTR ||
74 #ifdef EWOULDBLOCK
75         errno == EWOULDBLOCK ||
76 #endif
77         errno == EAGAIN)
78       return;
79     a_warn("TUN %s read-error -- %s", t->sl->name, strerror(errno));
80     return;
81   }
82   if (!n) {
83     a_warn("TUN %s slip eof", t->sl->name);
84     t->st = SLIPST_EOF;
85     sel_rmfile(&t->f);
86     return;
87   }
88   IF_TRACING(T_TUNNEL, {
89     trace_block(T_PACKET, "tunnel: SLIP-encapsulated data",
90                 buf_t, n);
91   })
92
93   /* --- Decapsulate the packet --- */
94
95   for (p = buf_t, l = p + n, st = t->st,
96        q = t->buf + t->n, ll = t->buf + sizeof(t->buf);
97        p < l;
98        p++) {
99     o = *p;
100     switch (o) {
101       case SL_END:
102         if (st & SLIPST_BAD)
103           ;
104         else if (st & SLIPST_ESC)
105           a_warn("TUN %s slip escape-end", t->sl->name);
106         else if (q == t->buf) {
107           T( trace(T_TUNNEL, "tunnel: empty packet"); )
108         } else {
109           IF_TRACING(T_TUNNEL, {
110             trace(T_TUNNEL, "tunnel: packet arrived");
111             trace_block(T_PACKET, "tunnel: packet contents",
112                         t->buf, q - t->buf);
113           })
114           buf_init(&b, t->buf, q - t->buf);
115           p_tun(t->p, &b);
116         }
117         q = t->buf;
118         st &= ~(SLIPST_ESC | SLIPST_BAD);
119         break;
120       case SL_ESC:
121         if ((st & SLIPST_ESC) && !(st & SLIPST_BAD)) {
122           a_warn("TUN %s slip bad-escape", t->sl->name);
123           st |= SLIPST_BAD;
124         } else
125           st |= SLIPST_ESC;
126         break;
127       case SL_ESCEND:
128         if (st & SLIPST_ESC)
129           o = SL_END;
130         goto emit;
131       case SL_ESCESC:
132         if (st & SLIPST_ESC)
133           o = SL_ESC;
134         goto emit;
135       default:
136         if ((st & SLIPST_ESC) && !(st & SLIPST_BAD)) {
137           a_warn("TUN %s slip bad-escape", t->sl->name);
138           st |= SLIPST_BAD;
139         }
140       emit:
141         if (!(st & SLIPST_BAD)) {
142           if (q < ll)
143             *q++ = o;
144           else {
145             a_warn("TUN %s slip overflow", t->sl->name);
146             st |= SLIPST_BAD;
147           }
148         }
149         st &= ~SLIPST_ESC;
150         break;
151     }
152   }
153
154   t->n = q - t->buf;
155   t->st = st;
156 }
157
158 /* --- @tun_init@ --- *
159  *
160  * Arguments:   ---
161  *
162  * Returns:     ---
163  *
164  * Use:         Initializes the tunneling system.  Maybe this will require
165  *              opening file descriptors or something.
166  */
167
168 void tun_init(void)
169 {
170   char *p, *q;
171   dstr d = DSTR_INIT;
172   slipif *sl, **tail = &slipifs;
173   unsigned long uli, ulo;
174   size_t n;
175
176   /* --- Build the list of available interfaces --- */
177
178   if ((p = getenv("TRIPE_SLIPIF")) == 0)
179     die(1, "no slip interfaces listed: set TRIPE_SLIPIF");
180   dstr_puts(&d, p);
181
182   p = d.buf;
183   for (;;) {
184     uli = strtoul(p, &q, 0);
185     if (uli > INT_MAX || q == p)
186       goto whine;
187     if (*q != ',')
188       ulo = uli;
189     else {
190       p = q + 1;
191       ulo = strtoul(p, &q, 0);
192       if (ulo > INT_MAX || q == p)
193         goto whine;
194     }
195     if (*q != '=' || (n = strcspn(q + 1, ":")) == 0)
196       goto whine;
197     sl = CREATE(slipif);
198     sl->next = 0;
199     sl->ifd = uli;
200     sl->ofd = ulo;
201     sl->name = xmalloc(n + 1);
202     sl->f = 0;
203     memcpy(sl->name, q + 1, n);
204     sl->name[n] = 0;
205     *tail = sl;
206     tail = &sl->next;
207     T( trace(T_TUNNEL, "tunnel: declared slipif %d,%d=%s",
208              sl->ifd, sl->ofd, sl->name); )
209     p = q + n + 1;
210     if (!*p)
211       break;
212     p++;
213   }
214   return;
215
216 whine:
217   die(1, "bad slip interface list");
218 }
219
220 /* --- @tun_create@ --- *
221  *
222  * Arguments:   @tunnel *t@ = pointer to tunnel block
223  *              @peer *p@ = pointer to peer block
224  *
225  * Returns:     Zero if it worked, nonzero on failure.
226  *
227  * Use:         Initializes a new tunnel.
228  */
229
230 int tun_create(tunnel *t, peer *p)
231 {
232   slipif *sl;
233   static const char end[] = { SL_END, SL_END };
234
235   for (sl = slipifs; sl; sl = sl->next) {
236     if (!(sl->f & SLIPIFF_INUSE))
237       goto found;
238   }
239   a_warn("TUN - slip no-slip-interfaces");
240   return (-1);
241
242 found:
243   t->p = p;
244   t->sl = sl;
245   t->st = 0;
246   t->n = 0;
247   sl->f |= SLIPIFF_INUSE;
248   sel_initfile(&sel, &t->f, sl->ifd, SEL_READ, t_read, t);
249   sel_addfile(&t->f);
250   write(sl->ofd, end, sizeof(end));
251   T( trace(T_TUNNEL, "tunnel: attached interface %s to peer `%s'",
252            sl->name, p_name(p)); )
253   return (0);
254 }
255
256 /* --- @tun_ifname@ --- *
257  *
258  * Arguments:   @tunnel *t@ = pointer to tunnel block
259  *
260  * Returns:     A pointer to the tunnel's interface name.
261  */
262
263 const char *tun_ifname(tunnel *t)
264 {
265   return (t->sl->name);
266 }
267
268 /* --- @tun_inject@ --- *
269  *
270  * Arguments:   @tunnel *t@ = pointer to tunnel block
271  *              @buf *b@ = buffer to send
272  *
273  * Returns:     ---
274  *
275  * Use:         Injects a packet into the local network stack.
276  */
277
278 void tun_inject(tunnel *t, buf *b)
279 {
280   octet buf[PKBUFSZ * 2 + 2];
281   const octet *p, *l;
282   octet *q;
283
284   IF_TRACING(T_TUNNEL, {
285     trace(T_TUNNEL, "tunnel: inject decrypted packet");
286     trace_block(T_PACKET, "tunnel: packet contents", BBASE(b), BLEN(b));
287   })
288
289   q = buf;
290   *q++ = SL_END;
291   for (p = BBASE(b), l = BCUR(b); p < l; p++) {
292     switch (*p) {
293       case SL_END: *q++ = SL_ESC; *q++ = SL_ESCEND; break;
294       case SL_ESC: *q++ = SL_ESC; *q++ = SL_ESCESC; break;
295       default: *q++ = *p; break;
296     }
297   }
298   *q++ = SL_END;
299   IF_TRACING(T_TUNNEL, {
300     trace_block(T_PACKET, "tunnel: SLIP-encapsulated contents",
301                 buf, q - buf);
302   })
303   write(t->sl->ofd, buf, q - buf);
304 }
305
306 /* --- @tun_destroy@ --- *
307  *
308  * Arguments:   @tunnel *t@ = pointer to tunnel block
309  *
310  * Returns:     ---
311  *
312  * Use:         Destroys a tunnel.
313  */
314
315 void tun_destroy(tunnel *t)
316 {
317   /* --- If it reported EOF, leave it out-of-action --- */
318
319   if (!(t->st & SLIPST_EOF)) {
320     sel_rmfile(&t->f);
321     t->sl->f &= ~SLIPIFF_INUSE;
322   }
323 }
324
325 /*----- That's all, folks -------------------------------------------------*/