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