/* * Answer if this is an AXFR or IXFR query. */ query_state_type answer_axfr_ixfr(struct nsd *nsd, struct query *q) { struct acl_options *acl = NULL; /* Is it AXFR? */ switch (q->qtype) { case TYPE_AXFR: if (q->tcp) { struct zone_options* zone_opt; zone_opt = zone_options_find(nsd->options, q->qname); if(!zone_opt || acl_check_incoming(zone_opt->pattern->provide_xfr, q, &acl)==-1) { if (verbosity >= 2) { char a[128]; addr2str(&q->addr, a, sizeof(a)); VERBOSITY(2, (LOG_INFO, "axfr for %s from %s refused, %s", dname_to_string(q->qname, NULL), a, acl?"blocked":"no acl matches")); } DEBUG(DEBUG_XFRD,1, (LOG_INFO, "axfr refused, %s", acl?"blocked":"no acl matches")); if (!zone_opt) { RCODE_SET(q->packet, RCODE_NOTAUTH); } else { RCODE_SET(q->packet, RCODE_REFUSE); } return QUERY_PROCESSED; } DEBUG(DEBUG_XFRD,1, (LOG_INFO, "axfr admitted acl %s %s", acl->ip_address_spec, acl->key_name?acl->key_name:"NOKEY")); if (verbosity >= 1) { char a[128]; addr2str(&q->addr, a, sizeof(a)); VERBOSITY(1, (LOG_INFO, "%s for %s from %s", (q->qtype==TYPE_AXFR?"axfr":"ixfr"), dname_to_string(q->qname, NULL), a)); } return query_axfr(nsd, q); } /** Fallthrough: AXFR over UDP queries are discarded. */ /* fallthrough */ case TYPE_IXFR: RCODE_SET(q->packet, RCODE_IMPL); return QUERY_PROCESSED; default: return QUERY_DISCARDED; } }
/* * Answer if this is an AXFR or IXFR query. */ query_state_type answer_axfr_ixfr(struct nsd *nsd, struct query *q) { acl_options_t *acl; /* Is it AXFR? */ switch (q->qtype) { case TYPE_AXFR: if (q->tcp) { zone_options_t* zone_opt; zone_opt = zone_options_find(nsd->options, q->qname); if(!zone_opt || acl_check_incoming(zone_opt->provide_xfr, q, &acl)==-1) { if (verbosity > 0) { char address[128]; if (addr2ip(q->addr, address, sizeof(address))) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "addr2ip failed")); strlcpy(address, "[unknown]", sizeof(address)); } VERBOSITY(1, (LOG_INFO, "axfr for zone %s from client %s refused, %s", dname_to_string(q->qname, NULL), address, acl?"blocked":"no acl matches")); } DEBUG(DEBUG_XFRD,1, (LOG_INFO, "axfr refused, %s", acl?"blocked":"no acl matches")); if (!zone_opt) { RCODE_SET(q->packet, RCODE_NOTAUTH); } else { RCODE_SET(q->packet, RCODE_REFUSE); } return QUERY_PROCESSED; } DEBUG(DEBUG_XFRD,1, (LOG_INFO, "axfr admitted acl %s %s", acl->ip_address_spec, acl->key_name?acl->key_name:"NOKEY")); return query_axfr(nsd, q); } case TYPE_IXFR: RCODE_SET(q->packet, RCODE_IMPL); return QUERY_PROCESSED; default: return QUERY_DISCARDED; } }
static void handle_tcp_writing(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 sent; struct query *q = data->query; if (event_types & NETIO_EVENT_TIMEOUT) { /* Connection timed out. */ cleanup_tcp_handler(netio, handler); return; } assert(event_types & NETIO_EVENT_WRITE); if (data->bytes_transmitted < sizeof(q->tcplen)) { /* Writing the response packet length. */ uint16_t n_tcplen = htons(q->tcplen); sent = write(handler->fd, (const char *) &n_tcplen + data->bytes_transmitted, sizeof(n_tcplen) - data->bytes_transmitted); if (sent == -1) { if (errno == EAGAIN || errno == EINTR) { /* * Write would block, wait until * socket becomes writable again. */ return; } else { #ifdef ECONNRESET if(verbosity >= 2 || errno != ECONNRESET) #endif /* ECONNRESET */ #ifdef EPIPE if(verbosity >= 2 || errno != EPIPE) #endif /* EPIPE 'broken pipe' */ log_msg(LOG_ERR, "failed writing to tcp: %s", strerror(errno)); cleanup_tcp_handler(netio, handler); return; } } data->bytes_transmitted += sent; if (data->bytes_transmitted < sizeof(q->tcplen)) { /* * Writing not complete, wait until socket * becomes writable again. */ return; } assert(data->bytes_transmitted == sizeof(q->tcplen)); } assert(data->bytes_transmitted < q->tcplen + sizeof(q->tcplen)); sent = write(handler->fd, buffer_current(q->packet), buffer_remaining(q->packet)); if (sent == -1) { if (errno == EAGAIN || errno == EINTR) { /* * Write would block, wait until * socket becomes writable again. */ return; } else { #ifdef ECONNRESET if(verbosity >= 2 || errno != ECONNRESET) #endif /* ECONNRESET */ #ifdef EPIPE if(verbosity >= 2 || errno != EPIPE) #endif /* EPIPE 'broken pipe' */ log_msg(LOG_ERR, "failed writing to tcp: %s", strerror(errno)); cleanup_tcp_handler(netio, handler); return; } } buffer_skip(q->packet, sent); data->bytes_transmitted += sent; if (data->bytes_transmitted < q->tcplen + sizeof(q->tcplen)) { /* * Still more data to write when socket becomes * writable again. */ return; } assert(data->bytes_transmitted == q->tcplen + sizeof(q->tcplen)); if (data->query_state == QUERY_IN_AXFR) { /* Continue processing AXFR and writing back results. */ buffer_clear(q->packet); data->query_state = query_axfr(data->nsd, q); if (data->query_state != QUERY_PROCESSED) { query_add_optional(data->query, data->nsd); /* Reset data. */ buffer_flip(q->packet); q->tcplen = buffer_remaining(q->packet); data->bytes_transmitted = 0; /* Reset timeout. */ handler->timeout->tv_sec = data->nsd->tcp_timeout; handler->timeout->tv_nsec = 0; timespec_add(handler->timeout, netio_current_time(netio)); /* * Write data if/when the socket is writable * again. */ return; } } /* * Done sending, wait for the next request to arrive on the * TCP socket by installing the TCP read handler. */ if (data->nsd->tcp_query_count > 0 && data->query_count >= data->nsd->tcp_query_count) { (void) shutdown(handler->fd, SHUT_WR); } data->bytes_transmitted = 0; handler->timeout->tv_sec = data->nsd->tcp_timeout; handler->timeout->tv_nsec = 0; timespec_add(handler->timeout, netio_current_time(netio)); handler->event_types = NETIO_EVENT_READ | NETIO_EVENT_TIMEOUT; handler->event_handler = handle_tcp_reading; }