/** handle is_signal events and see if signalled */ static void _getdns_handle_signal(struct _getdns_event* ev) { DWORD ret; //log_assert(ev->is_signal && ev->hEvent); /* see if the event is signalled */ ret = WSAWaitForMultipleEvents(1, &ev->hEvent, 0 /* any object */, 0 /* return immediately */, 0 /* not alertable for IOcomple*/); if(ret == WSA_WAIT_IO_COMPLETION || ret == WSA_WAIT_FAILED) { log_err("getdns: WSAWaitForMultipleEvents(signal) failed: %s", wsa_strerror(WSAGetLastError())); return; } if(ret == WSA_WAIT_TIMEOUT) { /* not signalled */ return; } /* reset the signal */ if(!WSAResetEvent(ev->hEvent)) log_err("getdns: WSAResetEvent failed: %s", wsa_strerror(WSAGetLastError())); /* do the callback (which may set the signal again) */ fptr_ok(fptr_whitelist_event(ev->ev_callback)); (*ev->ev_callback)(ev->ev_fd, ev->ev_events, ev->ev_arg); }
/** open TCP socket to svr */ static int open_svr(const char* svr, int udp) { struct sockaddr_storage addr; socklen_t addrlen; int fd = -1; /* svr can be ip@port */ memset(&addr, 0, sizeof(addr)); if(!extstrtoaddr(svr, &addr, &addrlen)) { printf("fatal: bad server specs '%s'\n", svr); exit(1); } fd = socket(addr_is_ip6(&addr, addrlen)?PF_INET6:PF_INET, udp?SOCK_DGRAM:SOCK_STREAM, 0); if(fd == -1) { #ifndef USE_WINSOCK perror("socket() error"); #else printf("socket: %s\n", wsa_strerror(WSAGetLastError())); #endif exit(1); } if(connect(fd, (struct sockaddr*)&addr, addrlen) < 0) { #ifndef USE_WINSOCK perror("connect() error"); #else printf("connect: %s\n", wsa_strerror(WSAGetLastError())); #endif exit(1); } return fd; }
/** * The main function for the service. * Called by the services API when starting on windows in background. * Arguments could have been present in the string 'path'. * @param argc: nr args * @param argv: arg text. */ static void service_main(DWORD ATTR_UNUSED(argc), LPTSTR* ATTR_UNUSED(argv)) { struct cfg* cfg = NULL; struct svr* svr = NULL; service_status_handle = RegisterServiceCtrlHandler(SERVICE_NAME, (LPHANDLER_FUNCTION)hdlr); if(!service_status_handle) { reportev("Could not RegisterServiceCtrlHandler"); return; } service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; service_status.dwServiceSpecificExitCode = 0; /* we are now starting up */ report_status(SERVICE_START_PENDING, NO_ERROR, 3000); if(!service_init(&svr, &cfg)) { reportev("Could not service_init"); report_status(SERVICE_STOPPED, NO_ERROR, 0); return; } /* event that gets signalled when we want to quit */ service_stop_event = WSACreateEvent(); if(service_stop_event == WSA_INVALID_EVENT) { log_err("WSACreateEvent: %s", wsa_strerror(WSAGetLastError())); reportev("Could not WSACreateEvent"); report_status(SERVICE_STOPPED, NO_ERROR, 0); return; } if(!WSAResetEvent(service_stop_event)) { log_err("WSAResetEvent: %s", wsa_strerror(WSAGetLastError())); } wsvc_setup_worker(svr->base); /* SetServiceStatus SERVICE_RUNNING;*/ report_status(SERVICE_RUNNING, NO_ERROR, 0); verbose(VERB_QUERY, "winservice - init complete"); /* register DHCP hook and perform first sweep */ netlist_start(svr); /* daemon performs work */ svr_service(svr); /* exit */ verbose(VERB_ALGO, "winservice - cleanup."); report_status(SERVICE_STOP_PENDING, NO_ERROR, 0); netlist_stop(); wsvc_desetup_worker(); service_deinit(svr, cfg); free(service_cfgfile); if(service_stop_event) (void)WSACloseEvent(service_stop_event); verbose(VERB_QUERY, "winservice - full stop"); report_status(SERVICE_STOPPED, NO_ERROR, 0); }
/** contact the server with TCP connect */ static int contact_server(const char* svr, struct config_file* cfg, int statuscmd) { struct sockaddr_storage addr; socklen_t addrlen; int fd; /* use svr or the first config entry */ if(!svr) { if(cfg->control_ifs) svr = cfg->control_ifs->str; else svr = "127.0.0.1"; /* config 0 addr (everything), means ask localhost */ if(strcmp(svr, "0.0.0.0") == 0) svr = "127.0.0.1"; else if(strcmp(svr, "::0") == 0 || strcmp(svr, "0::0") == 0 || strcmp(svr, "0::") == 0 || strcmp(svr, "::") == 0) svr = "::1"; } if(strchr(svr, '@')) { if(!extstrtoaddr(svr, &addr, &addrlen)) fatal_exit("could not parse IP@port: %s", svr); } else { if(!ipstrtoaddr(svr, cfg->control_port, &addr, &addrlen)) fatal_exit("could not parse IP: %s", svr); } fd = socket(addr_is_ip6(&addr, addrlen)?AF_INET6:AF_INET, SOCK_STREAM, 0); if(fd == -1) { #ifndef USE_WINSOCK fatal_exit("socket: %s", strerror(errno)); #else fatal_exit("socket: %s", wsa_strerror(WSAGetLastError())); #endif } if(connect(fd, (struct sockaddr*)&addr, addrlen) < 0) { log_addr(0, "address", &addr, addrlen); #ifndef USE_WINSOCK log_err("connect: %s", strerror(errno)); if(errno == ECONNREFUSED && statuscmd) { printf("unbound is stopped\n"); exit(3); } #else log_err("connect: %s", wsa_strerror(WSAGetLastError())); if(WSAGetLastError() == WSAECONNREFUSED && statuscmd) { printf("unbound is stopped\n"); exit(3); } #endif exit(1); } return fd; }
/** send out waiting packets */ static void service_send(struct ringbuf* ring, struct timeval* now, sldns_buffer* pkt, struct sockaddr_storage* srv_addr, socklen_t srv_len) { struct proxy* p; struct timeval tv; ssize_t sent; while(!ring_empty(ring) && dl_tv_smaller(ring_peek_time(ring), now)) { /* this items needs to be sent out */ if(!ring_pop(ring, pkt, &tv, &p)) fatal_exit("ringbuf error: pop failed"); verbose(1, "send out query %d.%6.6d", (unsigned)tv.tv_sec, (unsigned)tv.tv_usec); log_addr(1, "from client", &p->addr, p->addr_len); /* send it */ sent = sendto(p->s, (void*)sldns_buffer_begin(pkt), sldns_buffer_limit(pkt), 0, (struct sockaddr*)srv_addr, srv_len); if(sent == -1) { #ifndef USE_WINSOCK log_err("sendto: %s", strerror(errno)); #else log_err("sendto: %s", wsa_strerror(WSAGetLastError())); #endif } else if(sent != (ssize_t)sldns_buffer_limit(pkt)) { log_err("sendto: partial send"); } p->lastuse = *now; p->numsent++; } }
/** create context functionality, but no pipes */ static struct ub_ctx* ub_ctx_create_nopipe(void) { struct ub_ctx* ctx; unsigned int seed; #ifdef USE_WINSOCK int r; WSADATA wsa_data; #endif log_init(NULL, 0, NULL); /* logs to stderr */ log_ident_set("libunbound"); #ifdef USE_WINSOCK if((r = WSAStartup(MAKEWORD(2,2), &wsa_data)) != 0) { log_err("could not init winsock. WSAStartup: %s", wsa_strerror(r)); return NULL; } #endif verbosity = 0; /* errors only */ checklock_start(); ctx = (struct ub_ctx*)calloc(1, sizeof(*ctx)); if(!ctx) { errno = ENOMEM; return NULL; } alloc_init(&ctx->superalloc, NULL, 0); seed = (unsigned int)time(NULL) ^ (unsigned int)getpid(); if(!(ctx->seed_rnd = ub_initstate(seed, NULL))) { seed = 0; ub_randfree(ctx->seed_rnd); free(ctx); errno = ENOMEM; return NULL; } seed = 0; lock_basic_init(&ctx->qqpipe_lock); lock_basic_init(&ctx->rrpipe_lock); lock_basic_init(&ctx->cfglock); ctx->env = (struct module_env*)calloc(1, sizeof(*ctx->env)); if(!ctx->env) { ub_randfree(ctx->seed_rnd); free(ctx); errno = ENOMEM; return NULL; } ctx->env->cfg = config_create_forlib(); if(!ctx->env->cfg) { free(ctx->env); ub_randfree(ctx->seed_rnd); free(ctx); errno = ENOMEM; return NULL; } ctx->env->alloc = &ctx->superalloc; ctx->env->worker = NULL; ctx->env->need_to_validate = 0; modstack_init(&ctx->mods); rbtree_init(&ctx->queries, &context_query_cmp); return ctx; }
/** send new query for io */ static void perfsend(struct perfinfo* info, size_t n, struct timeval* now) { ssize_t r; r = sendto(info->io[n].fd, (void*)info->qlist_data[info->qlist_idx], info->qlist_len[info->qlist_idx], 0, (struct sockaddr*)&info->dest, info->destlen); /*log_hex("send", info->qlist_data[info->qlist_idx], info->qlist_len[info->qlist_idx]);*/ if(r == -1) { #ifndef USE_WINSOCK log_err("sendto: %s", strerror(errno)); #else log_err("sendto: %s", wsa_strerror(WSAGetLastError())); #endif } else if(r != (ssize_t)info->qlist_len[info->qlist_idx]) { log_err("partial sendto"); } info->qlist_idx = (info->qlist_idx+1) % info->qlist_size; info->numsent++; info->io[n].timeout.tv_sec = IO_TIMEOUT/1000; info->io[n].timeout.tv_usec = (IO_TIMEOUT%1000)*1000; perf_tv_add(&info->io[n].timeout, now); }
int tube_queue_item(struct tube* tube, uint8_t* msg, size_t len) { struct tube_res_list* item = (struct tube_res_list*)malloc(sizeof(*item)); verbose(VERB_ALGO, "tube queue_item len %d", (int)len); if(!item) { free(msg); log_err("out of memory for async answer"); return 0; } item->buf = msg; item->len = len; item->next = NULL; lock_basic_lock(&tube->res_lock); /* add at back of list, since the first one may be partially written */ if(tube->res_last) tube->res_last->next = item; else tube->res_list = item; tube->res_last = item; /* signal the eventhandle */ if(!WSASetEvent(tube->event)) { log_err("WSASetEvent: %s", wsa_strerror(WSAGetLastError())); } lock_basic_unlock(&tube->res_lock); return 1; }
/** read from ssl or fd, fatalexit on error, 0 EOF, 1 success */ static int remote_read(SSL* ssl, int fd, char* buf, size_t len) { if(ssl) { int r; ERR_clear_error(); if((r = SSL_read(ssl, buf, (int)len-1)) <= 0) { if(SSL_get_error(ssl, r) == SSL_ERROR_ZERO_RETURN) { /* EOF */ return 0; } ssl_err("could not SSL_read"); } buf[r] = 0; } else { ssize_t rr = recv(fd, buf, len-1, 0); if(rr <= 0) { if(rr == 0) { /* EOF */ return 0; } #ifndef USE_WINSOCK fatal_exit("could not recv: %s", strerror(errno)); #else fatal_exit("could not recv: %s", wsa_strerror(WSAGetLastError())); #endif } buf[rr] = 0; } return 1; }
void tube_close_write(struct tube* ATTR_UNUSED(tube)) { verbose(VERB_ALGO, "tube close_write"); /* wake up waiting reader with an empty queue */ if(!WSASetEvent(tube->event)) { log_err("WSASetEvent: %s", wsa_strerror(WSAGetLastError())); } }
void tube_delete(struct tube* tube) { if(!tube) return; tube_remove_bg_listen(tube); tube_remove_bg_write(tube); tube_close_read(tube); tube_close_write(tube); if(!WSACloseEvent(tube->event)) log_err("WSACloseEvent: %s", wsa_strerror(WSAGetLastError())); lock_basic_destroy(&tube->res_lock); verbose(VERB_ALGO, "tube deleted"); free(tube); }
/** setup perf test environment */ static void perfsetup(struct perfinfo* info) { size_t i; if(gettimeofday(&info->start, NULL) < 0) fatal_exit("gettimeofday: %s", strerror(errno)); sig_info = info; if( signal(SIGINT, perf_sigh) == SIG_ERR || #ifdef SIGQUIT signal(SIGQUIT, perf_sigh) == SIG_ERR || #endif #ifdef SIGHUP signal(SIGHUP, perf_sigh) == SIG_ERR || #endif #ifdef SIGBREAK signal(SIGBREAK, perf_sigh) == SIG_ERR || #endif signal(SIGTERM, perf_sigh) == SIG_ERR) fatal_exit("could not bind to signal"); info->io = (struct perfio*)calloc(sizeof(struct perfio), info->io_num); if(!info->io) fatal_exit("out of memory"); #ifndef S_SPLINT_S FD_ZERO(&info->rset); #endif info->since = info->start; for(i=0; i<info->io_num; i++) { info->io[i].id = i; info->io[i].info = info; info->io[i].fd = socket( addr_is_ip6(&info->dest, info->destlen)? AF_INET6:AF_INET, SOCK_DGRAM, 0); if(info->io[i].fd == -1) { #ifndef USE_WINSOCK fatal_exit("socket: %s", strerror(errno)); #else fatal_exit("socket: %s", wsa_strerror(WSAGetLastError())); #endif } if(info->io[i].fd > info->maxfd) info->maxfd = info->io[i].fd; #ifndef S_SPLINT_S FD_SET(FD_SET_T info->io[i].fd, &info->rset); info->io[i].timeout.tv_usec = ((START_IO_INTERVAL*i)%1000) *1000; info->io[i].timeout.tv_sec = (START_IO_INTERVAL*i)/1000; perf_tv_add(&info->io[i].timeout, &info->since); #endif } }
int _getdns_event_del(struct _getdns_event *ev) { //verbose(VERB_ALGO, "event_del %p added=%d fd=%d tv=" ARG_LL "d %s%s%s", // ev, ev->added, ev->ev_fd, // (ev->ev_events&EV_TIMEOUT)?(long long)ev->ev_timeout.tv_sec*1000+ // (long long)ev->ev_timeout.tv_usec/1000:-1, // (ev->ev_events&EV_READ)?" EV_READ":"", // (ev->ev_events&EV_WRITE)?" EV_WRITE":"", // (ev->ev_events&EV_TIMEOUT)?" EV_TIMEOUT":""); if(!ev->added) return 0; //log_assert(ev->added); if((ev->ev_events&EV_TIMEOUT)) (void)_getdns_rbtree_delete(ev->ev_base->times, &ev->node); if((ev->ev_events&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) { //log_assert(ev->ev_base->max > 0); /* remove item and compact the list */ ev->ev_base->items[ev->idx] = ev->ev_base->items[ev->ev_base->max-1]; ev->ev_base->items[ev->ev_base->max-1] = NULL; ev->ev_base->max--; if(ev->idx < ev->ev_base->max) ev->ev_base->items[ev->idx]->idx = ev->idx; zero_waitfor(ev->ev_base->waitfor, ev->hEvent); if(WSAEventSelect(ev->ev_fd, ev->hEvent, 0) != 0) log_err("getdns: WSAEventSelect(disable) failed: %s", wsa_strerror(WSAGetLastError())); if(!WSACloseEvent(ev->hEvent)) log_err("getdns: WSACloseEvent failed: %s", wsa_strerror(WSAGetLastError())); } ev->just_checked = 0; ev->added = 0; return 0; }
/** do proxy for one readable client */ static void do_proxy(struct proxy* p, int retsock, sldns_buffer* pkt) { int i; ssize_t r; for(i=0; i<TRIES_PER_SELECT; i++) { r = recv(p->s, (void*)sldns_buffer_begin(pkt), sldns_buffer_capacity(pkt), 0); if(r == -1) { #ifndef USE_WINSOCK if(errno == EAGAIN || errno == EINTR) return; log_err("recv: %s", strerror(errno)); #else if(WSAGetLastError() == WSAEINPROGRESS || WSAGetLastError() == WSAEWOULDBLOCK) return; log_err("recv: %s", wsa_strerror(WSAGetLastError())); #endif return; } sldns_buffer_set_limit(pkt, (size_t)r); log_addr(1, "return reply to client", &p->addr, p->addr_len); /* send reply back to the real client */ p->numreturn++; r = sendto(retsock, (void*)sldns_buffer_begin(pkt), (size_t)r, 0, (struct sockaddr*)&p->addr, p->addr_len); if(r == -1) { #ifndef USE_WINSOCK log_err("sendto: %s", strerror(errno)); #else log_err("sendto: %s", wsa_strerror(WSAGetLastError())); #endif } } }
struct tube* tube_create(void) { /* windows does not have forks like unix, so we only support * threads on windows. And thus the pipe need only connect * threads. We use a mutex and a list of datagrams. */ struct tube* tube = (struct tube*)calloc(1, sizeof(*tube)); if(!tube) { int err = errno; log_err("tube_create: out of memory"); errno = err; return NULL; } tube->event = WSACreateEvent(); if(tube->event == WSA_INVALID_EVENT) { free(tube); log_err("WSACreateEvent: %s", wsa_strerror(WSAGetLastError())); } if(!WSAResetEvent(tube->event)) { log_err("WSAResetEvent: %s", wsa_strerror(WSAGetLastError())); } lock_basic_init(&tube->res_lock); verbose(VERB_ALGO, "tube created"); return tube; }
/** write to ssl or fd, fatalexit on error */ static void remote_write(SSL* ssl, int fd, const char* buf, size_t len) { if(ssl) { if(SSL_write(ssl, buf, (int)len) <= 0) ssl_err("could not SSL_write"); } else { if(send(fd, buf, len, 0) < (ssize_t)len) { #ifndef USE_WINSOCK fatal_exit("could not send: %s", strerror(errno)); #else fatal_exit("could not send: %s", wsa_strerror(WSAGetLastError())); #endif } } }
/** find or else create proxy for this remote client */ static struct proxy* find_create_proxy(struct sockaddr_storage* from, socklen_t from_len, fd_set* rorig, int* max, struct proxy** proxies, int serv_ip6, struct timeval* now, struct timeval* reuse_timeout) { struct proxy* p; struct timeval t; for(p = *proxies; p; p = p->next) { if(sockaddr_cmp(from, from_len, &p->addr, p->addr_len)==0) return p; } /* possibly: reuse lapsed entries */ for(p = *proxies; p; p = p->next) { if(p->numwait > p->numsent || p->numsent > p->numreturn) continue; t = *now; dl_tv_subtract(&t, &p->lastuse); if(dl_tv_smaller(&t, reuse_timeout)) continue; /* yes! */ verbose(1, "reuse existing entry"); memmove(&p->addr, from, from_len); p->addr_len = from_len; p->numreuse++; return p; } /* create new */ p = (struct proxy*)calloc(1, sizeof(*p)); if(!p) fatal_exit("out of memory"); p->s = socket(serv_ip6?AF_INET6:AF_INET, SOCK_DGRAM, 0); if(p->s == -1) { #ifndef USE_WINSOCK fatal_exit("socket: %s", strerror(errno)); #else fatal_exit("socket: %s", wsa_strerror(WSAGetLastError())); #endif } fd_set_nonblock(p->s); memmove(&p->addr, from, from_len); p->addr_len = from_len; p->next = *proxies; *proxies = p; FD_SET(FD_SET_T p->s, rorig); if(p->s+1 > *max) *max = p->s+1; return p; }
/** * Service control handler. Called by serviceControlManager when a control * code is sent to the service (with ControlService). * @param ctrl: control code */ static void hdlr(DWORD ctrl) { if(ctrl == SERVICE_CONTROL_STOP) { report_status(SERVICE_STOP_PENDING, NO_ERROR, 0); service_stop_shutdown = 1; /* send signal to stop */ if(!WSASetEvent(service_stop_event)) log_err("Could not WSASetEvent: %s", wsa_strerror(WSAGetLastError())); return; } else { /* ctrl == SERVICE_CONTROL_INTERROGATE or whatever */ /* update status */ report_status(service_status.dwCurrentState, NO_ERROR, 0); } }
/** wait for cron process to finish */ static void waitforit(PROCESS_INFORMATION* pinfo) { DWORD ret = WaitForSingleObject(pinfo->hProcess, INFINITE); verbose(VERB_ALGO, "cronaction done"); if(ret != WAIT_OBJECT_0) { return; /* did not end successfully */ } if(!GetExitCodeProcess(pinfo->hProcess, &ret)) { log_err("GetExitCodeProcess failed"); return; } verbose(VERB_ALGO, "exit code is %d", (int)ret); if(ret != 1) { if(!WSASetEvent(service_stop_event)) log_err("Could not WSASetEvent: %s", wsa_strerror(WSAGetLastError())); } }
/** got reply for io */ static void perfreply(struct perfinfo* info, size_t n, struct timeval* now) { ssize_t r; r = recv(info->io[n].fd, (void*)sldns_buffer_begin(info->buf), sldns_buffer_capacity(info->buf), 0); if(r == -1) { #ifndef USE_WINSOCK log_err("recv: %s", strerror(errno)); #else log_err("recv: %s", wsa_strerror(WSAGetLastError())); #endif } else { info->by_rcode[LDNS_RCODE_WIRE(sldns_buffer_begin( info->buf))]++; info->numrecv++; } /*sldns_buffer_set_limit(info->buf, r); log_buf(0, "reply", info->buf);*/ perfsend(info, n, now); }
/** recv new waiting packets */ static void service_recv(int s, struct ringbuf* ring, sldns_buffer* pkt, fd_set* rorig, int* max, struct proxy** proxies, struct sockaddr_storage* srv_addr, socklen_t srv_len, struct timeval* now, struct timeval* delay, struct timeval* reuse) { int i; struct sockaddr_storage from; socklen_t from_len; ssize_t len; struct proxy* p; for(i=0; i<TRIES_PER_SELECT; i++) { from_len = (socklen_t)sizeof(from); len = recvfrom(s, (void*)sldns_buffer_begin(pkt), sldns_buffer_capacity(pkt), 0, (struct sockaddr*)&from, &from_len); if(len < 0) { #ifndef USE_WINSOCK if(errno == EAGAIN || errno == EINTR) return; fatal_exit("recvfrom: %s", strerror(errno)); #else if(WSAGetLastError() == WSAEWOULDBLOCK || WSAGetLastError() == WSAEINPROGRESS) return; fatal_exit("recvfrom: %s", wsa_strerror(WSAGetLastError())); #endif } sldns_buffer_set_limit(pkt, (size_t)len); /* find its proxy element */ p = find_create_proxy(&from, from_len, rorig, max, proxies, addr_is_ip6(srv_addr, srv_len), now, reuse); if(!p) fatal_exit("error: cannot find or create proxy"); p->lastuse = *now; ring_add(ring, pkt, now, delay, p); p->numwait++; log_addr(1, "recv from client", &p->addr, p->addr_len); } }
int net_lib_init(char **errstr) { #ifdef W32_NATIVE WORD wVersionRequested; WSADATA wsaData; int error_code; wVersionRequested = MAKEWORD(2, 0); if ((error_code = WSAStartup(wVersionRequested, &wsaData)) != 0) { *errstr = xasprintf("%s", wsa_strerror(error_code)); return NET_ELIBFAILED; } else { return NET_EOK; } #else /* noone else needs this... */ (void)errstr; return NET_EOK; #endif }
int fd_set_nonblock(int s) { #ifdef HAVE_FCNTL int flag; if((flag = fcntl(s, F_GETFL)) == -1) { log_err("can't fcntl F_GETFL: %s", strerror(errno)); flag = 0; } flag |= O_NONBLOCK; if(fcntl(s, F_SETFL, flag) == -1) { log_err("can't fcntl F_SETFL: %s", strerror(errno)); return 0; } #elif defined(HAVE_IOCTLSOCKET) unsigned long on = 1; if(ioctlsocket(s, FIONBIO, &on) != 0) { log_err("can't ioctlsocket FIONBIO on: %s", wsa_strerror(WSAGetLastError())); } #endif return 1; }
int tube_read_msg(struct tube* tube, uint8_t** buf, uint32_t* len, int nonblock) { struct tube_res_list* item = NULL; verbose(VERB_ALGO, "tube read_msg %s", nonblock?"nonblock":"blocking"); *buf = NULL; if(!tube_poll(tube)) { verbose(VERB_ALGO, "tube read_msg nodata"); /* nothing ready right now, wait if we want to */ if(nonblock) return -1; /* would block waiting for items */ if(!tube_wait(tube)) return 0; } lock_basic_lock(&tube->res_lock); if(tube->res_list) { item = tube->res_list; tube->res_list = item->next; if(tube->res_last == item) { /* the list is now empty */ tube->res_last = NULL; verbose(VERB_ALGO, "tube read_msg lastdata"); if(!WSAResetEvent(tube->event)) { log_err("WSAResetEvent: %s", wsa_strerror(WSAGetLastError())); } } } lock_basic_unlock(&tube->res_lock); if(!item) return 0; /* would block waiting for items */ *buf = item->buf; *len = item->len; free(item); verbose(VERB_ALGO, "tube read_msg len %d", (int)*len); return 1; }
int fd_set_block(int s) { #ifdef HAVE_FCNTL int flag; if((flag = fcntl(s, F_GETFL)) == -1) { log_err("cannot fcntl F_GETFL: %s", strerror(errno)); flag = 0; } flag &= ~O_NONBLOCK; if(fcntl(s, F_SETFL, flag) == -1) { log_err("cannot fcntl F_SETFL: %s", strerror(errno)); return 0; } #elif defined(HAVE_IOCTLSOCKET) unsigned long off = 0; if(ioctlsocket(s, FIONBIO, &off) != 0) { if(WSAGetLastError() != WSAEINVAL || verbosity >= 4) log_err("can't ioctlsocket FIONBIO off: %s", wsa_strerror(WSAGetLastError())); } #endif return 1; }
/** Main routine for unbound-control */ int main(int argc, char* argv[]) { int c, ret; const char* cfgfile = CONFIGFILE; char* svr = NULL; #ifdef USE_WINSOCK int r; WSADATA wsa_data; #endif #ifdef USE_THREAD_DEBUG /* stop the file output from unbound-control, overwites the servers */ extern int check_locking_order; check_locking_order = 0; #endif /* USE_THREAD_DEBUG */ log_ident_set("unbound-control"); log_init(NULL, 0, NULL); checklock_start(); #ifdef USE_WINSOCK if((r = WSAStartup(MAKEWORD(2,2), &wsa_data)) != 0) fatal_exit("WSAStartup failed: %s", wsa_strerror(r)); #endif ERR_load_crypto_strings(); ERR_load_SSL_strings(); OpenSSL_add_all_algorithms(); (void)SSL_library_init(); if(!RAND_status()) { /* try to seed it */ unsigned char buf[256]; unsigned int v, seed=(unsigned)time(NULL) ^ (unsigned)getpid(); size_t i; for(i=0; i<256/sizeof(v); i++) { memmove(buf+i*sizeof(v), &v, sizeof(v)); v = v*seed + (unsigned int)i; } RAND_seed(buf, 256); log_warn("no entropy, seeding openssl PRNG with time\n"); } /* parse the options */ while( (c=getopt(argc, argv, "c:s:h")) != -1) { switch(c) { case 'c': cfgfile = optarg; break; case 's': svr = optarg; break; case '?': case 'h': default: usage(); } } argc -= optind; argv += optind; if(argc == 0) usage(); if(argc >= 1 && strcmp(argv[0], "start")==0) { if(execlp("unbound", "unbound", "-c", cfgfile, (char*)NULL) < 0) { fatal_exit("could not exec unbound: %s", strerror(errno)); } } ret = go(cfgfile, svr, argc, argv); #ifdef USE_WINSOCK WSACleanup(); #endif checklock_stop(); return ret; }
/** contact the server with TCP connect */ static int contact_server(const char* svr, struct config_file* cfg, int statuscmd) { struct sockaddr_storage addr; socklen_t addrlen; int addrfamily = 0; int fd; /* use svr or the first config entry */ if(!svr) { if(cfg->control_ifs) svr = cfg->control_ifs->str; else svr = "127.0.0.1"; /* config 0 addr (everything), means ask localhost */ if(strcmp(svr, "0.0.0.0") == 0) svr = "127.0.0.1"; else if(strcmp(svr, "::0") == 0 || strcmp(svr, "0::0") == 0 || strcmp(svr, "0::") == 0 || strcmp(svr, "::") == 0) svr = "::1"; } if(strchr(svr, '@')) { if(!extstrtoaddr(svr, &addr, &addrlen)) fatal_exit("could not parse IP@port: %s", svr); #ifdef HAVE_SYS_UN_H } else if(svr[0] == '/') { struct sockaddr_un* usock = (struct sockaddr_un *) &addr; usock->sun_family = AF_LOCAL; #ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN usock->sun_len = (socklen_t)sizeof(usock); #endif (void)strlcpy(usock->sun_path, svr, sizeof(usock->sun_path)); addrlen = (socklen_t)sizeof(struct sockaddr_un); addrfamily = AF_LOCAL; #endif } else { if(!ipstrtoaddr(svr, cfg->control_port, &addr, &addrlen)) fatal_exit("could not parse IP: %s", svr); } if(addrfamily == 0) addrfamily = addr_is_ip6(&addr, addrlen)?AF_INET6:AF_INET; fd = socket(addrfamily, SOCK_STREAM, 0); if(fd == -1) { #ifndef USE_WINSOCK fatal_exit("socket: %s", strerror(errno)); #else fatal_exit("socket: %s", wsa_strerror(WSAGetLastError())); #endif } if(connect(fd, (struct sockaddr*)&addr, addrlen) < 0) { #ifndef USE_WINSOCK log_err_addr("connect", strerror(errno), &addr, addrlen); if(errno == ECONNREFUSED && statuscmd) { printf("unbound is stopped\n"); exit(3); } #else log_err_addr("connect", wsa_strerror(WSAGetLastError()), &addr, addrlen); if(WSAGetLastError() == WSAECONNREFUSED && statuscmd) { printf("unbound is stopped\n"); exit(3); } #endif exit(1); } return fd; }
/** * The main function for the service. * Called by the services API when starting unbound on windows in background. * Arguments could have been present in the string 'path'. * @param argc: nr args * @param argv: arg text. */ static void service_main(DWORD ATTR_UNUSED(argc), LPTSTR* ATTR_UNUSED(argv)) { struct config_file* cfg = NULL; struct daemon* daemon = NULL; service_status_handle = RegisterServiceCtrlHandler(SERVICE_NAME, (LPHANDLER_FUNCTION)hdlr); if(!service_status_handle) { reportev("Could not RegisterServiceCtrlHandler"); return; } service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; service_status.dwServiceSpecificExitCode = 0; /* see if we have root anchor update enabled */ call_root_update(); /* we are now starting up */ report_status(SERVICE_START_PENDING, NO_ERROR, 3000); if(!service_init(0, &daemon, &cfg)) { reportev("Could not service_init"); report_status(SERVICE_STOPPED, NO_ERROR, 0); return; } /* event that gets signalled when we want to quit; it * should get registered in the worker-0 waiting loop. */ service_stop_event = WSACreateEvent(); if(service_stop_event == WSA_INVALID_EVENT) { log_err("WSACreateEvent: %s", wsa_strerror(WSAGetLastError())); reportev("Could not WSACreateEvent"); report_status(SERVICE_STOPPED, NO_ERROR, 0); return; } if(!WSAResetEvent(service_stop_event)) { log_err("WSAResetEvent: %s", wsa_strerror(WSAGetLastError())); } /* SetServiceStatus SERVICE_RUNNING;*/ report_status(SERVICE_RUNNING, NO_ERROR, 0); verbose(VERB_QUERY, "winservice - init complete"); /* daemon performs work */ while(!service_stop_shutdown) { daemon_fork(daemon); if(!service_stop_shutdown) { daemon_cleanup(daemon); config_delete(cfg); cfg=NULL; if(!service_init(1, &daemon, &cfg)) { reportev("Could not service_init"); report_status(SERVICE_STOPPED, NO_ERROR, 0); return; } } } /* exit */ verbose(VERB_ALGO, "winservice - cleanup."); report_status(SERVICE_STOP_PENDING, NO_ERROR, 0); service_deinit(daemon, cfg); free(service_cfgfile); if(service_stop_event) (void)WSACloseEvent(service_stop_event); verbose(VERB_QUERY, "winservice - full stop"); report_status(SERVICE_STOPPED, NO_ERROR, 0); }
/** Main routine for unbound-control */ int main(int argc, char* argv[]) { int c, ret; int quiet = 0; const char* cfgfile = CONFIGFILE; char* svr = NULL; #ifdef USE_WINSOCK int r; WSADATA wsa_data; #endif #ifdef USE_THREAD_DEBUG /* stop the file output from unbound-control, overwrites the servers */ extern int check_locking_order; check_locking_order = 0; #endif /* USE_THREAD_DEBUG */ log_ident_set("unbound-control"); log_init(NULL, 0, NULL); checklock_start(); #ifdef USE_WINSOCK /* use registry config file in preference to compiletime location */ if(!(cfgfile=w_lookup_reg_str("Software\\Unbound", "ConfigFile"))) cfgfile = CONFIGFILE; #endif /* parse the options */ while( (c=getopt(argc, argv, "c:s:qh")) != -1) { switch(c) { case 'c': cfgfile = optarg; break; case 's': svr = optarg; break; case 'q': quiet = 1; break; case '?': case 'h': default: usage(); } } argc -= optind; argv += optind; if(argc == 0) usage(); if(argc >= 1 && strcmp(argv[0], "start")==0) { if(execlp("unbound", "unbound", "-c", cfgfile, (char*)NULL) < 0) { fatal_exit("could not exec unbound: %s", strerror(errno)); } } if(argc >= 1 && strcmp(argv[0], "stats_shm")==0) { print_stats_shm(cfgfile); return 0; } #ifdef USE_WINSOCK if((r = WSAStartup(MAKEWORD(2,2), &wsa_data)) != 0) fatal_exit("WSAStartup failed: %s", wsa_strerror(r)); #endif #ifdef HAVE_ERR_LOAD_CRYPTO_STRINGS ERR_load_crypto_strings(); #endif #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL) ERR_load_SSL_strings(); #endif #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_CRYPTO) OpenSSL_add_all_algorithms(); #else OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS | OPENSSL_INIT_ADD_ALL_DIGESTS | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL); #endif #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL) (void)SSL_library_init(); #else (void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL); #endif if(!RAND_status()) { /* try to seed it */ unsigned char buf[256]; unsigned int seed=(unsigned)time(NULL) ^ (unsigned)getpid(); unsigned int v = seed; size_t i; for(i=0; i<256/sizeof(v); i++) { memmove(buf+i*sizeof(v), &v, sizeof(v)); v = v*seed + (unsigned int)i; } RAND_seed(buf, 256); log_warn("no entropy, seeding openssl PRNG with time\n"); } ret = go(cfgfile, svr, quiet, argc, argv); #ifdef USE_WINSOCK WSACleanup(); #endif checklock_stop(); return ret; }
int create_udp_sock(int family, int socktype, struct sockaddr* addr, socklen_t addrlen, int v6only, int* inuse, int* noproto, int rcv, int snd) { int s; #if defined(IPV6_USE_MIN_MTU) int on=1; #endif #ifdef IPV6_MTU int mtu = IPV6_MIN_MTU; #endif #if !defined(SO_RCVBUFFORCE) && !defined(SO_RCVBUF) (void)rcv; #endif #if !defined(SO_SNDBUFFORCE) && !defined(SO_SNDBUF) (void)snd; #endif #ifndef IPV6_V6ONLY (void)v6only; #endif if((s = socket(family, socktype, 0)) == -1) { *inuse = 0; #ifndef USE_WINSOCK if(errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT) { *noproto = 1; return -1; } log_err("can't create socket: %s", strerror(errno)); #else if(WSAGetLastError() == WSAEAFNOSUPPORT || WSAGetLastError() == WSAEPROTONOSUPPORT) { *noproto = 1; return -1; } log_err("can't create socket: %s", wsa_strerror(WSAGetLastError())); #endif *noproto = 0; return -1; } if(rcv) { #ifdef SO_RCVBUF int got; socklen_t slen = (socklen_t)sizeof(got); # ifdef SO_RCVBUFFORCE /* Linux specific: try to use root permission to override * system limits on rcvbuf. The limit is stored in * /proc/sys/net/core/rmem_max or sysctl net.core.rmem_max */ if(setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, (void*)&rcv, (socklen_t)sizeof(rcv)) < 0) { if(errno != EPERM) { # ifndef USE_WINSOCK log_err("setsockopt(..., SO_RCVBUFFORCE, " "...) failed: %s", strerror(errno)); close(s); # else log_err("setsockopt(..., SO_RCVBUFFORCE, " "...) failed: %s", wsa_strerror(WSAGetLastError())); closesocket(s); # endif *noproto = 0; *inuse = 0; return -1; } # endif /* SO_RCVBUFFORCE */ if(setsockopt(s, SOL_SOCKET, SO_RCVBUF, (void*)&rcv, (socklen_t)sizeof(rcv)) < 0) { # ifndef USE_WINSOCK log_err("setsockopt(..., SO_RCVBUF, " "...) failed: %s", strerror(errno)); close(s); # else log_err("setsockopt(..., SO_RCVBUF, " "...) failed: %s", wsa_strerror(WSAGetLastError())); closesocket(s); # endif *noproto = 0; *inuse = 0; return -1; } /* check if we got the right thing or if system * reduced to some system max. Warn if so */ if(getsockopt(s, SOL_SOCKET, SO_RCVBUF, (void*)&got, &slen) >= 0 && got < rcv/2) { log_warn("so-rcvbuf %u was not granted. " "Got %u. To fix: start with " "root permissions(linux) or sysctl " "bigger net.core.rmem_max(linux) or " "kern.ipc.maxsockbuf(bsd) values.", (unsigned)rcv, (unsigned)got); } # ifdef SO_RCVBUFFORCE } # endif #endif /* SO_RCVBUF */ } /* first do RCVBUF as the receive buffer is more important */ if(snd) { #ifdef SO_SNDBUF int got; socklen_t slen = (socklen_t)sizeof(got); # ifdef SO_SNDBUFFORCE /* Linux specific: try to use root permission to override * system limits on sndbuf. The limit is stored in * /proc/sys/net/core/wmem_max or sysctl net.core.wmem_max */ if(setsockopt(s, SOL_SOCKET, SO_SNDBUFFORCE, (void*)&snd, (socklen_t)sizeof(snd)) < 0) { if(errno != EPERM) { # ifndef USE_WINSOCK log_err("setsockopt(..., SO_SNDBUFFORCE, " "...) failed: %s", strerror(errno)); close(s); # else log_err("setsockopt(..., SO_SNDBUFFORCE, " "...) failed: %s", wsa_strerror(WSAGetLastError())); closesocket(s); # endif *noproto = 0; *inuse = 0; return -1; } # endif /* SO_SNDBUFFORCE */ if(setsockopt(s, SOL_SOCKET, SO_SNDBUF, (void*)&snd, (socklen_t)sizeof(snd)) < 0) { # ifndef USE_WINSOCK log_err("setsockopt(..., SO_SNDBUF, " "...) failed: %s", strerror(errno)); close(s); # else log_err("setsockopt(..., SO_SNDBUF, " "...) failed: %s", wsa_strerror(WSAGetLastError())); closesocket(s); # endif *noproto = 0; *inuse = 0; return -1; } /* check if we got the right thing or if system * reduced to some system max. Warn if so */ if(getsockopt(s, SOL_SOCKET, SO_SNDBUF, (void*)&got, &slen) >= 0 && got < snd/2) { log_warn("so-sndbuf %u was not granted. " "Got %u. To fix: start with " "root permissions(linux) or sysctl " "bigger net.core.wmem_max(linux) or " "kern.ipc.maxsockbuf(bsd) values.", (unsigned)snd, (unsigned)got); } # ifdef SO_SNDBUFFORCE } # endif #endif /* SO_SNDBUF */ } if(family == AF_INET6) { # if defined(IPV6_V6ONLY) if(v6only) { int val=(v6only==2)?0:1; if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&val, (socklen_t)sizeof(val)) < 0) { #ifndef USE_WINSOCK log_err("setsockopt(..., IPV6_V6ONLY" ", ...) failed: %s", strerror(errno)); close(s); #else log_err("setsockopt(..., IPV6_V6ONLY" ", ...) failed: %s", wsa_strerror(WSAGetLastError())); closesocket(s); #endif *noproto = 0; *inuse = 0; return -1; } } # endif # if defined(IPV6_USE_MIN_MTU) /* * There is no fragmentation of IPv6 datagrams * during forwarding in the network. Therefore * we do not send UDP datagrams larger than * the minimum IPv6 MTU of 1280 octets. The * EDNS0 message length can be larger if the * network stack supports IPV6_USE_MIN_MTU. */ if (setsockopt(s, IPPROTO_IPV6, IPV6_USE_MIN_MTU, (void*)&on, (socklen_t)sizeof(on)) < 0) { # ifndef USE_WINSOCK log_err("setsockopt(..., IPV6_USE_MIN_MTU, " "...) failed: %s", strerror(errno)); close(s); # else log_err("setsockopt(..., IPV6_USE_MIN_MTU, " "...) failed: %s", wsa_strerror(WSAGetLastError())); closesocket(s); # endif *noproto = 0; *inuse = 0; return -1; } # elif defined(IPV6_MTU) /* * On Linux, to send no larger than 1280, the PMTUD is * disabled by default for datagrams anyway, so we set * the MTU to use. */ if (setsockopt(s, IPPROTO_IPV6, IPV6_MTU, (void*)&mtu, (socklen_t)sizeof(mtu)) < 0) { # ifndef USE_WINSOCK log_err("setsockopt(..., IPV6_MTU, ...) failed: %s", strerror(errno)); close(s); # else log_err("setsockopt(..., IPV6_MTU, ...) failed: %s", wsa_strerror(WSAGetLastError())); closesocket(s); # endif *noproto = 0; *inuse = 0; return -1; } # endif /* IPv6 MTU */ } else if(family == AF_INET) { # if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT) int action = IP_PMTUDISC_DONT; if (setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, &action, (socklen_t)sizeof(action)) < 0) { log_err("setsockopt(..., IP_MTU_DISCOVER, " "IP_PMTUDISC_DONT...) failed: %s", strerror(errno)); # ifndef USE_WINSOCK close(s); # else closesocket(s); # endif return -1; } # elif defined(IP_DONTFRAG) int off = 0; if (setsockopt(s, IPPROTO_IP, IP_DONTFRAG, &off, (socklen_t)sizeof(off)) < 0) { log_err("setsockopt(..., IP_DONTFRAG, ...) failed: %s", strerror(errno)); # ifndef USE_WINSOCK close(s); # else closesocket(s); # endif return -1; } # endif /* IPv4 MTU */ } if(bind(s, (struct sockaddr*)addr, addrlen) != 0) { *noproto = 0; #ifndef USE_WINSOCK #ifdef EADDRINUSE *inuse = (errno == EADDRINUSE); /* detect freebsd jail with no ipv6 permission */ if(family==AF_INET6 && errno==EINVAL) *noproto = 1; else if(errno != EADDRINUSE) { log_err("can't bind socket: %s", strerror(errno)); log_addr(0, "failed address", (struct sockaddr_storage*)addr, addrlen); } #endif /* EADDRINUSE */ close(s); #else /* USE_WINSOCK */ if(WSAGetLastError() != WSAEADDRINUSE && WSAGetLastError() != WSAEADDRNOTAVAIL) { log_err("can't bind socket: %s", wsa_strerror(WSAGetLastError())); log_addr(0, "failed address", (struct sockaddr_storage*)addr, addrlen); } closesocket(s); #endif return -1; } if(!fd_set_nonblock(s)) { *noproto = 0; *inuse = 0; #ifndef USE_WINSOCK close(s); #else closesocket(s); #endif return -1; } return s; }