static void handle_tcp_reading(netio_type *netio, netio_handler_type *handler, netio_event_types_type event_types) { struct tcp_handler_data *data = (struct tcp_handler_data *) handler->user_data; ssize_t received; if (event_types & NETIO_EVENT_TIMEOUT) { /* Connection timed out. */ cleanup_tcp_handler(netio, handler); return; } if (data->nsd->tcp_query_count > 0 && data->query_count >= data->nsd->tcp_query_count) { /* No more queries allowed on this tcp connection. */ cleanup_tcp_handler(netio, handler); return; } assert(event_types & NETIO_EVENT_READ); if (data->bytes_transmitted == 0) { query_reset(data->query, TCP_MAX_MESSAGE_LEN, 1); } /* * Check if we received the leading packet length bytes yet. */ if (data->bytes_transmitted < sizeof(uint16_t)) { received = read(handler->fd, (char *) &data->query->tcplen + data->bytes_transmitted, sizeof(uint16_t) - data->bytes_transmitted); if (received == -1) { if (errno == EAGAIN || errno == EINTR) { /* * Read would block, wait until more * data is available. */ return; } else { #ifdef ECONNRESET if (verbosity >= 2 || errno != ECONNRESET) #endif /* ECONNRESET */ log_msg(LOG_ERR, "failed reading from tcp: %s", strerror(errno)); cleanup_tcp_handler(netio, handler); return; } } else if (received == 0) { /* EOF */ cleanup_tcp_handler(netio, handler); return; } data->bytes_transmitted += received; if (data->bytes_transmitted < sizeof(uint16_t)) { /* * Not done with the tcplen yet, wait for more * data to become available. */ return; } assert(data->bytes_transmitted == sizeof(uint16_t)); data->query->tcplen = ntohs(data->query->tcplen); /* * Minimum query size is: * * Size of the header (12) * + Root domain name (1) * + Query class (2) * + Query type (2) */ if (data->query->tcplen < QHEADERSZ + 1 + sizeof(uint16_t) + sizeof(uint16_t)) { VERBOSITY(2, (LOG_WARNING, "packet too small, dropping tcp connection")); cleanup_tcp_handler(netio, handler); return; } if (data->query->tcplen > data->query->maxlen) { VERBOSITY(2, (LOG_WARNING, "insufficient tcp buffer, dropping connection")); cleanup_tcp_handler(netio, handler); return; } buffer_set_limit(data->query->packet, data->query->tcplen); } assert(buffer_remaining(data->query->packet) > 0); /* Read the (remaining) query data. */ received = read(handler->fd, buffer_current(data->query->packet), buffer_remaining(data->query->packet)); if (received == -1) { if (errno == EAGAIN || errno == EINTR) { /* * Read would block, wait until more data is * available. */ return; } else { #ifdef ECONNRESET if (verbosity >= 2 || errno != ECONNRESET) #endif /* ECONNRESET */ log_msg(LOG_ERR, "failed reading from tcp: %s", strerror(errno)); cleanup_tcp_handler(netio, handler); return; } } else if (received == 0) { /* EOF */ cleanup_tcp_handler(netio, handler); return; } data->bytes_transmitted += received; buffer_skip(data->query->packet, received); if (buffer_remaining(data->query->packet) > 0) { /* * Message not yet complete, wait for more data to * become available. */ return; } assert(buffer_position(data->query->packet) == data->query->tcplen); /* Account... */ #ifdef BIND8_STATS # ifndef INET6 STATUP(data->nsd, ctcp); # else if (data->query->addr.ss_family == AF_INET) { STATUP(data->nsd, ctcp); } else if (data->query->addr.ss_family == AF_INET6) { STATUP(data->nsd, ctcp6); } # endif #endif /* BIND8_STATS */ /* We have a complete query, process it. */ /* tcp-query-count: handle query counter ++ */ data->query_count++; buffer_flip(data->query->packet); data->query_state = server_process_query(data->nsd, data->query); if (data->query_state == QUERY_DISCARDED) { /* Drop the packet and the entire connection... */ STATUP(data->nsd, dropped); #if defined(BIND8_STATS) && defined(USE_ZONE_STATS) if (data->query->zone) { ZTATUP(data->query->zone, dropped); } #endif cleanup_tcp_handler(netio, handler); return; } #ifdef BIND8_STATS if (RCODE(data->query->packet) == RCODE_OK && !AA(data->query->packet)) { STATUP(data->nsd, nona); ZTATUP(data->query->zone, nona); } # ifdef USE_ZONE_STATS # ifndef INET6 ZTATUP(data->query->zone, ctcp); # else if (data->query->addr.ss_family == AF_INET) { ZTATUP(data->query->zone, ctcp); } else if (data->query->addr.ss_family == AF_INET6) { ZTATUP(data->query->zone, ctcp6); } # endif # endif /* USE_ZONE_STATS */ #endif /* BIND8_STATS */ query_add_optional(data->query, data->nsd); /* Switch to the tcp write handler. */ buffer_flip(data->query->packet); data->query->tcplen = buffer_remaining(data->query->packet); data->bytes_transmitted = 0; handler->timeout->tv_sec = data->nsd->tcp_timeout; handler->timeout->tv_nsec = 0L; timespec_add(handler->timeout, netio_current_time(netio)); handler->event_types = NETIO_EVENT_WRITE | NETIO_EVENT_TIMEOUT; handler->event_handler = handle_tcp_writing; }
query_state_type query_axfr(struct nsd *nsd, struct query *query) { domain_type *closest_match; domain_type *closest_encloser; int exact; int added; uint16_t total_added = 0; if (query->axfr_is_done) return QUERY_PROCESSED; if (query->maxlen > AXFR_MAX_MESSAGE_LEN) query->maxlen = AXFR_MAX_MESSAGE_LEN; assert(!query_overflow(query)); /* only keep running values for most packets */ query->tsig_prepare_it = 0; query->tsig_update_it = 1; if(query->tsig_sign_it) { /* prepare for next updates */ query->tsig_prepare_it = 1; query->tsig_sign_it = 0; } if (query->axfr_zone == NULL) { domain_type* qdomain; /* Start AXFR. */ STATUP(nsd, raxfr); exact = namedb_lookup(nsd->db, query->qname, &closest_match, &closest_encloser); qdomain = closest_encloser; query->axfr_zone = domain_find_zone(nsd->db, closest_encloser); if (!exact || query->axfr_zone == NULL || query->axfr_zone->apex != qdomain || query->axfr_zone->soa_rrset == NULL) { /* No SOA no transfer */ RCODE_SET(query->packet, RCODE_NOTAUTH); return QUERY_PROCESSED; } ZTATUP(nsd, query->axfr_zone, raxfr); query->axfr_current_domain = qdomain; query->axfr_current_rrset = NULL; query->axfr_current_rr = 0; if(query->tsig.status == TSIG_OK) { query->tsig_sign_it = 1; /* sign first packet in stream */ } query_add_compression_domain(query, qdomain, QHEADERSZ); assert(query->axfr_zone->soa_rrset->rr_count == 1); added = packet_encode_rr(query, query->axfr_zone->apex, &query->axfr_zone->soa_rrset->rrs[0], query->axfr_zone->soa_rrset->rrs[0].ttl); if (!added) { /* XXX: This should never happen... generate error code? */ abort(); } ++total_added; } else { /* * Query name and EDNS need not be repeated after the * first response packet. */ query->edns.status = EDNS_NOT_PRESENT; buffer_set_limit(query->packet, QHEADERSZ); QDCOUNT_SET(query->packet, 0); query_prepare_response(query); } /* Add zone RRs until answer is full. */ while (query->axfr_current_domain != NULL && domain_is_subdomain(query->axfr_current_domain, query->axfr_zone->apex)) { if (!query->axfr_current_rrset) { query->axfr_current_rrset = domain_find_any_rrset( query->axfr_current_domain, query->axfr_zone); query->axfr_current_rr = 0; } while (query->axfr_current_rrset) { if (query->axfr_current_rrset != query->axfr_zone->soa_rrset && query->axfr_current_rrset->zone == query->axfr_zone) { while (query->axfr_current_rr < query->axfr_current_rrset->rr_count) { added = packet_encode_rr( query, query->axfr_current_domain, &query->axfr_current_rrset->rrs[query->axfr_current_rr], query->axfr_current_rrset->rrs[query->axfr_current_rr].ttl); if (!added) goto return_answer; ++total_added; ++query->axfr_current_rr; } } query->axfr_current_rrset = query->axfr_current_rrset->next; query->axfr_current_rr = 0; } assert(query->axfr_current_domain); query->axfr_current_domain = domain_next(query->axfr_current_domain); } /* Add terminating SOA RR. */ assert(query->axfr_zone->soa_rrset->rr_count == 1); added = packet_encode_rr(query, query->axfr_zone->apex, &query->axfr_zone->soa_rrset->rrs[0], query->axfr_zone->soa_rrset->rrs[0].ttl); if (added) { ++total_added; query->tsig_sign_it = 1; /* sign last packet */ query->axfr_is_done = 1; } return_answer: AA_SET(query->packet); ANCOUNT_SET(query->packet, total_added); NSCOUNT_SET(query->packet, 0); ARCOUNT_SET(query->packet, 0); /* check if it needs tsig signatures */ if(query->tsig.status == TSIG_OK) { if(query->tsig.updates_since_last_prepare >= AXFR_TSIG_SIGN_EVERY_NTH) { query->tsig_sign_it = 1; } } query_clear_compression_tables(query); return QUERY_IN_AXFR; }
static void handle_udp(netio_type *ATTR_UNUSED(netio), netio_handler_type *handler, netio_event_types_type event_types) { struct udp_handler_data *data = (struct udp_handler_data *) handler->user_data; int received, sent; struct query *q = data->query; if (!(event_types & NETIO_EVENT_READ)) { return; } /* Account... */ #ifdef BIND8_STATS if (data->socket->addr->ai_family == AF_INET) { STATUP(data->nsd, qudp); } else if (data->socket->addr->ai_family == AF_INET6) { STATUP(data->nsd, qudp6); } #endif /* Initialize the query... */ query_reset(q, UDP_MAX_MESSAGE_LEN, 0); received = recvfrom(handler->fd, buffer_begin(q->packet), buffer_remaining(q->packet), 0, (struct sockaddr *)&q->addr, &q->addrlen); if (received == -1) { if (errno != EAGAIN && errno != EINTR) { log_msg(LOG_ERR, "recvfrom failed: %s", strerror(errno)); STATUP(data->nsd, rxerr); /* No zone statup */ } } else { buffer_skip(q->packet, received); buffer_flip(q->packet); /* Process and answer the query... */ if (server_process_query(data->nsd, q) != QUERY_DISCARDED) { #ifdef BIND8_STATS if (RCODE(q->packet) == RCODE_OK && !AA(q->packet)) { STATUP(data->nsd, nona); ZTATUP(q->zone, nona); } # ifdef USE_ZONE_STATS if (data->socket->addr->ai_family == AF_INET) { ZTATUP(q->zone, qudp); } else if (data->socket->addr->ai_family == AF_INET6) { ZTATUP(q->zone, qudp6); } # endif #endif /* Add EDNS0 and TSIG info if necessary. */ query_add_optional(q, data->nsd); buffer_flip(q->packet); sent = sendto(handler->fd, buffer_begin(q->packet), buffer_remaining(q->packet), 0, (struct sockaddr *) &q->addr, q->addrlen); if (sent == -1) { log_msg(LOG_ERR, "sendto failed: %s", strerror(errno)); STATUP(data->nsd, txerr); ZTATUP(q->zone, txerr); } else if ((size_t) sent != buffer_remaining(q->packet)) { log_msg(LOG_ERR, "sent %d in place of %d bytes", sent, (int) buffer_remaining(q->packet)); #ifdef BIND8_STATS } else { /* Account the rcode & TC... */ STATUP2(data->nsd, rcode, RCODE(q->packet)); ZTATUP2(q->zone, rcode, RCODE(q->packet)); if (TC(q->packet)) { STATUP(data->nsd, truncated); ZTATUP(q->zone, truncated); } #endif /* BIND8_STATS */ } #ifdef BIND8_STATS } else { STATUP(data->nsd, dropped); # ifdef USE_ZONE_STATS if (q->zone) { ZTATUP(q->zone, dropped); } # endif #endif } } }