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