summaryrefslogtreecommitdiff
path: root/client
diff options
context:
space:
mode:
authorIan Jackson <ijackson@chiark.greenend.org.uk>2014-06-03 20:42:01 +0100
committerIan Jackson <ijackson@chiark.greenend.org.uk>2014-10-19 21:08:41 +0100
commit5806b74528bbe1d70e5e1795224b1c6ecd8c4341 (patch)
treee9f5e5b1dd74a2995f4807f7e469851541a057cb /client
parent07554ccd8286775b4f88a608ba3b94ff7b9efaf9 (diff)
New public-facing functions for address/text conversions.
The usual functions for doing these conversions are getaddrinfo(3) and getnameinfo(3). Unfortunately, these seem generally to be rather buggy (with different bugs on different platforms). For example, the Linux glibc implementation tries to do complicated things with AF_NETLINK sockets even though it's only going to do a simple syntactic transformation. So we provide our own versions, which only handle conversions between addresses and their text numerical representations (and don't try to do anything complicated with DNS). For compatibility, the functions handle various crazy things which are generally undesirable: * traditional IPv4 text conversions allow degenerate forms A, A.B and A.B.C, where the host part is given as a simple number rather than being split into octets; * traditional IPv4 text conversions allow the individual components to be given in bases other than 10, using the usual C prefixes; * IPv6 socket addresses (but, annoyingly, not `struct in6_addr') have a `scope-id' field (which actually identifies what RFC4007 calls a `zone', i.e., the namespace in which the address should be interpreted), and these are described by a `%...' suffix; and * the `scope-id' may be a name, though the syntax and meaning of such names isn't defined anywhere except for the link-local scope, where the names and numbers are interface names and indices, which need to be looked up. All of this means that there are a number of options and unfortunate error conditions, which make the interface more complicated than is really ideal. Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk> Signed-off-by: Mark Wooding <mdw@distorted.org.uk>
Diffstat (limited to 'client')
-rw-r--r--client/Makefile.in2
-rw-r--r--client/addrtext.c197
2 files changed, 198 insertions, 1 deletions
diff --git a/client/Makefile.in b/client/Makefile.in
index 01f2fcd..0588072 100644
--- a/client/Makefile.in
+++ b/client/Makefile.in
@@ -27,7 +27,7 @@ PROGS_SYSDEP= @PROGS_HAVE_TSEARCH@
ENABLE_DYNAMIC= @ENABLE_DYNAMIC@
PROGRAMS= adnslogres adnsheloex adnshost $(PROGS_SYSDEP)
-PROGRAMS_LOCAL= fanftest adnstest
+PROGRAMS_LOCAL= fanftest adnstest addrtext
PROGRAMS_ALL= $(PROGRAMS) $(PROGRAMS_LOCAL)
STATIC_LIB= ../src/libadns.a
diff --git a/client/addrtext.c b/client/addrtext.c
new file mode 100644
index 0000000..f61aa68
--- /dev/null
+++ b/client/addrtext.c
@@ -0,0 +1,197 @@
+/*
+ some test cases
+
+
+ ./addrtext_s fe80::1%wlanx
+ ./addrtext_s fe80::1%wlan0
+ ./addrtext_s fe80::1%23
+ ./addrtext_s fe80::1%1
+ ./addrtext_s 2001:ba8:1e3::%wlan0
+ ./addrtext_s 2001:ba8:1e3::%23
+ ./addrtext_s 2001:ba8:1e3::%1 # normally lo
+ ./addrtext_s 127.0.0.1x
+ ./addrtext_s 172.18.45.6
+ ./addrtext_s 12345
+
+
+ */
+
+/*
+ * addrtext.c
+ * - test program for address<->string conversion, not part of the library
+ */
+/*
+ * This file is part of adns, which is
+ * Copyright (C) 1997-2000,2003,2006,2014 Ian Jackson
+ * Copyright (C) 1999-2000,2003,2006 Tony Finch
+ * Copyright (C) 1991 Massachusetts Institute of Technology
+ * (See the file INSTALL for full details.)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <stdbool.h>
+#include <string.h>
+#include <errno.h>
+#include <inttypes.h>
+
+#include "config.h"
+#include "adns.h"
+
+#define PORT 1234
+
+#define STRING(x) STRING2(x)
+#define STRING2(x) #x
+
+static int fails;
+
+static void hex(const void *data_v, int l) {
+ const uint8_t *data= data_v;
+ int i;
+ for (i=0; i<l; i++)
+ printf("%02x",data[i]);
+}
+
+static void dump(const char *pfx, struct sockaddr *sa, socklen_t salen) {
+ int i;
+ printf(" %s: ",pfx);
+ hex(sa, salen);
+
+ for (i=0; i<salen; i++)
+ printf("%02x",((const uint8_t*)sa)[i]);
+
+ printf(" %d ", sa->sa_family);
+
+ switch (sa->sa_family) {
+ case AF_INET: {
+ const struct sockaddr_in *s = (const void*)sa;
+ printf(".port=%d .addr=%08"PRIx32"",
+ ntohs(s->sin_port),
+ (uint32_t)ntohl(s->sin_addr.s_addr));
+ break;
+ }
+ case AF_INET6: {
+ const struct sockaddr_in6 *s = (const void*)sa;
+ printf(".port=%d .flowinfo=%08"PRIx32" .scope_id=%08"PRIx32" .addr=",
+ ntohs(s->sin6_port),
+ (uint32_t)ntohl(s->sin6_flowinfo),
+ (uint32_t)ntohl(s->sin6_scope_id));
+ hex(&s->sin6_addr, sizeof(s->sin6_addr));
+ break;
+ }
+ }
+ printf("\n");
+}
+
+static void dotest(const char *input) {
+ adns_sockaddr ours;
+ socklen_t socklen;
+ struct addrinfo aip;
+ struct addrinfo *air=0;
+ char ourbuf[ADNS_ADDR2TEXT_BUFLEN];
+ char theirbuf[ADNS_ADDR2TEXT_BUFLEN];
+
+ memset(&ours,0,sizeof(ours));
+
+ socklen= sizeof(ours);
+ int our_r= adns_text2addr(input,PORT,0,&ours.sa,&socklen);
+
+ memset(&aip,0,sizeof(aip));
+ aip.ai_flags= AI_NUMERICHOST|AI_NUMERICSERV;
+ aip.ai_socktype= SOCK_DGRAM;
+ aip.ai_protocol= IPPROTO_UDP;
+ air= 0;
+ int libc_r= getaddrinfo(input,STRING(PORT),&aip,&air);
+ printf("`%s': us %s; libc %s, air=%p",
+ input, strerror(our_r), libc_r ? gai_strerror(libc_r) : "0", air);
+ if (air)
+ printf(" .family=%d .socklen=%ld .addr=%p .next=%p",
+ air->ai_family, (long)air->ai_addrlen, air->ai_addr, air->ai_next);
+ printf(":");
+
+ if (libc_r==EAI_NONAME && !air) {
+ if (strchr(input,'%') && (our_r==ENOSYS || our_r==ENXIO)) {
+ printf(" bad-scope");
+ goto ok;
+ }
+ if (strchr(input,'%') && our_r==ENOSYS) {
+ printf(" bad-scope");
+ goto ok;
+ }
+ if (our_r==EINVAL) {
+ printf(" invalid");
+ goto ok;
+ }
+ }
+ printf(" valid");
+
+#define FAIL do{ printf(" | FAIL\n"); fails++; }while(0)
+#define WANT(x) if (!(x)) { printf(" not %s",STRING(x)); FAIL; return; } else;
+
+ WANT(!our_r);
+ WANT(!libc_r);
+ WANT(air);
+ WANT(air->ai_addr);
+ WANT(!air->ai_next);
+ if (air->ai_addrlen!=socklen || memcmp(&ours,air->ai_addr,socklen)) {
+ printf(" mismatch");
+ FAIL;
+ dump("ours",&ours.sa,socklen);
+ dump("libc",air->ai_addr,air->ai_addrlen);
+ return;
+ }
+
+ printf(" |");
+
+ int ourbuflen= sizeof(ourbuf);
+ int ourport;
+ our_r= adns_addr2text(&ours.sa,0, ourbuf,&ourbuflen, &ourport);
+
+ printf(" us %s",strerror(our_r));
+ if (!our_r)
+ printf(" `%s'",ourbuf);
+
+ size_t theirbuflen= sizeof(theirbuf);
+ libc_r= getnameinfo(&ours.sa,socklen, theirbuf,theirbuflen, 0,0,
+ NI_NUMERICHOST|NI_NUMERICSERV);
+ printf("; libc %s", libc_r ? gai_strerror(libc_r) : "0");
+ if (!libc_r)
+ printf(" `%s'",theirbuf);
+
+ printf(":");
+
+ WANT(!our_r);
+ WANT(!libc_r);
+ WANT(ourport==PORT);
+ if (strcmp(ourbuf,theirbuf)) {
+ printf(" mismatch");
+ FAIL;
+ return;
+ }
+
+ ok:
+ printf(" | PASS\n");
+}
+
+int main(int argc, char **argv) {
+ const char *arg;
+ while ((arg= *++argv)) {
+ dotest(arg);
+ }
+ return !!fails;
+}