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; }
int main (int argc, char **argv) { int i, c; int pid_flags = 0; char *user = NULL; char *password = NULL; char *timeout = NULL; char *method = NULL; char *pid_path = NULL; char *conf_path = NULL; char *iface = NULL; int server_num = 0; const char *server_host[MAX_REMOTE_NUM]; const char *server_port = NULL; int dns_thread_num = DNS_THREAD_NUM; int option_index = 0; static struct option long_options[] = { {"fast-open", no_argument, 0, 0 }, {"port-start", required_argument, 0, 0 }, {"port-end", required_argument, 0, 0 }, {0, 0, 0, 0 } }; opterr = 0; while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:c:i:d:a:uv", long_options, &option_index)) != -1) { printf("option_index %d\n", option_index); switch (c) { case 0: if (option_index == 0) { #ifdef TCP_FASTOPEN fast_open = 1; LOGD("using tcp fast open"); #else LOGE("tcp fast open is not supported by this environment"); #endif } else if (option_index == 1) { start_port = atoi(optarg); } else if (option_index == 2) { end_port = atoi(optarg); } break; case 's': server_host[server_num++] = optarg; break; case 'p': server_port = optarg; break; case 'k': password = optarg; break; case 'f': pid_flags = 1; pid_path = optarg; break; case 't': timeout = optarg; break; case 'm': method = optarg; break; case 'c': conf_path = optarg; break; case 'i': iface = optarg; break; case 'd': dns_thread_num = atoi(optarg); if (!dns_thread_num) FATAL("Invalid DNS thread number"); break; case 'a': user = optarg; break; case 'u': udprelay = 1; break; case 'v': verbose = 1; break; } } printf("start %d end %d\n", start_port, end_port); if (opterr) { usage(); exit(EXIT_FAILURE); } if (conf_path != NULL) { jconf_t *conf = read_jconf(conf_path); if (server_num == 0) { server_num = conf->remote_num; for (i = 0; i < server_num; i++) { server_host[i] = conf->remote_addr[i].host; } } if (server_port == NULL) server_port = conf->remote_port; if (password == NULL) password = conf->password; if (method == NULL) method = conf->method; if (timeout == NULL) timeout = conf->timeout; #ifdef TCP_FASTOPEN if (fast_open == 0) fast_open = conf->fast_open; #endif #ifdef HAVE_SETRLIMIT if (nofile == 0) nofile = conf->nofile; /* * no need to check the return value here since we will show * the user an error message if setrlimit(2) fails */ if (nofile) { if (verbose) { LOGD("setting NOFILE to %d", nofile); } set_nofile(nofile); } #endif } if ((start_port > 0 && end_port <= 0) || (start_port <= 0 && end_port > 0)) { printf("Both start_prot and end_port needs to be specified\n"); usage(); exit(EXIT_FAILURE); } if (server_port != NULL && start_port > 0) { printf("server port can't be set if you want to use a port range\n"); usage(); exit(EXIT_FAILURE); } if (server_num == 0 || (server_port == NULL && start_port <= 0) || password == NULL) { usage(); exit(EXIT_FAILURE); } if (timeout == NULL) timeout = "60"; if (pid_flags) { USE_SYSLOG(argv[0]); daemonize(pid_path); } // ignore SIGPIPE signal(SIGPIPE, SIG_IGN); signal(SIGCHLD, SIG_IGN); signal(SIGABRT, SIG_IGN); // setup asyncns asyncns_t *asyncns; if (!(asyncns = asyncns_new(dns_thread_num))) { FATAL("asyncns failed"); } // setup keys LOGD("initialize ciphers... %s", method); int m = enc_init(password, method); // inilitialize ev loop struct ev_loop *loop = EV_DEFAULT; // inilitialize listen context struct listen_ctx listen_ctx_list[server_num + 1]; // bind to each interface while (server_num > 0) { int index = --server_num; const char* host = server_host[index]; int success = 1; int listenfd; if (start_port > 0) { server_port = itoa(start_port); } do { // Bind to port listenfd = create_and_bind(host, server_port); success = 1; if (listenfd < 0) { success = 0; } if (listen(listenfd, SOMAXCONN) == -1) { success = 0; } if (!success) { if (start_port < end_port) { start_port++; server_port = itoa(start_port); } else { FATAL("Out of listen ports!"); exit(1); } } } while (!success); setnonblocking(listenfd); LOGD("server listening at port %s.", server_port); struct listen_ctx *listen_ctx = &listen_ctx_list[index + 1]; // Setup proxy context listen_ctx->timeout = atoi(timeout); listen_ctx->asyncns = asyncns; listen_ctx->fd = listenfd; listen_ctx->method = m; listen_ctx->iface = iface; ev_io_init (&listen_ctx->io, accept_cb, listenfd, EV_READ); ev_io_start (loop, &listen_ctx->io); } // initialize the DNS struct listen_ctx *listen_ctx = &listen_ctx_list[0]; int asyncnsfd = asyncns_fd(asyncns); listen_ctx->timeout = atoi(timeout); listen_ctx->asyncns = asyncns; listen_ctx->fd = asyncnsfd; listen_ctx->method = m; listen_ctx->iface = iface; ev_io_init (&listen_ctx->io, server_resolve_cb, asyncnsfd, EV_READ); ev_io_start (loop, &listen_ctx->io); // Setup UDP if (udprelay) { LOGD("udprelay enabled."); udprelay_init(server_host[0], server_port, dns_thread_num, m, listen_ctx->timeout, iface); } // setuid if (user != NULL) run_as(user); // start ev loop ev_run (loop, 0); return 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; }
int main (int argc, char **argv) { int i, c; int pid_flags = 0; char *password = NULL; char *timeout = NULL; char *method = NULL; char *pid_path = NULL; char *conf_path = NULL; char *iface = NULL; int server_num = 0; char *server_host[MAX_REMOTE_NUM]; char *server_port = NULL; int dns_thread_num = DNS_THREAD_NUM; opterr = 0; while ((c = getopt (argc, argv, "f:s:p:l:k:t:m:c:i:d:v")) != -1) { switch (c) { case 's': server_host[server_num++] = optarg; break; case 'p': server_port = optarg; break; case 'k': password = optarg; break; case 'f': pid_flags = 1; pid_path = optarg; break; case 't': timeout = optarg; break; case 'm': method = optarg; break; case 'c': conf_path = optarg; break; case 'i': iface = optarg; break; case 'd': dns_thread_num = atoi(optarg); if (!dns_thread_num) FATAL("Invalid DNS thread number"); break; case 'v': verbose = 1; break; } } if (opterr) { usage(); exit(EXIT_FAILURE); } if (conf_path != NULL) { jconf_t *conf = read_jconf(conf_path); if (server_num == 0) { server_num = conf->remote_num; for (i = 0; i < server_num; i++) { server_host[i] = conf->remote_host[i]; } } if (server_port == NULL) server_port = conf->remote_port; if (password == NULL) password = conf->password; if (method == NULL) method = conf->method; if (timeout == NULL) timeout = conf->timeout; } if (server_num == 0 || server_port == NULL || password == NULL) { usage(); exit(EXIT_FAILURE); } if (timeout == NULL) timeout = "60"; if (pid_flags) { demonize(pid_path); } // ignore SIGPIPE signal(SIGPIPE, SIG_IGN); signal(SIGCHLD, SIG_IGN); signal(SIGABRT, SIG_IGN); // setup asyncns asyncns_t *asyncns; if (!(asyncns = asyncns_new(dns_thread_num))) { FATAL("asyncns failed"); } // setup keys LOGD("initialize cihpers... %s", method); int m = enc_init(password, method); // inilitialize ev loop struct ev_loop *loop = EV_DEFAULT; // bind to each interface while (server_num > 0) { int index = --server_num; const char* host = server_host[index]; // Bind to port int listenfd; listenfd = create_and_bind(host, server_port); if (listenfd < 0) { FATAL("bind() error.."); } if (listen(listenfd, SOMAXCONN) == -1) { FATAL("listen() error."); } setnonblocking(listenfd); LOGD("server listening at port %s.", server_port); // Setup proxy context struct listen_ctx *listen_ctx = malloc(sizeof(struct listen_ctx)); listen_ctx->timeout = atoi(timeout); listen_ctx->asyncns = asyncns; listen_ctx->fd = listenfd; listen_ctx->method = m; listen_ctx->iface = iface; ev_io_init (&listen_ctx->io, accept_cb, listenfd, EV_READ); ev_io_start (loop, &listen_ctx->io); } // start ev loop ev_run (loop, 0); return 0; }
int init_udprelay(const char *server_host, const char *server_port, #ifdef UDPRELAY_LOCAL const char *remote_host, const char *remote_port, #ifdef UDPRELAY_TUNNEL const ss_addr_t tunnel_addr, #endif #endif #ifdef UDPRELAY_REMOTE int dns_thread_num, #endif int method, int timeout, const char *iface) { // Inilitialize ev loop struct ev_loop *loop = EV_DEFAULT; // Inilitialize cache struct cache *conn_cache; cache_create(&conn_cache, MAX_UDP_CONN_NUM, free_cb); ////////////////////////////////////////////////// // Setup server context #ifdef UDPRELAY_REMOTE // setup asyncns asyncns_t *asyncns; if (!(asyncns = asyncns_new(dns_thread_num))) { FATAL("[udp] asyncns failed"); } resolve_ctx = malloc(sizeof(struct resolve_ctx)); int asyncnsfd = asyncns_fd(asyncns); ev_io_init(&resolve_ctx->io, query_resolve_cb, asyncnsfd, EV_READ); ev_io_start(loop, &resolve_ctx->io); resolve_ctx->asyncns = asyncns; resolve_ctx->asyncnsfd = asyncnsfd; #endif // Bind to port int serverfd = create_server_socket(server_host, server_port); if (serverfd < 0) { FATAL("[udp] bind() error.."); } setnonblocking(serverfd); server_ctx = new_server_ctx(serverfd); server_ctx->timeout = min(timeout, MAX_CONNECT_TIMEOUT); server_ctx->method = method; server_ctx->iface = iface; server_ctx->conn_cache = conn_cache; #ifdef UDPRELAY_LOCAL server_ctx->remote_host = remote_host; server_ctx->remote_port = remote_port; #ifdef UDPRELAY_TUNNEL server_ctx->tunnel_addr = tunnel_addr; #endif #endif #ifdef UDPRELAY_REMOTE server_ctx->asyncns = asyncns; #endif ev_io_start(loop, &server_ctx->io); return 0; }