Beispiel #1
0
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);
}
Beispiel #2
0
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);
        }
    }
}
Beispiel #3
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);
}
Beispiel #4
0
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;
}
Beispiel #5
0
/*       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;
}