xref: /netbsd-src/external/ibm-public/postfix/dist/src/dns/dns_rr_to_sa.c (revision e89934bbf778a6d6d6894877c4da59d0c7835b0f)
1 /*	$NetBSD: dns_rr_to_sa.c,v 1.2 2017/02/14 01:16:44 christos Exp $	*/
2 
3 /*++
4 /* NAME
5 /*	dns_rr_to_sa 3
6 /* SUMMARY
7 /*	resource record to socket address
8 /* SYNOPSIS
9 /*	#include <dns.h>
10 /*
11 /*	int	dns_rr_to_sa(rr, port, sa, sa_length)
12 /*	DNS_RR	*rr;
13 /*	unsigned port;
14 /*	struct sockaddr *sa;
15 /*	SOCKADDR_SIZE *sa_length;
16 /* DESCRIPTION
17 /*	dns_rr_to_sa() converts the address in a DNS resource record into
18 /*	a socket address of the corresponding type.
19 /*
20 /*	Arguments:
21 /* .IP rr
22 /*	DNS resource record pointer.
23 /* .IP port
24 /*	TCP or UDP port, network byte order.
25 /* .IP sa
26 /*	Socket address pointer.
27 /* .IP sa_length
28 /*	On input, the available socket address storage space.
29 /*	On output, the amount of space actually used.
30 /* DIAGNOSTICS
31 /*	The result is non-zero in case of problems, with the
32 /*	error type returned via the errno variable.
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 #include <errno.h>
48 
49 /* Utility library. */
50 
51 #include <msg.h>
52 
53 /* DNS library. */
54 
55 #include <dns.h>
56 
57 /* dns_rr_to_sa - resource record to socket address */
58 
dns_rr_to_sa(DNS_RR * rr,unsigned port,struct sockaddr * sa,SOCKADDR_SIZE * sa_length)59 int     dns_rr_to_sa(DNS_RR *rr, unsigned port, struct sockaddr *sa,
60 		             SOCKADDR_SIZE *sa_length)
61 {
62     SOCKADDR_SIZE sock_addr_len;
63 
64     if (rr->type == T_A) {
65 	if (rr->data_len != sizeof(SOCK_ADDR_IN_ADDR(sa))) {
66 	    errno = EINVAL;
67 	    return (-1);
68 	} else if ((sock_addr_len = sizeof(*SOCK_ADDR_IN_PTR(sa))) > *sa_length) {
69 	    errno = ENOSPC;
70 	    return (-1);
71 	} else {
72 	    memset((void *) SOCK_ADDR_IN_PTR(sa), 0, sock_addr_len);
73 	    SOCK_ADDR_IN_FAMILY(sa) = AF_INET;
74 	    SOCK_ADDR_IN_PORT(sa) = port;
75 	    SOCK_ADDR_IN_ADDR(sa) = IN_ADDR(rr->data);
76 #ifdef HAS_SA_LEN
77 	    sa->sa_len = sock_addr_len;
78 #endif
79 	    *sa_length = sock_addr_len;
80 	    return (0);
81 	}
82 #ifdef HAS_IPV6
83     } else if (rr->type == T_AAAA) {
84 	if (rr->data_len != sizeof(SOCK_ADDR_IN6_ADDR(sa))) {
85 	    errno = EINVAL;
86 	    return (-1);
87 	} else if ((sock_addr_len = sizeof(*SOCK_ADDR_IN6_PTR(sa))) > *sa_length) {
88 	    errno = ENOSPC;
89 	    return (-1);
90 	} else {
91 	    memset((void *) SOCK_ADDR_IN6_PTR(sa), 0, sock_addr_len);
92 	    SOCK_ADDR_IN6_FAMILY(sa) = AF_INET6;
93 	    SOCK_ADDR_IN6_PORT(sa) = port;
94 	    SOCK_ADDR_IN6_ADDR(sa) = IN6_ADDR(rr->data);
95 #ifdef HAS_SA_LEN
96 	    sa->sa_len = sock_addr_len;
97 #endif
98 	    *sa_length = sock_addr_len;
99 	    return (0);
100 	}
101 #endif
102     } else {
103 	errno = EAFNOSUPPORT;
104 	return (-1);
105     }
106 }
107 
108  /*
109   * Stand-alone test program.
110   */
111 #ifdef TEST
112 #include <stdlib.h>
113 
114 #include <stringops.h>
115 #include <vstream.h>
116 #include <myaddrinfo.h>
117 
118 static const char *myname;
119 
usage(void)120 static NORETURN usage(void)
121 {
122     msg_fatal("usage: %s dnsaddrtype hostname portnumber", myname);
123 }
124 
main(int argc,char ** argv)125 int     main(int argc, char **argv)
126 {
127     DNS_RR *rr;
128     MAI_HOSTADDR_STR hostaddr;
129     MAI_SERVPORT_STR portnum;
130     struct sockaddr_storage ss;
131     struct sockaddr *sa = (struct sockaddr *) &ss;
132     SOCKADDR_SIZE sa_length = sizeof(ss);
133     VSTRING *why;
134     int     type;
135     int     port;
136 
137     myname = argv[0];
138     if (argc < 4)
139 	usage();
140     why = vstring_alloc(1);
141 
142     while (*++argv) {
143 	if (argv[1] == 0 || argv[2] == 0)
144 	    usage();
145 	if ((type = dns_type(argv[0])) == 0)
146 	    usage();
147 	if (!alldig(argv[2]) || (port = atoi(argv[2])) > 65535)
148 	    usage();
149 	if (dns_lookup(argv[1], type, 0, &rr, (VSTRING *) 0, why) != DNS_OK)
150 	    msg_fatal("%s: %s", argv[1], vstring_str(why));
151 	sa_length = sizeof(ss);
152 	if (dns_rr_to_sa(rr, htons(port), sa, &sa_length) != 0)
153 	    msg_fatal("dns_rr_to_sa: %m");
154 	SOCKADDR_TO_HOSTADDR(sa, sa_length, &hostaddr, &portnum, 0);
155 	vstream_printf("%s %s -> %s %s\n",
156 		       argv[1], argv[2], hostaddr.buf, portnum.buf);
157 	vstream_fflush(VSTREAM_OUT);
158 	argv += 2;
159 	dns_rr_free(rr);
160     }
161     vstring_free(why);
162     return (0);
163 }
164 
165 #endif
166