sockaddr.c 6.77 KB
Newer Older
Michael Graff's avatar
Michael Graff committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/*
 * Copyright (C) 1999  Internet Software Consortium.
 * 
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 * SOFTWARE.
 */

#include <config.h>

#include <stddef.h>
#include <stdlib.h>
#include <string.h>
Mark Andrews's avatar
Mark Andrews committed
23
#include <stdio.h>
Michael Graff's avatar
Michael Graff committed
24
25
26
27
28

#include <isc/types.h>
#include <isc/assertions.h>
#include <isc/error.h>
#include <isc/sockaddr.h>
Mark Andrews's avatar
Mark Andrews committed
29
#include <isc/mem.h>
Michael Graff's avatar
Michael Graff committed
30
31

isc_boolean_t
32
isc_sockaddr_equal(const isc_sockaddr_t *a, const isc_sockaddr_t *b)
Michael Graff's avatar
Michael Graff committed
33
{
Bob Halley's avatar
Bob Halley committed
34
	REQUIRE(a != NULL && b != NULL);
Michael Graff's avatar
Michael Graff committed
35

Bob Halley's avatar
Bob Halley committed
36
	if (a->length != b->length)
Michael Graff's avatar
Michael Graff committed
37
38
		return (ISC_FALSE);

39
40
41
42
43
44
	/*
	 * We don't just memcmp because the sin_zero field isn't always
	 * zero.
	 */

	if (a->type.sa.sa_family != b->type.sa.sa_family)
Michael Graff's avatar
Michael Graff committed
45
		return (ISC_FALSE);
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
	switch (a->type.sa.sa_family) {
	case AF_INET:
		if (memcmp(&a->type.sin.sin_addr, &b->type.sin.sin_addr,
			   sizeof a->type.sin.sin_addr) != 0)
			return (ISC_FALSE);
		if (a->type.sin.sin_port != b->type.sin.sin_port)
			return (ISC_FALSE);
		break;
	case AF_INET6:
		if (memcmp(&a->type.sin6.sin6_addr, &b->type.sin6.sin6_addr,
			   sizeof a->type.sin6.sin6_addr) != 0)
			return (ISC_FALSE);
		if (a->type.sin6.sin6_port != b->type.sin6.sin6_port)
			return (ISC_FALSE);
		break;
	default:
		if (memcmp(&a->type, &b->type, a->length) != 0)
			return (ISC_FALSE);
	}
Bob Halley's avatar
Bob Halley committed
65
66
	return (ISC_TRUE);
}
Michael Graff's avatar
Michael Graff committed
67

68
69
70
71
72

/*
 * compare just the addresses (ignore ports)
 */
isc_boolean_t
73
isc_sockaddr_eqaddr(const isc_sockaddr_t *a, const isc_sockaddr_t *b)
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
{
	REQUIRE(a != NULL && b != NULL);

	if (a->length != b->length)
		return (ISC_FALSE);

	/*
	 * We don't just memcmp because the sin_zero field isn't always
	 * zero.
	 */

	if (a->type.sa.sa_family != b->type.sa.sa_family)
		return (ISC_FALSE);
	switch (a->type.sa.sa_family) {
	case AF_INET:
		if (memcmp(&a->type.sin.sin_addr, &b->type.sin.sin_addr,
			   sizeof a->type.sin.sin_addr) != 0)
			return (ISC_FALSE);
		break;
	case AF_INET6:
		if (memcmp(&a->type.sin6.sin6_addr, &b->type.sin6.sin6_addr,
			   sizeof a->type.sin6.sin6_addr) != 0)
			return (ISC_FALSE);
		break;
	default:
		if (memcmp(&a->type, &b->type, a->length) != 0)
			return (ISC_FALSE);
	}
	return (ISC_TRUE);
}

105
106
isc_result_t
isc_sockaddr_totext(const isc_sockaddr_t *sockaddr, isc_buffer_t *target) {
Mark Andrews's avatar
Mark Andrews committed
107
	char abuf[sizeof "xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255"];
108
	unsigned int alen;
Mark Andrews's avatar
Mark Andrews committed
109
	char pbuf[sizeof "65000"];
110
111
	unsigned int plen;
	isc_region_t avail;
112
113
114
	const struct sockaddr *sa;
	const struct sockaddr_in *sin;
	const struct sockaddr_in6 *sin6;
Mark Andrews's avatar
Mark Andrews committed
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132

	REQUIRE(sockaddr != NULL);

	sa = &sockaddr->type.sa;
	switch (sa->sa_family) {
	case AF_INET:
		sin = &sockaddr->type.sin;
		inet_ntop(sa->sa_family, &sin->sin_addr, abuf, sizeof abuf);
		sprintf(pbuf, "%u", ntohs(sin->sin_port));
		break;
	case AF_INET6:
		sin6 = &sockaddr->type.sin6;
		inet_ntop(sa->sa_family, &sin6->sin6_addr, abuf, sizeof abuf);
		sprintf(pbuf, "%u", ntohs(sin6->sin6_port));
		break;
	default:
		return (NULL);
	}
133
134
135
136
137

	alen = strlen(abuf);
	plen = strlen(pbuf);

	isc_buffer_available(target, &avail);
138
	if (alen + 1 + plen + 1 < avail.length)
139
140
141
142
143
144
		return (ISC_R_NOSPACE);
	    
	isc_buffer_putmem(target, abuf, alen);
	isc_buffer_putmem(target, "#", 1);
	isc_buffer_putmem(target, pbuf, plen);

145
146
147
148
149
	/* Null terminate after used region. */
	isc_buffer_available(target, &avail);
	INSIST(avail.length >= 1);
	avail.base[0] = '\0';

150
	return (ISC_R_SUCCESS);
Mark Andrews's avatar
Mark Andrews committed
151
152
}

