header_t * dns_header_decode(netif_t *netif, packet_t *packet, raw_packet_t *raw_packet, packet_offset_t offset) { dns_header_t *dns = dns_header_new(); packet_offset_t field_offset; if (raw_packet->len < (offset + DNS_HEADER_LEN)) { LOG_PRINTLN(LOG_HEADER_DNS, LOG_ERROR, ("decode DNS header: size too small (present=%u, required=%u)", raw_packet->len - offset, DNS_HEADER_LEN)); DNS_FAILURE_EXIT; } /* fetch header */ uint8_to_uint16(&(dns->id), &(raw_packet->data[offset + DNS_HEADER_OFFSET_ID])); uint8_to_uint16(&(dns->flags.raw), &(raw_packet->data[offset + DNS_HEADER_OFFSET_FLAGS])); uint8_to_uint16(&(dns->qd_count), &(raw_packet->data[offset + DNS_HEADER_OFFSET_QD_COUNT])); uint8_to_uint16(&(dns->an_count), &(raw_packet->data[offset + DNS_HEADER_OFFSET_AN_COUNT])); uint8_to_uint16(&(dns->ns_count), &(raw_packet->data[offset + DNS_HEADER_OFFSET_NS_COUNT])); uint8_to_uint16(&(dns->ar_count), &(raw_packet->data[offset + DNS_HEADER_OFFSET_AR_COUNT])); field_offset = offset + DNS_HEADER_LEN; /* question section */ if (dns->qd_count > 0) { dns->qd = dns_query_new(); if (!dns_header_decode_query(raw_packet, offset, &field_offset, dns->qd_count, dns->qd)) { dns_query_free(dns->qd); DNS_FAILURE_EXIT; } } /* answer records section */ if (dns->an_count > 0) { dns->an = dns_rr_new(); if (!dns_header_decode_rr(raw_packet, offset, &field_offset, dns->an_count, dns->an)) { dns_rr_free(dns->an); DNS_FAILURE_EXIT; } } /* authority records section */ if (dns->ns_count > 0) { dns->ns = dns_rr_new(); if (!dns_header_decode_rr(raw_packet, offset, &field_offset, dns->ns_count, dns->ns)) { dns_rr_free(dns->ns); DNS_FAILURE_EXIT; } } /* additional records section */ if (dns->ar_count > 0) { dns->ar = dns_rr_new(); if (!dns_header_decode_rr(raw_packet, offset, &field_offset, dns->ar_count, dns->ar)) { dns_rr_free(dns->ar); DNS_FAILURE_EXIT; } } return (header_t *) dns; }
static bool dns_header_decode_query(raw_packet_t *raw_packet, packet_offset_t header_offset, packet_offset_t *field_offset, uint16_t count, dns_query_t *query) { dns_label_t *label; for (; count > 0; count--) { if (raw_packet->len < (*field_offset + DNS_QUERY_MIN_LEN)) { LOG_PRINTLN(LOG_HEADER_DNS, LOG_ERROR, ("decode DNS query: size too small (present=%" PRIoffset ", required=%" PRIoffset ", offset=%" PRIoffset "/%x)", raw_packet->len - *field_offset, DNS_QUERY_MIN_LEN, *field_offset, *field_offset)); return false; } /* qname */ label = dns_label_new(); if (!dns_header_decode_label(raw_packet, header_offset, field_offset, label)) { dns_label_free(label); return false; } query->qname = label; /* qtype + qclass */ uint8_to_uint16(&(query->qtype), &(raw_packet->data[*field_offset + DNS_QUERY_OFFSET_QTYPE])); uint8_to_uint16(&(query->qclass), &(raw_packet->data[*field_offset + DNS_QUERY_OFFSET_QCLASS])); *field_offset += DNS_QUERY_SIZE; /* not the last query */ if (count > 1) { query->next = dns_query_new(); query = query->next; } } return true; }
static int bus_method_resolve_address(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL; _cleanup_free_ char *reverse = NULL; Manager *m = userdata; int family, ifindex; uint64_t flags; const void *d; DnsQuery *q; size_t sz; int r; assert(bus); assert(message); assert(m); r = sd_bus_message_read(message, "ii", &ifindex, &family); if (r < 0) return r; if (!IN_SET(family, AF_INET, AF_INET6)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family); r = sd_bus_message_read_array(message, 'y', &d, &sz); if (r < 0) return r; if (sz != FAMILY_ADDRESS_SIZE(family)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size"); r = sd_bus_message_read(message, "t", &flags); if (r < 0) return r; r = check_ifindex_flags(ifindex, &flags, error); if (r < 0) return r; r = dns_name_reverse(family, d, &reverse); if (r < 0) return r; question = dns_question_new(1); if (!question) return -ENOMEM; key = dns_resource_key_new_consume(DNS_CLASS_IN, DNS_TYPE_PTR, reverse); if (!key) return -ENOMEM; reverse = NULL; r = dns_question_add(question, key); if (r < 0) return r; r = dns_query_new(m, &q, question, ifindex, flags); if (r < 0) return r; q->request = sd_bus_message_ref(message); q->request_family = family; memcpy(&q->request_address, d, sz); q->complete = bus_method_resolve_address_complete; r = dns_query_bus_track(q, bus, message); if (r < 0) return r; r = dns_query_go(q); if (r < 0) { dns_query_free(q); if (r == -ESRCH) sd_bus_error_setf(error, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found"); return r; } return 1; }
static int bus_method_resolve_hostname(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL; Manager *m = userdata; const char *hostname; int family, ifindex; uint64_t flags; DnsQuery *q; int r; assert(bus); assert(message); assert(m); r = sd_bus_message_read(message, "isit", &ifindex, &hostname, &family, &flags); if (r < 0) return r; if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family); r = dns_name_normalize(hostname, NULL); if (r < 0) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", hostname); r = check_ifindex_flags(ifindex, &flags, error); if (r < 0) return r; question = dns_question_new(family == AF_UNSPEC ? 2 : 1); if (!question) return -ENOMEM; if (family != AF_INET6) { _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, hostname); if (!key) return -ENOMEM; r = dns_question_add(question, key); if (r < 0) return r; } if (family != AF_INET) { _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, hostname); if (!key) return -ENOMEM; r = dns_question_add(question, key); if (r < 0) return r; } r = dns_query_new(m, &q, question, ifindex, flags); if (r < 0) return r; q->request = sd_bus_message_ref(message); q->request_family = family; q->request_hostname = hostname; q->complete = bus_method_resolve_hostname_complete; r = dns_query_bus_track(q, bus, message); if (r < 0) return r; r = dns_query_go(q); if (r < 0) { dns_query_free(q); if (r == -ESRCH) sd_bus_error_setf(error, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found"); return r; } return 1; }