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