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; }
/** find soa serial (if any) */ static int udb_zone_get_serial(udb_base* udb, udb_ptr* zone, uint32_t* serial) { udb_ptr domain, rrset, rr; buffer_type buffer; if(!udb_domain_find(udb, zone, ZONE(zone)->name, ZONE(zone)->namelen, &domain)) return 0; if(!udb_rrset_find(udb, &domain, TYPE_SOA, &rrset)) { udb_ptr_unlink(&domain, udb); return 0; } /* got SOA rrset, use first RR */ if(!RRSET(&rrset)->rrs.data) { udb_ptr_unlink(&domain, udb); udb_ptr_unlink(&rrset, udb); return 0; } udb_ptr_new(&rr, udb, &RRSET(&rrset)->rrs); udb_ptr_unlink(&domain, udb); udb_ptr_unlink(&rrset, udb); /* find serial */ buffer_create_from(&buffer, RR(&rr)->wire, RR(&rr)->len); /* skip two dnames */ if(!packet_skip_dname(&buffer) || !packet_skip_dname(&buffer)) { udb_ptr_unlink(&rr, udb); return 0; } if(!buffer_available(&buffer, 4*5)) { /* soa rdata u32s */ udb_ptr_unlink(&rr, udb); return 0; } *serial = buffer_read_u32(&buffer); udb_ptr_unlink(&rr, udb); return 1; }
static void handle_dns_query(const uint8_t *raw_data, uint16_t data_len, socket_t *client_socket, const addr_t *client_addr, void *arg) { //header is 12 octets, wire name is 1 octets, //class is 2 octets, type is 2 octets if (data_len < 12 + 4 + 1) { log_warning(QUERY_LOG, "get invalid query package\n"); return; } if (dns_header_get_opt(raw_data) != QUERY_STAND) { log_warning(QUERY_LOG, "get non-query package\n"); return; } zipper_t *zipper = (zipper_t *)arg; query_session_t *session = memorypool_alloc_node(zipper->query_session_pool_); if (session == NULL) { log_warning(QUERY_LOG, "no memory left to handle more query\n"); return; } memcpy(session->query_raw_data_, raw_data, data_len); session->query_data_len_ = data_len; session->zipper_ = zipper; session->client_socket_ = *client_socket; session->client_addr_ = *client_addr; char ip_addr_str[MAX_IP_STR_LEN]; addr_get_ip(client_addr, ip_addr_str); log_debug(QUERY_LOG, "get query from ip [%s]\n", ip_addr_str); session->location_info_ = ipstore_get_location_use_int(zipper->ip_store_, addr_get_v4_addr(client_addr)); if (!session->location_info_) { log_warning(QUERY_LOG, "get ip failed\n"); goto BAD_QUERY; } buffer_t buf; buffer_create_from(&buf, (void *)(raw_data + 12), data_len - 12 - 4); session->query_wire_name_ = wire_name_from_wire(&buf); if (session->query_wire_name_) { buffer_t name_buf; char str_name[MAX_DOMAIN_NAME_LEN] = {0}; buffer_create_from(&name_buf, str_name, MAX_DOMAIN_NAME_LEN); wire_name_to_text(session->query_wire_name_, &name_buf); log_debug(QUERY_LOG, "handle query name [%s]\n", str_name); char view_name[MAX_VIEW_NAME_LEN]; rule_store_get_view(zipper->rule_store_, session->query_wire_name_, session->location_info_, view_name); query_named_with_view(view_name, session); wire_name_delete(session->query_wire_name_); } else { wire_name_delete(session->query_wire_name_); log_warning(QUERY_LOG, "get invalid query name\n"); goto BAD_QUERY; } return; BAD_QUERY: memorypool_free_node(zipper->query_session_pool_, session); }