int buffer_printf(buffer_type *buffer, const char *format, ...) { va_list args; int written; size_t remaining; buffer_invariant(buffer); assert(buffer->_limit == buffer->_capacity); remaining = buffer_remaining(buffer); va_start(args, format); written = vsnprintf((char *) buffer_current(buffer), remaining, format, args); va_end(args); if (written >= 0 && (size_t) written >= remaining) { buffer_reserve(buffer, written + 1); va_start(args, format); written = vsnprintf((char *) buffer_current(buffer), buffer_remaining(buffer), format, args); va_end(args); } buffer->_position += written; return written; }
static char* unmarshal_str(region_type* r, struct buffer* b) { uint8_t nonnull = unmarshal_u8(b); if(nonnull) { char* result = region_strdup(r, (char*)buffer_current(b)); size_t len = strlen((char*)buffer_current(b)); buffer_skip(b, len+1); return result; } else return NULL; }
static void __emit_call(struct buffer *buf, void *call_target) { int disp = call_target - buffer_current(buf) - X86_CALL_INSN_SIZE; emit(buf, 0xe8); emit_imm32(buf, disp); }
static void __emit_call(struct buffer *buf, void *call_target) { int disp = x86_call_disp(buffer_current(buf), call_target); emit(buf, 0xe8); emit_imm32(buf, disp); }
int xfrd_send_udp(acl_options_t* acl, buffer_type* packet, acl_options_t* ifc) { #ifdef INET6 struct sockaddr_storage to; #else struct sockaddr_in to; #endif /* INET6 */ int fd, family; /* this will set the remote port to acl->port or TCP_PORT */ socklen_t to_len = xfrd_acl_sockaddr_to(acl, &to); /* get the address family of the remote host */ if(acl->is_ipv6) { #ifdef INET6 family = PF_INET6; #else return -1; #endif /* INET6 */ } else { family = PF_INET; } fd = socket(family, SOCK_DGRAM, IPPROTO_UDP); if(fd == -1) { log_msg(LOG_ERR, "xfrd: cannot create udp socket to %s: %s", acl->ip_address_spec, strerror(errno)); return -1; } /* bind it */ if (!xfrd_bind_local_interface(fd, ifc, acl, 0)) { log_msg(LOG_ERR, "xfrd: cannot bind outgoing interface '%s' to " "udp socket: No matching ip addresses found", ifc->ip_address_spec); return -1; } /* send it (udp) */ if(sendto(fd, buffer_current(packet), buffer_remaining(packet), 0, (struct sockaddr*)&to, to_len) == -1) { log_msg(LOG_ERR, "xfrd: sendto %s failed %s", acl->ip_address_spec, strerror(errno)); return -1; } return fd; }
static void send_response(uv_stream_t *client, struct buffer response_buffer) { uv_buf_t *uv_response_buffer; uv_write_t *response; uv_response_buffer = malloc(sizeof(uv_buf_t)); uv_response_buffer->base = buffer_current(&response_buffer); uv_response_buffer->len = buffer_len(&response_buffer); response = malloc(sizeof(uv_write_t)); response->data = (void *) client; uv_write(response, client, uv_response_buffer, 1, on_response_end); }
int skip_record(buffer_type *buffer) { char* p; u_int16_t rdlength; p = buffer_current(buffer); while (*p != '\0') { if (buffer_available(buffer, *p + 1)) buffer_skip(buffer, *p + 1); else return -1; p = buffer_current(buffer); } if (*p != '\0') return -1; if (!buffer_available(buffer, 11)) return -1; buffer_skip(buffer, 1); buffer_skip(buffer, 8); rdlength = buffer_read_u16(buffer); if (buffer_available(buffer, rdlength)) return 0; return -1; }
static int rdata_base64_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { int length; size_t size = rdata_atom_size(rdata); if(size == 0) return 1; buffer_reserve(output, size * 2 + 1); length = __b64_ntop(rdata_atom_data(rdata), size, (char *) buffer_current(output), size * 2); if (length > 0) { buffer_skip(output, length); } return length != -1; }
static int rdata_base64_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { int length; size_t size = rdata_atom_size(rdata); if(size == 0) { /* single zero represents empty buffer */ buffer_write(output, "0", 1); return 1; } buffer_reserve(output, size * 2 + 1); length = b64_ntop(rdata_atom_data(rdata), size, (char *) buffer_current(output), size * 2); if (length > 0) { buffer_skip(output, length); } return length != -1; }
static int rdata_base32_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { int length; size_t size = rdata_atom_size(rdata); if(size == 0) { buffer_write(output, "-", 1); return 1; } size -= 1; /* remove length byte from count */ buffer_reserve(output, size * 2 + 1); length = b32_ntop(rdata_atom_data(rdata)+1, size, (char *) buffer_current(output), size * 2); if (length > 0) { buffer_skip(output, length); } return length != -1; }
/** * Send notify over udp. * */ static int notify_send_udp(notify_type* notify, buffer_type* buffer) { struct sockaddr_storage to; socklen_t to_len = 0; int fd = -1; int family = PF_INET; ssize_t nb = 0; ods_log_assert(buffer); ods_log_assert(notify); ods_log_assert(notify->secondary); ods_log_assert(notify->secondary->address); /* this will set the remote port to acl->port or TCP_PORT */ to_len = xfrd_acl_sockaddr_to(notify->secondary, &to); /* get the address family of the remote host */ if (notify->secondary->family == AF_INET6) { family = PF_INET6; } /* create socket */ fd = socket(family, SOCK_DGRAM, IPPROTO_UDP); if (fd == -1) { ods_log_error("[%s] unable to send data over udp to %s: " "socket() failed (%s)", notify_str, notify->secondary->address, strerror(errno)); return -1; } /* bind it? */ /* send it (udp) */ ods_log_deeebug("[%s] send %d bytes over udp to %s", notify_str, buffer_remaining(buffer), notify->secondary->address); nb = sendto(fd, buffer_current(buffer), buffer_remaining(buffer), 0, (struct sockaddr*)&to, to_len); if (nb == -1) { ods_log_error("[%s] unable to send data over udp to %s: " "sendto() failed (%s)", notify_str, notify->secondary->address, strerror(errno)); close(fd); return -1; } return fd; }
int packet_read_query_section(buffer_type *packet, uint8_t* dst, uint16_t* qtype, uint16_t* qclass) { uint8_t *query_name = buffer_current(packet); uint8_t *src = query_name; size_t len; while (*src) { /* * If we are out of buffer limits or we have a pointer * in question dname or the domain name is longer than * MAXDOMAINLEN ... */ if ((*src & 0xc0) || (src + *src + 2 > buffer_end(packet)) || (src + *src + 2 > query_name + MAXDOMAINLEN)) { return 0; } memcpy(dst, src, *src + 1); dst += *src + 1; src += *src + 1; } *dst++ = *src++; /* Make sure name is not too long or we have stripped packet... */ len = src - query_name; if (len > MAXDOMAINLEN || (src + 2*sizeof(uint16_t) > buffer_end(packet))) { return 0; } buffer_set_position(packet, src - buffer_begin(packet)); *qtype = buffer_read_u16(packet); *qclass = buffer_read_u16(packet); return 1; }
static int rdata_nsec_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { size_t saved_position = buffer_position(output); buffer_type packet; int insert_space = 0; buffer_create_from( &packet, rdata_atom_data(rdata), rdata_atom_size(rdata)); while (buffer_available(&packet, 2)) { uint8_t window = buffer_read_u8(&packet); uint8_t bitmap_size = buffer_read_u8(&packet); uint8_t *bitmap = buffer_current(&packet); int i; if (!buffer_available(&packet, bitmap_size)) { buffer_set_position(output, saved_position); return 0; } for (i = 0; i < bitmap_size * 8; ++i) { if (get_bit(bitmap, i)) { buffer_printf(output, "%s%s", insert_space ? " " : "", rrtype_to_string( window * 256 + i)); insert_space = 1; } } buffer_skip(&packet, bitmap_size); } return 1; }
static int rdata_services_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* ATTR_UNUSED(rr)) { int result = 0; buffer_type packet; buffer_create_from( &packet, rdata_atom_data(rdata), rdata_atom_size(rdata)); if (buffer_available(&packet, 1)) { uint8_t protocol_number = buffer_read_u8(&packet); ssize_t bitmap_size = buffer_remaining(&packet); uint8_t *bitmap = buffer_current(&packet); struct protoent *proto = getprotobynumber(protocol_number); if (proto) { int i; buffer_printf(output, "%s", proto->p_name); for (i = 0; i < bitmap_size * 8; ++i) { if (get_bit(bitmap, i)) { struct servent *service = getservbyport((int)htons(i), proto->p_name); if (service) { buffer_printf(output, " %s", service->s_name); } else { buffer_printf(output, " %d", i); } } } buffer_skip(&packet, bitmap_size); result = 1; } } return result; }
int dname_make_wire_from_packet(uint8_t *buf, buffer_type *packet, int allow_pointers) { int done = 0; uint8_t visited[(MAX_PACKET_SIZE+7)/8]; size_t dname_length = 0; const uint8_t *label; ssize_t mark = -1; memset(visited, 0, (buffer_limit(packet)+7)/8); while (!done) { if (!buffer_available(packet, 1)) { /* error("dname out of bounds"); */ return 0; } if (get_bit(visited, buffer_position(packet))) { /* error("dname loops"); */ return 0; } set_bit(visited, buffer_position(packet)); label = buffer_current(packet); if (label_is_pointer(label)) { size_t pointer; if (!allow_pointers) { return 0; } if (!buffer_available(packet, 2)) { /* error("dname pointer out of bounds"); */ return 0; } pointer = label_pointer_location(label); if (pointer >= buffer_limit(packet)) { /* error("dname pointer points outside packet"); */ return 0; } buffer_skip(packet, 2); if (mark == -1) { mark = buffer_position(packet); } buffer_set_position(packet, pointer); } else if (label_is_normal(label)) { size_t length = label_length(label) + 1; done = label_is_root(label); if (!buffer_available(packet, length)) { /* error("dname label out of bounds"); */ return 0; } if (dname_length + length >= MAXDOMAINLEN+1) { /* error("dname too large"); */ return 0; } buffer_read(packet, buf + dname_length, length); dname_length += length; } else { /* error("bad label type"); */ return 0; } } if (mark != -1) { buffer_set_position(packet, mark); } return dname_length; }
ssize_t rdata_wireformat_to_rdata_atoms(region_type *region, domain_table_type *owners, uint16_t rrtype, uint16_t data_size, buffer_type *packet, rdata_atom_type **rdatas) { size_t end = buffer_position(packet) + data_size; size_t i; rdata_atom_type temp_rdatas[MAXRDATALEN]; rrtype_descriptor_type *descriptor = rrtype_descriptor_by_type(rrtype); region_type *temp_region; assert(descriptor->maximum <= MAXRDATALEN); if (!buffer_available(packet, data_size)) { return -1; } temp_region = region_create(xalloc, free); for (i = 0; i < descriptor->maximum; ++i) { int is_domain = 0; int is_normalized = 0; int is_wirestore = 0; size_t length = 0; int required = i < descriptor->minimum; switch (rdata_atom_wireformat_type(rrtype, i)) { case RDATA_WF_COMPRESSED_DNAME: case RDATA_WF_UNCOMPRESSED_DNAME: is_domain = 1; is_normalized = 1; break; case RDATA_WF_LITERAL_DNAME: is_domain = 1; is_wirestore = 1; break; case RDATA_WF_BYTE: length = sizeof(uint8_t); break; case RDATA_WF_SHORT: length = sizeof(uint16_t); break; case RDATA_WF_LONG: length = sizeof(uint32_t); break; case RDATA_WF_TEXTS: case RDATA_WF_LONG_TEXT: length = end - buffer_position(packet); break; case RDATA_WF_TEXT: case RDATA_WF_BINARYWITHLENGTH: /* Length is stored in the first byte. */ length = 1; if (buffer_position(packet) + length <= end) { length += buffer_current(packet)[length - 1]; } break; case RDATA_WF_A: length = sizeof(in_addr_t); break; case RDATA_WF_AAAA: length = IP6ADDRLEN; break; case RDATA_WF_ILNP64: length = IP6ADDRLEN/2; break; case RDATA_WF_EUI48: length = EUI48ADDRLEN; break; case RDATA_WF_EUI64: length = EUI64ADDRLEN; break; case RDATA_WF_BINARY: /* Remaining RDATA is binary. */ length = end - buffer_position(packet); break; case RDATA_WF_APL: length = (sizeof(uint16_t) /* address family */ + sizeof(uint8_t) /* prefix */ + sizeof(uint8_t)); /* length */ if (buffer_position(packet) + length <= end) { /* Mask out negation bit. */ length += (buffer_current(packet)[length - 1] & APL_LENGTH_MASK); } break; case RDATA_WF_IPSECGATEWAY: switch(rdata_atom_data(temp_rdatas[1])[0]) /* gateway type */ { default: case IPSECKEY_NOGATEWAY: length = 0; break; case IPSECKEY_IP4: length = IP4ADDRLEN; break; case IPSECKEY_IP6: length = IP6ADDRLEN; break; case IPSECKEY_DNAME: is_domain = 1; is_normalized = 1; is_wirestore = 1; break; } break; } if (is_domain) { const dname_type *dname; if (!required && buffer_position(packet) == end) { break; } dname = dname_make_from_packet( temp_region, packet, 1, is_normalized); if (!dname || buffer_position(packet) > end) { /* Error in domain name. */ region_destroy(temp_region); return -1; } if(is_wirestore) { temp_rdatas[i].data = (uint16_t *) region_alloc( region, sizeof(uint16_t) + ((size_t)dname->name_size)); temp_rdatas[i].data[0] = dname->name_size; memcpy(temp_rdatas[i].data+1, dname_name(dname), dname->name_size); } else { temp_rdatas[i].domain = domain_table_insert(owners, dname); temp_rdatas[i].domain->usage ++; } } else { if (buffer_position(packet) + length > end) { if (required) { /* Truncated RDATA. */ region_destroy(temp_region); return -1; } else { break; } } if (!required && buffer_position(packet) == end) { break; } temp_rdatas[i].data = (uint16_t *) region_alloc( region, sizeof(uint16_t) + length); temp_rdatas[i].data[0] = length; buffer_read(packet, temp_rdatas[i].data + 1, length); } } if (buffer_position(packet) < end) { /* Trailing garbage. */ region_destroy(temp_region); return -1; } *rdatas = (rdata_atom_type *) region_alloc_array_init( region, temp_rdatas, i, sizeof(rdata_atom_type)); region_destroy(temp_region); return (ssize_t)i; }
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; }
static int dns_name_from_wire(buffer_type* data, struct decompress_ctx *decompress, char* text_name) { char *q; u_int8_t *p, label_len; int length, off, saved = -1, i; if (data == NULL || text_name == NULL || decompress == NULL) return -1; p = buffer_current(data); q = text_name; length = 0; label_len = buffer_read_u8(data); if (label_len == 0) { *q = '.'; q++; } while (label_len != 0 && length < NAME_MAX_LENGTH) { if ((label_len & 0xc0) == 0xc0) { buffer_set_position(data, buffer_position(data) - 1); label_len = buffer_read_u16(data); off = label_len & ~0xc0; if (off >= buffer_limit(data) /*|| decompress->pos[off] != off*/) return -1; if (saved == -1) saved = buffer_position(data); buffer_set_position(data, off); label_len = buffer_read_u8(data); } else { if (!buffer_available(data, label_len)) return -1; for (i = 0; i < label_len; i++) { if (decompress->pos[i] == -1) decompress->pos[i] = buffer_position(data); } length += label_len; p = buffer_current(data); memcpy(q, p, label_len); buffer_skip(data, label_len); q += label_len; *q = '.'; q++; label_len = buffer_read_u8(data); } } if (label_len == 0) { *q = '\0'; if (saved > -1) buffer_set_position(data, saved); } else { log_msg("dns:domain not ends with \\0\n"); return -1; } return 0; }
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; }
/** * Process query. * */ query_state query_process(query_type* q, void* engine) { ldns_status status = LDNS_STATUS_OK; ldns_pkt* pkt = NULL; ldns_rr* rr = NULL; ldns_pkt_rcode rcode = LDNS_RCODE_NOERROR; ldns_pkt_opcode opcode = LDNS_PACKET_QUERY; ldns_rr_type qtype = LDNS_RR_TYPE_SOA; engine_type* e = (engine_type*) engine; ods_log_assert(e); ods_log_assert(q); ods_log_assert(q->buffer); if (!e || !q || !q->buffer) { ods_log_error("[%s] drop query: assertion error", query_str); return QUERY_DISCARDED; /* should not happen */ } if (buffer_limit(q->buffer) < BUFFER_PKT_HEADER_SIZE) { ods_log_debug("[%s] drop query: packet too small", query_str); return QUERY_DISCARDED; /* too small */ } if (buffer_pkt_qr(q->buffer)) { ods_log_debug("[%s] drop query: qr bit set", query_str); return QUERY_DISCARDED; /* not a query */ } /* parse packet */ status = ldns_wire2pkt(&pkt, buffer_current(q->buffer), buffer_remaining(q->buffer)); if (status != LDNS_STATUS_OK) { ods_log_debug("[%s] got bad packet: %s", query_str, ldns_get_errorstr_by_id(status)); return query_formerr(q); } rr = ldns_rr_list_rr(ldns_pkt_question(pkt), 0); lock_basic_lock(&e->zonelist->zl_lock); /* we can just lookup the zone, because we will only handle SOA queries, zone transfers, updates and notifies */ q->zone = zonelist_lookup_zone_by_dname(e->zonelist, ldns_rr_owner(rr), ldns_rr_get_class(rr)); /* don't answer for zones that are just added */ if (q->zone && q->zone->zl_status == ZONE_ZL_ADDED) { ods_log_warning("[%s] zone %s just added, don't answer for now", query_str, q->zone->name); q->zone = NULL; } lock_basic_unlock(&e->zonelist->zl_lock); if (!q->zone) { ods_log_debug("[%s] zone not found", query_str); return query_servfail(q); } /* see if it is tsig signed */ if (!query_find_tsig(q)) { return query_formerr(q); } /* else: valid tsig, or no tsig present */ ods_log_debug("[%s] tsig %s", query_str, tsig_status2str(q->tsig_rr->status)); rcode = query_process_tsig(q); if (rcode != LDNS_RCODE_NOERROR) { return query_error(q, rcode); } /* process edns */ rcode = query_process_edns(q); if (rcode != LDNS_RCODE_NOERROR) { /* We should not return FORMERR, but BADVERS (=16). * BADVERS is created with Ext. RCODE, followed by RCODE. * Ext. RCODE is set to 1, RCODE must be 0 (getting 0x10 = 16). * Thus RCODE = NOERROR = NSD_RC_OK. */ return query_error(q, LDNS_RCODE_NOERROR); } /* handle incoming request */ opcode = ldns_pkt_get_opcode(pkt); qtype = ldns_rr_get_type(rr); ldns_pkt_free(pkt); switch (opcode) { case LDNS_PACKET_NOTIFY: return query_process_notify(q, qtype, engine); case LDNS_PACKET_QUERY: return query_process_query(q, qtype, engine); case LDNS_PACKET_UPDATE: return query_process_update(q); default: break; } return query_notimpl(q); }
int print_rr(FILE *out, struct state_pretty_rr *state, rr_type *record) { region_type *region = region_create(xalloc, free); buffer_type *output = buffer_create(region, MAX_RDLENGTH); rrtype_descriptor_type *descriptor = rrtype_descriptor_by_type(record->type); int result; const dname_type *owner = domain_dname(record->owner); const dname_type *owner_origin = dname_origin(region, owner); int owner_changed = (!state->previous_owner || dname_compare(state->previous_owner, owner) != 0); if (owner_changed) { int origin_changed = (!state->previous_owner_origin || dname_compare( state->previous_owner_origin, owner_origin) != 0); if (origin_changed) { buffer_printf( output, "$ORIGIN %s\n", dname_to_string(owner_origin, NULL)); } set_previous_owner(state, owner); buffer_printf(output, "%s", dname_to_string(owner, state->previous_owner_origin)); } buffer_printf(output, "\t%lu\t%s\t%s", (unsigned long) record->ttl, rrclass_to_string(record->klass), rrtype_to_string(record->type)); result = print_rdata(output, descriptor, record); if (!result) { /* * Some RDATA failed to print, so print the record's * RDATA in unknown format. */ result = rdata_atoms_to_unknown_string(output, descriptor, record->rdata_count, record->rdatas); } if (result) { buffer_printf(output, "\n"); buffer_flip(output); (void)write_data(out, buffer_current(output), buffer_remaining(output)); /* fflush(out); */ } region_destroy(region); return result; }