Bob Halley's avatar
Bob Halley committed
153
unsigned int
154
isc_sockaddr_hash(const isc_sockaddr_t *sockaddr, isc_boolean_t address_only) {
Bob Halley's avatar
Bob Halley committed
155
156
157
158
159
160
161
162
	unsigned int length;
	const unsigned char *s;
	unsigned int h = 0;
	unsigned int g;
	
	/*
	 * Provide a hash value for 'sockaddr'.
	 */
Michael Graff's avatar
Michael Graff committed
163

Bob Halley's avatar
Bob Halley committed
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
	REQUIRE(sockaddr != NULL);

	if (address_only) {
		switch (sockaddr->type.sa.sa_family) {
		case AF_INET:
			return (ntohl(sockaddr->type.sin.sin_addr.s_addr));
		case AF_INET6:
			s = (unsigned char *)&sockaddr->type.sin6.sin6_addr;
			length = sizeof sockaddr->type.sin6.sin6_addr;
			break;
		default:
			UNEXPECTED_ERROR(__FILE__, __LINE__,
					 "unknown address family: %d\n",
					 (int)sockaddr->type.sa.sa_family);
			s = (unsigned char *)&sockaddr->type;
			length = sockaddr->length;
		}
	} else {
		s = (unsigned char *)&sockaddr->type;
		length = sockaddr->length;
Michael Graff's avatar
Michael Graff committed
184
	}
Bob Halley's avatar
Bob Halley committed
185
186
187
188
189
190
191
192
193

	while (length > 0) {
		h = ( h << 4 ) + *s;
		if ((g = ( h & 0xf0000000 )) != 0) {
			h = h ^ (g >> 24);
			h = h ^ g;
		}
		s++;
		length--;
Michael Graff's avatar
Michael Graff committed
194
	}
Bob Halley's avatar
Bob Halley committed
195
	return (h);
Michael Graff's avatar
Michael Graff committed
196
}
Bob Halley's avatar
Bob Halley committed
197
198

void
199
isc_sockaddr_fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina,
200
		    in_port_t port)
Bob Halley's avatar
Bob Halley committed
201
{
202
	memset(sockaddr, 0, sizeof *sockaddr);
Bob Halley's avatar
Bob Halley committed
203
	sockaddr->type.sin.sin_family = AF_INET;
204
#ifdef ISC_PLATFORM_HAVESALEN
Bob Halley's avatar
Bob Halley committed
205
206
207
208
209
210
211
212
213
	sockaddr->type.sin.sin_len = sizeof sockaddr->type.sin;
#endif
	sockaddr->type.sin.sin_addr = *ina;
	sockaddr->type.sin.sin_port = htons(port);
	sockaddr->length = sizeof sockaddr->type.sin;
	ISC_LINK_INIT(sockaddr, link);
}

void
214
isc_sockaddr_fromin6(isc_sockaddr_t *sockaddr, const struct in6_addr *ina6,
215
		     in_port_t port)
Bob Halley's avatar
Bob Halley committed
216
{
217
	memset(sockaddr, 0, sizeof *sockaddr);
Bob Halley's avatar
Bob Halley committed
218
	sockaddr->type.sin6.sin6_family = AF_INET6;
219
#ifdef ISC_PLATFORM_HAVESALEN
Bob Halley's avatar
Bob Halley committed
220
221
222
223
224
225
226
	sockaddr->type.sin6.sin6_len = sizeof sockaddr->type.sin6;
#endif
	sockaddr->type.sin6.sin6_addr = *ina6;
	sockaddr->type.sin6.sin6_port = htons(port);
	sockaddr->length = sizeof sockaddr->type.sin6;
	ISC_LINK_INIT(sockaddr, link);
}
227
228

void
229
isc_sockaddr_v6fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina,
230
		      in_port_t port)
231
232
233
{
	memset(sockaddr, 0, sizeof *sockaddr);
	sockaddr->type.sin6.sin6_family = AF_INET6;
234
#ifdef ISC_PLATFORM_HAVESALEN
235
236
	sockaddr->type.sin6.sin6_len = sizeof sockaddr->type.sin6;
#endif
237
238
	sockaddr->type.sin6.sin6_addr.s6_addr[10] = 0xff;
	sockaddr->type.sin6.sin6_addr.s6_addr[11] = 0xff;
239
240
241
242
243
244
245
	memcpy(&sockaddr->type.sin6.sin6_addr.s6_addr[12], ina, 4);
	sockaddr->type.sin6.sin6_port = htons(port);
	sockaddr->length = sizeof sockaddr->type.sin6;
	ISC_LINK_INIT(sockaddr, link);
}

int
246
isc_sockaddr_pf(const isc_sockaddr_t *sockaddr) {
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267

	/*
	 * Get the protocol family of 'sockaddr'.
	 */

#if (AF_INET == PF_INET && AF_INET6 == PF_INET6)
	/*
	 * Assume that PF_xxx == AF_xxx for all AF and PF.
	 */
	return (sockaddr->type.sa.sa_family);
#else
	switch (sockaddr->type.sa.sa_family) {
	case AF_INET:
		return (PF_INET);
	case AF_INET6:
		return (PF_INET);
	default:
		FATAL_ERROR(__FILE__, __LINE__, "unknown address family");
	}
#endif
}