1 /* $NetBSD: sock_addr.c,v 1.3 2023/12/23 20:30:46 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