diff options
Diffstat (limited to '')
-rw-r--r-- | src/util/sock_addr.c | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/src/util/sock_addr.c b/src/util/sock_addr.c new file mode 100644 index 0000000..dc5c4b1 --- /dev/null +++ b/src/util/sock_addr.c @@ -0,0 +1,173 @@ +/*++ +/* NAME +/* sock_addr 3 +/* SUMMARY +/* sockaddr utilities +/* SYNOPSIS +/* #include <sock_addr.h> +/* +/* int sock_addr_cmp_addr(sa, sb) +/* const struct sockaddr *sa; +/* const struct sockaddr *sb; +/* +/* int sock_addr_cmp_port(sa, sb) +/* const struct sockaddr *sa; +/* const struct sockaddr *sb; +/* +/* int SOCK_ADDR_EQ_ADDR(sa, sb) +/* const struct sockaddr *sa; +/* const struct sockaddr *sb; +/* +/* int SOCK_ADDR_EQ_PORT(sa, sb) +/* const struct sockaddr *sa; +/* const struct sockaddr *sb; +/* +/* int sock_addr_in_loopback(sa) +/* const struct sockaddr *sa; +/* AUXILIARY MACROS +/* struct sockaddr *SOCK_ADDR_PTR(ptr) +/* unsigned char SOCK_ADDR_FAMILY(ptr) +/* unsigned char SOCK_ADDR_LEN(ptr) +/* unsigned short SOCK_ADDR_PORT(ptr) +/* unsigned short *SOCK_ADDR_PORTP(ptr) +/* +/* struct sockaddr_in *SOCK_ADDR_IN_PTR(ptr) +/* unsigned char SOCK_ADDR_IN_FAMILY(ptr) +/* unsigned short SOCK_ADDR_IN_PORT(ptr) +/* struct in_addr SOCK_ADDR_IN_ADDR(ptr) +/* struct in_addr IN_ADDR(ptr) +/* +/* struct sockaddr_in6 *SOCK_ADDR_IN6_PTR(ptr) +/* unsigned char SOCK_ADDR_IN6_FAMILY(ptr) +/* unsigned short SOCK_ADDR_IN6_PORT(ptr) +/* struct in6_addr SOCK_ADDR_IN6_ADDR(ptr) +/* struct in6_addr IN6_ADDR(ptr) +/* DESCRIPTION +/* These utilities take protocol-independent address structures +/* and perform protocol-dependent operations on structure members. +/* Some of the macros described here are called unsafe, +/* because they evaluate one or more arguments multiple times. +/* +/* sock_addr_cmp_addr() or sock_addr_cmp_port() compare the +/* address family and network address or port fields for +/* equality, and return indication of the difference between +/* their arguments: < 0 if the first argument is "smaller", +/* 0 for equality, and > 0 if the first argument is "larger". +/* +/* The unsafe macros SOCK_ADDR_EQ_ADDR() or SOCK_ADDR_EQ_PORT() +/* compare compare the address family and network address or +/* port fields for equality, and return non-zero when their +/* arguments differ. +/* +/* sock_addr_in_loopback() determines if the argument specifies +/* a loopback address. +/* +/* The SOCK_ADDR_PTR() macro casts a generic pointer to (struct +/* sockaddr *). The name is upper case for consistency not +/* safety. SOCK_ADDR_FAMILY() and SOCK_ADDR_LEN() return the +/* address family and length of the real structure that hides +/* inside a generic sockaddr structure. On systems where struct +/* sockaddr has no sa_len member, SOCK_ADDR_LEN() cannot be +/* used as lvalue. SOCK_ADDR_PORT() returns the IPv4 or IPv6 +/* port number, in network byte order; it must not be used as +/* lvalue. SOCK_ADDR_PORTP() returns a pointer to the same. +/* +/* The macros SOCK_ADDR_IN{,6}_{PTR,FAMILY,PORT,ADDR}() cast +/* a generic pointer to a specific socket address structure +/* pointer, or access a specific socket address structure +/* member. These can be used as lvalues. +/* +/* The unsafe INADDR() and IN6_ADDR() macros dereference a +/* generic pointer to a specific address structure. +/* DIAGNOSTICS +/* Panic: unsupported address family. +/* 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 library. */ + +#include <sys_defs.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <string.h> + +/* Utility library. */ + +#include <msg.h> +#include <sock_addr.h> + +/* sock_addr_cmp_addr - compare addresses for equality */ + +int sock_addr_cmp_addr(const struct sockaddr *sa, + const struct sockaddr *sb) +{ + if (sa->sa_family != sb->sa_family) + return (sa->sa_family - sb->sa_family); + + /* + * With IPv6 address structures, assume a non-hostile implementation that + * stores the address as a contiguous sequence of bits. Any holes in the + * sequence would invalidate the use of memcmp(). + */ + if (sa->sa_family == AF_INET) { + return (SOCK_ADDR_IN_ADDR(sa).s_addr - SOCK_ADDR_IN_ADDR(sb).s_addr); +#ifdef HAS_IPV6 + } else if (sa->sa_family == AF_INET6) { + return (memcmp((void *) &(SOCK_ADDR_IN6_ADDR(sa)), + (void *) &(SOCK_ADDR_IN6_ADDR(sb)), + sizeof(SOCK_ADDR_IN6_ADDR(sa)))); +#endif + } else { + msg_panic("sock_addr_cmp_addr: unsupported address family %d", + sa->sa_family); + } +} + +/* sock_addr_cmp_port - compare ports for equality */ + +int sock_addr_cmp_port(const struct sockaddr *sa, + const struct sockaddr *sb) +{ + if (sa->sa_family != sb->sa_family) + return (sa->sa_family - sb->sa_family); + + if (sa->sa_family == AF_INET) { + return (SOCK_ADDR_IN_PORT(sa) - SOCK_ADDR_IN_PORT(sb)); +#ifdef HAS_IPV6 + } else if (sa->sa_family == AF_INET6) { + return (SOCK_ADDR_IN6_PORT(sa) - SOCK_ADDR_IN6_PORT(sb)); +#endif + } else { + msg_panic("sock_addr_cmp_port: unsupported address family %d", + sa->sa_family); + } +} + +/* sock_addr_in_loopback - determine if address is loopback */ + +int sock_addr_in_loopback(const struct sockaddr *sa) +{ + unsigned long inaddr; + + if (sa->sa_family == AF_INET) { + inaddr = ntohl(SOCK_ADDR_IN_ADDR(sa).s_addr); + return (IN_CLASSA(inaddr) + && ((inaddr & IN_CLASSA_NET) >> IN_CLASSA_NSHIFT) + == IN_LOOPBACKNET); +#ifdef HAS_IPV6 + } else if (sa->sa_family == AF_INET6) { + return (IN6_IS_ADDR_LOOPBACK(&SOCK_ADDR_IN6_ADDR(sa))); +#endif + } else { + msg_panic("sock_addr_in_loopback: unsupported address family %d", + sa->sa_family); + } +} |