X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?p=secnet.git;a=blobdiff_plain;f=util.c;h=b91497edc8b3bc8606054008898d8bc98a6da230;hp=cfa6b4ccbd5ee6008aca3dee1a99003a6046c403;hb=c6a3b1f54ccc754be82f0a2ea5b4d60746053a2b;hpb=ccf25024a3b46e9ca2b1842883b2f0953daf4842 diff --git a/util.c b/util.c index cfa6b4c..b91497e 100644 --- a/util.c +++ b/util.c @@ -36,9 +36,11 @@ #include #include #include +#include #include "util.h" #include "unaligned.h" #include "magic.h" +#include "ipaddr.h" #define MIN_BUFFER_SIZE 64 #define DEFAULT_BUFFER_SIZE 4096 @@ -170,6 +172,13 @@ void setcloexec(int fd) { if (r<0) fatal_perror("fcntl(,F_SETFD,|FD_CLOEXEC) failed"); } +void pipe_cloexec(int fd[2]) { + int r=pipe(fd); + if (r) fatal_perror("pipe"); + setcloexec(fd[0]); + setcloexec(fd[1]); +} + static const char *phases[NR_PHASES]={ "PHASE_INIT", "PHASE_GETOPTS", @@ -470,3 +479,106 @@ extern void slilog_part(struct log_if *lf, int priority, const char *message, .. vslilog_part(lf,priority,message,ap); va_end(ap); } + +void text2iaddr(const item_t *item, uint16_t port, union iaddr *ia, + const char *desc) +{ +#ifndef CONFIG_IPV6 + + ia->sin.sin_family=AF_INET; + ia->sin.sin_addr.s_addr=string_item_to_ipaddr(item,desc); + +#else /* CONFIG_IPV6 => we have adns_text2addr */ + + if (item->type!=t_string) + cfgfatal(item->loc,desc,"expecting a string IP (v4 or v6) address\n"); + socklen_t salen=sizeof(*ia); + int r=adns_text2addr(item->data.string, port, + adns_qf_addrlit_ipv4_quadonly, + &ia->sa, &salen); + assert(r!=ENOSPC); + if (r) cfgfatal(item->loc,desc,"invalid IP (v4 or v6) address: %s\n", + strerror(r)); + +#endif /* CONFIG_IPV6 */ +} + +#define IADDR_NBUFS_SHIFT 3 +#define IADDR_NBUFS (1 << IADDR_NBUFS_SHIFT) + +const char *iaddr_to_string(const union iaddr *ia) +{ + static int b; + + b++; + b &= IADDR_NBUFS-1; + +#ifndef CONFIG_IPV6 + + static char bufs[IADDR_NBUFS][100]; + + assert(ia->sa.sa_family == AF_INET); + + snprintf(bufs[b], sizeof(bufs[b]), "[%s]:%d", + inet_ntoa(ia->sin.sin_addr), + ntohs(ia->sin.sin_port)); + +#else /* CONFIG_IPV6 => we have adns_addr2text */ + + static char bufs[IADDR_NBUFS][1+ADNS_ADDR2TEXT_BUFLEN+20]; + + int port; + + char *addrbuf = bufs[b]; + *addrbuf++ = '['; + int addrbuflen = ADNS_ADDR2TEXT_BUFLEN; + + int r = adns_addr2text(&ia->sa, 0, addrbuf, &addrbuflen, &port); + if (r) { + const char fmt[]= "scoped IPv6 addr, error: %.*s"; + sprintf(addrbuf, fmt, + ADNS_ADDR2TEXT_BUFLEN - sizeof(fmt) /* underestimate */, + strerror(r)); + } + + char *portbuf = addrbuf; + int addrl = strlen(addrbuf); + portbuf += addrl; + + snprintf(portbuf, sizeof(bufs[b])-addrl, "]:%d", port); + +#endif /* CONFIG_IPV6 */ + + return bufs[b]; +} + +bool_t iaddr_equal(const union iaddr *ia, const union iaddr *ib) +{ + if (ia->sa.sa_family != ib->sa.sa_family) + return 0; + switch (ia->sa.sa_family) { + case AF_INET: + return ia->sin.sin_addr.s_addr == ib->sin.sin_addr.s_addr + && ia->sin.sin_port == ib->sin.sin_port; +#ifdef CONFIG_IPV6 + case AF_INET6: + return !memcmp(&ia->sin6.sin6_addr, &ib->sin6.sin6_addr, 16) + && ia->sin6.sin6_scope_id == ib->sin6.sin6_scope_id + && ia->sin6.sin6_port == ib->sin6.sin6_port + /* we ignore the flowinfo field */; +#endif /* CONFIG_IPV6 */ + default: + abort(); + } +} + +int iaddr_socklen(const union iaddr *ia) +{ + switch (ia->sa.sa_family) { + case AF_INET: return sizeof(ia->sin); +#ifdef CONFIG_IPV6 + case AF_INET6: return sizeof(ia->sin6); +#endif /* CONFIG_IPV6 */ + default: abort(); + } +}