Home | History | Annotate | Line # | Download | only in util
      1 /*	$NetBSD: sock_addr.c,v 1.4 2025/02/25 19:15:52 christos Exp $	*/
      2 
      3 /*++
      4 /* NAME
      5 /*	sock_addr 3
      6 /* SUMMARY
      7 /*	sockaddr utilities
      8 /* SYNOPSIS
      9 /*	#include <sock_addr.h>
     10 /*
     11 /*	int	sock_addr_cmp_addr(sa, sb)
     12 /*	const struct sockaddr *sa;
     13 /*	const struct sockaddr *sb;
     14 /*
     15 /*	int	sock_addr_cmp_port(sa, sb)
     16 /*	const struct sockaddr *sa;
     17 /*	const struct sockaddr *sb;
     18 /*
     19 /*	int	SOCK_ADDR_EQ_ADDR(sa, sb)
     20 /*	const struct sockaddr *sa;
     21 /*	const struct sockaddr *sb;
     22 /*
     23 /*	int	SOCK_ADDR_EQ_PORT(sa, sb)
     24 /*	const struct sockaddr *sa;
     25 /*	const struct sockaddr *sb;
     26 /*
     27 /*	int	sock_addr_in_loopback(sa)
     28 /*	const struct sockaddr *sa;
     29 /* AUXILIARY MACROS
     30 /*	struct sockaddr *SOCK_ADDR_PTR(ptr)
     31 /*	unsigned char SOCK_ADDR_FAMILY(ptr)
     32 /*	unsigned char SOCK_ADDR_LEN(ptr)
     33 /*	void *SOCK_ADDR_ADDRP(ptr)
     34 /*	unsigned short SOCK_ADDR_PORT(ptr)
     35 /*	unsigned short *SOCK_ADDR_PORTP(ptr)
     36 /*
     37 /*	struct sockaddr_in *SOCK_ADDR_IN_PTR(ptr)
     38 /*	unsigned char SOCK_ADDR_IN_FAMILY(ptr)
     39 /*	unsigned short SOCK_ADDR_IN_PORT(ptr)
     40 /*	struct in_addr SOCK_ADDR_IN_ADDR(ptr)
     41 /*	struct in_addr IN_ADDR(ptr)
     42 /*
     43 /*	struct sockaddr_in6 *SOCK_ADDR_IN6_PTR(ptr)
     44 /*	unsigned char SOCK_ADDR_IN6_FAMILY(ptr)
     45 /*	unsigned short SOCK_ADDR_IN6_PORT(ptr)
     46 /*	struct in6_addr SOCK_ADDR_IN6_ADDR(ptr)
     47 /*	struct in6_addr IN6_ADDR(ptr)
     48 /* DESCRIPTION
     49 /*	These utilities take protocol-independent address structures
     50 /*	and perform protocol-dependent operations on structure members.
     51 /*	Some of the macros described here are called unsafe,
     52 /*	because they evaluate one or more arguments multiple times.
     53 /*
     54 /*	sock_addr_cmp_addr() or sock_addr_cmp_port() compare the
     55 /*	address family and network address or port fields for
     56 /*	equality, and return indication of the difference between
     57 /*	their arguments:  < 0 if the first argument is "smaller",
     58 /*	0 for equality, and > 0 if the first argument is "larger".
     59 /*
     60 /*	The unsafe macros SOCK_ADDR_EQ_ADDR() or SOCK_ADDR_EQ_PORT()
     61 /*	compare compare the address family and network address or
     62 /*	port fields for equality, and return non-zero when their
     63 /*	arguments differ.
     64 /*
     65 /*	sock_addr_in_loopback() determines if the argument specifies
     66 /*	a loopback address.
     67 /*
     68 /*	The SOCK_ADDR_PTR() macro casts a generic pointer to (struct
     69 /*	sockaddr *).  The name is upper case for consistency not
     70 /*	safety.  SOCK_ADDR_FAMILY() and SOCK_ADDR_LEN() return the
     71 /*	address family and length of the real structure that hides
     72 /*	inside a generic sockaddr structure. On systems where struct
     73 /*	sockaddr has no sa_len member, SOCK_ADDR_LEN() cannot be
     74 /*	used as lvalue. SOCKADDR_ADDRP() returns a pointer to the
     75 /*	IPv4 or IPv6 address. SOCK_ADDR_PORT() returns the IPv4 or IPv6
     76 /*	port number, in network byte order; it must not be used as
     77 /*	lvalue. SOCK_ADDR_PORTP() returns a pointer to the same.
     78 /*
     79 /*	The macros SOCK_ADDR_IN{,6}_{PTR,FAMILY,PORT,ADDR}() cast
     80 /*	a generic pointer to a specific socket address structure
     81 /*	pointer, or access a specific socket address structure
     82 /*	member. These can be used as lvalues.
     83 /*
     84 /*	The unsafe INADDR() and IN6_ADDR() macros dereference a
     85 /*	generic pointer to a specific address structure.
     86 /* DIAGNOSTICS
     87 /*	Panic: unsupported address family.
     88 /* LICENSE
     89 /* .ad
     90 /* .fi
     91 /*	The Secure Mailer license must be distributed with this software.
     92 /* AUTHOR(S)
     93 /*	Wietse Venema
     94 /*	IBM T.J. Watson Research
     95 /*	P.O. Box 704
     96 /*	Yorktown Heights, NY 10598, USA
     97 /*--*/
     98 
     99 /* System library. */
    100 
    101 #include <sys_defs.h>
    102 #include <sys/socket.h>
    103 #include <netinet/in.h>
    104 #include <string.h>
    105 
    106 /* Utility library. */
    107 
    108 #include <msg.h>
    109 #include <sock_addr.h>
    110 
    111 /* sock_addr_cmp_addr - compare addresses for equality */
    112 
    113 int     sock_addr_cmp_addr(const struct sockaddr *sa,
    114 			           const struct sockaddr *sb)
    115 {
    116     if (sa->sa_family != sb->sa_family)
    117 	return (sa->sa_family - sb->sa_family);
    118 
    119     /*
    120      * With IPv6 address structures, assume a non-hostile implementation that
    121      * stores the address as a contiguous sequence of bits. Any holes in the
    122      * sequence would invalidate the use of memcmp().
    123      */
    124     if (sa->sa_family == AF_INET) {
    125 	return (SOCK_ADDR_IN_ADDR(sa).s_addr - SOCK_ADDR_IN_ADDR(sb).s_addr);
    126 #ifdef HAS_IPV6
    127     } else if (sa->sa_family == AF_INET6) {
    128 	return (memcmp((void *) &(SOCK_ADDR_IN6_ADDR(sa)),
    129 		       (void *) &(SOCK_ADDR_IN6_ADDR(sb)),
    130 		       sizeof(SOCK_ADDR_IN6_ADDR(sa))));
    131 #endif
    132     } else {
    133 	msg_panic("sock_addr_cmp_addr: unsupported address family %d",
    134 		  sa->sa_family);
    135     }
    136 }
    137 
    138 /* sock_addr_cmp_port - compare ports for equality */
    139 
    140 int     sock_addr_cmp_port(const struct sockaddr *sa,
    141 			           const struct sockaddr *sb)
    142 {
    143     if (sa->sa_family != sb->sa_family)
    144 	return (sa->sa_family - sb->sa_family);
    145 
    146     if (sa->sa_family == AF_INET) {
    147 	return (SOCK_ADDR_IN_PORT(sa) - SOCK_ADDR_IN_PORT(sb));
    148 #ifdef HAS_IPV6
    149     } else if (sa->sa_family == AF_INET6) {
    150 	return (SOCK_ADDR_IN6_PORT(sa) - SOCK_ADDR_IN6_PORT(sb));
    151 #endif
    152     } else {
    153 	msg_panic("sock_addr_cmp_port: unsupported address family %d",
    154 		  sa->sa_family);
    155     }
    156 }
    157 
    158 /* sock_addr_in_loopback - determine if address is loopback */
    159 
    160 int     sock_addr_in_loopback(const struct sockaddr *sa)
    161 {
    162     unsigned long inaddr;
    163 
    164     if (sa->sa_family == AF_INET) {
    165 	inaddr = ntohl(SOCK_ADDR_IN_ADDR(sa).s_addr);
    166 	return (IN_CLASSA(inaddr)
    167 		&& ((inaddr & IN_CLASSA_NET) >> IN_CLASSA_NSHIFT)
    168 		== IN_LOOPBACKNET);
    169 #ifdef HAS_IPV6
    170     } else if (sa->sa_family == AF_INET6) {
    171 	return (IN6_IS_ADDR_LOOPBACK(&SOCK_ADDR_IN6_ADDR(sa)));
    172 #endif
    173     } else {
    174 	msg_panic("sock_addr_in_loopback: unsupported address family %d",
    175 		  sa->sa_family);
    176     }
    177 }
    178