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