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 
sock_addr_cmp_addr(const struct sockaddr * sa,const struct sockaddr * sb)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 
sock_addr_cmp_port(const struct sockaddr * sa,const struct sockaddr * sb)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 
sock_addr_in_loopback(const struct sockaddr * sa)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