Example #1
0
static void query_resolve_cb(EV_P_ ev_timer *watcher, int revents)
{
    int err;
    struct addrinfo *result, *rp;
    struct query_ctx *query_ctx = (struct query_ctx *)((void*)watcher);
    asyncns_t *asyncns = query_ctx->server_ctx->asyncns;
    asyncns_query_t *query = query_ctx->query;

    if (asyncns == NULL || query == NULL)
    {
        LOGE("invalid dns query.");
        close_and_free_query(EV_A_ query_ctx);
        return;
    }

    if (asyncns_wait(asyncns, 0) == -1)
    {
        // asyncns error
        FATAL("asyncns exit unexpectedly.");
    }

    if (!asyncns_isdone(asyncns, query))
    {
        // wait reolver
        return;
    }

    if (verbose)
    {
        LOGD("[udp] asyncns resolved.");
    }

    ev_timer_stop(EV_A_ watcher);

    err = asyncns_getaddrinfo_done(asyncns, query, &result);

    if (err)
    {
        ERROR("getaddrinfo");
    }
    else
    {
        // Use IPV4 address if possible
        for (rp = result; rp != NULL; rp = rp->ai_next)
        {
            if (rp->ai_family == AF_INET) break;
        }

        if (rp == NULL)
        {
            rp = result;
        }

        int remotefd = create_remote_socket(rp->ai_family == AF_INET6);
        if (remotefd != -1)
        {
            setnonblocking(remotefd);
#ifdef SO_NOSIGPIPE
            int opt = 1;
            setsockopt(remotefd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt));
#endif
#ifdef SET_INTERFACE
            if (query_ctx->server_ctx->iface)
                setinterface(remotefd, query_ctx->server_ctx->iface);
#endif

            struct remote_ctx *remote_ctx = new_remote(remotefd, query_ctx->server_ctx);
            remote_ctx->src_addr = query_ctx->src_addr;
            remote_ctx->dst_addr = *rp->ai_addr;
            remote_ctx->server_ctx = query_ctx->server_ctx;
            remote_ctx->addr_header_len = query_ctx->addr_header_len;
            memcpy(remote_ctx->addr_header, query_ctx->addr_header, query_ctx->addr_header_len);

            // Add to conn cache
            char *key = hash_key(remote_ctx->addr_header,
                                 remote_ctx->addr_header_len, &remote_ctx->src_addr);
            cache_insert(query_ctx->server_ctx->conn_cache, key, (void *)remote_ctx);

            ev_io_start(EV_A_ &remote_ctx->io);

            int s = sendto(remote_ctx->fd, query_ctx->buf, query_ctx->buf_len, 0, &remote_ctx->dst_addr, sizeof(remote_ctx->dst_addr));

            if (s == -1)
            {
                ERROR("udprelay_sendto_remote");
                close_and_free_remote(EV_A_ remote_ctx);
            }

        }
        else
        {
            ERROR("udprelay bind() error..");
        }
    }

    // clean up
    asyncns_freeaddrinfo(result);
    close_and_free_query(EV_A_ query_ctx);
}
Example #2
0
static void server_resolve_cb(EV_P_ ev_timer *watcher, int revents) {
    int err;
    struct addrinfo *result, *rp;
    struct server_ctx *server_ctx = (struct server_ctx *) (((void*)watcher)
            - sizeof(ev_io));
    struct server *server = server_ctx->server;
    asyncns_t *asyncns = server->listen_ctx->asyncns;
    asyncns_query_t *query = server->query;

    if (asyncns == NULL || query == NULL) {
        LOGE("invalid dns query.");
        close_and_free_server(EV_A_ server);
        return;
    }

    if (asyncns_wait(asyncns, 0) == -1) {
        // asyncns error
        FATAL("asyncns exit unexpectedly.");
    }

    if (!asyncns_isdone(asyncns, query)) {
        // wait for reolver
        return;
    }

    if (verbose) {
        LOGD("asyncns resolved.");
    }

    ev_timer_stop(EV_A_ watcher);

    err = asyncns_getaddrinfo_done(asyncns, query, &result);

    if (err) {
        ERROR("getaddrinfo");
        close_and_free_server(EV_A_ server);
    } else {
        // Use IPV4 address if possible
        for (rp = result; rp != NULL; rp = rp->ai_next) {
            if (rp->ai_family == AF_INET) break;
        }

        if (rp == NULL) {
            rp = result;
        }

        struct remote *remote = connect_to_remote(rp, server->listen_ctx->iface);

        if (remote == NULL) {
            LOGE("connect error.");
            close_and_free_server(EV_A_ server);
        } else {
            server->remote = remote;
            remote->server = server;

            // XXX: should handel buffer carefully
            if (server->buf_len > 0) {
                memcpy(remote->buf, server->buf + server->buf_idx, server->buf_len);
                remote->buf_len = server->buf_len;
                remote->buf_idx = 0;
                server->buf_len = 0;
                server->buf_idx = 0;
            }

            // listen to remote connected event
            ev_io_start(EV_A_ &remote->send_ctx->io);
        }
    }

    // release addrinfo
    asyncns_freeaddrinfo(result);
}
Example #3
0
int main(int argc, char *argv[]) {
    asyncns_t* asyncns = NULL;
    asyncns_query_t *q1, *q2, *q3;
    int r = 1, ret;
    struct addrinfo *ai, hints;
    struct sockaddr_in sa;
    char host[NI_MAXHOST] = "", serv[NI_MAXSERV] = "";
    unsigned char *srv;

    signal(SIGCHLD, SIG_IGN);

    if (!(asyncns = asyncns_new(2))) {
        fprintf(stderr, "asyncns_new() failed\n");
        goto fail;
    }

    /* Make a name -> address query */
    memset(&hints, 0, sizeof(hints));
    hints.ai_family = PF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;

    q1 = asyncns_getaddrinfo(asyncns, argc >= 2 ? argv[1] : "www.heise.de", NULL, &hints);

    if (!q1)
        fprintf(stderr, "asyncns_getaddrinfo(): %s\n", strerror(errno));

    /* Make an address -> name query */
    memset(&sa, 0, sizeof(sa));
    sa.sin_family = AF_INET;
    sa.sin_addr.s_addr = inet_addr(argc >= 3 ? argv[2] : "193.99.144.71");
    sa.sin_port = htons(80);

    q2 = asyncns_getnameinfo(asyncns, (struct sockaddr*) &sa, sizeof(sa), 0, 1, 1);

    if (!q2)
        fprintf(stderr, "asyncns_getnameinfo(): %s\n", strerror(errno));

    /* Make a res_query() call */
    q3 = asyncns_res_query(asyncns, "_xmpp-client._tcp.gmail.com", C_IN, T_SRV);

    if (!q3)
        fprintf(stderr, "asyncns_res_query(): %s\n", strerror(errno));

    /* Wait until the three queries are completed */
    while (!asyncns_isdone(asyncns, q1)
           || !asyncns_isdone(asyncns, q2)
           || !asyncns_isdone(asyncns, q3)) {
        if (asyncns_wait(asyncns, 1) < 0) {
            fprintf(stderr, "asyncns_wait(): %s\n", strerror(errno));
            goto fail;
        }
    }

    /* Interpret the result of the name -> addr query */
    if ((ret = asyncns_getaddrinfo_done(asyncns, q1, &ai)))
        fprintf(stderr, "error: %s %i\n", gai_strerror(ret), ret);
    else {
        struct addrinfo *i;

        for (i = ai; i; i = i->ai_next) {
            char t[256];
            const char *p = NULL;

            if (i->ai_family == PF_INET)
                p = inet_ntop(AF_INET, &((struct sockaddr_in*) i->ai_addr)->sin_addr, t, sizeof(t));
            else if (i->ai_family == PF_INET6)
                p = inet_ntop(AF_INET6, &((struct sockaddr_in6*) i->ai_addr)->sin6_addr, t, sizeof(t));

            printf("%s\n", p);
        }

        asyncns_freeaddrinfo(ai);
    }

    /* Interpret the result of the addr -> name query */
    if ((ret = asyncns_getnameinfo_done(asyncns, q2, host, sizeof(host), serv, sizeof(serv))))
        fprintf(stderr, "error: %s %i\n", gai_strerror(ret), ret);
    else
        printf("%s -- %s\n", host, serv);

    /* Interpret the result of the SRV lookup */
    if ((ret = asyncns_res_done(asyncns, q3, &srv)) < 0) {
        fprintf(stderr, "error: %s %i\n", strerror(errno), ret);
    } else if (ret == 0) {
        fprintf(stderr, "No reply for SRV lookup\n");
    } else {
        int qdcount;
        int ancount;
        int len;
        const unsigned char *pos = srv + sizeof(HEADER);
        unsigned char *end = srv + ret;
        HEADER *head = (HEADER *)srv;
        char name[256];

        qdcount = ntohs(head->qdcount);
        ancount = ntohs(head->ancount);

        printf("%d answers for srv lookup:\n", ancount);

        /* Ignore the questions */
        while (qdcount-- > 0 && (len = dn_expand(srv, end, pos, name, 255)) >= 0) {
            assert(len >= 0);
            pos += len + QFIXEDSZ;
        }

        /* Parse the answers */
        while (ancount-- > 0 && (len = dn_expand(srv, end, pos, name, 255)) >= 0) {
            /* Ignore the initial string */
            uint16_t pref, weight, port;
            assert(len >= 0);
            pos += len;
            /* Ignore type, ttl, class and dlen */
            pos += 10;

            GETSHORT(pref, pos);
            GETSHORT(weight, pos);
            GETSHORT(port, pos);
            len = dn_expand(srv, end, pos, name, 255);
            printf("\tpreference: %2d weight: %2d port: %d host: %s\n",
                   pref, weight, port, name);

            pos += len;
        }

        asyncns_freeanswer(srv);
    }

    r = 0;

fail:

    if (asyncns)
        asyncns_free(asyncns);

    return r;
}
Example #4
0
int
main(int argc, char **argv)
{
	asyncns_t *asyncns;
	asyncns_query_t *query;
	struct addrinfo *result;
	struct pollfd pollfd = { .events = POLLIN };
	int status;

	asyncns = asyncns_new(10);
	assert(asyncns);
	assert(asyncns_getnqueries(asyncns) == 0);
	assert(asyncns_getnext(asyncns) == NULL);

	pollfd.fd = asyncns_fd(asyncns);
	assert(pollfd.fd > 2);

	query = asyncns_getaddrinfo(asyncns, "127.0.0.1", NULL, NULL);
	assert(query);
	assert(asyncns_getnqueries(asyncns) == 1);
	assert(asyncns_getnext(asyncns) == NULL);

	asyncns_cancel(asyncns, query);
	query = NULL;
	assert(asyncns_getnqueries(asyncns) == 0);
	assert(asyncns_getnext(asyncns) == NULL);

	query = asyncns_getaddrinfo(asyncns, "127.0.0.1", NULL, NULL);
	assert(query);
	assert(asyncns_getnqueries(asyncns) == 1);
	assert(asyncns_getnext(asyncns) == NULL);

	usleep(100000);
	status = poll(&pollfd, 1, 0);
	assert(status == 1);
	status = asyncns_wait(asyncns, 0);
	assert(status == 0);
	assert(asyncns_isdone(asyncns, query));
	assert(asyncns_getnqueries(asyncns) == 1);
	assert(asyncns_getnext(asyncns) == query);

	status = poll(&pollfd, 1, 100);
	assert(status == 0);

	status = asyncns_getaddrinfo_done(asyncns, query, &result);
	assert(asyncns_getnqueries(asyncns) == 0);

	/* Intuitively, this should not be needed but the docs state that
	 * a call to `asyncns_wait()` is necessary so that `asyncns_getnext()`
	 * provides meaningful results.
	 */
	status = asyncns_wait(asyncns, 0);
	assert(status == 0);

	/* There were two queries issued, one of which has been cancelled
	 * and the other has been freed afterwards. As none of them can be
	 * returned, the only meaningful result of `asyncns_getnext()` is
	 * NULL.
	 */
	assert(asyncns_getnext(asyncns) == NULL);

	asyncns_free(asyncns);
	asyncns_freeaddrinfo(result);

	return EXIT_SUCCESS;
}