X-Git-Url: https://git.distorted.org.uk/~mdw/yaid/blobdiff_plain/38b211f2a0e292153413e6edb543308f1443d0de..bf4d97617c92530ab67923aaba802333ee258352:/yaid.c diff --git a/yaid.c b/yaid.c index 4bb44fd..f70c2a3 100644 --- a/yaid.c +++ b/yaid.c @@ -31,8 +31,7 @@ /*----- Data structures ---------------------------------------------------*/ struct listen { - int af; - const char *proto; + const struct addrops *ao; sel_file f; }; @@ -76,48 +75,6 @@ static int randfd; /*----- Main code ---------------------------------------------------------*/ -static void socket_to_sockaddr(int af, const struct socket *s, - struct sockaddr *sa, size_t *ssz) -{ - sa->sa_family = af; - switch (af) { - case AF_INET: { - struct sockaddr_in *sin = (struct sockaddr_in *)sa; - sin->sin_addr = s->addr.ipv4; - sin->sin_port = htons(s->port); - *ssz = sizeof(*sin); - } break; - case AF_INET6: { - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; - sin6->sin6_addr = s->addr.ipv6; - sin6->sin6_port = htons(s->port); - sin6->sin6_flowinfo = 0; - sin6->sin6_scope_id = 0; - *ssz = sizeof(*sin6); - } break; - default: abort(); - } -} - -static void sockaddr_to_addr(const struct sockaddr *sa, union addr *a) -{ - switch (sa->sa_family) { - case AF_INET: a->ipv4 = ((struct sockaddr_in *)sa)->sin_addr; break; - case AF_INET6: a->ipv6 = ((struct sockaddr_in6 *)sa)->sin6_addr; break; - default: abort(); - } -} - -static void dputsock(dstr *d, int af, const struct socket *s) -{ - char buf[ADDRLEN]; - - inet_ntop(af, &s->addr, buf, sizeof(buf)); - if (!s->port || af != AF_INET6) dstr_puts(d, buf); - else { dstr_putc(d, '['); dstr_puts(d, buf); dstr_putc(d, ']'); } - if (s->port) dstr_putf(d, ":%d", s->port); -} - void logmsg(const struct query *q, int prio, const char *msg, ...) { va_list ap; @@ -125,9 +82,9 @@ void logmsg(const struct query *q, int prio, const char *msg, ...) va_start(ap, msg); if (q) { - dputsock(&d, q->af, &q->s[L]); + dputsock(&d, q->ao, &q->s[L]); dstr_puts(&d, " <-> "); - dputsock(&d, q->af, &q->s[R]); + dputsock(&d, q->ao, &q->s[R]); dstr_puts(&d, ": "); } dstr_vputf(&d, msg, &ap); @@ -251,6 +208,12 @@ static void reply(struct client *c, const char *ty, const char *msg) c->q.s[L].port, c->q.s[R].port, ty, msg); } +const char *const errtok[] = { +#define DEFTOK(err, tok) tok, + ERROR(DEFTOK) +#undef DEFTOK +}; + static void reply_error(struct client *c, unsigned err) { assert(err < E_LIMIT); @@ -358,7 +321,7 @@ static void proxy_connected(int fd, void *p) if (fd < 0) { logmsg(&px->c->q, LOG_ERR, "failed to make %s proxy connection to %s: %s", - px->c->l->proto, px->nat, strerror(errno)); + px->c->l->ao->name, px->nat, strerror(errno)); reply_error(px->c, E_UNKNOWN); cancel_proxy(px); return; @@ -380,33 +343,31 @@ static void proxy_query(struct client *c) struct sockaddr_storage ss; size_t ssz; struct proxy *px; - int o; int fd; px = xmalloc(sizeof(*px)); - inet_ntop(c->q.af, &c->q.u.nat.addr, px->nat, sizeof(px->nat)); + inet_ntop(c->q.ao->af, &c->q.u.nat.addr, px->nat, sizeof(px->nat)); - if ((fd = socket(c->q.af, SOCK_STREAM, 0)) < 0) { + if ((fd = socket(c->q.ao->af, SOCK_STREAM, 0)) < 0) { logmsg(&c->q, LOG_ERR, "failed to make %s socket for proxy: %s", - c->l->proto, strerror(errno)); + c->l->ao->name, strerror(errno)); goto err_0; } - if ((o = fcntl(fd, F_GETFL)) < 0 || - fcntl(fd, F_SETFL, o | O_NONBLOCK)) { + if (fdflags(fd, O_NONBLOCK, O_NONBLOCK, 0, 0)) { logmsg(&c->q, LOG_ERR, "failed to set %s proxy socket nonblocking: %s", - c->l->proto, strerror(errno)); + c->l->ao->name, strerror(errno)); goto err_1; } s = c->q.u.nat; s.port = 113; - socket_to_sockaddr(c->q.af, &s, (struct sockaddr *)&ss, &ssz); + c->l->ao->socket_to_sockaddr(&s, &ss, &ssz); selbuf_disable(&c->b); if (conn_init(&px->cn, &sel, fd, (struct sockaddr *)&ss, ssz, proxy_connected, px)) { logmsg(&c->q, LOG_ERR, "failed to make %s proxy connection to %s: %s", - c->l->proto, px->nat, strerror(errno)); + c->l->ao->name, px->nat, strerror(errno)); goto err_2; } @@ -582,28 +543,28 @@ static void accept_client(int fd, unsigned mode, void *p) if ((sk = accept(fd, (struct sockaddr *)&ssr, &ssz)) < 0) { if (errno != EAGAIN && errno == EWOULDBLOCK) { logmsg(0, LOG_ERR, "failed to accept incoming %s connection: %s", - l->proto, strerror(errno)); + l->ao->name, strerror(errno)); } return; } c = xmalloc(sizeof(*c)); c->l = l; - c->q.af = l->af; - sockaddr_to_addr((struct sockaddr *)&ssr, &c->q.s[R].addr); + c->q.ao = l->ao; + l->ao->sockaddr_to_addr(&ssr, &c->q.s[R].addr); ssz = sizeof(ssl); if (getsockname(sk, (struct sockaddr *)&ssl, &ssz)) { logmsg(0, LOG_ERR, "failed to read local address for incoming %s connection: %s", - l->proto, strerror(errno)); + l->ao->name, strerror(errno)); close(sk); xfree(c); return; } - sockaddr_to_addr((struct sockaddr *)&ssl, &c->q.s[L].addr); + l->ao->sockaddr_to_addr(&ssl, &c->q.s[L].addr); c->q.s[L].port = c->q.s[R].port = 0; - /* logmsg(&c->q, LOG_INFO, "accepted %s connection", l->proto); */ + /* logmsg(&c->q, LOG_INFO, "accepted %s connection", l->ao->name); */ selbuf_init(&c->b, &sel, sk, client_line, c); selbuf_setsize(&c->b, 1024); @@ -612,53 +573,41 @@ static void accept_client(int fd, unsigned mode, void *p) init_writebuf(&c->wb, sk, done_client_write, c); } -static int make_listening_socket(int af, int port, const char *proto) +static int make_listening_socket(const struct addrops *ao, int port) { int fd; - int o; + int yes = 1; + struct socket s; struct sockaddr_storage ss; struct listen *l; size_t ssz; - if ((fd = socket(af, SOCK_STREAM, 0)) < 0) { + if ((fd = socket(ao->af, SOCK_STREAM, 0)) < 0) { if (errno == EAFNOSUPPORT) return (-1); die(1, "failed to create %s listening socket: %s", - proto, strerror(errno)); + ao->name, strerror(errno)); } - o = 1; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &o, sizeof(o)); - ss.ss_family = af; - switch (af) { - case AF_INET: { - struct sockaddr_in *sin = (struct sockaddr_in *)&ss; - sin->sin_addr.s_addr = INADDR_ANY; - sin->sin_port = htons(port); - ssz = sizeof(*sin); - } break; - case AF_INET6: { - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss; - o = 1; setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &o, sizeof(o)); - sin6->sin6_family = AF_INET6; - sin6->sin6_addr = in6addr_any; - sin6->sin6_scope_id = 0; - sin6->sin6_flowinfo = 0; - ssz = sizeof(*sin6); - } break; - default: - abort(); + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)); + s.addr = *ao->any; + s.port = port; + ao->socket_to_sockaddr(&s, &ss, &ssz); + if (ao->init_listen_socket(fd)) { + die(1, "failed to initialize %s listening socket: %s", + ao->name, strerror(errno)); + } + if (bind(fd, (struct sockaddr *)&ss, ssz)) { + die(1, "failed to bind %s listening socket: %s", + ao->name, strerror(errno)); } - if (bind(fd, (struct sockaddr *)&ss, ssz)) - die(1, "failed to bind %s listening socket: %s", proto, strerror(errno)); - if ((o = fcntl(fd, F_GETFL)) < 0 || - fcntl(fd, F_SETFL, o | O_NONBLOCK)) { + if (fdflags(fd, O_NONBLOCK, O_NONBLOCK, 0, 0)) { die(1, "failed to set %s listening socket nonblocking: %s", - proto, strerror(errno)); + ao->name, strerror(errno)); } if (listen(fd, 5)) - die(1, "failed to listen for %s: %s", proto, strerror(errno)); + die(1, "failed to listen for %s: %s", ao->name, strerror(errno)); l = xmalloc(sizeof(*l)); - l->af = af; - l->proto = proto; + l->ao = ao; sel_initfile(&sel, &l->f, fd, SEL_READ, accept_client, l); sel_addfile(&l->f); @@ -668,6 +617,8 @@ static int make_listening_socket(int af, int port, const char *proto) int main(int argc, char *argv[]) { int port = 113; + const struct addrops *ao; + int any = 0; ego(argv[0]); @@ -685,8 +636,9 @@ int main(int argc, char *argv[]) } sel_init(&sel); - if (make_listening_socket(AF_INET, port, "IPv4") && - make_listening_socket(AF_INET6, port, "IPv6")) + for (ao = addroptab; ao->name; ao++) + if (!make_listening_socket(ao, port)) any = 1; + if (!any) die(1, "no IP protocols supported"); for (;;)