int main(int argc, char *argv[]) { static struct WSAData wsa_state; TCHAR *c, stunnel_exe_path[MAX_PATH]; /* set current working directory and engine path */ GetModuleFileName(0, stunnel_exe_path, MAX_PATH); c=_tcsrchr(stunnel_exe_path, TEXT('\\')); /* last backslash */ if(c) /* found */ c[1]=TEXT('\0'); /* truncate program name */ #ifndef _WIN32_WCE if(!SetCurrentDirectory(stunnel_exe_path)) { /* log to stderr, as s_log() is not initialized */ _ftprintf(stderr, TEXT("Cannot set directory to %s"), stunnel_exe_path); return 1; } #endif _tputenv_s(TEXT("OPENSSL_ENGINES"), stunnel_exe_path); str_init(); /* initialize per-thread string management */ if(WSAStartup(MAKEWORD(1, 1), &wsa_state)) return 1; resolver_init(); main_init(); if(!main_configure(argc>1 ? argv[1] : NULL, argc>2 ? argv[2] : NULL)) daemon_loop(); main_cleanup(); return 0; }
static gint sock_connect_by_hostname(gint sock, const gchar *hostname, gushort port) { struct hostent *hp; struct sockaddr_in ad; resolver_init(); memset(&ad, 0, sizeof(ad)); ad.sin_family = AF_INET; ad.sin_port = htons(port); if (!my_inet_aton(hostname, &ad.sin_addr)) { if ((hp = my_gethostbyname(hostname)) == NULL) { fprintf(stderr, "%s: unknown host.\n", hostname); errno = 0; return -1; } if (hp->h_length != 4 && hp->h_length != 8) { fprintf(stderr, "illegal address length received for host %s\n", hostname); errno = 0; return -1; } memcpy(&ad.sin_addr, hp->h_addr, hp->h_length); } return sock_connect_with_timeout(sock, (struct sockaddr *)&ad, sizeof(ad), io_timeout); }
/* try to load winsock2 resolver functions from a specified dll name */ NOEXPORT int initialize_winsock() { static struct WSAData wsa_state; if(WSAStartup(MAKEWORD( 2, 2 ), &wsa_state)) { message_box(TEXT("Failed to initialize winsock"), MB_ICONERROR); return 1; /* error */ } resolver_init(); return 0; /* IPv4 detected -> OK */ }
static SockDesc sock_connect_by_getaddrinfo(const gchar *hostname, gushort port) { SockDesc sock = INVALID_SOCKET; gint gai_error; struct addrinfo hints, *res, *ai; gchar port_str[6]; resolver_init(); memset(&hints, 0, sizeof(hints)); /* hints.ai_flags = AI_CANONNAME; */ hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; /* convert port from integer to string. */ g_snprintf(port_str, sizeof(port_str), "%d", port); if ((gai_error = getaddrinfo(hostname, port_str, &hints, &res)) != 0) { fprintf(stderr, "getaddrinfo for %s:%s failed: %s\n", hostname, port_str, gai_strerror(gai_error)); return INVALID_SOCKET; } for (ai = res; ai != NULL; ai = ai->ai_next) { sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (!SOCKET_IS_VALID(sock)) continue; sock_set_buffer_size(sock); if (sock_connect_with_timeout (sock, ai->ai_addr, ai->ai_addrlen, io_timeout) == 0) break; fd_close(sock); } if (res != NULL) freeaddrinfo(res); if (ai == NULL) return INVALID_SOCKET; return sock; }
void consumer_start(void *arg) { uv_loop_t loop; struct server_context *server = arg; #ifndef CROSS_COMPILE char name[24] = {0}; sprintf(name, "consumer-%d", server->index + 1); pthread_setname_np(pthread_self(), name); #endif uv_loop_init(&loop); struct resolver_context *res = NULL; if (server->nameserver_num >= 0) { res = resolver_init(&loop, 0, server->nameserver_num == 0 ? NULL : server->nameservers, server->nameserver_num); loop.data = res; } tcp_bind(&loop, server); if (server->udprelay) { udprelay_start(&loop, server); } uv_run(&loop, UV_RUN_DEFAULT); close_loop(&loop); if (server->nameserver_num >= 0) { resolver_destroy(res); } uv_sem_post(&server->semaphore); }
int main(int argc, char *argv[]) { int rc; uv_loop_t *loop; struct sockaddr local_addr; parse_opts(argc, argv); #ifndef _WIN32 if (xsignal) { return signal_process(xsignal, pidfile); } if (!password) { print_usage(argv[0]); return 1; } #endif #ifndef _WIN32 if (daemon_mode) { if (daemonize()) { return 1; } if (already_running(pidfile)) { logger_stderr("xsocksd already running."); return 1; } } #endif init(); loop = uv_default_loop(); rc = resolve_addr(local_addrbuf, &local_addr); if (rc) { logger_stderr("invalid local address"); return 1; } if (udprelay) { udprelay_init(); } if (concurrency <= 1) { struct server_context ctx; ctx.local_addr = &local_addr; ctx.udprelay = udprelay; ctx.resolver = 1; ctx.udp_fd = create_socket(SOCK_DGRAM, 0); uv_tcp_init(loop, &ctx.tcp); rc = uv_tcp_bind(&ctx.tcp, &local_addr, 0); if (rc) { logger_stderr("tcp bind error: %s", uv_strerror(rc)); return 1; } rc = uv_listen((uv_stream_t*)&ctx.tcp, 128, client_accept_cb); if (rc == 0) { logger_log(LOG_INFO, "listening on %s", local_addrbuf); #ifndef _WIN32 setup_signal(loop, signal_cb, &ctx); #endif struct resolver_context *dns = resolver_init(loop, MODE_IPV4, nameserver_num == 0 ? NULL : nameservers, nameserver_num); uv_key_set(&thread_resolver_key, dns); if (udprelay) { udprelay_start(loop, &ctx); } uv_run(loop, UV_RUN_DEFAULT); close_loop(loop); resolver_destroy(dns); } else { logger_stderr("listen error: %s", uv_strerror(rc)); } } else { #ifndef _WIN32 struct server_context *servers = calloc(concurrency, sizeof(servers[0])); for (int i = 0; i < concurrency; i++) { struct server_context *ctx = servers + i; ctx->index = i; ctx->tcp_fd = create_socket(SOCK_STREAM, 1); ctx->udp_fd = create_socket(SOCK_DGRAM, 1); ctx->udprelay = udprelay; ctx->resolver = 1; ctx->accept_cb = client_accept_cb; ctx->nameservers = nameservers; ctx->nameserver_num = nameserver_num; ctx->local_addr = &local_addr; rc = uv_sem_init(&ctx->semaphore, 0); rc = uv_thread_create(&ctx->thread_id, consumer_start, ctx); } logger_log(LOG_INFO, "listening on %s", local_addrbuf); setup_signal(loop, signal_cb, servers); uv_run(loop, UV_RUN_DEFAULT); close_loop(loop); for (int i = 0; i < concurrency; i++) { uv_sem_wait(&servers[i].semaphore); } free(servers); #else logger_stderr("don't support multithreading."); return 1; #endif } if (udprelay) { udprelay_destroy(); } uv_key_delete(&thread_resolver_key); #ifndef _WIN32 if (daemon_mode) { delete_pidfile(pidfile); } #endif logger_exit(); return 0; }
/****************************************************************************** * This is the mail loop when running over sockets, receiving packets and * sending responses. ******************************************************************************/ void sockets_thread(struct Core *conf) { int err; SOCKET fd; struct sockaddr_in6 sin; static const unsigned port = 53; /* * This software obtains its speed by bypassing the operating system * stack. Thus, running on top of 'sockets' is going to be a lot * slower */ fprintf(stderr, "WARNING: running in slow 'sockets' mode\n"); /* * Legacy Windows is legacy. */ #if defined(WIN32) {WSADATA x; WSAStartup(0x201, &x);} #endif /* * Create a socket for incoming UDP packets. By specifying IPv6, we are * actually going to allow both IPv4 and IPv6. */ fd = socket(AF_INET6, SOCK_DGRAM, 0); if (fd <= 0) { LOG(0, "FAIL: couldn't create socket %u\n", WSAGetLastError()); return; } /* * Set the 'reuse' feature of the socket, otherwise restarting the process * requires a wait before binding back to the same port number */ { int on = 1; err = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&on,sizeof(on)); if (err < 0) { perror("setsockopt(SO_REUSEADDR) failed"); exit(1); } } /* * Enable both IPv4 and IPv6 to be used on the same sockets. This appears to * be needed for Windows, but not needed for Mac OS X. */ { int on = 0; err = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&on, sizeof(on)); if (err < 0) { perror("setsockopt(IPV6_V6ONLY) failed"); exit(1); } } /* * Listen on any IPv4 or IPv6 address in the system */ memset(&sin, 0, sizeof(sin)); sin.sin6_family = AF_INET6; sin.sin6_addr = in6addr_any; sin.sin6_port = htons(port); err = bind(fd, (struct sockaddr*)&sin, sizeof(sin)); if (err) { switch (WSAGetLastError()) { case WSA(EACCES): LOG(0, "FAIL: couldn't bind to port %u: %s\n", port, "access denied"); if (port <= 1024) LOG(0, " hint... need to be root for ports below 1024\n"); break; case WSA(EADDRINUSE): LOG(0, "FAIL: couldn't bind to port %u: %s\n", port, "address in use"); LOG(0, " hint... some other server is running on that port\n"); break; default: LOG(0, "FAIL: couldn't bind to port %u: %u\n", port, WSAGetLastError()); } exit(1); } else { fprintf(stderr, "UDP port: %u\n", port); } /* * Sit in loop processing incoming UDP packets */ for (;;) { unsigned char buf[2048]; int bytes_received; socklen_t sizeof_sin = sizeof(sin); struct DNS_Incoming request[1]; struct DNS_OutgoingResponse response[1]; struct Packet pkt; unsigned char buf2[2048]; /* * 1. receive 'packet' */ bytes_received = recvfrom(fd, (char*)buf, sizeof(buf), 0, (struct sockaddr*)&sin, &sizeof_sin); if (bytes_received == 0) continue; /* * 2. parse 'packet' into a 'request' */ proto_dns_parse(request, buf, 0, bytes_received); if (!request->is_valid) continue; /* * 3. resolve 'request' into a 'repsonse' */ resolver_init(response, request->query_name.name, request->query_name.length, request->query_type, request->id, request->opcode); resolver_algorithm(conf->db, response, request); /* * 4. format the 'response' into a 'packet' */ pkt.buf = buf2; pkt.max = sizeof(buf2); pkt.offset = 0; dns_format_response(response, &pkt); /* * 5. Transmit the 'packet' */ if (pkt.offset < pkt.max) { sendto(fd, (char*)pkt.buf, pkt.offset, 0, (struct sockaddr*)&sin, sizeof_sin); } } }
static void thread_worker(void *p) { struct CoreWorkerThread *t = (struct CoreWorkerThread *)p; struct Core *core = t->core; while (!t->should_end) { unsigned i; struct CoreSocketSet *sockets; fd_set readfds; int nfds = 0; int x; struct timeval ts; /* [SYNCHRONIZATION POINT] * mark the fact we are using the new socket-set */ sockets = (struct CoreSocketSet *)core->socket_run; t->loop_count++; /* During startup, the sockets argument may be NULL for a time. * if that's the case, then just wait for a little bit, and try * again */ if (sockets == NULL) { /* Sleep for a 10th of a second */ pixie_mssleep(10); continue; } /* * See if there are any packets waiting */ FD_ZERO(&readfds); for (i=0; i<sockets->count; i++) { FD_SET(sockets->list[i].fd, &readfds); if (nfds < sockets->list[i].fd) nfds = sockets->list[i].fd; } ts.tv_sec = 0; ts.tv_usec = 1000; /* one millisecond */ x = select(nfds, &readfds, 0, 0, &ts); if (x < 0) { LOG_ERR(C_NETWORK, "select() returned error %u\n", WSAGetLastError()); pixie_mssleep(1000); /* at this point, the errors are probably unrecoverable * until the system is manually reconfigured */ continue; } if (x == 0) continue; /* nothing found */ /* * Process any packets that have arrived */ for (i=0; i<sockets->count; i++) { struct sockaddr_storage sin; socklen_t sizeof_sin = sizeof(sin); unsigned char buf[2048]; unsigned char buf2[2048]; int bytes_received; struct DNS_Incoming request[1]; struct DNS_OutgoingResponse response[1]; struct Packet pkt; int fd; fd = sockets->list[i].fd; if (!FD_ISSET(fd, &readfds)) continue; /* * 1. receive 'packet' */ bytes_received = recvfrom(fd, (char*)buf, sizeof(buf), 0, (struct sockaddr*)&sin, &sizeof_sin); if (bytes_received == 0) continue; /* * 2. parse 'packet' into a 'request' */ proto_dns_parse(request, buf, 0, bytes_received); if (!request->is_valid) continue; /* * 3. resolve 'request' into a 'repsonse' */ resolver_init(response, request->query_name.name, request->query_name.length, request->query_type, request->id, request->opcode); resolver_algorithm(core->db_run, response, request); /* * 4. format the 'response' into a 'packet' */ pkt.buf = buf2; pkt.max = sizeof(buf2); pkt.offset = 0; dns_format_response(response, &pkt); /* * 5. Transmit the 'packet' */ if (pkt.offset < pkt.max) { sendto(fd, (char*)pkt.buf, pkt.offset, 0, (struct sockaddr*)&sin, sizeof_sin); } } } }
static SockLookupData *sock_get_address_info_async(const gchar *hostname, gushort port, SockAddrFunc func, gpointer data) { SockLookupData *lookup_data = NULL; gint pipe_fds[2]; pid_t pid; resolver_init(); if (pipe(pipe_fds) < 0) { perror("pipe"); func(NULL, data); return NULL; } if ((pid = fork()) < 0) { perror("fork"); func(NULL, data); return NULL; } /* child process */ if (pid == 0) { #ifdef INET6 gint gai_err; struct addrinfo hints, *res, *ai; gchar port_str[6]; #else /* !INET6 */ struct hostent *hp; gchar **addr_list_p; struct sockaddr_in ad; #endif /* INET6 */ gint ai_member[4] = {AF_UNSPEC, 0, 0, 0}; close(pipe_fds[0]); #ifdef INET6 memset(&hints, 0, sizeof(hints)); /* hints.ai_flags = AI_CANONNAME; */ hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; g_snprintf(port_str, sizeof(port_str), "%d", port); gai_err = getaddrinfo(hostname, port_str, &hints, &res); if (gai_err != 0) { g_warning("getaddrinfo for %s:%s failed: %s\n", hostname, port_str, gai_strerror(gai_err)); fd_write_all(pipe_fds[1], (gchar *)ai_member, sizeof(ai_member)); close(pipe_fds[1]); _exit(1); } for (ai = res; ai != NULL; ai = ai->ai_next) { ai_member[0] = ai->ai_family; ai_member[1] = ai->ai_socktype; ai_member[2] = ai->ai_protocol; ai_member[3] = ai->ai_addrlen; fd_write_all(pipe_fds[1], (gchar *)ai_member, sizeof(ai_member)); fd_write_all(pipe_fds[1], (gchar *)ai->ai_addr, ai->ai_addrlen); } if (res != NULL) freeaddrinfo(res); #else /* !INET6 */ hp = my_gethostbyname(hostname); if (hp == NULL || hp->h_addrtype != AF_INET) { fd_write_all(pipe_fds[1], (gchar *)ai_member, sizeof(ai_member)); close(pipe_fds[1]); _exit(1); } ai_member[0] = AF_INET; ai_member[1] = SOCK_STREAM; ai_member[2] = IPPROTO_TCP; ai_member[3] = sizeof(ad); memset(&ad, 0, sizeof(ad)); ad.sin_family = AF_INET; ad.sin_port = htons(port); for (addr_list_p = hp->h_addr_list; *addr_list_p != NULL; addr_list_p++) { memcpy(&ad.sin_addr, *addr_list_p, hp->h_length); fd_write_all(pipe_fds[1], (gchar *)ai_member, sizeof(ai_member)); fd_write_all(pipe_fds[1], (gchar *)&ad, sizeof(ad)); } #endif /* INET6 */ close(pipe_fds[1]); _exit(0); } else { close(pipe_fds[1]); lookup_data = g_new0(SockLookupData, 1); lookup_data->hostname = g_strdup(hostname); lookup_data->child_pid = pid; lookup_data->func = func; lookup_data->data = data; lookup_data->channel = g_io_channel_unix_new(pipe_fds[0]); lookup_data->io_tag = g_io_add_watch (lookup_data->channel, G_IO_IN, sock_get_address_info_async_cb, lookup_data); } return lookup_data; }