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 */ |
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 -------------------------------------------------*/ |