1/*	$NetBSD$	*/
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
111int     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((char *) &(SOCK_ADDR_IN6_ADDR(sa)),
127		       (char *) &(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
138int     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
158int 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