1 /*        $NetBSD: dns_rr_eq_sa.c,v 1.3 2023/12/23 20:30:43 christos Exp $      */
2 
3 /*++
4 /* NAME
5 /*        dns_rr_eq_sa 3
6 /* SUMMARY
7 /*        compare resource record with socket address
8 /* SYNOPSIS
9 /*        #include <dns.h>
10 /*
11 /*        int       dns_rr_eq_sa(DNS_RR *rr, struct sockaddr *sa)
12 /*        DNS_RR    *rr;
13 /*        struct sockaddr *sa;
14 /*
15 /*        int       DNS_RR_EQ_SA(DNS_RR *rr, struct sockaddr *sa)
16 /*        DNS_RR    *rr;
17 /*        struct sockaddr *sa;
18 /* DESCRIPTION
19 /*        dns_rr_eq_sa() compares a DNS resource record with a socket
20 /*        address.  The result is non-zero when the resource type
21 /*        matches the socket address family, and when the network
22 /*        address information is identical.
23 /*
24 /*        DNS_RR_EQ_SA() is an unsafe macro version for those who live fast.
25 /*
26 /*        Arguments:
27 /* .IP rr
28 /*        DNS resource record pointer.
29 /* .IP sa
30 /*        Binary address pointer.
31 /* DIAGNOSTICS
32 /*        Panic: unknown socket address family.
33 /* LICENSE
34 /* .ad
35 /* .fi
36 /*        The Secure Mailer license must be distributed with this software.
37 /* AUTHOR(S)
38 /*        Wietse Venema
39 /*        IBM T.J. Watson Research
40 /*        P.O. Box 704
41 /*        Yorktown Heights, NY 10598, USA
42 /*--*/
43 
44 /* System libraries. */
45 
46 #include <sys_defs.h>
47 
48 /* Utility library. */
49 
50 #include <msg.h>
51 #include <sock_addr.h>
52 
53 /* DNS library. */
54 
55 #include <dns.h>
56 
57 /* dns_rr_eq_sa - compare resource record with socket address */
58 
dns_rr_eq_sa(DNS_RR * rr,struct sockaddr * sa)59 int     dns_rr_eq_sa(DNS_RR *rr, struct sockaddr *sa)
60 {
61     const char *myname = "dns_rr_eq_sa";
62 
63     if (sa->sa_family == AF_INET) {
64           return (rr->type == T_A
65                     && SOCK_ADDR_IN_ADDR(sa).s_addr == IN_ADDR(rr->data).s_addr);
66 #ifdef HAS_IPV6
67     } else if (sa->sa_family == AF_INET6) {
68           return (rr->type == T_AAAA
69                     && memcmp((void *) &SOCK_ADDR_IN6_ADDR(sa),
70                                 rr->data, rr->data_len) == 0);
71 #endif
72     } else {
73           msg_panic("%s: unsupported socket address family type: %d",
74                       myname, sa->sa_family);
75     }
76 }
77 
78  /*
79   * Stand-alone test program.
80   */
81 #ifdef TEST
82 #include <stdlib.h>
83 #include <vstream.h>
84 #include <myaddrinfo.h>
85 #include <inet_proto.h>
86 #include <mymalloc.h>
87 
88 static const char *myname;
89 
usage(void)90 static NORETURN usage(void)
91 {
92     msg_fatal("usage: %s hostname address", myname);
93 }
94 
compare_family(const void * a,const void * b)95 static int compare_family(const void *a, const void *b)
96 {
97     struct addrinfo *resa = *(struct addrinfo **) a;
98     struct addrinfo *resb = *(struct addrinfo **) b;
99 
100     return (resa->ai_family - resb->ai_family);
101 }
102 
main(int argc,char ** argv)103 int     main(int argc, char **argv)
104 {
105     MAI_HOSTADDR_STR hostaddr;
106     DNS_RR *rr;
107     struct addrinfo *res0;
108     struct addrinfo *res1;
109     struct addrinfo *res;
110     struct addrinfo **resv;
111     size_t  len, n;
112     int     aierr;
113 
114     myname = argv[0];
115 
116     if (argc < 3)
117           usage();
118 
119     inet_proto_init(argv[0], INET_PROTO_NAME_ALL);
120 
121     while (*++argv) {
122           if (argv[1] == 0)
123               usage();
124 
125           if ((aierr = hostaddr_to_sockaddr(argv[1], (char *) 0, 0, &res1)) != 0)
126               msg_fatal("host address %s: %s", argv[1], MAI_STRERROR(aierr));
127           if ((rr = dns_sa_to_rr(argv[1], DNS_RR_NOPREF, res1->ai_addr)) == 0)
128               msg_fatal("dns_sa_to_rr: %m");
129           freeaddrinfo(res1);
130 
131           if ((aierr = hostname_to_sockaddr(argv[0], (char *) 0, 0, &res0)) != 0)
132               msg_fatal("host name %s: %s", argv[0], MAI_STRERROR(aierr));
133           for (len = 0, res = res0; res != 0; res = res->ai_next)
134               len += 1;
135           resv = (struct addrinfo **) mymalloc(len * sizeof(*resv));
136           for (len = 0, res = res0; res != 0; res = res->ai_next)
137               resv[len++] = res;
138           qsort((void *) resv, len, sizeof(*resv), compare_family);
139           for (n = 0; n < len; n++) {
140               SOCKADDR_TO_HOSTADDR(resv[n]->ai_addr, resv[n]->ai_addrlen,
141                                          &hostaddr, (MAI_SERVPORT_STR *) 0, 0);
142               vstream_printf("%s =?= %s\n", hostaddr.buf, argv[1]);
143               vstream_printf("tested by function: %s\n",
144                                  dns_rr_eq_sa(rr, resv[n]->ai_addr) ?
145                                  "yes" : "no");
146               vstream_printf("tested by macro:    %s\n",
147                                  DNS_RR_EQ_SA(rr, resv[n]->ai_addr) ?
148                                  "yes" : "no");
149           }
150           dns_rr_free(rr);
151           freeaddrinfo(res0);
152           myfree((void *) resv);
153           vstream_fflush(VSTREAM_OUT);
154           argv += 1;
155     }
156     return (0);
157 }
158 
159 #endif
160