chiark / gitweb /
dee9f94d63e92d64df14c538d810ad34d3d0171b
[tripe] / uslip / uslip.c
1 /* -*-c-*-
2  *
3  * A simple SLIP implementation drivable from the command-line
4  *
5  * (c) 2008 Straylight/Edgeware
6  */
7
8 /*----- Licensing notice --------------------------------------------------*
9  *
10  * This file is part of Trivial IP Encryption (TrIPE).
11  *
12  * TrIPE is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * TrIPE is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with TrIPE; if not, write to the Free Software Foundation,
24  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25  */
26
27 /*----- Header files ------------------------------------------------------*/
28
29 #include "config.h"
30
31 #include <assert.h>
32 #include <ctype.h>
33 #include <errno.h>
34 #include <signal.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38
39 #include <sys/types.h>
40 #include <sys/time.h>
41 #include <unistd.h>
42
43 #include <sys/socket.h>
44 #include <sys/un.h>
45 #include <netinet/in.h>
46 #include <arpa/inet.h>
47 #include <netdb.h>
48
49 #include <mLib/alloc.h>
50 #include <mLib/dstr.h>
51 #include <mLib/fdflags.h>
52 #include <mLib/mdwopt.h>
53 #include <mLib/quis.h>
54 #include <mLib/report.h>
55 #include <mLib/sel.h>
56 #include <mLib/sub.h>
57
58 #include "slip.h"
59
60 #undef sun
61
62 /*----- Data structures ---------------------------------------------------*/
63
64 typedef struct pkq_node {
65   struct pkq_node *next;
66   unsigned char *buf;
67   size_t n, sz;
68 } pkq_node;
69
70 typedef struct pkq {
71   pkq_node *head, **tail;
72 } pkq;
73
74 enum { START, OK, ESC, BAD, SYNC1, SYNC2 };
75
76 typedef struct client {
77   sel_file f;
78   dstr d;
79   int mode;
80 } client;
81
82 typedef struct gobbler {
83   sel_file f;
84   void (*done)(struct gobbler *, int, void *);
85   void *p;
86 } gobbler;
87
88 typedef struct dribbler {
89   sel_file f;
90   pkq q;
91   void (*done)(struct dribbler *, int, void *);
92   void *p;
93 } dribbler;
94
95 typedef struct waiter {
96   struct waiter *next;
97   int fd;
98   gobbler *g;
99 } waiter;
100
101 /*----- Static variables --------------------------------------------------*/
102
103 static pkq q_in;
104 static dribbler *dribble_out;
105 static dstr slipbuf = DSTR_INIT;
106 static int slipstate = SYNC1;
107 static sel_file slip_in, listener;
108 static sel_state sel;
109 static unsigned reasons;
110 static waiter *wait_head, **wait_tail = &wait_head;
111 static unsigned char buf[16384];
112 static const char *name;
113
114 /*----- Utilities ---------------------------------------------------------*/
115
116 static void socketaddr(struct sockaddr_un *sun, size_t *sz)
117 {
118   size_t n = strlen(name) + 1;
119   if (n + offsetof(struct sockaddr_un, sun_path) > sizeof(*sun))
120     die(EXIT_FAILURE, "name too long: `%s'", name);
121   sun->sun_family = AF_UNIX;
122   memcpy(sun->sun_path, name, n);
123   if (sz)
124     *sz = n + offsetof(struct sockaddr_un, sun_path);
125 }
126
127 /*------ Packet queue -----------------------------------------------------*
128  *
129  * A packet queue contains a sequence of octet strings.  Packets can be added
130  * to the end and read off the front.
131  */
132
133 static void initqueue(pkq *q) { q->head = 0; q->tail = &q->head; }
134
135 static pkq_node *make_pkqnode(void *p, size_t n)
136 {
137   pkq_node *pn;
138
139   if (!n)
140     return (0);
141   pn = CREATE(pkq_node);
142   pn->next = 0;
143   pn->buf = xmalloc(n);
144   memcpy(pn->buf, p, n);
145   pn->sz = n;
146   pn->n = 0;
147   return (pn);
148 }
149
150 static int enqueue(pkq *q, pkq_node *pn)
151 {
152   int rc = 0;
153
154   if (!pn)
155     return (0);
156   rc = !q->head;
157   pn->next = 0;
158   *q->tail = pn;
159   q->tail = &pn->next;
160   return (rc);
161 }
162
163 static void destroy_pkqnode(pkq_node *pn) { xfree(pn->buf); DESTROY(pn); }
164
165 static int dequeue(pkq *q, int freep)
166 {
167   pkq_node *pn = q->head;
168   assert(pn);
169   q->head = pn->next;
170   if (freep)
171     destroy_pkqnode(pn);
172   if (!q->head) {
173     q->tail = &q->head;
174     return (1);
175   }
176   return (0);
177 }
178
179 static void destroy_pkq(pkq *q)
180 {
181   pkq_node *pn, *pnn;
182
183   for (pn = q->head; pn; pn = pnn) {
184     pnn = pn->next;
185     destroy_pkqnode(pn);
186   }
187   q->head = 0; q->tail = &q->head;
188 }
189
190 /*----- Gobblers ----------------------------------------------------------*
191  *
192  * A gobbler just eats everything it sees on its input descriptor.
193  * Eventually, when it sees end-of-file, it closes the input descriptor,
194  * calls a user-supplied calback function, and quits.
195  */
196
197 static void gobbler_close(gobbler *g)
198   { if (g->f.fd != -1) { sel_rmfile(&g->f); close(g->f.fd); g->f.fd = -1; } }
199
200 static void gobbler_destroy(gobbler *g) { gobbler_close(g); DESTROY(g); }
201
202 static void do_gobble_in(int fd, unsigned mode, void *p)
203 {
204   gobbler *g = p;
205   ssize_t n;
206
207   for (;;) {
208     n = read(fd, buf, sizeof(buf));
209     if (n < 0) {
210       if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
211         break;
212       else {
213         moan("read (gobble): %s", strerror(errno));
214         if (g->done) g->done(g, errno, g->p);
215         gobbler_close(g);
216         break;
217       }
218     } else if (n == 0) {
219       if (g->done) g->done(g, 0, g->p);
220       gobbler_close(g);
221       break;
222     }
223   }
224 }
225
226 static gobbler *make_gobbler(int fd,
227                              void (*done)(gobbler *, int, void *),
228                              void *p)
229 {
230   gobbler *g;
231
232   g = CREATE(gobbler);
233   g->done = done;
234   g->p = p;
235   sel_initfile(&sel, &g->f, fd, SEL_READ, do_gobble_in, g);
236   sel_addfile(&g->f);
237   do_gobble_in(fd, SEL_READ, g);
238   return (g);
239 }
240
241 /*----- Dribbler ----------------------------------------------------------*
242  *
243  * A dribbler hands out data from a packet queue to a file descriptor.  It
244  * makes no attempt to preserve the record boundaries inherent in the packet
245  * queue structure.  If the dribbler reaches the end of its queue, it invokes
246  * a user-supplied `done' function and stops selecting its output descriptor
247  * for writing.
248  */
249
250 static void cripple_dribbler(dribbler *d) { close(d->f.fd); d->f.fd = -1; }
251
252 static void destroy_dribbler(dribbler *d)
253   { cripple_dribbler(d); DESTROY(d); }
254
255 static void dribble_done(dribbler *d, int err)
256 {
257   if (d->q.head) {
258     sel_rmfile(&d->f);
259     destroy_pkq(&d->q);
260   }
261   d->done(d, err, d->p);
262 }
263
264 static void do_dribble_out(int fd, unsigned mode, void *p)
265 {
266   dribbler *d = p;
267   ssize_t n;
268   pkq_node *pn;
269
270   for (;;) {
271     pn = d->q.head;
272     n = write(fd, pn->buf + pn->n, pn->sz - pn->n);
273     if (n < 0) {
274       if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
275         break;
276       else {
277         dribble_done(d, errno);
278         break;
279       }
280     }
281     pn->n += n;
282     if (pn->n == pn->sz && dequeue(&d->q, 1)) {
283       sel_rmfile(&d->f);
284       dribble_done(d, 0);
285       break;
286     }
287   }
288 }
289
290 static int enqueue_dribble(dribbler *d, pkq_node *pn)
291 {
292   if (d->f.fd == -1) {
293     destroy_pkqnode(pn);
294     return (0);
295   }
296   if (enqueue(&d->q, pn)) {
297     sel_addfile(&d->f);
298     do_dribble_out(d->f.fd, SEL_WRITE, d);
299     return (1);
300   }
301   return (0);
302 }
303
304 static dribbler *make_dribbler(int fd,
305                                void (*done)(dribbler *, int, void *),
306                                void *p)
307 {
308   dribbler *d = CREATE(dribbler);
309   sel_initfile(&sel, &d->f, fd, SEL_WRITE, do_dribble_out, d);
310   initqueue(&d->q);
311   d->done = done;
312   d->p = p;
313   return (d);
314 }
315
316 /*----- Clients -----------------------------------------------------------*/
317
318 static void done_client_dribble(dribbler *d, int err, void *p)
319 {
320   if (err)
321     moan("write (client): %s", strerror(err));
322   gobbler_destroy(p);
323   destroy_dribbler(d);
324   reasons--;
325 }
326
327 static void dequeue_to_waiter(void)
328 {
329   waiter *w;
330   dribbler *d;
331   pkq_node *pn;
332
333   while (q_in.head && wait_head) {
334     w = wait_head;
335     wait_head = w->next;
336     if (!wait_head)
337       wait_tail = &wait_head;
338     d = make_dribbler(w->fd, done_client_dribble, w->g);
339     DESTROY(w);
340     pn = q_in.head;
341     if (dequeue(&q_in, 0))
342       reasons--;
343     enqueue_dribble(d, pn);
344   }
345 }
346
347 static void client_destroy(client *c)
348 {
349   sel_rmfile(&c->f);
350   close(c->f.fd);
351   dstr_destroy(&c->d);
352   reasons--;
353   DESTROY(c);
354 }
355
356 static void do_client_in(int fd, unsigned mode, void *p)
357 {
358   client *c = p;
359   ssize_t n, i, i0;
360   waiter *w;
361
362   /* --- Attention --- *
363    *
364    * The queue for outbound packets is SLIP-encoded; we need to encode it
365    * here. The queue for inbound packets is raw.
366    */
367
368   for (;;) {
369     n = read(fd, buf, sizeof(buf));
370     i0 = 0;
371     if (n < 0) {
372       if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
373         break;
374       else {
375         moan("read (client): %s", strerror(errno));
376         client_destroy(c);
377         return;
378       }
379     } else if (n == 0) {
380       if (c->mode == '>') {
381         DPUTC(&c->d, SL_END);
382         if (enqueue_dribble(dribble_out, make_pkqnode(c->d.buf, c->d.len)))
383           reasons++;
384       }
385       client_destroy(c);
386       return;
387     }
388     if (c->mode == '?') {
389       switch (buf[0]) {
390         case '>':
391           i0 = 1;
392           c->mode = '>';
393           break;
394         case '<':
395           w = CREATE(waiter);
396           w->g = make_gobbler(fd, 0, 0);
397           w->next = 0;
398           w->fd = fd;
399           *wait_tail = w;
400           wait_tail = &w->next;
401           sel_rmfile(&c->f);
402           DESTROY(c);
403           dequeue_to_waiter();
404           return;
405         default:
406           moan("bad client mode `%c'", buf[0]);
407           client_destroy(c);
408           return;
409       }
410     }
411     for (i = i0; i < n; i++) {
412       switch (buf[i]) {
413         case SL_ESC:
414           DPUTC(&c->d, SL_ESC);
415           DPUTC(&c->d, SL_ESCESC);
416           break;
417         case SL_END:
418           DPUTC(&c->d, SL_ESC);
419           DPUTC(&c->d, SL_ESCEND);
420           break;
421         default:
422           DPUTC(&c->d, buf[i]);
423           break;
424       }
425     }
426   }
427 }
428
429 static void do_accept(int fd, unsigned mode, void *hunoz)
430 {
431   client *c;
432   struct sockaddr_un sun;
433   socklen_t n = sizeof(sun);
434   int nfd;
435
436   if ((nfd = accept(fd, (struct sockaddr *)&sun, &n)) < 0) {
437     if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
438       return;
439     else
440       die(EXIT_FAILURE, "accept: %s", strerror(errno));
441   }
442   c = CREATE(client);
443   c->mode = '?';
444   dstr_create(&c->d);
445   fdflags(nfd, O_NONBLOCK, O_NONBLOCK, 0, 0);
446   sel_initfile(&sel, &c->f, nfd, SEL_READ, do_client_in, c);
447   sel_addfile(&c->f);
448   reasons++;
449 }
450
451 /*----- Main daemon -------------------------------------------------------*/
452
453 static void done_slip_dribble(dribbler *d, int err, void *p)
454 {
455   if (!err)
456     reasons--;
457   else if (err != EPIPE)
458     die(EXIT_FAILURE, "write (slip): %s", strerror(errno));
459   else
460     cripple_dribbler(d);
461 }
462
463 static void do_slip_in(int fd, unsigned mode, void *hunoz)
464 {
465   ssize_t i, n;
466
467   /* --- Attention --- *
468    *
469    * The queue for inbound packets contains raw data; we need to decode it
470    * here.  The queue for outbound packets is SLIP-encoded.
471    *
472    * TrIPE sends two empty packets on start-up, in order to resynchronize the
473    * target.  We don't need this and it messes us up.
474    */
475
476   for (;;) {
477     n = read(fd, buf, sizeof(buf));
478     if (n == 0) {
479       switch (slipstate) {
480         case SYNC1:
481         case SYNC2:
482         case START:
483         case BAD:
484           break;
485         default:
486           moan("eof found while processing packet (discarding)");
487           break;
488       }
489       close(fd);
490       sel_rmfile(&slip_in);
491       reasons--;
492       return;
493     } else if (n < 0) {
494       if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
495         break;
496       die(EXIT_FAILURE, "read (slip in): %s", strerror(errno));
497     }
498     for (i = 0; i < n; i++) {
499       switch (slipstate) {
500         case SYNC1:
501           switch (buf[i]) {
502             case SL_END:
503               slipstate = SYNC2;
504               break;
505             default:
506               goto start;
507           }
508           break;
509         case SYNC2:
510           switch (buf[i]) {
511             case SL_END:
512               slipstate = START;
513               break;
514             default:
515               goto start;
516           }
517           break;
518         case BAD:
519           switch (buf[i]) {
520             case SL_END:
521               DRESET(&slipbuf);
522               slipstate = OK;
523               break;
524             default:
525               break;
526           }
527           break;
528         case ESC:
529           switch (buf[i]) {
530             case SL_ESCEND:
531               DPUTC(&slipbuf, SL_END);
532               slipstate = OK;
533               break;
534             case SL_ESCESC:
535               DPUTC(&slipbuf, SL_ESC);
536               slipstate = OK;
537               break;
538             case SL_END:
539               moan("found escaped end byte (discard packet and resync");
540               DRESET(&slipbuf);
541               slipstate = OK;
542               break;
543             default:
544               moan("unexpected escape char 0x%02x", buf[i]);
545               slipstate = BAD;
546               break;
547           }
548           break;
549         case START:
550         case OK:
551         start:
552           switch (buf[i]) {
553             case SL_ESC:
554               slipstate = ESC;
555               break;
556             case SL_END:
557               if (enqueue(&q_in, make_pkqnode(slipbuf.buf, slipbuf.len)))
558                 reasons++;
559               DRESET(&slipbuf);
560               dequeue_to_waiter();
561               slipstate = START;
562               break;
563             default:
564               DPUTC(&slipbuf, buf[i]);
565               slipstate = OK;
566               break;
567           }
568           break;
569       }
570     }
571   }
572 }
573
574 static void slipif(void)
575 {
576   int fd;
577   dstr d = DSTR_INIT;
578   struct sockaddr_un sun;
579   size_t sz;
580
581   /* --- Make the socket --- */
582
583   if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
584     die(EXIT_FAILURE, "socket: %s", strerror(errno));
585   socketaddr(&sun, &sz);
586   if (bind(fd, (struct sockaddr *)&sun, sz))
587     die(EXIT_FAILURE, "bind: %s", strerror(errno));
588   if (listen(fd, 5))
589     die(EXIT_FAILURE, "listen: %s", strerror(errno));
590
591   /* --- Set up listeners for things --- */
592
593   fdflags(fd, O_NONBLOCK, O_NONBLOCK, 0, 0);
594   sel_initfile(&sel, &listener, fd, SEL_READ, do_accept, 0);
595   sel_addfile(&listener);
596
597   fdflags(STDIN_FILENO, O_NONBLOCK, O_NONBLOCK, 0, 0);
598   fdflags(STDOUT_FILENO, O_NONBLOCK, O_NONBLOCK, 0, 0);
599   sel_initfile(&sel, &slip_in, STDIN_FILENO, SEL_READ, do_slip_in, 0);
600   dribble_out = make_dribbler(STDOUT_FILENO, done_slip_dribble, 0);
601   sel_addfile(&slip_in);
602
603   initqueue(&q_in);
604   reasons++;
605
606   /* --- Write the interface name --- */
607
608   dstr_putf(&d, "%s-%s\n", QUIS, name);
609   if (enqueue_dribble(dribble_out, make_pkqnode(d.buf, d.len)))
610     reasons++;
611   dstr_destroy(&d);
612
613   /* --- Main loop --- */
614
615   while (reasons) {
616     if (sel_select(&sel))
617       die(EXIT_FAILURE, "select: %s", strerror(errno));
618   }
619
620   /* --- Done --- */
621
622   unlink(name);
623 }
624
625 /*----- Putting and getting -----------------------------------------------*/
626
627 static int make_sock(int mode)
628 {
629   struct sockaddr_un sun;
630   size_t sz;
631   int fd;
632   char ch;
633
634   if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
635     die(EXIT_FAILURE, "socket: %s", strerror(errno));
636   socketaddr(&sun, &sz);
637   if (connect(fd, (struct sockaddr *)&sun, sz))
638     die(EXIT_FAILURE, "connect: %s", strerror(errno));
639   ch = mode;
640   if (write(fd, &ch, 1) < 0)
641     die(EXIT_FAILURE, "write (mode): %s", strerror(errno));
642   return (fd);
643 }
644
645 static void shovel(int from, int to)
646 {
647   ssize_t n;
648   size_t sz;
649   unsigned char *p;
650
651   for (;;) {
652     n = read(from, buf, sizeof(buf));
653     if (n < 0) {
654       if (errno == EINTR)
655         continue;
656       else
657         die(EXIT_FAILURE, "read (shovel): %s", strerror(errno));
658     } else if (n == 0)
659       break;
660
661     sz = n;
662     p = buf;
663     while (sz) {
664       n = write(to, p, sz);
665       if (n < 0) {
666         if (errno == EINTR)
667           continue;
668         else
669           die(EXIT_FAILURE, "write (shovel): %s", strerror(errno));
670       }
671       p += n;
672       sz -= n;
673     }
674   }
675   close(from);
676   close(to);
677 }
678
679 static void put(void) { shovel(STDIN_FILENO, make_sock('>')); }
680 static void get(void) { shovel(make_sock('<'), STDOUT_FILENO); }
681
682 /*----- Main code ---------------------------------------------------------*/
683
684 static void usage(FILE *fp) { pquis(fp, "Usage: $ [-pg] SOCKET\n"); }
685
686 static void version(void)
687   { pquis(stdout, "$ (" PACKAGE " version " VERSION")\n"); }
688
689 static void help(void)
690 {
691   version();
692   fputc('\n', stdout);
693   usage(stdout);
694   puts("\n\
695 With no options, provides a SLIP interface for TrIPE.\n\
696 \n\
697 Options:\n\
698   -p, --put     Send packet on stdin to TrIPE.\n\
699   -g, --get     Receive packet from TrIPE and write to stdout.");
700 }
701
702 int main(int argc, char *argv[])
703 {
704   int mode = 'd';
705   int i;
706
707   ego(argv[0]);
708   for (;;) {
709     const struct option opt[] = {
710       { "help",                 0,              0,              'h' },
711       { "version",              0,              0,              'v' },
712       { "put",                  0,              0,              'p' },
713       { "get",                  0,              0,              'g' },
714       { 0,                      0,              0,              0 }
715     };
716     i = mdwopt(argc, argv, "hvpg", opt, 0, 0, 0);
717     if (i < 0)
718       break;
719     switch (i) {
720       case 'h': help(); return (0);
721       case 'v': version(); return (0);
722       case 'p': case 'g': mode = i; break;
723       default: usage(stderr); exit(EXIT_FAILURE); break;
724     }
725   }
726   if (argc - optind != 1) { usage(stderr); exit(EXIT_FAILURE); }
727   name = argv[optind];
728   signal(SIGPIPE, SIG_IGN);
729   switch (mode) {
730     case 'd': slipif(); break;
731     case 'p': put(); break;
732     case 'g': get(); break;
733   }
734   return (0);
735 }
736
737 /*----- That's all, folks -------------------------------------------------*/