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

/* System library. */

#include <sys_defs.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>

/* Utility library. */

#include <msg.h>
#include <sock_addr.h>

/* sock_addr_cmp_addr - compare addresses for equality */

int     sock_addr_cmp_addr(const struct sockaddr *sa,
			           const struct sockaddr *sb)
{
    if (sa->sa_family != sb->sa_family)
	return (sa->sa_family - sb->sa_family);

    /*
     * With IPv6 address structures, assume a non-hostile implementation that
     * stores the address as a contiguous sequence of bits. Any holes in the
     * sequence would invalidate the use of memcmp().
     */
    if (sa->sa_family == AF_INET) {
	return (SOCK_ADDR_IN_ADDR(sa).s_addr - SOCK_ADDR_IN_ADDR(sb).s_addr);
#ifdef HAS_IPV6
    } else if (sa->sa_family == AF_INET6) {
	return (memcmp((void *) &(SOCK_ADDR_IN6_ADDR(sa)),
		       (void *) &(SOCK_ADDR_IN6_ADDR(sb)),
		       sizeof(SOCK_ADDR_IN6_ADDR(sa))));
#endif
    } else {
	msg_panic("sock_addr_cmp_addr: unsupported address family %d",
		  sa->sa_family);
    }
}

/* sock_addr_cmp_port - compare ports for equality */

int     sock_addr_cmp_port(const struct sockaddr *sa,
			           const struct sockaddr *sb)
{
    if (sa->sa_family != sb->sa_family)
	return (sa->sa_family - sb->sa_family);

    if (sa->sa_family == AF_INET) {
	return (SOCK_ADDR_IN_PORT(sa) - SOCK_ADDR_IN_PORT(sb));
#ifdef HAS_IPV6
    } else if (sa->sa_family == AF_INET6) {
	return (SOCK_ADDR_IN6_PORT(sa) - SOCK_ADDR_IN6_PORT(sb));
#endif
    } else {
	msg_panic("sock_addr_cmp_port: unsupported address family %d",
		  sa->sa_family);
    }
}

/* sock_addr_in_loopback - determine if address is loopback */

int     sock_addr_in_loopback(const struct sockaddr *sa)
{
    unsigned long inaddr;

    if (sa->sa_family == AF_INET) {
	inaddr = ntohl(SOCK_ADDR_IN_ADDR(sa).s_addr);
	return (IN_CLASSA(inaddr)
		&& ((inaddr & IN_CLASSA_NET) >> IN_CLASSA_NSHIFT)
		== IN_LOOPBACKNET);
#ifdef HAS_IPV6
    } else if (sa->sa_family == AF_INET6) {
	return (IN6_IS_ADDR_LOOPBACK(&SOCK_ADDR_IN6_ADDR(sa)));
#endif
    } else {
	msg_panic("sock_addr_in_loopback: unsupported address family %d",
		  sa->sa_family);
    }
}