summaryrefslogtreecommitdiffstats
path: root/src/util/sock_addr.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/sock_addr.c')
-rw-r--r--src/util/sock_addr.c173
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);
+ }
+}