summaryrefslogtreecommitdiffstats
path: root/src/dns/dns_rr_to_sa.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/dns/dns_rr_to_sa.c')
-rw-r--r--src/dns/dns_rr_to_sa.c163
1 files changed, 163 insertions, 0 deletions
diff --git a/src/dns/dns_rr_to_sa.c b/src/dns/dns_rr_to_sa.c
new file mode 100644
index 0000000..f264260
--- /dev/null
+++ b/src/dns/dns_rr_to_sa.c
@@ -0,0 +1,163 @@
+/*++
+/* NAME
+/* dns_rr_to_sa 3
+/* SUMMARY
+/* resource record to socket address
+/* SYNOPSIS
+/* #include <dns.h>
+/*
+/* int dns_rr_to_sa(rr, port, sa, sa_length)
+/* DNS_RR *rr;
+/* unsigned port;
+/* struct sockaddr *sa;
+/* SOCKADDR_SIZE *sa_length;
+/* DESCRIPTION
+/* dns_rr_to_sa() converts the address in a DNS resource record into
+/* a socket address of the corresponding type.
+/*
+/* Arguments:
+/* .IP rr
+/* DNS resource record pointer.
+/* .IP port
+/* TCP or UDP port, network byte order.
+/* .IP sa
+/* Socket address pointer.
+/* .IP sa_length
+/* On input, the available socket address storage space.
+/* On output, the amount of space actually used.
+/* DIAGNOSTICS
+/* The result is non-zero in case of problems, with the
+/* error type returned via the errno variable.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System libraries. */
+
+#include <sys_defs.h>
+#include <errno.h>
+
+/* Utility library. */
+
+#include <msg.h>
+
+/* DNS library. */
+
+#include <dns.h>
+
+/* dns_rr_to_sa - resource record to socket address */
+
+int dns_rr_to_sa(DNS_RR *rr, unsigned port, struct sockaddr *sa,
+ SOCKADDR_SIZE *sa_length)
+{
+ SOCKADDR_SIZE sock_addr_len;
+
+ if (rr->type == T_A) {
+ if (rr->data_len != sizeof(SOCK_ADDR_IN_ADDR(sa))) {
+ errno = EINVAL;
+ return (-1);
+ } else if ((sock_addr_len = sizeof(*SOCK_ADDR_IN_PTR(sa))) > *sa_length) {
+ errno = ENOSPC;
+ return (-1);
+ } else {
+ memset((void *) SOCK_ADDR_IN_PTR(sa), 0, sock_addr_len);
+ SOCK_ADDR_IN_FAMILY(sa) = AF_INET;
+ SOCK_ADDR_IN_PORT(sa) = port;
+ SOCK_ADDR_IN_ADDR(sa) = IN_ADDR(rr->data);
+#ifdef HAS_SA_LEN
+ sa->sa_len = sock_addr_len;
+#endif
+ *sa_length = sock_addr_len;
+ return (0);
+ }
+#ifdef HAS_IPV6
+ } else if (rr->type == T_AAAA) {
+ if (rr->data_len != sizeof(SOCK_ADDR_IN6_ADDR(sa))) {
+ errno = EINVAL;
+ return (-1);
+ } else if ((sock_addr_len = sizeof(*SOCK_ADDR_IN6_PTR(sa))) > *sa_length) {
+ errno = ENOSPC;
+ return (-1);
+ } else {
+ memset((void *) SOCK_ADDR_IN6_PTR(sa), 0, sock_addr_len);
+ SOCK_ADDR_IN6_FAMILY(sa) = AF_INET6;
+ SOCK_ADDR_IN6_PORT(sa) = port;
+ SOCK_ADDR_IN6_ADDR(sa) = IN6_ADDR(rr->data);
+#ifdef HAS_SA_LEN
+ sa->sa_len = sock_addr_len;
+#endif
+ *sa_length = sock_addr_len;
+ return (0);
+ }
+#endif
+ } else {
+ errno = EAFNOSUPPORT;
+ return (-1);
+ }
+}
+
+ /*
+ * Stand-alone test program.
+ */
+#ifdef TEST
+#include <stdlib.h>
+
+#include <stringops.h>
+#include <vstream.h>
+#include <myaddrinfo.h>
+
+static const char *myname;
+
+static NORETURN usage(void)
+{
+ msg_fatal("usage: %s dnsaddrtype hostname portnumber", myname);
+}
+
+int main(int argc, char **argv)
+{
+ DNS_RR *rr;
+ MAI_HOSTADDR_STR hostaddr;
+ MAI_SERVPORT_STR portnum;
+ struct sockaddr_storage ss;
+ struct sockaddr *sa = (struct sockaddr *) &ss;
+ SOCKADDR_SIZE sa_length = sizeof(ss);
+ VSTRING *why;
+ int type;
+ int port;
+
+ myname = argv[0];
+ if (argc < 4)
+ usage();
+ why = vstring_alloc(1);
+
+ while (*++argv) {
+ if (argv[1] == 0 || argv[2] == 0)
+ usage();
+ if ((type = dns_type(argv[0])) == 0)
+ usage();
+ if (!alldig(argv[2]) || (port = atoi(argv[2])) > 65535)
+ usage();
+ if (dns_lookup(argv[1], type, 0, &rr, (VSTRING *) 0, why) != DNS_OK)
+ msg_fatal("%s: %s", argv[1], vstring_str(why));
+ sa_length = sizeof(ss);
+ if (dns_rr_to_sa(rr, htons(port), sa, &sa_length) != 0)
+ msg_fatal("dns_rr_to_sa: %m");
+ SOCKADDR_TO_HOSTADDR(sa, sa_length, &hostaddr, &portnum, 0);
+ vstream_printf("%s %s -> %s %s\n",
+ argv[1], argv[2], hostaddr.buf, portnum.buf);
+ vstream_fflush(VSTREAM_OUT);
+ argv += 2;
+ dns_rr_free(rr);
+ }
+ vstring_free(why);
+ return (0);
+}
+
+#endif