void iter_merge_retry_counts(struct delegpt* dp, struct delegpt* old) { struct delegpt_addr* a, *o, *prev; for(a=dp->target_list; a; a = a->next_target) { o = delegpt_find_addr(old, &a->addr, a->addrlen); if(o) { log_addr(VERB_ALGO, "copy attempt count previous dp", &a->addr, a->addrlen); a->attempts = o->attempts; } } prev = NULL; a = dp->usable_list; while(a) { if(a->attempts >= OUTBOUND_MSG_RETRY) { log_addr(VERB_ALGO, "remove from usable list dp", &a->addr, a->addrlen); /* remove from result list */ if(prev) prev->next_usable = a->next_usable; else dp->usable_list = a->next_usable; /* prev stays the same */ a = a->next_usable; continue; } prev = a; a = a->next_usable; } }
/** filter out unsuitable targets * @param iter_env: iterator environment with ipv6-support flag. * @param env: module environment with infra cache. * @param name: zone name * @param namelen: length of name * @param qtype: query type (host order). * @param now: current time * @param a: address in delegation point we are examining. * @return an integer that signals the target suitability. * as follows: * -1: The address should be omitted from the list. * Because: * o The address is bogus (DNSSEC validation failure). * o Listed as donotquery * o is ipv6 but no ipv6 support (in operating system). * o is ipv4 but no ipv4 support (in operating system). * o is lame * Otherwise, an rtt in milliseconds. * 0 .. USEFUL_SERVER_TOP_TIMEOUT-1 * The roundtrip time timeout estimate. less than 2 minutes. * Note that util/rtt.c has a MIN_TIMEOUT of 50 msec, thus * values 0 .. 49 are not used, unless that is changed. * USEFUL_SERVER_TOP_TIMEOUT * This value exactly is given for unresponsive blacklisted. * USEFUL_SERVER_TOP_TIMEOUT+1 * For non-blacklisted servers: huge timeout, but has traffic. * USEFUL_SERVER_TOP_TIMEOUT*1 .. * parent-side lame servers get this penalty. A dispreferential * server. (lame in delegpt). * USEFUL_SERVER_TOP_TIMEOUT*2 .. * dnsseclame servers get penalty * USEFUL_SERVER_TOP_TIMEOUT*3 .. * recursion lame servers get penalty * UNKNOWN_SERVER_NICENESS * If no information is known about the server, this is * returned. 376 msec or so. * +BLACKLIST_PENALTY (of USEFUL_TOP_TIMEOUT*4) for dnssec failed IPs. * * When a final value is chosen that is dnsseclame ; dnsseclameness checking * is turned off (so we do not discard the reply). * When a final value is chosen that is recursionlame; RD bit is set on query. * Because of the numbers this means recursionlame also have dnssec lameness * checking turned off. */ static int iter_filter_unsuitable(struct iter_env* iter_env, struct module_env* env, uint8_t* name, size_t namelen, uint16_t qtype, time_t now, struct delegpt_addr* a) { int rtt, lame, reclame, dnsseclame; if(a->bogus) return -1; /* address of server is bogus */ if(donotq_lookup(iter_env->donotq, &a->addr, a->addrlen)) { log_addr(VERB_ALGO, "skip addr on the donotquery list", &a->addr, a->addrlen); return -1; /* server is on the donotquery list */ } if(!iter_env->supports_ipv6 && addr_is_ip6(&a->addr, a->addrlen)) { return -1; /* there is no ip6 available */ } if(!iter_env->supports_ipv4 && !addr_is_ip6(&a->addr, a->addrlen)) { return -1; /* there is no ip4 available */ } /* check lameness - need zone , class info */ if(infra_get_lame_rtt(env->infra_cache, &a->addr, a->addrlen, name, namelen, qtype, &lame, &dnsseclame, &reclame, &rtt, now)) { log_addr(VERB_ALGO, "servselect", &a->addr, a->addrlen); verbose(VERB_ALGO, " rtt=%d%s%s%s%s", rtt, lame?" LAME":"", dnsseclame?" DNSSEC_LAME":"", reclame?" REC_LAME":"", a->lame?" ADDR_LAME":""); if(lame) return -1; /* server is lame */ else if(rtt >= USEFUL_SERVER_TOP_TIMEOUT) /* server is unresponsive, * we used to return TOP_TIMEOUT, but fairly useless, * because if == TOP_TIMEOUT is dropped because * blacklisted later, instead, remove it here, so * other choices (that are not blacklisted) can be * tried */ return -1; /* select remainder from worst to best */ else if(reclame) return rtt+USEFUL_SERVER_TOP_TIMEOUT*3; /* nonpref */ else if(dnsseclame || a->dnsseclame) return rtt+USEFUL_SERVER_TOP_TIMEOUT*2; /* nonpref */ else if(a->lame) return rtt+USEFUL_SERVER_TOP_TIMEOUT+1; /* nonpref */ else return rtt; } /* no server information present */ if(a->dnsseclame) return UNKNOWN_SERVER_NICENESS+USEFUL_SERVER_TOP_TIMEOUT*2; /* nonpref */ else if(a->lame) return USEFUL_SERVER_TOP_TIMEOUT+1+UNKNOWN_SERVER_NICENESS; /* nonpref */ return UNKNOWN_SERVER_NICENESS; }
/** 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++; } }
/** log a sock_list entry */ static void sock_list_logentry(enum verbosity_value v, const char* s, struct sock_list* p) { if(p->len) log_addr(v, s, &p->addr, p->len); else verbose(v, "%s cache", s); }
/** * Find the range that matches this pending message. * @param runtime: runtime with current moment, and range list. * @param entry: returns the pointer to entry that matches. * @param pend: the pending that the entry must match. * @return: true if a match is found. */ static int pending_find_match(struct replay_runtime* runtime, struct entry** entry, struct fake_pending* pend) { int timenow = runtime->now->time_step; struct replay_range* p = runtime->scenario->range_list; while(p) { if(p->start_step <= timenow && timenow <= p->end_step && (p->addrlen == 0 || sockaddr_cmp(&p->addr, p->addrlen, &pend->addr, pend->addrlen) == 0) && (*entry = find_match(p->match, pend->pkt, pend->pkt_len, pend->transport))) { log_info("matched query time %d in range [%d, %d] " "with entry line %d", timenow, p->start_step, p->end_step, (*entry)->lineno); if(p->addrlen != 0) log_addr(0, "matched ip", &p->addr, p->addrlen); log_pkt("matched pkt: ", (*entry)->reply_list->reply_pkt, (*entry)->reply_list->reply_len); return 1; } p = p->next_range; } return 0; }
char * log_fmt_peer(const struct peer_config *peer) { const char *ip; char *pfmt, *p; ip = log_addr(&peer->remote_addr); if ((peer->remote_addr.aid == AID_INET && peer->remote_masklen != 32) || (peer->remote_addr.aid == AID_INET6 && peer->remote_masklen != 128)) { if (asprintf(&p, "%s/%u", ip, peer->remote_masklen) == -1) fatal(NULL); } else { if ((p = strdup(ip)) == NULL) fatal(NULL); } if (peer->descr[0]) { if (asprintf(&pfmt, "neighbor %s (%s)", p, peer->descr) == -1) fatal(NULL); } else { if (asprintf(&pfmt, "neighbor %s", p) == -1) fatal(NULL); } free(p); return (pfmt); }
static int deny_refuse(struct comm_point* c, enum acl_access acl, enum acl_access deny, enum acl_access refuse, struct worker* worker, struct comm_reply* repinfo) { if(acl == deny) { comm_point_drop_reply(repinfo); if(worker->stats.extended) worker->stats.unwanted_queries++; return 0; } else if(acl == refuse) { log_addr(VERB_ALGO, "refused query from", &repinfo->addr, repinfo->addrlen); log_buf(VERB_ALGO, "refuse", c->buffer); if(worker->stats.extended) worker->stats.unwanted_queries++; if(worker_check_request(c->buffer, worker) == -1) { comm_point_drop_reply(repinfo); return 0; /* discard this */ } sldns_buffer_set_limit(c->buffer, LDNS_HEADER_SIZE); sldns_buffer_write_at(c->buffer, 4, (uint8_t*)"\0\0\0\0\0\0\0\0", 8); LDNS_QR_SET(sldns_buffer_begin(c->buffer)); LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), LDNS_RCODE_REFUSED); return 1; } return -1; }
/** delete tcp proxy */ static void tcp_proxy_delete(struct tcp_proxy* p) { struct tcp_send_list* s, *sn; if(!p) return; log_addr(1, "delete tcp proxy", &p->addr, p->addr_len); s = p->querylist; while(s) { sn = s->next; free(s->item); free(s); s = sn; } s = p->answerlist; while(s) { sn = s->next; free(s->item); free(s); s = sn; } #ifndef USE_WINSOCK close(p->client_s); if(p->server_s != -1) close(p->server_s); #else closesocket(p->client_s); if(p->server_s != -1) closesocket(p->server_s); #endif free(p); }
static uint64_t ReadMMIO(uint64_t phys, uint8_t length){ uint64_t value = 0; //uint32_t *ioaddr; IOMemoryDescriptor* io_desc; IOMemoryMap* io_map; uint64_t page_offset = phys & PAGE_MASK; log_addr((uint64_t) page_offset, 64, "page_offset"); xlate_pa_va(phys, &io_desc, &io_map); if(io_map) { log_addr(io_map->getVirtualAddress(), 64, "io_map->getVirtualAddress"); switch (length) { case 1: value = *(volatile uint8_t *)((uintptr_t)(io_map->getVirtualAddress()) + page_offset); break; case 2: value = OSReadLittleInt16((void *)io_map->getVirtualAddress(), page_offset); break; case 4: value = OSReadLittleInt32((void *)io_map->getVirtualAddress(), page_offset); break; case 8: value = OSReadLittleInt64((void *)io_map->getVirtualAddress(), page_offset); default: pmem_error("ReadMMIO Incorrect read length"); break; } // DEBUG //ioaddr = (uint32_t *) (io_map->getVirtualAddress() + page_offset); //log_addr((uint64_t)ioaddr, 64, "ioaddr"); } unxlate_pa_va(&io_desc, &io_map); return value; }
/** Store RTT in infra cache */ static void do_infra_rtt(struct replay_runtime* runtime) { struct replay_moment* now = runtime->now; int rto = infra_rtt_update(runtime->infra, &now->addr, now->addrlen, atoi(now->string), -1, runtime->now_secs); log_addr(0, "INFRA_RTT for", &now->addr, now->addrlen); log_info("INFRA_RTT(roundtrip %d): rto of %d", atoi(now->string), rto); if(rto == 0) fatal_exit("infra_rtt_update failed"); }
/** 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; }
// Copy the requested amount to userspace if it doesn't cross page boundaries // or memory mapped io. If it does, stop at the boundary. Will copy zeroes // if the given physical address is not backed by physical memory. // // args: uio is the userspace io request object // return: number of bytes copied successfully // static uint64_t pmem_partial_read(struct uio *uio, addr64_t start_addr, addr64_t end_addr) { // Separate page and offset uint64_t page_offset = start_addr & PAGE_MASK; addr64_t page = trunc_page_64(start_addr); // don't copy across page boundaries uint32_t chunk_len = (uint32_t)MIN(PAGE_SIZE - page_offset, end_addr - start_addr); // Prepare the page for IOKit IOMemoryDescriptor *page_desc = ( IOMemoryDescriptor::withPhysicalAddress(page, PAGE_SIZE, kIODirectionIn)); if (page_desc == NULL) { pmem_error("Can't read from %#016llx, address not in physical memory range", start_addr); // Skip this range as it is not even in the physical address space return chunk_len; } else { // Map the page containing address into kernel address space. IOMemoryMap *page_map = ( page_desc->createMappingInTask(kernel_task, 0, kIODirectionIn, 0, 0)); // Check if the mapping succeded. if (!page_map) { pmem_error("page %#016llx could not be mapped into the kernel, " "zero padding return buffer", page); // Zero pad this chunk, as it is not inside a valid page frame. uiomove64((addr64_t)pmem_zero_page + page_offset, (uint32_t)chunk_len, uio); } else { // Successfully mapped page, copy contents... pmem_log("partial_read"); log_addr(page_map->getAddress(), 64, "page_map->getAddress()"); log_addr(page_offset, 64, "page_offset"); uiomove64(page_map->getAddress() + page_offset, (uint32_t)chunk_len, uio); page_map->release(); } page_desc->release(); } return chunk_len; }
/** run the scenario in event callbacks */ static void run_scenario(struct replay_runtime* runtime) { struct entry* entry = NULL; struct fake_pending* pending = NULL; int max_rounds = 5000; int rounds = 0; runtime->now = runtime->scenario->mom_first; log_info("testbound: entering fake runloop"); do { /* if moment matches pending query do it. */ /* else if moment matches given answer, do it */ /* else if precoded_range matches pending, do it */ /* else do the current moment */ if(pending_matches_current(runtime, &entry, &pending)) { log_info("testbound: do STEP %d CHECK_OUT_QUERY", runtime->now->time_step); advance_moment(runtime); if(entry->copy_id) answer_callback_from_entry(runtime, entry, pending); } else if(runtime->answer_list && runtime->now && runtime->now->evt_type == repevt_front_reply) { answer_check_it(runtime); advance_moment(runtime); } else if(pending_matches_range(runtime, &entry, &pending)) { answer_callback_from_entry(runtime, entry, pending); } else { do_moment_and_advance(runtime); } log_info("testbound: end of event stage"); rounds++; if(rounds > max_rounds) fatal_exit("testbound: too many rounds, it loops."); } while(runtime->now); if(runtime->pending_list) { struct fake_pending* p; log_err("testbound: there are still messages pending."); for(p = runtime->pending_list; p; p=p->next) { log_pkt("pending msg", p->pkt, p->pkt_len); log_addr(0, "pending to", &p->addr, p->addrlen); } fatal_exit("testbound: there are still messages pending."); } if(runtime->answer_list) { fatal_exit("testbound: there are unmatched answers."); } log_info("testbound: exiting fake runloop."); runtime->exit_cleanly = 1; }
static uint64_t WriteMMIO(uint64_t phys, uint8_t length, uint64_t value){ IOMemoryDescriptor* io_desc; IOMemoryMap* io_map; uint64_t page_offset = phys & PAGE_MASK; log_addr((uint64_t) page_offset, 64, "page_offset"); xlate_pa_va(phys, &io_desc, &io_map); if(io_map) { log_addr(io_map->getVirtualAddress(), 64, "io_map->getVirtualAddress"); switch (length) { case 1: *(volatile uint8_t *)((uintptr_t)io_map->getVirtualAddress() + page_offset) = value; break; case 2: OSWriteLittleInt16((void *)io_map->getVirtualAddress(), page_offset, (uint16_t) value); break; case 4: OSWriteLittleInt32((void *)io_map->getVirtualAddress(), page_offset, (uint32_t) value); break; case 8: OSWriteLittleInt64((void *)io_map->getVirtualAddress(), page_offset, value); default: pmem_error("WriteMMIO Incorrect write length"); break; } } unxlate_pa_va(&io_desc, &io_map); return value; }
/** Store RTT in infra cache */ static void do_infra_rtt(struct replay_runtime* runtime) { struct replay_moment* now = runtime->now; int rto; size_t dplen = 0; uint8_t* dp = sldns_str2wire_dname(now->variable, &dplen); if(!dp) fatal_exit("cannot parse %s", now->variable); rto = infra_rtt_update(runtime->infra, &now->addr, now->addrlen, dp, dplen, LDNS_RR_TYPE_A, atoi(now->string), -1, runtime->now_secs); log_addr(0, "INFRA_RTT for", &now->addr, now->addrlen); log_info("INFRA_RTT(%s roundtrip %d): rto of %d", now->variable, atoi(now->string), rto); if(rto == 0) fatal_exit("infra_rtt_update failed"); free(dp); }
/** 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); } }
void delegpt_log(enum verbosity_value v, struct delegpt* dp) { char buf[LDNS_MAX_DOMAINLEN+1]; struct delegpt_ns* ns; struct delegpt_addr* a; size_t missing=0, numns=0, numaddr=0, numres=0, numavail=0; if(verbosity < v) return; dname_str(dp->name, buf); if(dp->nslist == NULL && dp->target_list == NULL) { log_info("DelegationPoint<%s>: empty", buf); return; } delegpt_count_ns(dp, &numns, &missing); delegpt_count_addr(dp, &numaddr, &numres, &numavail); log_info("DelegationPoint<%s>: %u names (%u missing), " "%u addrs (%u result, %u avail)%s", buf, (unsigned)numns, (unsigned)missing, (unsigned)numaddr, (unsigned)numres, (unsigned)numavail, (dp->has_parent_side_NS?" parentNS":" cacheNS")); if(verbosity >= VERB_ALGO) { for(ns = dp->nslist; ns; ns = ns->next) { dname_str(ns->name, buf); log_info(" %s %s%s%s%s%s%s%s", buf, (ns->resolved?"*":""), (ns->got4?" A":""), (ns->got6?" AAAA":""), (dp->bogus?" BOGUS":""), (ns->lame?" PARENTSIDE":""), (ns->done_pside4?" PSIDE_A":""), (ns->done_pside6?" PSIDE_AAAA":"")); } for(a = dp->target_list; a; a = a->next_target) { const char* str = " "; if(a->bogus && a->lame) str = " BOGUS ADDR_LAME "; else if(a->bogus) str = " BOGUS "; else if(a->lame) str = " ADDR_LAME "; log_addr(VERB_ALGO, str, &a->addr, a->addrlen); } } }
/** 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 } } }
/** perform TCP relaying */ static void service_tcp_relay(struct tcp_proxy** tcp_proxies, struct timeval* now, struct timeval* delay, struct timeval* tcp_timeout, sldns_buffer* pkt, fd_set* rset, fd_set* rorig, fd_set* worig) { struct tcp_proxy* p, **prev; struct timeval tout; int delete_it; p = *tcp_proxies; prev = tcp_proxies; tout = *now; dl_tv_add(&tout, tcp_timeout); while(p) { delete_it = 0; /* can we receive further queries? */ if(!delete_it && FD_ISSET(p->client_s, rset)) { p->timeout = tout; log_addr(1, "read tcp query", &p->addr, p->addr_len); if(!tcp_relay_read(p->client_s, &p->querylist, &p->querylast, now, delay, pkt)) delete_it = 1; } /* can we receive further answers? */ if(!delete_it && p->server_s != -1 && FD_ISSET(p->server_s, rset)) { p->timeout = tout; log_addr(1, "read tcp answer", &p->addr, p->addr_len); if(!tcp_relay_read(p->server_s, &p->answerlist, &p->answerlast, now, delay, pkt)) { #ifndef USE_WINSOCK close(p->server_s); #else closesocket(p->server_s); #endif FD_CLR(FD_SET_T p->server_s, worig); FD_CLR(FD_SET_T p->server_s, rorig); p->server_s = -1; } } /* can we send on further queries */ if(!delete_it && p->querylist && p->server_s != -1) { p->timeout = tout; if(dl_tv_smaller(&p->querylist->wait, now)) log_addr(1, "write tcp query", &p->addr, p->addr_len); if(!tcp_relay_write(p->server_s, &p->querylist, &p->querylast, now)) delete_it = 1; if(p->querylist && p->server_s != -1 && dl_tv_smaller(&p->querylist->wait, now)) FD_SET(FD_SET_T p->server_s, worig); else FD_CLR(FD_SET_T p->server_s, worig); } /* can we send on further answers */ if(!delete_it && p->answerlist) { p->timeout = tout; if(dl_tv_smaller(&p->answerlist->wait, now)) log_addr(1, "write tcp answer", &p->addr, p->addr_len); if(!tcp_relay_write(p->client_s, &p->answerlist, &p->answerlast, now)) delete_it = 1; if(p->answerlist && dl_tv_smaller(&p->answerlist->wait, now)) FD_SET(FD_SET_T p->client_s, worig); else FD_CLR(FD_SET_T p->client_s, worig); if(!p->answerlist && p->server_s == -1) delete_it = 1; } /* does this entry timeout? (unused too long) */ if(dl_tv_smaller(&p->timeout, now)) { delete_it = 1; } if(delete_it) { struct tcp_proxy* np = p->next; *prev = np; FD_CLR(FD_SET_T p->client_s, rorig); FD_CLR(FD_SET_T p->client_s, worig); if(p->server_s != -1) { FD_CLR(FD_SET_T p->server_s, rorig); FD_CLR(FD_SET_T p->server_s, worig); } tcp_proxy_delete(p); p = np; continue; } prev = &p->next; p = p->next; } }
int worker_handle_request(struct comm_point* c, void* arg, int error, struct comm_reply* repinfo) { struct worker* worker = (struct worker*)arg; int ret; hashvalue_t h; struct lruhash_entry* e; struct query_info qinfo; struct edns_data edns; enum acl_access acl; int rc = 0; if(error != NETEVENT_NOERROR) { /* some bad tcp query DNS formats give these error calls */ verbose(VERB_ALGO, "handle request called with err=%d", error); return 0; } #ifdef USE_DNSTAP if(worker->dtenv.log_client_query_messages) dt_msg_send_client_query(&worker->dtenv, &repinfo->addr, c->type, c->buffer); #endif acl = acl_list_lookup(worker->daemon->acl, &repinfo->addr, repinfo->addrlen); if((ret=deny_refuse_all(c, acl, worker, repinfo)) != -1) { if(ret == 1) goto send_reply; return ret; } if((ret=worker_check_request(c->buffer, worker)) != 0) { verbose(VERB_ALGO, "worker check request: bad query."); log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); if(ret != -1) { LDNS_QR_SET(sldns_buffer_begin(c->buffer)); LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), ret); return 1; } comm_point_drop_reply(repinfo); return 0; } worker->stats.num_queries++; /* see if query is in the cache */ if(!query_info_parse(&qinfo, c->buffer)) { verbose(VERB_ALGO, "worker parse request: formerror."); log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); if(worker_err_ratelimit(worker, LDNS_RCODE_FORMERR) == -1) { comm_point_drop_reply(repinfo); return 0; } sldns_buffer_rewind(c->buffer); LDNS_QR_SET(sldns_buffer_begin(c->buffer)); LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), LDNS_RCODE_FORMERR); server_stats_insrcode(&worker->stats, c->buffer); goto send_reply; } if(worker->env.cfg->log_queries) { char ip[128]; addr_to_str(&repinfo->addr, repinfo->addrlen, ip, sizeof(ip)); log_nametypeclass(0, ip, qinfo.qname, qinfo.qtype, qinfo.qclass); } if(qinfo.qtype == LDNS_RR_TYPE_AXFR || qinfo.qtype == LDNS_RR_TYPE_IXFR) { verbose(VERB_ALGO, "worker request: refused zone transfer."); log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); sldns_buffer_rewind(c->buffer); LDNS_QR_SET(sldns_buffer_begin(c->buffer)); LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), LDNS_RCODE_REFUSED); if(worker->stats.extended) { worker->stats.qtype[qinfo.qtype]++; server_stats_insrcode(&worker->stats, c->buffer); } goto send_reply; } if((ret=parse_edns_from_pkt(c->buffer, &edns, worker->scratchpad)) != 0) { struct edns_data reply_edns; verbose(VERB_ALGO, "worker parse edns: formerror."); log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); memset(&reply_edns, 0, sizeof(reply_edns)); reply_edns.edns_present = 1; reply_edns.udp_size = EDNS_ADVERTISED_SIZE; LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), ret); error_encode(c->buffer, ret, &qinfo, *(uint16_t*)(void *)sldns_buffer_begin(c->buffer), sldns_buffer_read_u16_at(c->buffer, 2), &reply_edns); regional_free_all(worker->scratchpad); server_stats_insrcode(&worker->stats, c->buffer); goto send_reply; } if(edns.edns_present && edns.edns_version != 0) { edns.ext_rcode = (uint8_t)(EDNS_RCODE_BADVERS>>4); edns.edns_version = EDNS_ADVERTISED_VERSION; edns.udp_size = EDNS_ADVERTISED_SIZE; edns.bits &= EDNS_DO; edns.opt_list = NULL; verbose(VERB_ALGO, "query with bad edns version."); log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); error_encode(c->buffer, EDNS_RCODE_BADVERS&0xf, &qinfo, *(uint16_t*)(void *)sldns_buffer_begin(c->buffer), sldns_buffer_read_u16_at(c->buffer, 2), NULL); attach_edns_record(c->buffer, &edns); regional_free_all(worker->scratchpad); goto send_reply; }
void print_set(struct filter_set_head *set) { struct filter_set *s; if (TAILQ_EMPTY(set)) return; printf("set { "); TAILQ_FOREACH(s, set, entry) { switch (s->type) { case ACTION_SET_LOCALPREF: printf("localpref %u ", s->action.metric); break; case ACTION_SET_RELATIVE_LOCALPREF: printf("localpref %+d ", s->action.relative); break; case ACTION_SET_MED: printf("metric %u ", s->action.metric); break; case ACTION_SET_RELATIVE_MED: printf("metric %+d ", s->action.relative); break; case ACTION_SET_WEIGHT: printf("weight %u ", s->action.metric); break; case ACTION_SET_RELATIVE_WEIGHT: printf("weight %+d ", s->action.relative); break; case ACTION_SET_NEXTHOP: printf("nexthop %s ", log_addr(&s->action.nexthop)); break; case ACTION_SET_NEXTHOP_REJECT: printf("nexthop reject "); break; case ACTION_SET_NEXTHOP_BLACKHOLE: printf("nexthop blackhole "); break; case ACTION_SET_NEXTHOP_NOMODIFY: printf("nexthop no-modify "); break; case ACTION_SET_NEXTHOP_SELF: printf("nexthop self "); break; case ACTION_SET_PREPEND_SELF: printf("prepend-self %u ", s->action.prepend); break; case ACTION_SET_PREPEND_PEER: printf("prepend-neighbor %u ", s->action.prepend); break; case ACTION_DEL_COMMUNITY: printf("community delete "); print_community(s->action.community.as, s->action.community.type); printf(" "); break; case ACTION_SET_COMMUNITY: printf("community "); print_community(s->action.community.as, s->action.community.type); printf(" "); break; case ACTION_PFTABLE: printf("pftable %s ", s->action.pftable); break; case ACTION_RTLABEL: printf("rtlabel %s ", s->action.rtlabel); break; case ACTION_SET_ORIGIN: printf("origin "); print_origin(s->action.origin); break; case ACTION_RTLABEL_ID: case ACTION_PFTABLE_ID: /* not possible */ printf("king bula saiz: config broken"); break; case ACTION_SET_EXT_COMMUNITY: printf("ext-community "); print_extcommunity(&s->action.ext_community); break; case ACTION_DEL_EXT_COMMUNITY: printf("ext-community delete "); print_extcommunity(&s->action.ext_community); break; } } printf("}"); }
/** accept new TCP connections, and set them up */ static void service_tcp_listen(int s, fd_set* rorig, int* max, struct tcp_proxy** proxies, struct sockaddr_storage* srv_addr, socklen_t srv_len, struct timeval* now, struct timeval* tcp_timeout) { int newfd; struct sockaddr_storage addr; struct tcp_proxy* p; socklen_t addr_len; newfd = accept(s, (struct sockaddr*)&addr, &addr_len); if(newfd == -1) { #ifndef USE_WINSOCK if(errno == EAGAIN || errno == EINTR) return; fatal_exit("accept: %s", strerror(errno)); #else if(WSAGetLastError() == WSAEWOULDBLOCK || WSAGetLastError() == WSAEINPROGRESS || WSAGetLastError() == WSAECONNRESET) return; fatal_exit("accept: %s", wsa_strerror(WSAGetLastError())); #endif } p = (struct tcp_proxy*)calloc(1, sizeof(*p)); if(!p) fatal_exit("out of memory"); memmove(&p->addr, &addr, addr_len); p->addr_len = addr_len; log_addr(1, "new tcp proxy", &p->addr, p->addr_len); p->client_s = newfd; p->server_s = socket(addr_is_ip6(srv_addr, srv_len)?AF_INET6:AF_INET, SOCK_STREAM, 0); if(p->server_s == -1) { #ifndef USE_WINSOCK fatal_exit("tcp socket: %s", strerror(errno)); #else fatal_exit("tcp socket: %s", wsa_strerror(WSAGetLastError())); #endif } fd_set_nonblock(p->client_s); fd_set_nonblock(p->server_s); if(connect(p->server_s, (struct sockaddr*)srv_addr, srv_len) == -1) { #ifndef USE_WINSOCK if(errno != EINPROGRESS) { log_err("tcp connect: %s", strerror(errno)); close(p->server_s); close(p->client_s); #else if(WSAGetLastError() != WSAEWOULDBLOCK && WSAGetLastError() != WSAEINPROGRESS) { log_err("tcp connect: %s", wsa_strerror(WSAGetLastError())); closesocket(p->server_s); closesocket(p->client_s); #endif free(p); return; } } p->timeout = *now; dl_tv_add(&p->timeout, tcp_timeout); /* listen to client and server */ FD_SET(FD_SET_T p->client_s, rorig); FD_SET(FD_SET_T p->server_s, rorig); if(p->client_s+1 > *max) *max = p->client_s+1; if(p->server_s+1 > *max) *max = p->server_s+1; /* add into proxy list */ p->next = *proxies; *proxies = p; } /** relay TCP, read a part */ static int tcp_relay_read(int s, struct tcp_send_list** first, struct tcp_send_list** last, struct timeval* now, struct timeval* delay, sldns_buffer* pkt) { struct tcp_send_list* item; ssize_t r = recv(s, (void*)sldns_buffer_begin(pkt), sldns_buffer_capacity(pkt), 0); if(r == -1) { #ifndef USE_WINSOCK if(errno == EINTR || errno == EAGAIN) return 1; log_err("tcp read: %s", strerror(errno)); #else if(WSAGetLastError() == WSAEINPROGRESS || WSAGetLastError() == WSAEWOULDBLOCK) return 1; log_err("tcp read: %s", wsa_strerror(WSAGetLastError())); #endif return 0; } else if(r == 0) { /* connection closed */ return 0; } item = (struct tcp_send_list*)malloc(sizeof(*item)); if(!item) { log_err("out of memory"); return 0; } verbose(1, "read item len %d", (int)r); item->len = (size_t)r; item->item = memdup(sldns_buffer_begin(pkt), item->len); if(!item->item) { free(item); log_err("out of memory"); return 0; } item->done = 0; item->wait = *now; dl_tv_add(&item->wait, delay); item->next = NULL; /* link in */ if(*first) { (*last)->next = item; } else { *first = item; } *last = item; return 1; } /** relay TCP, write a part */ static int tcp_relay_write(int s, struct tcp_send_list** first, struct tcp_send_list** last, struct timeval* now) { ssize_t r; struct tcp_send_list* p; while(*first) { p = *first; /* is the item ready? */ if(!dl_tv_smaller(&p->wait, now)) return 1; /* write it */ r = send(s, (void*)(p->item + p->done), p->len - p->done, 0); if(r == -1) { #ifndef USE_WINSOCK if(errno == EAGAIN || errno == EINTR) return 1; log_err("tcp write: %s", strerror(errno)); #else if(WSAGetLastError() == WSAEWOULDBLOCK || WSAGetLastError() == WSAEINPROGRESS) return 1; log_err("tcp write: %s", wsa_strerror(WSAGetLastError())); #endif return 0; } else if(r == 0) { /* closed */ return 0; } /* account it */ p->done += (size_t)r; verbose(1, "write item %d of %d", (int)p->done, (int)p->len); if(p->done >= p->len) { free(p->item); *first = p->next; if(!*first) *last = NULL; free(p); } else { /* partial write */ return 1; } } return 1; }
int remote_accept_callback(struct comm_point* c, void* arg, int err, struct comm_reply* ATTR_UNUSED(rep)) { struct daemon_remote* rc = (struct daemon_remote*)arg; struct sockaddr_storage addr; socklen_t addrlen; int newfd; struct rc_state* n; if(err != NETEVENT_NOERROR) { log_err("error %d on remote_accept_callback", err); return 0; } /* perform the accept */ newfd = comm_point_perform_accept(c, &addr, &addrlen); if(newfd == -1) return 0; /* create new commpoint unless we are servicing already */ if(rc->active >= rc->max_active) { log_warn("drop incoming remote control: too many connections"); comm_point_stop_listening(c); close_exit: #ifndef USE_WINSOCK close(newfd); #else closesocket(newfd); #endif return 0; } /* setup commpoint to service the remote control command */ n = (struct rc_state*)calloc(1, sizeof(*n)); if(!n) { log_err("out of memory"); goto close_exit; } /* start in reading state */ n->c = comm_point_create_raw(rc->worker->base, newfd, 0, &remote_control_callback, n); if(!n->c) { log_err("out of memory"); free(n); goto close_exit; } log_addr(VERB_QUERY, "new control connection from", &addr, addrlen); n->c->do_not_close = 0; comm_point_stop_listening(n->c); comm_point_start_listening(n->c, -1, REMOTE_CONTROL_TCP_TIMEOUT); memcpy(&n->c->repinfo.addr, &addr, addrlen); n->c->repinfo.addrlen = addrlen; n->shake_state = rc_hs_read; n->ssl = SSL_new(rc->ctx); if(!n->ssl) { log_crypto_err("could not SSL_new"); free(n); goto close_exit; } SSL_set_accept_state(n->ssl); (void)SSL_set_mode(n->ssl, SSL_MODE_AUTO_RETRY); if(!SSL_set_fd(n->ssl, newfd)) { log_crypto_err("could not SSL_set_fd"); SSL_free(n->ssl); free(n); goto close_exit; } n->rc = rc; n->next = rc->busy_list; rc->busy_list = n; rc->active ++; /* perform the first nonblocking read already, for windows, * so it can return wouldblock. could be faster too. */ (void)remote_control_callback(n->c, n, NETEVENT_NOERROR, NULL); return 0; }
int create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto, int* reuseport) { int s; #if defined(SO_REUSEADDR) || defined(SO_REUSEPORT) || defined(IPV6_V6ONLY) int on = 1; #endif /* SO_REUSEADDR || IPV6_V6ONLY */ verbose_print_addr(addr); *noproto = 0; if((s = socket(addr->ai_family, addr->ai_socktype, 0)) == -1) { #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 return -1; } #ifdef SO_REUSEADDR if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void*)&on, (socklen_t)sizeof(on)) < 0) { #ifndef USE_WINSOCK log_err("setsockopt(.. SO_REUSEADDR ..) failed: %s", strerror(errno)); close(s); #else log_err("setsockopt(.. SO_REUSEADDR ..) failed: %s", wsa_strerror(WSAGetLastError())); closesocket(s); #endif return -1; } #endif /* SO_REUSEADDR */ #if defined(__linux__) && defined(SO_REUSEPORT) /* Linux specific: try to set SO_REUSEPORT so that incoming * connections are distributed evenly among the receiving threads. * Each thread must have its own socket bound to the same port, * with SO_REUSEPORT set on each socket. */ if (reuseport && *reuseport && setsockopt(s, SOL_SOCKET, SO_REUSEPORT, (void*)&on, (socklen_t)sizeof(on)) < 0) { #ifdef ENOPROTOOPT if(errno != ENOPROTOOPT || verbosity >= 3) log_warn("setsockopt(.. SO_REUSEPORT ..) failed: %s", strerror(errno)); #endif /* this option is not essential, we can continue */ *reuseport = 0; } #else (void)reuseport; #endif /* defined(__linux__) && defined(SO_REUSEPORT) */ #if defined(IPV6_V6ONLY) if(addr->ai_family == AF_INET6 && v6only) { if(setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&on, (socklen_t)sizeof(on)) < 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 return -1; } } #else (void)v6only; #endif /* IPV6_V6ONLY */ if(bind(s, addr->ai_addr, addr->ai_addrlen) != 0) { #ifndef USE_WINSOCK /* detect freebsd jail with no ipv6 permission */ if(addr->ai_family==AF_INET6 && errno==EINVAL) *noproto = 1; else { log_err("can't bind socket: %s", strerror(errno)); log_addr(0, "failed address", (struct sockaddr_storage*)addr->ai_addr, addr->ai_addrlen); } close(s); #else log_err("can't bind socket: %s", wsa_strerror(WSAGetLastError())); log_addr(0, "failed address", (struct sockaddr_storage*)addr->ai_addr, addr->ai_addrlen); closesocket(s); #endif return -1; } if(!fd_set_nonblock(s)) { #ifndef USE_WINSOCK close(s); #else closesocket(s); #endif return -1; } if(listen(s, TCP_BACKLOG) == -1) { #ifndef USE_WINSOCK log_err("can't listen: %s", strerror(errno)); close(s); #else log_err("can't listen: %s", wsa_strerror(WSAGetLastError())); closesocket(s); #endif return -1; } return s; }
int worker_handle_request(struct comm_point* c, void* arg, int error, struct comm_reply* repinfo) { struct worker* worker = (struct worker*)arg; int ret; hashvalue_t h; struct lruhash_entry* e; struct query_info qinfo; struct edns_data edns; enum acl_access acl; if(error != NETEVENT_NOERROR) { /* some bad tcp query DNS formats give these error calls */ verbose(VERB_ALGO, "handle request called with err=%d", error); return 0; } acl = acl_list_lookup(worker->daemon->acl, &repinfo->addr, repinfo->addrlen); if(acl == acl_deny) { comm_point_drop_reply(repinfo); if(worker->stats.extended) worker->stats.unwanted_queries++; return 0; } else if(acl == acl_refuse) { log_addr(VERB_ALGO, "refused query from", &repinfo->addr, repinfo->addrlen); log_buf(VERB_ALGO, "refuse", c->buffer); if(worker->stats.extended) worker->stats.unwanted_queries++; if(worker_check_request(c->buffer, worker) == -1) { comm_point_drop_reply(repinfo); return 0; /* discard this */ } ldns_buffer_set_limit(c->buffer, LDNS_HEADER_SIZE); ldns_buffer_write_at(c->buffer, 4, (uint8_t*)"\0\0\0\0\0\0\0\0", 8); LDNS_QR_SET(ldns_buffer_begin(c->buffer)); LDNS_RCODE_SET(ldns_buffer_begin(c->buffer), LDNS_RCODE_REFUSED); return 1; } if((ret=worker_check_request(c->buffer, worker)) != 0) { verbose(VERB_ALGO, "worker check request: bad query."); log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); if(ret != -1) { LDNS_QR_SET(ldns_buffer_begin(c->buffer)); LDNS_RCODE_SET(ldns_buffer_begin(c->buffer), ret); return 1; } comm_point_drop_reply(repinfo); return 0; } worker->stats.num_queries++; /* see if query is in the cache */ if(!query_info_parse(&qinfo, c->buffer)) { verbose(VERB_ALGO, "worker parse request: formerror."); log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); ldns_buffer_rewind(c->buffer); LDNS_QR_SET(ldns_buffer_begin(c->buffer)); LDNS_RCODE_SET(ldns_buffer_begin(c->buffer), LDNS_RCODE_FORMERR); server_stats_insrcode(&worker->stats, c->buffer); return 1; } if(worker->env.cfg->log_queries) { char ip[128]; addr_to_str(&repinfo->addr, repinfo->addrlen, ip, sizeof(ip)); log_nametypeclass(0, ip, qinfo.qname, qinfo.qtype, qinfo.qclass); } if(qinfo.qtype == LDNS_RR_TYPE_AXFR || qinfo.qtype == LDNS_RR_TYPE_IXFR) { verbose(VERB_ALGO, "worker request: refused zone transfer."); log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); ldns_buffer_rewind(c->buffer); LDNS_QR_SET(ldns_buffer_begin(c->buffer)); LDNS_RCODE_SET(ldns_buffer_begin(c->buffer), LDNS_RCODE_REFUSED); if(worker->stats.extended) { worker->stats.qtype[qinfo.qtype]++; server_stats_insrcode(&worker->stats, c->buffer); } return 1; } if((ret=parse_edns_from_pkt(c->buffer, &edns)) != 0) { verbose(VERB_ALGO, "worker parse edns: formerror."); log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); ldns_buffer_rewind(c->buffer); LDNS_QR_SET(ldns_buffer_begin(c->buffer)); LDNS_RCODE_SET(ldns_buffer_begin(c->buffer), ret); server_stats_insrcode(&worker->stats, c->buffer); return 1; } if(edns.edns_present && edns.edns_version != 0) { edns.ext_rcode = (uint8_t)(EDNS_RCODE_BADVERS>>4); edns.edns_version = EDNS_ADVERTISED_VERSION; edns.udp_size = EDNS_ADVERTISED_SIZE; edns.bits &= EDNS_DO; verbose(VERB_ALGO, "query with bad edns version."); log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); error_encode(c->buffer, EDNS_RCODE_BADVERS&0xf, &qinfo, *(uint16_t*)ldns_buffer_begin(c->buffer), ldns_buffer_read_u16_at(c->buffer, 2), NULL); attach_edns_record(c->buffer, &edns); return 1; }
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; }
int create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto) { int s; #if defined(SO_REUSEADDR) || defined(IPV6_V6ONLY) int on = 1; #endif /* SO_REUSEADDR || IPV6_V6ONLY */ verbose_print_addr(addr); *noproto = 0; if((s = socket(addr->ai_family, addr->ai_socktype, 0)) == -1) { #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 return -1; } #ifdef SO_REUSEADDR if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void*)&on, (socklen_t)sizeof(on)) < 0) { #ifndef USE_WINSOCK log_err("setsockopt(.. SO_REUSEADDR ..) failed: %s", strerror(errno)); close(s); #else log_err("setsockopt(.. SO_REUSEADDR ..) failed: %s", wsa_strerror(WSAGetLastError())); closesocket(s); #endif return -1; } #endif /* SO_REUSEADDR */ #if defined(IPV6_V6ONLY) if(addr->ai_family == AF_INET6 && v6only) { if(setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&on, (socklen_t)sizeof(on)) < 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 return -1; } } #else (void)v6only; #endif /* IPV6_V6ONLY */ if(bind(s, addr->ai_addr, addr->ai_addrlen) != 0) { #ifndef USE_WINSOCK /* detect freebsd jail with no ipv6 permission */ if(addr->ai_family==AF_INET6 && errno==EINVAL) *noproto = 1; else { log_err("can't bind socket: %s", strerror(errno)); log_addr(0, "failed address", (struct sockaddr_storage*)addr->ai_addr, addr->ai_addrlen); } close(s); #else log_err("can't bind socket: %s", wsa_strerror(WSAGetLastError())); log_addr(0, "failed address", (struct sockaddr_storage*)addr->ai_addr, addr->ai_addrlen); closesocket(s); #endif return -1; } if(!fd_set_nonblock(s)) { #ifndef USE_WINSOCK close(s); #else closesocket(s); #endif return -1; } if(listen(s, TCP_BACKLOG) == -1) { #ifndef USE_WINSOCK log_err("can't listen: %s", strerror(errno)); close(s); #else log_err("can't listen: %s", wsa_strerror(WSAGetLastError())); closesocket(s); #endif return -1; } return s; }
/* Handles ioctl's from userspace. See ioctl codes in chipsec-common/chipsec_ioctl.h */ static kern_return_t pmem_ioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) { //TODO (dynamically allocate these) pci_msg_t kpci; mmio_msg_t kmmio; cr_msg_t kcr; io_msg_t kio; msr_msg_t kmsr; cpuid_msg_t kcpuid; swsmi_msg_t kswsmi; hypercall_msg_t khypercall; msgbus_msg_t kmsgbus; cpudes_msg_t kcpudes; alloc_pmem_msg_t kalloc_pmem; pmem_log("cmd = %x", cmd); switch (cmd) { case CHIPSEC_IOC_RDPCI: pmem_log("RDPCI"); log_addr((uint64_t) data, 64, "data"); log_addr((uint64_t) &kpci, 64, "&krdpci"); bcopy(data, &kpci, sizeof(pci_msg_t)); pmem_log("ReadPCICfg(%lx, %lx, %lx, %lx, %lx)", kpci.bus, kpci.device, kpci.function, kpci.offset, kpci.length); kpci.value = ReadPCICfg(kpci.bus, kpci.device, kpci.function, kpci.offset, kpci.length); pmem_log("kpci.value = %08x", kpci.value); bcopy(&kpci, data, sizeof(pci_msg_t)); break; case CHIPSEC_IOC_WRPCI: pmem_log("WRPCI"); bcopy(data, &kpci, sizeof(pci_msg_t)); pmem_log("WritePCICfg(%lx, %lx, %lx, %lx, %lx, %lx)", kpci.bus, kpci.device, kpci.function, kpci.offset, kpci.length, kpci.value); WritePCICfg(kpci.bus, kpci.device, kpci.function, kpci.offset, kpci.length, kpci.value); break; case CHIPSEC_IOC_RDMMIO: pmem_log("RDMMIO"); bcopy(data, &kmmio, sizeof(mmio_msg_t)); pmem_log("ReadMMIO(%lx, %x)", kmmio.addr, kmmio.length); kmmio.value = ReadMMIO(kmmio.addr, kmmio.length); pmem_log("val = %08llx", kmmio.value); bcopy(&kmmio, data, sizeof(mmio_msg_t)); break; case CHIPSEC_IOC_WRMMIO: pmem_log("WRMMIO"); bcopy(data, &kmmio, sizeof(mmio_msg_t)); pmem_log("WriteMMIO(%lx, %x, %x)", kmmio.addr, kmmio.length, (uint32_t) kmmio.value); WriteMMIO(kmmio.addr, kmmio.length, kmmio.value); break; case CHIPSEC_IOC_RDCR: pmem_log("RDCR"); bcopy(data, &kcr, sizeof(cr_msg_t)); pmem_log("ReadCR%d()", kcr.register_number); switch(kcr.register_number) { case 0: kcr.value = ReadCR0(); break; case 2: kcr.value = ReadCR2(); break; case 3: kcr.value = ReadCR3(); break; case 4: kcr.value = ReadCR4(); break; case 8: kcr.value = ReadCR8(); break; default: pmem_error("Incorrect CR number"); break; } bcopy(&kcr, data, sizeof(cr_msg_t)); break; case CHIPSEC_IOC_WRCR: pmem_log("WRCR"); bcopy(data, &kcr, sizeof(cr_msg_t)); pmem_log("WriteCR%d(%x)", kcr.register_number, kcr.value); switch(kcr.register_number) { case 0: WriteCR0(kcr.value); break; case 2: WriteCR2(kcr.value); break; case 3: WriteCR3(kcr.value); break; case 4: WriteCR4(kcr.value); break; case 8: WriteCR8(kcr.value); break; default: pmem_error("Incorrect CR number"); break; } bcopy(&kcr, data, sizeof(cr_msg_t)); break; case CHIPSEC_IOC_RDIO: pmem_log("RDIO"); bcopy(data,&kio, sizeof(io_msg_t)); pmem_log("ReadIO %i from %x", kio.size, kio.port); kio.value = ReadIOPort((uint32_t)kio.port, kio.size); bcopy(&kio,data,sizeof(io_msg_t)); break; case CHIPSEC_IOC_WRIO: pmem_log("WRIO"); bcopy(data,&kio, sizeof(io_msg_t)); pmem_log("WriteIO %x to %x size %d", kio.value, kio.port,kio.size); WriteIOPort((uint32_t)kio.port, kio.size, (uint32_t)kio.value); break; case CHIPSEC_IOC_RDMSR: pmem_log("RDMSR"); bcopy(data,&kmsr, sizeof(msr_msg_t)); pmem_log("ReadMSR %x", kmsr.msr_num); ReadMSR(kmsr.msr_num, &kmsr.msr_lo, &kmsr.msr_hi); bcopy(&kmsr,data,sizeof(msr_msg_t)); break; case CHIPSEC_IOC_WRMSR: pmem_log("WRMSR"); bcopy(data,&kmsr, sizeof(msr_msg_t)); pmem_log("WriteMSR %x with %x%x", kmsr.msr_num, kmsr.msr_hi,kmsr.msr_lo); WriteMSR(kmsr.msr_num, kmsr.msr_lo, kmsr.msr_hi); break; case CHIPSEC_IOC_CPUID: pmem_log("CPUID"); bcopy(data,&kcpuid, sizeof(cpuid_msg_t)); pmem_log("WriteMSR rax %x rcx %x", kcpuid.rax, kcpuid.rcx); chipCPUID(&kcpuid); bcopy(&kcpuid, data, sizeof(cpuid_msg_t)); break; case CHIPSEC_IOC_SWSMI: pmem_log("SWSMI"); bcopy(data,&kswsmi, sizeof(swsmi_msg_t)); pmem_log("Blah"); SWSMI(&kswsmi); bcopy(&kswsmi, data, sizeof(swsmi_msg_t)); break; case CHIPSEC_IOC_HYPERCALL: pmem_log("HYPERCALL"); bcopy(data,&khypercall, sizeof(hypercall_msg_t)); pmem_log("Hypercall Data"); khypercall.hypercall_page = (uint64_t) & hypercall_page; hypercall(khypercall.rdi, khypercall.rsi, khypercall.rdx, khypercall.rcx, khypercall.r8, khypercall.r9, khypercall.rax, khypercall.rbx, khypercall.r10, khypercall.r11, khypercall.xmm_buffer, khypercall.hypercall_page); bcopy(&khypercall,data, sizeof(hypercall_msg_t)); break; case CHIPSEC_IOC_MSGBUS_SEND_MESSAGE: pmem_log("MSGBUG SEND MESSAGE"); bcopy(data,&kmsgbus, sizeof(msgbus_msg_t)); pmem_log("MSGBUS DATA:"); if (kmsgbus.direction & MSGBUS_MDR_IN_MASK){ //Write data to MDR register WritePCICfg(MSGBUS_BUS, MSGBUS_DEV, MSGBUS_FUN, MDR, 4, (uint32_t)kmsgbus.mdr); } //TODO investigate comment (from linux driver) //Write extended address to MCRX register if address is > 0xff if (kmsgbus.mcrx != 0){ WritePCICfg(MSGBUS_BUS, MSGBUS_DEV, MSGBUS_FUN, MCRX, 4, (uint32_t)kmsgbus.mcrx); } //Write to MCR register to send the message on the message bus WritePCICfg(MSGBUS_BUS, MSGBUS_DEV, MSGBUS_FUN, MCR, 4, (uint32_t)kmsgbus.mcr); if (kmsgbus.direction & MSGBUS_MDR_OUT_MASK){ //Read data from MDR register kmsgbus.mdr_out = ReadPCICfg(MSGBUS_BUS, MSGBUS_DEV, MSGBUS_FUN, MDR, 4); } bcopy(&kmsgbus, data, sizeof(msgbus_msg_t)); break; case CHIPSEC_IOC_CPU_DESCRIPTOR_TABLE: descriptor_table_record kdtr; IOMemoryDescriptor* io_desc; IOMemoryMap* io_map; pmem_log("GET CPU DESCRIPTOR TABLE"); bcopy(data, &kcpudes, sizeof(cpudes_msg_t)); pmem_log("GET_CPU_DESCRIPTOR TABLE %x thread %d", kcpudes.des_table_code, kcpudes.cpu_thread_id); switch (kcpudes.des_table_code) { case CPU_DT_CODE_GDTR: store_gdtr(&kdtr); break; case CPU_DT_CODE_LDTR: store_ldtr(&kdtr); break; case CPU_DT_CODE_IDTR: store_idtr(&kdtr); break; } xlate_pa_va(kdtr.base, &io_desc, &io_map); kcpudes.limit = kdtr.limit; kcpudes.base_hi = (kdtr.base >> 32); kcpudes.base_lo = (kdtr.base & 0xFFFFFFFF); kcpudes.pa_hi = (io_map->getPhysicalAddress() >> 32); kcpudes.pa_lo = (io_map->getPhysicalAddress() & 0xFFFFFFFF); bcopy(&kcpudes, data, sizeof(cpudes_msg_t)); break; case CHIPSEC_IOC_ALLOC_PHYSMEM: void *va; IOMemoryDescriptor* io_desc1; IOMemoryMap* io_map1; pmem_log("ALLOC PHYSMEM"); bcopy(data, &kalloc_pmem, sizeof(alloc_pmem_msg_t)); pmem_log("Allocating %x memory, with pa limit of %x", kalloc_pmem.num_bytes, kalloc_pmem.max_addr); va = IOMalloc((uint32_t)kalloc_pmem.num_bytes); if (!va){ pmem_log("Could not allocate memory"); return -EFAULT; } memset(va, 0, kalloc_pmem.num_bytes); if ( xlate_pa_va((addr64_t) va, &io_desc1, &io_map1) ){ pmem_log("Could not map memory"); } if (io_map1->getPhysicalAddress() > kalloc_pmem.max_addr){ pmem_log("Allocate memory is above max_pa"); } kalloc_pmem.virt_addr = (uint64_t)va; kalloc_pmem.phys_addr = io_map1->getPhysicalAddress(); bcopy(&kalloc_pmem, data, sizeof(alloc_pmem_msg_t)); break; default: pmem_error("Illegal ioctl %08lx", cmd); return -EFAULT; } return KERN_SUCCESS; }