summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRahul Thakur2024-02-20 07:30:17 +0000
committerFelix Fietkau2025-05-28 22:40:37 +0000
commit2b28094d31caa75cd60ef86f0a27a793beaff968 (patch)
tree459979e499c8003413c1012cf4f85d1052218ceb
parentcecbe1c0caaee3de70bea0413b9f90d4b5b5ca36 (diff)
downloadmdnsd-2b28094d31caa75cd60ef86f0a27a793beaff968.tar.gz
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 <rahul.thakur@iopsys.eu> Signed-off-by: Felix Fietkau <nbd@nbd.name> [cleanup]
-rw-r--r--dns.c151
1 files changed, 150 insertions, 1 deletions
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 {