1/*	$NetBSD$	*/
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
59int     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((char *) 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((char *) 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
118static const char *myname;
119
120static NORETURN usage(void)
121{
122    msg_fatal("usage: %s dnsaddrtype hostname portnumber", myname);
123}
124
125int     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