3 * A simple SLIP implementation drivable from the command-line
5 * (c) 2008 Straylight/Edgeware
8 /*----- Licensing notice --------------------------------------------------*
10 * This file is part of Trivial IP Encryption (TrIPE).
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.
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.
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.
27 /*----- Header files ------------------------------------------------------*/
39 #include <sys/types.h>
43 #include <sys/socket.h>
45 #include <netinet/in.h>
46 #include <arpa/inet.h>
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>
62 /*----- Data structures ---------------------------------------------------*/
64 typedef struct pkq_node {
65 struct pkq_node *next;
71 pkq_node *head, **tail;
74 enum { START, OK, ESC, BAD, SYNC1, SYNC2 };
76 typedef struct client {
82 typedef struct gobbler {
86 typedef struct dribbler {
89 void (*done)(struct dribbler *, int, void *);
93 typedef struct waiter {
99 /*----- Static variables --------------------------------------------------*/
102 static dribbler *dribble_out;
103 static dstr slipbuf = DSTR_INIT;
104 static int slipstate = SYNC1;
105 static sel_file slip_in, listener;
106 static sel_state sel;
107 static unsigned reasons;
108 static waiter *wait_head, **wait_tail = &wait_head;
109 static unsigned char buf[16384];
110 static const char *name;
112 /*----- Utilities ---------------------------------------------------------*/
114 static void socketaddr(struct sockaddr_un *sun, size_t *sz)
116 size_t n = strlen(name) + 1;
117 if (n + offsetof(struct sockaddr_un, sun_path) > sizeof(*sun))
118 die(EXIT_FAILURE, "name too long: `%s'", name);
119 sun->sun_family = AF_UNIX;
120 memcpy(sun->sun_path, name, n);
122 *sz = n + offsetof(struct sockaddr_un, sun_path);
125 /*------ Packet queue -----------------------------------------------------*
127 * A packet queue contains a sequence of octet strings. Packets can be added
128 * to the end and read off the front.
131 static void initqueue(pkq *q) { q->head = 0; q->tail = &q->head; }
133 static pkq_node *make_pkqnode(void *p, size_t n)
139 pn = CREATE(pkq_node);
141 pn->buf = xmalloc(n);
142 memcpy(pn->buf, p, n);
148 static int enqueue(pkq *q, pkq_node *pn)
161 static void destroy_pkqnode(pkq_node *pn) { xfree(pn->buf); DESTROY(pn); }
163 static int dequeue(pkq *q, int freep)
165 pkq_node *pn = q->head;
177 static void destroy_pkq(pkq *q)
181 for (pn = q->head; pn; pn = pnn) {
185 q->head = 0; q->tail = &q->head;
188 /*----- Gobblers ----------------------------------------------------------*
190 * A gobbler just eats everything it sees on its input descriptor.
191 * Eventually, when it sees end-of-file, it closes the input descriptor and
195 static void gobbler_close(gobbler *g)
196 { if (g->f.fd != -1) { sel_rmfile(&g->f); g->f.fd = -1; } }
198 static void gobbler_destroy(gobbler *g) { gobbler_close(g); DESTROY(g); }
200 static void do_gobble_in(int fd, unsigned mode, void *p)
206 n = read(fd, buf, sizeof(buf));
208 if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
211 moan("read (gobble): %s", strerror(errno));
222 static gobbler *make_gobbler(int fd)
227 sel_initfile(&sel, &g->f, fd, SEL_READ, do_gobble_in, g);
229 do_gobble_in(fd, SEL_READ, g);
233 /*----- Dribbler ----------------------------------------------------------*
235 * A dribbler hands out data from a packet queue to a file descriptor. It
236 * makes no attempt to preserve the record boundaries inherent in the packet
237 * queue structure. If the dribbler reaches the end of its queue, it invokes
238 * a user-supplied `done' function and stops selecting its output descriptor
242 static void cripple_dribbler(dribbler *d) { close(d->f.fd); d->f.fd = -1; }
244 static void destroy_dribbler(dribbler *d)
245 { cripple_dribbler(d); DESTROY(d); }
247 static void dribble_done(dribbler *d, int err)
253 d->done(d, err, d->p);
256 static void do_dribble_out(int fd, unsigned mode, void *p)
264 n = write(fd, pn->buf + pn->n, pn->sz - pn->n);
266 if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
269 dribble_done(d, errno);
274 if (pn->n == pn->sz && dequeue(&d->q, 1)) {
282 static int enqueue_dribble(dribbler *d, pkq_node *pn)
288 if (enqueue(&d->q, pn)) {
290 do_dribble_out(d->f.fd, SEL_WRITE, d);
296 static dribbler *make_dribbler(int fd,
297 void (*done)(dribbler *, int, void *),
300 dribbler *d = CREATE(dribbler);
301 sel_initfile(&sel, &d->f, fd, SEL_WRITE, do_dribble_out, d);
308 /*----- Clients -----------------------------------------------------------*/
310 static void done_client_dribble(dribbler *d, int err, void *p)
313 moan("write (client): %s", strerror(err));
319 static void dequeue_to_waiter(void)
325 while (q_in.head && wait_head) {
329 wait_tail = &wait_head;
330 d = make_dribbler(w->fd, done_client_dribble, w->g);
333 if (dequeue(&q_in, 0))
335 enqueue_dribble(d, pn);
339 static void client_destroy(client *c)
348 static void do_client_in(int fd, unsigned mode, void *p)
354 /* --- Attention --- *
356 * The queue for outbound packets is SLIP-encoded; we need to encode it
357 * here. The queue for inbound packets is raw.
361 n = read(fd, buf, sizeof(buf));
364 if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
367 moan("read (client): %s", strerror(errno));
372 if (c->mode == '>') {
373 DPUTC(&c->d, SL_END);
374 if (enqueue_dribble(dribble_out, make_pkqnode(c->d.buf, c->d.len)))
380 if (c->mode == '?') {
388 w->g = make_gobbler(fd);
392 wait_tail = &w->next;
398 moan("bad client mode `%c'", buf[0]);
403 for (i = i0; i < n; i++) {
406 DPUTC(&c->d, SL_ESC);
407 DPUTC(&c->d, SL_ESCESC);
410 DPUTC(&c->d, SL_ESC);
411 DPUTC(&c->d, SL_ESCEND);
414 DPUTC(&c->d, buf[i]);
421 static void do_accept(int fd, unsigned mode, void *hunoz)
424 struct sockaddr_un sun;
425 socklen_t n = sizeof(sun);
428 if ((nfd = accept(fd, (struct sockaddr *)&sun, &n)) < 0) {
429 if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
432 die(EXIT_FAILURE, "accept: %s", strerror(errno));
437 fdflags(nfd, O_NONBLOCK, O_NONBLOCK, 0, 0);
438 sel_initfile(&sel, &c->f, nfd, SEL_READ, do_client_in, c);
443 /*----- Main daemon -------------------------------------------------------*/
445 static void done_slip_dribble(dribbler *d, int err, void *p)
449 else if (err != EPIPE)
450 die(EXIT_FAILURE, "write (slip): %s", strerror(errno));
455 static void do_slip_in(int fd, unsigned mode, void *hunoz)
459 /* --- Attention --- *
461 * The queue for inbound packets contains raw data; we need to decode it
462 * here. The queue for outbound packets is SLIP-encoded.
464 * TrIPE sends two empty packets on start-up, in order to resynchronize the
465 * target. We don't need this and it messes us up.
469 n = read(fd, buf, sizeof(buf));
478 moan("eof found while processing packet (discarding)");
482 sel_rmfile(&slip_in);
486 if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
488 die(EXIT_FAILURE, "read (slip in): %s", strerror(errno));
490 for (i = 0; i < n; i++) {
523 DPUTC(&slipbuf, SL_END);
526 DPUTC(&slipbuf, SL_ESC);
529 moan("found escaped end byte (discard packet and resync");
534 moan("unspected escape char 0x%02x", buf[i]);
547 if (enqueue(&q_in, make_pkqnode(slipbuf.buf, slipbuf.len)))
554 DPUTC(&slipbuf, buf[i]);
564 static void slipif(void)
568 struct sockaddr_un sun;
571 /* --- Make the socket --- */
573 if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
574 die(EXIT_FAILURE, "socket: %s", strerror(errno));
575 socketaddr(&sun, &sz);
576 if (bind(fd, (struct sockaddr *)&sun, sz))
577 die(EXIT_FAILURE, "bind: %s", strerror(errno));
579 die(EXIT_FAILURE, "listen: %s", strerror(errno));
581 /* --- Set up listeners for things --- */
583 fdflags(fd, O_NONBLOCK, O_NONBLOCK, 0, 0);
584 sel_initfile(&sel, &listener, fd, SEL_READ, do_accept, 0);
585 sel_addfile(&listener);
587 fdflags(STDIN_FILENO, O_NONBLOCK, O_NONBLOCK, 0, 0);
588 fdflags(STDOUT_FILENO, O_NONBLOCK, O_NONBLOCK, 0, 0);
589 sel_initfile(&sel, &slip_in, STDIN_FILENO, SEL_READ, do_slip_in, 0);
590 dribble_out = make_dribbler(STDOUT_FILENO, done_slip_dribble, 0);
591 sel_addfile(&slip_in);
596 /* --- Write the interface name --- */
598 dstr_putf(&d, "%s-%s\n", QUIS, name);
599 if (enqueue_dribble(dribble_out, make_pkqnode(d.buf, d.len)))
603 /* --- Main loop --- */
606 if (sel_select(&sel))
607 die(EXIT_FAILURE, "select: %s", strerror(errno));
615 /*----- Putting and getting -----------------------------------------------*/
617 static int make_sock(int mode)
619 struct sockaddr_un sun;
624 if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
625 die(EXIT_FAILURE, "socket: %s", strerror(errno));
626 socketaddr(&sun, &sz);
627 if (connect(fd, (struct sockaddr *)&sun, sz))
628 die(EXIT_FAILURE, "connect: %s", strerror(errno));
630 if (write(fd, &ch, 1) < 0)
631 die(EXIT_FAILURE, "write (mode): %s", strerror(errno));
635 static void shovel(int from, int to)
642 n = read(from, buf, sizeof(buf));
647 die(EXIT_FAILURE, "read (shovel): %s", strerror(errno));
654 n = write(to, p, sz);
659 die(EXIT_FAILURE, "write (shovel): %s", strerror(errno));
669 static void put(void) { shovel(STDIN_FILENO, make_sock('>')); }
670 static void get(void) { shovel(make_sock('<'), STDOUT_FILENO); }
672 /*----- Main code ---------------------------------------------------------*/
674 static void usage(FILE *fp) { pquis(fp, "Usage: $ [-pg] SOCKET\n"); }
676 static void version(void)
677 { pquis(stdout, "$ (" PACKAGE " version " VERSION")\n"); }
679 static void help(void)
685 With no options, provides a SLIP interface for TrIPE.\n\
688 -p, --put Send packet on stdin to TrIPE.\n\
689 -g, --get Receive packet from TrIPE and write to stdout.");
692 int main(int argc, char *argv[])
699 const struct option opt[] = {
700 { "help", 0, 0, 'h' },
701 { "version", 0, 0, 'v' },
702 { "put", 0, 0, 'p' },
703 { "get", 0, 0, 'g' },
706 i = mdwopt(argc, argv, "hvpg", opt, 0, 0, 0);
710 case 'h': help(); return (0);
711 case 'v': version(); return (0);
712 case 'p': case 'g': mode = i; break;
713 default: usage(stderr); exit(EXIT_FAILURE); break;
716 if (argc - optind != 1) { usage(stderr); exit(EXIT_FAILURE); }
718 signal(SIGPIPE, SIG_IGN);
720 case 'd': slipif(); break;
721 case 'p': put(); break;
722 case 'g': get(); break;
727 /*----- That's all, folks -------------------------------------------------*/