static void proxy_init_front (proxy_t *p, char *front) { struct sockaddr_in6 ss; sockaddr_init(SA(&ss), front); p->sock_front = socket(SAFAM(&ss), SOCK_STREAM|O_NONBLOCK, 0); ASSERT(p->sock_front >= 0); int opt = 1; setsockopt(p->sock_front, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); if (0 > bind(p->sock_front, SA(&ss), SALEN(&ss))) { LOG("front(%d).bind(%s) failed", p->sock_front, front); exit(1); } LOG("front(%s) ready", front); }
static void main_init_srv (char **urlv) { int rc, opt; struct sockaddr_storage ss; for (char **pu = urlv; *pu; ++pu) { struct item_s *srv = malloc (sizeof (struct item_s)); item_init (srv); if (!sockaddr_init (SA (&ss), *pu)) abort (); srv->events = EPOLLIN; srv->type = SERVER; srv->fd = socket (SAFAM (&ss), SOCK_STREAM | O_CLOEXEC | O_NONBLOCK, 0); ASSERT (srv->fd >= 0); opt = 1; setsockopt (srv->fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)); rc = bind (srv->fd, SA (&ss), SALEN (&ss)); ASSERT (rc == 0); rc = listen (srv->fd, front_backlog); ASSERT (rc == 0); struct epoll_event evt; retry_add: evt.data.ptr = srv; evt.events = EPOLLIN; rc = epoll_ctl (fd_epoll, EPOLL_CTL_ADD, srv->fd, &evt); if (rc < 0) { if (errno == EINTR) goto retry_add; ASSERT (rc == 0); } } }
static void proxy_manage_event (proxy_t *p, uint32_t events) { struct sockaddr_in6 from, to; socklen_t slen; int rc, opt; (void) events; ASSERT(!(p->flags & FLAG_LISTED)); ASSERT(!(events & EPOLLOUT)); ASSERT(!(events & (EPOLLHUP|EPOLLERR))); if (!p->events) return; tunnel_t *t = tunnel_reserve(p); retry: slen = sizeof(from); t->front.sock = accept4(p->sock_front, SA(&from), &slen, SOCK_NONBLOCK|SOCK_CLOEXEC); if (t->front.sock < 0) { if (errno == EINTR) goto retry; ASSERT (errno == EAGAIN); tunnel_release(t); return proxy_register(p); } // The proxy front socket is maybe still active. Then instead of // systematically sending the proxy in ACTIVE, check if the limit // has been reached. It it is, re-monitor for only errors. if (p->pipes.max == ++(p->pipes.count)) proxy_pause(p); else proxy_resume(p); // Poll a backend void *buf = NULL; rc = nn_recv(p->nn_feed, &buf, NN_MSG, NN_DONTWAIT); if (rc < 0) { // TODO better manage the backend's starvation (e.g. retry) return tunnel_abort(t, "backend starvation: (%d) %s", nn_errno(), nn_strerror(nn_errno())); } else if (rc > 128) { nn_freemsg(buf); return tunnel_abort(t, "invalid backend: %s", "URL too big"); } else { char *sto = alloca(rc + 1); memcpy(sto, buf, rc); sto[rc] = 0; rc = sockaddr_init(SA(&to), sto); nn_freemsg(buf); if (!rc) return tunnel_abort(t, "invalid backend: %s", "bad URL"); char sfrom[64]; sockaddr_dump(SA(&from), sfrom, sizeof(sfrom)); ACCESS("%s -> %s", sfrom, sto); } // Connect to the polled backend t->back.sock = socket(SAFAM(&to), SOCK_STREAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0); if (t->back.sock < 0) return tunnel_abort(t, "socket() error: (%d) %s", errno, strerror(errno)); slen = sizeof(struct sockaddr_in6); rc = connect(t->back.sock, SA(&to), slen); if (0 > rc && errno != EINPROGRESS) return tunnel_abort(t, "connect() error: (%d) %s", errno, strerror(errno)); // Tweak the socket options opt = PIPE_SIZE/2; setsockopt(t->front.sock, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)); setsockopt(t->back.sock, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)); opt = PIPE_SIZE; setsockopt(t->front.sock, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)); setsockopt(t->back.sock, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)); errno = 0; tunnel_register(t); }
static const char *parse_host_port_ext(sockaddr_storage_t *sa, const char *s) { int delimeter; int family; char *p; int len; char addr_str[256]; int port; /* get delimeter character */ if ((*s < 33) || (*s > 126)) { return NULL; } delimeter = *s; s++; /* get address family */ if (*s == '1') { family = AF_INET; } #ifdef INET6 else if (*s == '2') { family = AF_INET6; } #endif else { return NULL; } s++; if (*s != delimeter) { return NULL; } s++; /* get address string */ p = strchr(s, delimeter); if (p == NULL) { return NULL; } len = p - s; if (len >= sizeof(addr_str)) { return NULL; } memcpy(addr_str, s, len); addr_str[len] = '\0'; s = p+1; /* get port */ s = parse_number(&port, s, 65535); if (s == NULL) { return NULL; } if (*s != delimeter) { return NULL; } s++; /* now parse the value passed */ #ifndef INET6 { struct in_addr in_addr; #ifdef HAVE_INET_ATON if (inet_aton(addr_str, &in_addr) == 0) { return NULL; } #else in_addr.s_addr = inet_addr(addr_str); if (in_addr.s_addr == -1) { return NULL; } #endif /* HAVE_INET_ATON */ SIN4ADDR(sa) = in_addr; } #else { struct addrinfo hints; struct *res; memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_NUMERICHOST; hints.ai_family = family; if (getaddrinfo(addr_str, NULL, &hints, &res) != 0) { return NULL; } memcpy(sa, res->ai_addr, res->ai_addrlen); freeaddrinfo(res); } #endif /* INET6 */ SAFAM(sa) = family; SINPORT(sa) = htons(port); /* return new pointer */ return s; }
/* this is okay, as long as subsequent uses VERIFY THE FAMILY first */ static const char *parse_host_port_long(sockaddr_storage_t *sa, const char *s) { int i; int family; int tmp; int addr_len; unsigned char addr[255]; int port_len; unsigned char port[255]; /* we are family */ s = parse_number(&family, s, 255); if (s == NULL) { return NULL; } if (*s != ',') { return NULL; } s++; /* parse host length */ s = parse_number(&addr_len, s, 255); if (s == NULL) { return NULL; } if (*s != ',') { return NULL; } s++; /* parse address */ for (i=0; i<addr_len; i++) { daemon_assert(i < sizeof(addr)/sizeof(addr[0])); s = parse_number(&tmp, s, 255); addr[i] = tmp; if (s == NULL) { return NULL; } if (*s != ',') { return NULL; } s++; } /* parse port length */ s = parse_number(&port_len, s, 255); if (s == NULL) { return NULL; } /* parse port */ for (i=0; i<port_len; i++) { if (*s != ',') { return NULL; } s++; daemon_assert(i < sizeof(port)/sizeof(port[0])); s = parse_number(&tmp, s, 255); port[i] = tmp; } /* okay, everything parses, load the address if possible */ if (family == 4) { SAFAM(sa) = AF_INET; if (addr_len != sizeof(struct in_addr)) { return NULL; } if (port_len != 2) { return NULL; } memcpy(&SINADDR(sa), addr, addr_len); SINPORT(sa) = htons((port[0] << 8) + port[1]); } #ifdef INET6 else if (family == 6) { SAFAM(sa) = AF_INET6; if (addr_len != sizeof(struct in6_addr)) { return NULL; } if (port_len != 2) { return NULL; } memcpy(&SIN6ADDR(sa), addr, addr_len); SINPORT(sa) = htons((port[0] << 8) + port[1]); } #endif else { SAFAM(sa) = -1; } /* return new pointer */ return s; }