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