From: Rahul Thakur Date: Tue, 20 Feb 2024 07:30:17 +0000 (+0530) Subject: dns: add support for reverse address mapping queries X-Git-Url: http://git.openwrt.org/?a=commitdiff_plain;h=2b28094d31caa75cd60ef86f0a27a793beaff968;p=project%2Fmdnsd.git dns: add support for reverse address mapping queries The mdnsd currently does not have the capability of responding to reverse address mapping dns requests for either IPv4 or IPv6. This commit adds support to handle reverse address mapping and respond with hostname if the address matches that of the DUT. Signed-off-by: Rahul Thakur Signed-off-by: Felix Fietkau [cleanup] --- diff --git a/dns.c b/dns.c index a20fb3e..e2db851 100644 --- a/dns.c +++ b/dns.c @@ -440,13 +440,144 @@ static int parse_answer(struct interface *iface, struct sockaddr *from, return 0; } +static int +match_ipv6_addresses(char *reverse_ip, struct in6_addr *intf_ip) +{ + int i = 0, j = 0, idx = 0; + char temp_ip[INET6_ADDRSTRLEN] = ""; + struct in6_addr buf; + + for (i = strlen(reverse_ip) - 1; i >= 0; i--) { + if (reverse_ip[i] == '.') + continue; + + if (j == 4) { + temp_ip[idx] = ':'; + idx++; + j = 0; + } + temp_ip[idx] = reverse_ip[i]; + idx++; + j++; + } + + if (inet_pton(AF_INET6, temp_ip, &buf) <= 0) + return 0; + + return !memcmp(&buf, intf_ip, sizeof(buf)); +} + +static int +match_ip_addresses(char *reverse_ip, char *intf_ip) +{ + int ip1[4], ip2[4]; + + sscanf(reverse_ip, "%d.%d.%d.%d", &ip1[3], &ip1[2], &ip1[1], &ip1[0]); + sscanf(intf_ip, "%d.%d.%d.%d", &ip2[0], &ip2[1], &ip2[2], &ip2[3]); + + int i; + for (i = 0; i < 4; i++) { + if (ip1[i] != ip2[i]) + return 0; + } + return 1; +} + +static void +dns_reply_reverse_ip6_mapping(struct interface *iface, struct sockaddr *to, int ttl, char *name, char *reverse_ip) +{ + struct ifaddrs *ifap, *ifa; + struct sockaddr_in6 *sa6; + + char intf_ip[INET6_ADDRSTRLEN] = ""; + uint8_t buffer[256]; + int len; + + getifaddrs(&ifap); + dns_packet_init(); + for (ifa = ifap; ifa; ifa = ifa->ifa_next) { + if (strcmp(ifa->ifa_name, iface->name)) + continue; + if (ifa->ifa_addr->sa_family == AF_INET6) { + sa6 = (struct sockaddr_in6 *) ifa->ifa_addr; + if (inet_ntop(AF_INET6, &sa6->sin6_addr, intf_ip, INET6_ADDRSTRLEN) == NULL) + continue; + + if (match_ipv6_addresses(reverse_ip, &sa6->sin6_addr)) { + len = dn_comp(mdns_hostname_local, buffer, sizeof(buffer), NULL, NULL); + + if (len < 1) + continue; + + dns_packet_answer(name, TYPE_PTR, buffer, len, ttl); + } + } + } + dns_packet_send(iface, to, 0, 0); + + freeifaddrs(ifap); +} + +static void +dns_reply_reverse_ip4_mapping(struct interface *iface, struct sockaddr *to, int ttl, char *name, char *reverse_ip) +{ + struct ifaddrs *ifap, *ifa; + struct sockaddr_in *sa; + + char intf_ip[INET_ADDRSTRLEN] = ""; + uint8_t buffer[256]; + int len; + + getifaddrs(&ifap); + dns_packet_init(); + for (ifa = ifap; ifa; ifa = ifa->ifa_next) { + if (strcmp(ifa->ifa_name, iface->name)) + continue; + if (ifa->ifa_addr->sa_family == AF_INET) { + sa = (struct sockaddr_in *) ifa->ifa_addr; + if (inet_ntop(AF_INET, &sa->sin_addr, intf_ip, INET_ADDRSTRLEN) == NULL) + continue; + + if (match_ip_addresses(reverse_ip, intf_ip)) { + len = dn_comp(mdns_hostname_local, buffer, sizeof(buffer), NULL, NULL); + + if (len < 1) + continue; + + dns_packet_answer(name, TYPE_PTR, buffer, len, ttl); + } + } + } + dns_packet_send(iface, to, 0, 0); + + freeifaddrs(ifap); +} + +static bool +is_reverse_dns_query(const char *name, const char *suffix) +{ + if (!name || !suffix) + return false; + + size_t name_len = strlen(name); + size_t suffix_len = strlen(suffix); + + if (suffix_len > name_len) + return false; + + if (strncmp(name + (name_len - suffix_len), suffix, suffix_len) == 0) + return true; + + return false; +} + static void parse_question(struct interface *iface, struct sockaddr *from, char *name, struct dns_question *q) { int is_unicast = (q->class & CLASS_UNICAST) != 0; struct sockaddr *to = NULL; struct hostname *h; - char *host; + char *host, *host6; /* TODO: Multicast if more than one quarter of TTL has passed */ if (is_unicast) { @@ -467,6 +598,24 @@ parse_question(struct interface *iface, struct sockaddr *from, char *name, struc break; case TYPE_PTR: + if (is_reverse_dns_query(name, ".in-addr.arpa")) { + host = strstr(name, ".in-addr.arpa"); + char name_buf[256]; + strcpy(name_buf, name); + *host = '\0'; + dns_reply_reverse_ip4_mapping(iface, to, announce_ttl, name_buf, name); + break; + } + + if (is_reverse_dns_query(name, ".ip6.arpa")) { + host6 = strstr(name, ".ip6.arpa"); + char name_buf6[256]; + strcpy(name_buf6, name); + *host6 = '\0'; + dns_reply_reverse_ip6_mapping(iface, to, announce_ttl, name_buf6, name); + break; + } + if (!strcasecmp(name, C_DNS_SD)) { service_announce_services(iface, to, announce_ttl); } else {