void dname_test(void) { sldns_buffer* loopbuf = sldns_buffer_new(14); sldns_buffer* boundbuf = sldns_buffer_new(16); sldns_buffer* buff = sldns_buffer_new(65800); unit_assert(loopbuf && boundbuf && buff); sldns_buffer_flip(buff); dname_setup_bufs(loopbuf, boundbuf); dname_test_qdl(buff); dname_test_qdtl(buff); dname_test_pdtl(loopbuf, boundbuf); dname_test_query_dname_compare(); dname_test_count_labels(); dname_test_count_size_labels(); dname_test_dname_lab_cmp(); dname_test_pkt_dname_len(buff); dname_test_strict_subdomain(); dname_test_subdomain(); dname_test_isroot(); dname_test_removelabel(); dname_test_sigcount(); dname_test_iswild(); dname_test_canoncmp(); dname_test_topdomain(); dname_test_valid(); sldns_buffer_free(buff); sldns_buffer_free(loopbuf); sldns_buffer_free(boundbuf); }
/** * Create commpoint (as return address) for a fake incoming query. */ static void fake_front_query(struct replay_runtime* runtime, struct replay_moment *todo) { struct comm_reply repinfo; memset(&repinfo, 0, sizeof(repinfo)); repinfo.c = (struct comm_point*)calloc(1, sizeof(struct comm_point)); repinfo.addrlen = (socklen_t)sizeof(struct sockaddr_in); if(todo->addrlen != 0) { repinfo.addrlen = todo->addrlen; memcpy(&repinfo.addr, &todo->addr, todo->addrlen); } repinfo.c->fd = -1; repinfo.c->ev = (struct internal_event*)runtime; repinfo.c->buffer = sldns_buffer_new(runtime->bufsize); if(todo->match->match_transport == transport_tcp) repinfo.c->type = comm_tcp; else repinfo.c->type = comm_udp; fill_buffer_with_reply(repinfo.c->buffer, todo->match, NULL, 0); log_info("testbound: incoming QUERY"); log_pkt("query pkt", todo->match->reply_list->reply_pkt, todo->match->reply_list->reply_len); /* call the callback for incoming queries */ if((*runtime->callback_query)(repinfo.c, runtime->cb_arg, NETEVENT_NOERROR, &repinfo)) { /* send immediate reply */ comm_point_send_reply(&repinfo); } /* clear it again, in case copy not done properly */ memset(&repinfo, 0, sizeof(repinfo)); }
/** * Perform callback for fake pending message. */ static void fake_pending_callback(struct replay_runtime* runtime, struct replay_moment* todo, int error) { struct fake_pending* p = runtime->pending_list; struct comm_reply repinfo; struct comm_point c; void* cb_arg; comm_point_callback_t* cb; memset(&c, 0, sizeof(c)); if(!p) fatal_exit("No pending queries."); cb_arg = p->cb_arg; cb = p->callback; c.buffer = sldns_buffer_new(runtime->bufsize); c.type = comm_udp; if(p->transport == transport_tcp) c.type = comm_tcp; if(todo->evt_type == repevt_back_reply && todo->match) { fill_buffer_with_reply(c.buffer, todo->match, p->pkt, p->pkt_len); } repinfo.c = &c; repinfo.addrlen = p->addrlen; memcpy(&repinfo.addr, &p->addr, p->addrlen); if(!p->serviced) pending_list_delete(runtime, p); if((*cb)(&c, cb_arg, error, &repinfo)) { fatal_exit("unexpected: pending callback returned 1"); } /* delete the pending item. */ sldns_buffer_free(c.buffer); }
/** verify DS matches DNSKEY from a file */ static void dstest_file(const char* fname) { /* * The file contains a list of ldns-testpkts entries. * The first entry must be a query for DNSKEY. * The answer rrset is the keyset that will be used for verification */ struct regional* region = regional_create(); struct alloc_cache alloc; sldns_buffer* buf = sldns_buffer_new(65535); struct entry* e; struct entry* list = read_datafile(fname, 1); struct module_env env; if(!list) fatal_exit("could not read %s: %s", fname, strerror(errno)); alloc_init(&alloc, NULL, 1); memset(&env, 0, sizeof(env)); env.scratch = region; env.scratch_buffer = buf; unit_assert(region && buf); /* ready to go! */ for(e = list; e; e = e->next) { dstest_entry(e, &alloc, region, buf, &env); } delete_entry(list); regional_destroy(region); alloc_clear(&alloc); sldns_buffer_free(buf); }
struct outside_network* outside_network_create(struct comm_base* base, size_t bufsize, size_t ATTR_UNUSED(num_ports), char** ATTR_UNUSED(ifs), int ATTR_UNUSED(num_ifs), int ATTR_UNUSED(do_ip4), int ATTR_UNUSED(do_ip6), size_t ATTR_UNUSED(num_tcp), struct infra_cache* infra, struct ub_randstate* ATTR_UNUSED(rnd), int ATTR_UNUSED(use_caps_for_id), int* ATTR_UNUSED(availports), int ATTR_UNUSED(numavailports), size_t ATTR_UNUSED(unwanted_threshold), void (*unwanted_action)(void*), void* ATTR_UNUSED(unwanted_param), int ATTR_UNUSED(do_udp), void* ATTR_UNUSED(sslctx), int ATTR_UNUSED(delayclose)) { struct replay_runtime* runtime = (struct replay_runtime*)base; struct outside_network* outnet = calloc(1, sizeof(struct outside_network)); (void)unwanted_action; if(!outnet) return NULL; runtime->infra = infra; outnet->base = base; outnet->udp_buff = sldns_buffer_new(bufsize); if(!outnet->udp_buff) { free(outnet); return NULL; } return outnet; }
/** * Perform range entry on pending message. * @param runtime: runtime buffer size preference. * @param entry: entry that codes for the reply to do. * @param pend: pending query that is answered, callback called. */ static void answer_callback_from_entry(struct replay_runtime* runtime, struct entry* entry, struct fake_pending* pend) { struct comm_point c; struct comm_reply repinfo; void* cb_arg = pend->cb_arg; comm_point_callback_t* cb = pend->callback; memset(&c, 0, sizeof(c)); c.fd = -1; c.buffer = sldns_buffer_new(runtime->bufsize); c.type = comm_udp; if(pend->transport == transport_tcp) c.type = comm_tcp; fill_buffer_with_reply(c.buffer, entry, pend->pkt, pend->pkt_len); repinfo.c = &c; repinfo.addrlen = pend->addrlen; memcpy(&repinfo.addr, &pend->addr, pend->addrlen); if(!pend->serviced) pending_list_delete(runtime, pend); if((*cb)(&c, cb_arg, NETEVENT_NOERROR, &repinfo)) { fatal_exit("testbound: unexpected: callback returned 1"); } sldns_buffer_free(c.buffer); }
/** send the TCP queries and print answers */ static void send_em(const char* svr, int udp, int usessl, int noanswer, int num, char** qs) { sldns_buffer* buf = sldns_buffer_new(65553); int fd = open_svr(svr, udp); int i; SSL_CTX* ctx = NULL; SSL* ssl = NULL; if(!buf) fatal_exit("out of memory"); if(usessl) { ctx = connect_sslctx_create(NULL, NULL, NULL); if(!ctx) fatal_exit("cannot create ssl ctx"); ssl = outgoing_ssl_fd(ctx, fd); if(!ssl) fatal_exit("cannot create ssl"); while(1) { int r; ERR_clear_error(); if( (r=SSL_do_handshake(ssl)) == 1) break; r = SSL_get_error(ssl, r); if(r != SSL_ERROR_WANT_READ && r != SSL_ERROR_WANT_WRITE) { log_crypto_err("could not ssl_handshake"); exit(1); } } if(1) { X509* x = SSL_get_peer_certificate(ssl); if(!x) printf("SSL: no peer certificate\n"); else { X509_print_fp(stdout, x); X509_free(x); } } } for(i=0; i<num; i+=3) { printf("\nNext query is %s %s %s\n", qs[i], qs[i+1], qs[i+2]); write_q(fd, udp, ssl, buf, (uint16_t)get_random(), qs[i], qs[i+1], qs[i+2]); /* print at least one result */ if(!noanswer) recv_one(fd, udp, ssl, buf); } if(usessl) { SSL_shutdown(ssl); SSL_free(ssl); SSL_CTX_free(ctx); } #ifndef USE_WINSOCK close(fd); #else closesocket(fd); #endif sldns_buffer_free(buf); printf("orderly exit\n"); }
struct listen_dnsport* listen_create(struct comm_base* base, struct listen_port* ports, size_t bufsize, int tcp_accept_count, void* sslctx, struct dt_env* dtenv, comm_point_callback_t* cb, void *cb_arg) { struct listen_dnsport* front = (struct listen_dnsport*) malloc(sizeof(struct listen_dnsport)); if(!front) return NULL; front->cps = NULL; front->udp_buff = sldns_buffer_new(bufsize); if(!front->udp_buff) { free(front); return NULL; } /* create comm points as needed */ while(ports) { struct comm_point* cp = NULL; if(ports->ftype == listen_type_udp) cp = comm_point_create_udp(base, ports->fd, front->udp_buff, cb, cb_arg); else if(ports->ftype == listen_type_tcp) cp = comm_point_create_tcp(base, ports->fd, tcp_accept_count, bufsize, cb, cb_arg); else if(ports->ftype == listen_type_ssl) { cp = comm_point_create_tcp(base, ports->fd, tcp_accept_count, bufsize, cb, cb_arg); cp->ssl = sslctx; } else if(ports->ftype == listen_type_udpancil) cp = comm_point_create_udp_ancil(base, ports->fd, front->udp_buff, cb, cb_arg); if(!cp) { log_err("can't create commpoint"); listen_delete(front); return NULL; } cp->dtenv = dtenv; cp->do_not_close = 1; if(!listen_cp_insert(cp, front)) { log_err("malloc failed"); comm_point_delete(cp); listen_delete(front); return NULL; } ports = ports->next; } if(!front->cps) { log_err("Could not open sockets to accept queries."); listen_delete(front); return NULL; } return front; }
void msgparse_test(void) { sldns_buffer* pkt = sldns_buffer_new(65553); sldns_buffer* out = sldns_buffer_new(65553); struct alloc_cache super_a, alloc; /* init */ alloc_init(&super_a, NULL, 0); alloc_init(&alloc, &super_a, 2); unit_show_feature("message parse"); simpletest(pkt, &alloc, out); /* plain hex dumps, like pcat */ testfromfile(pkt, &alloc, out, "testdata/test_packets.1"); testfromfile(pkt, &alloc, out, "testdata/test_packets.2"); testfromfile(pkt, &alloc, out, "testdata/test_packets.3"); /* like from drill -w - */ testfromdrillfile(pkt, &alloc, out, "testdata/test_packets.4"); testfromdrillfile(pkt, &alloc, out, "testdata/test_packets.5"); matches_nolocation = 1; /* RR order not important for the next test */ testfromdrillfile(pkt, &alloc, out, "testdata/test_packets.6"); check_rrsigs = 1; testfromdrillfile(pkt, &alloc, out, "testdata/test_packets.7"); check_rrsigs = 0; matches_nolocation = 0; check_formerr_gone = 1; testfromdrillfile(pkt, &alloc, out, "testdata/test_packets.8"); check_formerr_gone = 0; check_rrsigs = 1; check_nosameness = 1; testfromdrillfile(pkt, &alloc, out, "testdata/test_packets.9"); check_nosameness = 0; check_rrsigs = 0; /* cleanup */ alloc_clear(&alloc); alloc_clear(&super_a); sldns_buffer_free(pkt); sldns_buffer_free(out); }
void anchors_test(void) { sldns_buffer* buff = sldns_buffer_new(65800); struct val_anchors* a; unit_show_feature("trust anchor store"); unit_assert(a = anchors_create()); sldns_buffer_flip(buff); test_anchor_empty(a); test_anchor_one(buff, a); test_anchors(buff, a); anchors_delete(a); sldns_buffer_free(buff); }
/** main program for pktview */ int main(int argc, char* argv[]) { sldns_buffer* pkt = sldns_buffer_new(65553); if(argc != 1) { usage(argv); } if(!pkt) fatal_exit("out of memory"); read_input(pkt, stdin); analyze(pkt); sldns_buffer_free(pkt); return 0; }
struct waiting_tcp* pending_tcp_query(struct outside_network* outnet, sldns_buffer* packet, struct sockaddr_storage* addr, socklen_t addrlen, int timeout, comm_point_callback_t* callback, void* callback_arg, int ATTR_UNUSED(ssl_upstream)) { struct replay_runtime* runtime = (struct replay_runtime*)outnet->base; struct fake_pending* pend = (struct fake_pending*)calloc(1, sizeof(struct fake_pending)); log_assert(pend); pend->buffer = sldns_buffer_new(sldns_buffer_capacity(packet)); log_assert(pend->buffer); sldns_buffer_write(pend->buffer, sldns_buffer_begin(packet), sldns_buffer_limit(packet)); sldns_buffer_flip(pend->buffer); memcpy(&pend->addr, addr, addrlen); pend->addrlen = addrlen; pend->callback = callback; pend->cb_arg = callback_arg; pend->timeout = timeout; pend->transport = transport_tcp; pend->pkt = NULL; pend->zone = NULL; pend->runtime = runtime; pend->serviced = 0; pend->pkt_len = sldns_buffer_limit(packet); pend->pkt = memdup(sldns_buffer_begin(packet), pend->pkt_len); if(!pend->pkt) fatal_exit("out of memory"); log_pkt("pending tcp pkt: ", pend->pkt, pend->pkt_len); /* see if it matches the current moment */ if(runtime->now && runtime->now->evt_type == repevt_back_query && (runtime->now->addrlen == 0 || sockaddr_cmp( &runtime->now->addr, runtime->now->addrlen, &pend->addr, pend->addrlen) == 0) && find_match(runtime->now->match, pend->pkt, pend->pkt_len, pend->transport)) { log_info("testbound: matched pending to event. " "advance time between events."); log_info("testbound: do STEP %d %s", runtime->now->time_step, repevt_string(runtime->now->evt_type)); advance_moment(runtime); /* still create the pending, because we need it to callback */ } log_info("testbound: created fake pending"); /* add to list */ pend->next = runtime->pending_list; runtime->pending_list = pend; return (struct waiting_tcp*)pend; }
/** verify from a file */ static void verifytest_file(const char* fname, const char* at_date) { /* * The file contains a list of ldns-testpkts entries. * The first entry must be a query for DNSKEY. * The answer rrset is the keyset that will be used for verification */ struct ub_packed_rrset_key* dnskey; struct regional* region = regional_create(); struct alloc_cache alloc; sldns_buffer* buf = sldns_buffer_new(65535); struct entry* e; struct entry* list = read_datafile(fname, 1); struct module_env env; struct val_env ve; time_t now = time(NULL); if(!list) fatal_exit("could not read %s: %s", fname, strerror(errno)); alloc_init(&alloc, NULL, 1); memset(&env, 0, sizeof(env)); memset(&ve, 0, sizeof(ve)); env.scratch = region; env.scratch_buffer = buf; env.now = &now; ve.date_override = cfg_convert_timeval(at_date); unit_assert(region && buf); dnskey = extract_keys(list, &alloc, region, buf); if(vsig) log_nametypeclass(VERB_QUERY, "test dnskey", dnskey->rk.dname, ntohs(dnskey->rk.type), ntohs(dnskey->rk.rrset_class)); /* ready to go! */ for(e = list->next; e; e = e->next) { verifytest_entry(e, &alloc, region, buf, dnskey, &env, &ve); } ub_packed_rrset_parsedelete(dnskey, &alloc); delete_entry(list); regional_destroy(region); alloc_clear(&alloc); sldns_buffer_free(buf); }
struct listen_dnsport* listen_create(struct comm_base* base, struct listen_port* ATTR_UNUSED(ports), size_t bufsize, int ATTR_UNUSED(tcp_accept_count), void* ATTR_UNUSED(sslctx), comm_point_callback_t* cb, void* cb_arg) { struct replay_runtime* runtime = (struct replay_runtime*)base; struct listen_dnsport* l= calloc(1, sizeof(struct listen_dnsport)); if(!l) return NULL; l->base = base; l->udp_buff = sldns_buffer_new(bufsize); if(!l->udp_buff) { free(l); return NULL; } runtime->callback_query = cb; runtime->cb_arg = cb_arg; runtime->bufsize = bufsize; return l; }
void log_dns_msg(const char* str, struct query_info* qinfo, struct reply_info* rep) { /* not particularly fast but flexible, make wireformat and print */ sldns_buffer* buf = sldns_buffer_new(65535); struct regional* region = regional_create(); if(!reply_info_encode(qinfo, rep, 0, rep->flags, buf, 0, region, 65535, 1)) { log_info("%s: log_dns_msg: out of memory", str); } else { char* s = sldns_wire2str_pkt(sldns_buffer_begin(buf), sldns_buffer_limit(buf)); if(!s) { log_info("%s: log_dns_msg: ldns tostr failed", str); } else { log_info("%s %s", str, s); } free(s); } sldns_buffer_free(buf); regional_destroy(region); }
/** Read file to test NSEC3 hash algo */ static void nsec3_hash_test(const char* fname) { /* * The list contains a list of ldns-testpkts entries. * Every entry is a test. * The qname is hashed. * The answer section AAAA RR name is the required result. * The auth section NSEC3 is used to get hash parameters. * The hash cache is maintained per file. * * The test does not perform canonicalization during the compare. */ rbtree_type ct; struct regional* region = regional_create(); struct alloc_cache alloc; sldns_buffer* buf = sldns_buffer_new(65535); struct entry* e; struct entry* list = read_datafile(fname, 1); if(!list) fatal_exit("could not read %s: %s", fname, strerror(errno)); rbtree_init(&ct, &nsec3_hash_cmp); alloc_init(&alloc, NULL, 1); unit_assert(region && buf); /* ready to go! */ for(e = list; e; e = e->next) { nsec3_hash_test_entry(e, &ct, &alloc, region, buf); } delete_entry(list); regional_destroy(region); alloc_clear(&alloc); sldns_buffer_free(buf); }
int anchors_apply_cfg(struct val_anchors* anchors, struct config_file* cfg) { struct config_strlist* f; char* nm; sldns_buffer* parsebuf = sldns_buffer_new(65535); for(f = cfg->domain_insecure; f; f = f->next) { if(!f->str || f->str[0] == 0) /* empty "" */ continue; if(!anchor_insert_insecure(anchors, f->str)) { log_err("error in domain-insecure: %s", f->str); sldns_buffer_free(parsebuf); return 0; } } for(f = cfg->trust_anchor_file_list; f; f = f->next) { if(!f->str || f->str[0] == 0) /* empty "" */ continue; nm = f->str; if(cfg->chrootdir && cfg->chrootdir[0] && strncmp(nm, cfg->chrootdir, strlen(cfg->chrootdir)) == 0) nm += strlen(cfg->chrootdir); if(!anchor_read_file(anchors, parsebuf, nm, 0)) { log_err("error reading trust-anchor-file: %s", f->str); sldns_buffer_free(parsebuf); return 0; } } for(f = cfg->trusted_keys_file_list; f; f = f->next) { if(!f->str || f->str[0] == 0) /* empty "" */ continue; nm = f->str; if(cfg->chrootdir && cfg->chrootdir[0] && strncmp(nm, cfg->chrootdir, strlen(cfg->chrootdir)) == 0) nm += strlen(cfg->chrootdir); if(!anchor_read_bind_file_wild(anchors, parsebuf, nm)) { log_err("error reading trusted-keys-file: %s", f->str); sldns_buffer_free(parsebuf); return 0; } } for(f = cfg->trust_anchor_list; f; f = f->next) { if(!f->str || f->str[0] == 0) /* empty "" */ continue; if(!anchor_store_str(anchors, parsebuf, f->str)) { log_err("error in trust-anchor: \"%s\"", f->str); sldns_buffer_free(parsebuf); return 0; } } if(cfg->dlv_anchor_file && cfg->dlv_anchor_file[0] != 0) { struct trust_anchor* dlva; nm = cfg->dlv_anchor_file; if(cfg->chrootdir && cfg->chrootdir[0] && strncmp(nm, cfg->chrootdir, strlen(cfg->chrootdir)) == 0) nm += strlen(cfg->chrootdir); if(!(dlva = anchor_read_file(anchors, parsebuf, nm, 1))) { log_err("error reading dlv-anchor-file: %s", cfg->dlv_anchor_file); sldns_buffer_free(parsebuf); return 0; } lock_basic_lock(&anchors->lock); anchors->dlv_anchor = dlva; lock_basic_unlock(&anchors->lock); } for(f = cfg->dlv_anchor_list; f; f = f->next) { struct trust_anchor* dlva; if(!f->str || f->str[0] == 0) /* empty "" */ continue; if(!(dlva = anchor_store_str( anchors, parsebuf, f->str))) { log_err("error in dlv-anchor: \"%s\"", f->str); sldns_buffer_free(parsebuf); return 0; } lock_basic_lock(&anchors->lock); anchors->dlv_anchor = dlva; lock_basic_unlock(&anchors->lock); } /* do autr last, so that it sees what anchors are filled by other * means can can print errors about double config for the name */ for(f = cfg->auto_trust_anchor_file_list; f; f = f->next) { if(!f->str || f->str[0] == 0) /* empty "" */ continue; nm = f->str; if(cfg->chrootdir && cfg->chrootdir[0] && strncmp(nm, cfg->chrootdir, strlen(cfg->chrootdir)) == 0) nm += strlen(cfg->chrootdir); if(!autr_read_file(anchors, nm)) { log_err("error reading auto-trust-anchor-file: %s", f->str); sldns_buffer_free(parsebuf); return 0; } } /* first assemble, since it may delete useless anchors */ anchors_assemble_rrsets(anchors); init_parents(anchors); sldns_buffer_free(parsebuf); if(verbosity >= VERB_ALGO) autr_debug_print(anchors); return 1; }
/** 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); }
/** main program for perf */ int main(int argc, char* argv[]) { char* nm = argv[0]; int c; struct perfinfo info; #ifdef USE_WINSOCK int r; WSADATA wsa_data; #endif /* defaults */ memset(&info, 0, sizeof(info)); info.io_num = 16; log_init(NULL, 0, NULL); log_ident_set("perf"); checklock_start(); #ifdef USE_WINSOCK if((r = WSAStartup(MAKEWORD(2,2), &wsa_data)) != 0) fatal_exit("WSAStartup failed: %s", wsa_strerror(r)); #endif info.buf = sldns_buffer_new(65553); if(!info.buf) fatal_exit("out of memory"); /* parse the options */ while( (c=getopt(argc, argv, "d:ha:f:q")) != -1) { switch(c) { case 'q': info.quiet = 1; break; case 'd': if(atoi(optarg)==0 && strcmp(optarg, "0")!=0) { printf("-d not a number %s", optarg); return 1; } info.duration = atoi(optarg); break; case 'a': qlist_add_line(&info, optarg, 0); break; case 'f': qlist_read_file(&info, optarg); break; case '?': case 'h': default: usage(nm); } } argc -= optind; argv += optind; if(argc != 1) { printf("error: pass server IP address on commandline.\n"); usage(nm); } if(!extstrtoaddr(argv[0], &info.dest, &info.destlen)) { printf("Could not parse ip: %s\n", argv[0]); return 1; } if(info.qlist_size == 0) { printf("No queries to make, use -f or -a.\n"); return 1; } /* do the performance test */ perfmain(&info); sldns_buffer_free(info.buf); #ifdef USE_WINSOCK WSACleanup(); #endif checklock_stop(); return 0; }
/** setup fresh libworker struct */ static struct libworker* libworker_setup(struct ub_ctx* ctx, int is_bg, struct ub_event_base* eb) { unsigned int seed; struct libworker* w = (struct libworker*)calloc(1, sizeof(*w)); struct config_file* cfg = ctx->env->cfg; int* ports; int numports; if(!w) return NULL; w->is_bg = is_bg; w->ctx = ctx; w->env = (struct module_env*)malloc(sizeof(*w->env)); if(!w->env) { free(w); return NULL; } *w->env = *ctx->env; w->env->alloc = context_obtain_alloc(ctx, !w->is_bg || w->is_bg_thread); if(!w->env->alloc) { libworker_delete(w); return NULL; } w->thread_num = w->env->alloc->thread_num; alloc_set_id_cleanup(w->env->alloc, &libworker_alloc_cleanup, w); if(!w->is_bg || w->is_bg_thread) { lock_basic_lock(&ctx->cfglock); } w->env->scratch = regional_create_custom(cfg->msg_buffer_size); w->env->scratch_buffer = sldns_buffer_new(cfg->msg_buffer_size); w->env->fwds = forwards_create(); if(w->env->fwds && !forwards_apply_cfg(w->env->fwds, cfg)) { forwards_delete(w->env->fwds); w->env->fwds = NULL; } w->env->hints = hints_create(); if(w->env->hints && !hints_apply_cfg(w->env->hints, cfg)) { hints_delete(w->env->hints); w->env->hints = NULL; } if(cfg->ssl_upstream) { w->sslctx = connect_sslctx_create(NULL, NULL, cfg->tls_cert_bundle); if(!w->sslctx) { /* to make the setup fail after unlock */ hints_delete(w->env->hints); w->env->hints = NULL; } } if(!w->is_bg || w->is_bg_thread) { lock_basic_unlock(&ctx->cfglock); } if(!w->env->scratch || !w->env->scratch_buffer || !w->env->fwds || !w->env->hints) { libworker_delete(w); return NULL; } w->env->worker = (struct worker*)w; w->env->probe_timer = NULL; seed = (unsigned int)time(NULL) ^ (unsigned int)getpid() ^ (((unsigned int)w->thread_num)<<17); seed ^= (unsigned int)w->env->alloc->next_id; if(!w->is_bg || w->is_bg_thread) { lock_basic_lock(&ctx->cfglock); } if(!(w->env->rnd = ub_initstate(seed, ctx->seed_rnd))) { if(!w->is_bg || w->is_bg_thread) { lock_basic_unlock(&ctx->cfglock); } seed = 0; libworker_delete(w); return NULL; } if(!w->is_bg || w->is_bg_thread) { lock_basic_unlock(&ctx->cfglock); } if(1) { /* primitive lockout for threading: if it overwrites another * thread it is like wiping the cache (which is likely empty * at the start) */ /* note we are holding the ctx lock in normal threaded * cases so that is solved properly, it is only for many ctx * in different threads that this may clash */ static int done_raninit = 0; if(!done_raninit) { done_raninit = 1; hash_set_raninit((uint32_t)ub_random(w->env->rnd)); } } seed = 0; if(eb) w->base = comm_base_create_event(eb); else w->base = comm_base_create(0); if(!w->base) { libworker_delete(w); return NULL; } w->env->worker_base = w->base; if(!w->is_bg || w->is_bg_thread) { lock_basic_lock(&ctx->cfglock); } numports = cfg_condense_ports(cfg, &ports); if(numports == 0) { int locked = !w->is_bg || w->is_bg_thread; libworker_delete(w); if(locked) { lock_basic_unlock(&ctx->cfglock); } return NULL; } w->back = outside_network_create(w->base, cfg->msg_buffer_size, (size_t)cfg->outgoing_num_ports, cfg->out_ifs, cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6, cfg->do_tcp?cfg->outgoing_num_tcp:0, w->env->infra_cache, w->env->rnd, cfg->use_caps_bits_for_id, ports, numports, cfg->unwanted_threshold, cfg->outgoing_tcp_mss, &libworker_alloc_cleanup, w, cfg->do_udp || cfg->udp_upstream_without_downstream, w->sslctx, cfg->delay_close, NULL); w->env->outnet = w->back; if(!w->is_bg || w->is_bg_thread) { lock_basic_unlock(&ctx->cfglock); } free(ports); if(!w->back) { libworker_delete(w); return NULL; } w->env->mesh = mesh_create(&ctx->mods, w->env); if(!w->env->mesh) { libworker_delete(w); return NULL; } w->env->send_query = &libworker_send_query; w->env->detach_subs = &mesh_detach_subs; w->env->attach_sub = &mesh_attach_sub; w->env->add_sub = &mesh_add_sub; w->env->kill_sub = &mesh_state_delete; w->env->detect_cycle = &mesh_detect_cycle; comm_base_timept(w->base, &w->env->now, &w->env->now_tv); return w; }
/** process answer from bg worker */ static int process_answer_detail(struct ub_ctx* ctx, uint8_t* msg, uint32_t len, ub_callback_t* cb, void** cbarg, int* err, struct ub_result** res) { struct ctx_query* q; if(context_serial_getcmd(msg, len) != UB_LIBCMD_ANSWER) { log_err("error: bad data from bg worker %d", (int)context_serial_getcmd(msg, len)); return 0; } lock_basic_lock(&ctx->cfglock); q = context_deserialize_answer(ctx, msg, len, err); if(!q) { lock_basic_unlock(&ctx->cfglock); /* probably simply the lookup that failed, i.e. * response returned before cancel was sent out, so noerror */ return 1; } log_assert(q->async); /* grab cb while locked */ if(q->cancelled) { *cb = NULL; *cbarg = NULL; } else { *cb = q->cb; *cbarg = q->cb_arg; } if(*err) { *res = NULL; ub_resolve_free(q->res); } else { /* parse the message, extract rcode, fill result */ sldns_buffer* buf = sldns_buffer_new(q->msg_len); struct regional* region = regional_create(); *res = q->res; (*res)->rcode = LDNS_RCODE_SERVFAIL; if(region && buf) { sldns_buffer_clear(buf); sldns_buffer_write(buf, q->msg, q->msg_len); sldns_buffer_flip(buf); libworker_enter_result(*res, buf, region, q->msg_security); } (*res)->answer_packet = q->msg; (*res)->answer_len = (int)q->msg_len; q->msg = NULL; sldns_buffer_free(buf); regional_destroy(region); } q->res = NULL; /* delete the q from list */ (void)rbtree_delete(&ctx->queries, q->node.key); ctx->num_async--; context_query_delete(q); lock_basic_unlock(&ctx->cfglock); if(*cb) return 2; ub_resolve_free(*res); return 1; }
struct serviced_query* outnet_serviced_query(struct outside_network* outnet, uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec, int ATTR_UNUSED(want_dnssec), int ATTR_UNUSED(tcp_upstream), int ATTR_UNUSED(ssl_upstream), struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone, size_t zonelen, comm_point_callback_t* callback, void* callback_arg, sldns_buffer* ATTR_UNUSED(buff)) { struct replay_runtime* runtime = (struct replay_runtime*)outnet->base; struct fake_pending* pend = (struct fake_pending*)calloc(1, sizeof(struct fake_pending)); char z[256]; log_assert(pend); log_nametypeclass(VERB_OPS, "pending serviced query", qname, qtype, qclass); dname_str(zone, z); verbose(VERB_OPS, "pending serviced query zone %s flags%s%s%s%s", z, (flags&BIT_RD)?" RD":"", (flags&BIT_CD)?" CD":"", (flags&~(BIT_RD|BIT_CD))?" MORE":"", (dnssec)?" DO":""); /* create packet with EDNS */ pend->buffer = sldns_buffer_new(512); log_assert(pend->buffer); sldns_buffer_write_u16(pend->buffer, 0); /* id */ sldns_buffer_write_u16(pend->buffer, flags); sldns_buffer_write_u16(pend->buffer, 1); /* qdcount */ sldns_buffer_write_u16(pend->buffer, 0); /* ancount */ sldns_buffer_write_u16(pend->buffer, 0); /* nscount */ sldns_buffer_write_u16(pend->buffer, 0); /* arcount */ sldns_buffer_write(pend->buffer, qname, qnamelen); sldns_buffer_write_u16(pend->buffer, qtype); sldns_buffer_write_u16(pend->buffer, qclass); sldns_buffer_flip(pend->buffer); if(1) { /* add edns */ struct edns_data edns; edns.edns_present = 1; edns.ext_rcode = 0; edns.edns_version = EDNS_ADVERTISED_VERSION; edns.udp_size = EDNS_ADVERTISED_SIZE; edns.bits = 0; if(dnssec) edns.bits = EDNS_DO; attach_edns_record(pend->buffer, &edns); } memcpy(&pend->addr, addr, addrlen); pend->addrlen = addrlen; pend->zone = memdup(zone, zonelen); pend->zonelen = zonelen; pend->qtype = (int)qtype; log_assert(pend->zone); pend->callback = callback; pend->cb_arg = callback_arg; pend->timeout = UDP_AUTH_QUERY_TIMEOUT; pend->transport = transport_udp; /* pretend UDP */ pend->pkt = NULL; pend->runtime = runtime; pend->serviced = 1; pend->pkt_len = sldns_buffer_limit(pend->buffer); pend->pkt = memdup(sldns_buffer_begin(pend->buffer), pend->pkt_len); if(!pend->pkt) fatal_exit("out of memory"); /*log_pkt("pending serviced query: ", pend->pkt, pend->pkt_len);*/ /* see if it matches the current moment */ if(runtime->now && runtime->now->evt_type == repevt_back_query && (runtime->now->addrlen == 0 || sockaddr_cmp( &runtime->now->addr, runtime->now->addrlen, &pend->addr, pend->addrlen) == 0) && find_match(runtime->now->match, pend->pkt, pend->pkt_len, pend->transport)) { log_info("testbound: matched pending to event. " "advance time between events."); log_info("testbound: do STEP %d %s", runtime->now->time_step, repevt_string(runtime->now->evt_type)); advance_moment(runtime); /* still create the pending, because we need it to callback */ } log_info("testbound: created fake pending"); /* add to list */ pend->next = runtime->pending_list; runtime->pending_list = pend; return (struct serviced_query*)pend; }