int netblockstrtoaddr(const char* str, int port, struct sockaddr_storage* addr, socklen_t* addrlen, int* net) { char buf[64]; char* s; *net = (str_is_ip6(str)?128:32); if((s=strchr(str, '/'))) { if(atoi(s+1) > *net) { log_err("netblock too large: %s", str); return 0; } *net = atoi(s+1); if(*net == 0 && strcmp(s+1, "0") != 0) { log_err("cannot parse netblock: '%s'", str); return 0; } strlcpy(buf, str, sizeof(buf)); s = strchr(buf, '/'); if(s) *s = 0; s = buf; } if(!ipstrtoaddr(s?s:str, port, addr, addrlen)) { log_err("cannot parse ip address: '%s'", str); return 0; } if(s) { addr_mask(addr, *addrlen, *net); } return 1; }
/** check interface strings */ static void interfacechecks(struct config_file* cfg) { struct sockaddr_storage a; socklen_t alen; int i, j; for(i=0; i<cfg->num_ifs; i++) { if(!extstrtoaddr(cfg->ifs[i], &a, &alen)) { fatal_exit("cannot parse interface specified as '%s'", cfg->ifs[i]); } for(j=0; j<cfg->num_ifs; j++) { if(i!=j && strcmp(cfg->ifs[i], cfg->ifs[j])==0) fatal_exit("interface: %s present twice, " "cannot bind same ports twice.", cfg->ifs[i]); } } for(i=0; i<cfg->num_out_ifs; i++) { if(!ipstrtoaddr(cfg->out_ifs[i], UNBOUND_DNS_PORT, &a, &alen)) { fatal_exit("cannot parse outgoing-interface " "specified as '%s'", cfg->out_ifs[i]); } for(j=0; j<cfg->num_out_ifs; j++) { if(i!=j && strcmp(cfg->out_ifs[i], cfg->out_ifs[j])==0) fatal_exit("outgoing-interface: %s present " "twice, cannot bind same ports twice.", cfg->out_ifs[i]); } } }
int netblockstrtoaddr(const char* str, int port, struct sockaddr_storage* addr, socklen_t* addrlen, int* net) { char* s = NULL; *net = (str_is_ip6(str)?128:32); if((s=strchr(str, '/'))) { if(atoi(s+1) > *net) { log_err("netblock too large: %s", str); return 0; } *net = atoi(s+1); if(*net == 0 && strcmp(s+1, "0") != 0) { log_err("cannot parse netblock: '%s'", str); return 0; } if(!(s = strdup(str))) { log_err("out of memory"); return 0; } *strchr(s, '/') = '\0'; } if(!ipstrtoaddr(s?s:str, port, addr, addrlen)) { free(s); log_err("cannot parse ip address: '%s'", str); return 0; } if(s) { free(s); addr_mask(addr, *addrlen, *net); } return 1; }
int authextstrtoaddr(char* str, struct sockaddr_storage* addr, socklen_t* addrlen, char** auth_name) { char* s; int port = UNBOUND_DNS_PORT; if((s=strchr(str, '@'))) { char buf[MAX_ADDR_STRLEN]; size_t len = (size_t)(s-str); char* hash = strchr(s+1, '#'); if(hash) { *auth_name = hash+1; } else { *auth_name = NULL; } if(len >= MAX_ADDR_STRLEN) { return 0; } (void)strlcpy(buf, str, sizeof(buf)); buf[len] = 0; port = atoi(s+1); if(port == 0) { if(!hash && strcmp(s+1,"0")!=0) return 0; if(hash && strncmp(s+1,"0#",2)!=0) return 0; } return ipstrtoaddr(buf, port, addr, addrlen); } if((s=strchr(str, '#'))) { char buf[MAX_ADDR_STRLEN]; size_t len = (size_t)(s-str); if(len >= MAX_ADDR_STRLEN) { return 0; } (void)strlcpy(buf, str, sizeof(buf)); buf[len] = 0; port = UNBOUND_DNS_OVER_TLS_PORT; *auth_name = s+1; return ipstrtoaddr(buf, port, addr, addrlen); } *auth_name = NULL; return ipstrtoaddr(str, port, addr, addrlen); }
/** 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; }
int extstrtoaddr(const char* str, struct sockaddr_storage* addr, socklen_t* addrlen) { char* s; int port = UNBOUND_DNS_PORT; if((s=strchr(str, '@'))) { char buf[MAX_ADDR_STRLEN]; if(s-str >= MAX_ADDR_STRLEN) { return 0; } (void)strlcpy(buf, str, sizeof(buf)); buf[s-str] = 0; port = atoi(s+1); if(port == 0 && strcmp(s+1,"0")!=0) { return 0; } return ipstrtoaddr(buf, port, addr, addrlen); } return ipstrtoaddr(str, port, addr, addrlen); }
/** 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; }
/** delayer main service routine */ static void service(const char* bind_str, int bindport, const char* serv_str, size_t memsize, int delay_msec) { struct sockaddr_storage bind_addr, srv_addr; socklen_t bind_len, srv_len; struct ringbuf* ring = ring_create(memsize); struct timeval delay, reuse; sldns_buffer* pkt; int i, s, listen_s; #ifndef S_SPLINT_S delay.tv_sec = delay_msec / 1000; delay.tv_usec = (delay_msec % 1000)*1000; #endif reuse = delay; /* reuse is max(4*delay, 1 second) */ dl_tv_add(&reuse, &delay); dl_tv_add(&reuse, &delay); dl_tv_add(&reuse, &delay); if(reuse.tv_sec == 0) reuse.tv_sec = 1; if(!extstrtoaddr(serv_str, &srv_addr, &srv_len)) { printf("cannot parse forward address: %s\n", serv_str); exit(1); } pkt = sldns_buffer_new(65535); if(!pkt) fatal_exit("out of memory"); if( signal(SIGINT, delayer_sigh) == SIG_ERR || #ifdef SIGHUP signal(SIGHUP, delayer_sigh) == SIG_ERR || #endif #ifdef SIGQUIT signal(SIGQUIT, delayer_sigh) == SIG_ERR || #endif #ifdef SIGBREAK signal(SIGBREAK, delayer_sigh) == SIG_ERR || #endif #ifdef SIGALRM signal(SIGALRM, delayer_sigh) == SIG_ERR || #endif signal(SIGTERM, delayer_sigh) == SIG_ERR) fatal_exit("could not bind to signal"); /* bind UDP port */ if((s = socket(str_is_ip6(bind_str)?AF_INET6:AF_INET, SOCK_DGRAM, 0)) == -1) { #ifndef USE_WINSOCK fatal_exit("socket: %s", strerror(errno)); #else fatal_exit("socket: %s", wsa_strerror(WSAGetLastError())); #endif } i=0; if(bindport == 0) { bindport = 1024 + random()%64000; i = 100; } while(1) { if(!ipstrtoaddr(bind_str, bindport, &bind_addr, &bind_len)) { printf("cannot parse listen address: %s\n", bind_str); exit(1); } if(bind(s, (struct sockaddr*)&bind_addr, bind_len) == -1) { #ifndef USE_WINSOCK log_err("bind: %s", strerror(errno)); #else log_err("bind: %s", wsa_strerror(WSAGetLastError())); #endif if(i--==0) fatal_exit("cannot bind any port"); bindport = 1024 + random()%64000; } else break; } fd_set_nonblock(s); /* and TCP port */ if((listen_s = socket(str_is_ip6(bind_str)?AF_INET6:AF_INET, SOCK_STREAM, 0)) == -1) { #ifndef USE_WINSOCK fatal_exit("tcp socket: %s", strerror(errno)); #else fatal_exit("tcp socket: %s", wsa_strerror(WSAGetLastError())); #endif } #ifdef SO_REUSEADDR if(1) { int on = 1; if(setsockopt(listen_s, SOL_SOCKET, SO_REUSEADDR, (void*)&on, (socklen_t)sizeof(on)) < 0) #ifndef USE_WINSOCK fatal_exit("setsockopt(.. SO_REUSEADDR ..) failed: %s", strerror(errno)); #else fatal_exit("setsockopt(.. SO_REUSEADDR ..) failed: %s", wsa_strerror(WSAGetLastError())); #endif } #endif if(bind(listen_s, (struct sockaddr*)&bind_addr, bind_len) == -1) { #ifndef USE_WINSOCK fatal_exit("tcp bind: %s", strerror(errno)); #else fatal_exit("tcp bind: %s", wsa_strerror(WSAGetLastError())); #endif } if(listen(listen_s, 5) == -1) { #ifndef USE_WINSOCK fatal_exit("tcp listen: %s", strerror(errno)); #else fatal_exit("tcp listen: %s", wsa_strerror(WSAGetLastError())); #endif } fd_set_nonblock(listen_s); printf("listening on port: %d\n", bindport); /* process loop */ do_quit = 0; service_loop(s, listen_s, ring, &delay, &reuse, &srv_addr, srv_len, pkt); /* cleanup */ verbose(1, "cleanup"); #ifndef USE_WINSOCK close(s); close(listen_s); #else closesocket(s); closesocket(listen_s); #endif sldns_buffer_free(pkt); ring_delete(ring); }