1 /**
2  * @file sa.c  Socket Address
3  *
4  * Copyright (C) 2010 Creytiv.com
5  */
6 #define _BSD_SOURCE 1
7 #define _DEFAULT_SOURCE 1
8 #include <string.h>
9 #include <re_types.h>
10 #include <re_fmt.h>
11 #include <re_list.h>
12 #include <re_sa.h>
13 #include "sa.h"
14 
15 
16 #define DEBUG_MODULE "sa"
17 #define DEBUG_LEVEL 5
18 #include <re_dbg.h>
19 
20 
21 /**
22  * Initialize a Socket Address
23  *
24  * @param sa Socket Address
25  * @param af Address Family
26  */
sa_init(struct sa * sa,int af)27 void sa_init(struct sa *sa, int af)
28 {
29 	if (!sa)
30 		return;
31 
32 	memset(sa, 0, sizeof(*sa));
33 	sa->u.sa.sa_family = af;
34 	sa->len = sizeof(sa->u);
35 }
36 
37 
38 /**
39  * Set a Socket Address from a PL string
40  *
41  * @param sa   Socket Address
42  * @param addr IP-address
43  * @param port Port number
44  *
45  * @return 0 if success, otherwise errorcode
46  */
sa_set(struct sa * sa,const struct pl * addr,uint16_t port)47 int sa_set(struct sa *sa, const struct pl *addr, uint16_t port)
48 {
49 	char buf[64];
50 
51 	(void)pl_strcpy(addr, buf, sizeof(buf));
52 	return sa_set_str(sa, buf, port);
53 }
54 
55 
56 /**
57  * Set a Socket Address from a string
58  *
59  * @param sa   Socket Address
60  * @param addr IP-address
61  * @param port Port number
62  *
63  * @return 0 if success, otherwise errorcode
64  */
sa_set_str(struct sa * sa,const char * addr,uint16_t port)65 int sa_set_str(struct sa *sa, const char *addr, uint16_t port)
66 {
67 	int err;
68 
69 	if (!sa || !addr)
70 		return EINVAL;
71 
72 	err = net_inet_pton(addr, sa);
73 	if (err)
74 		return err;
75 
76 	switch (sa->u.sa.sa_family) {
77 
78 	case AF_INET:
79 		sa->u.in.sin_port = htons(port);
80 		sa->len = sizeof(struct sockaddr_in);
81 		break;
82 
83 #ifdef HAVE_INET6
84 	case AF_INET6:
85 		sa->u.in6.sin6_port = htons(port);
86 		sa->len = sizeof(struct sockaddr_in6);
87 		break;
88 #endif
89 
90 	default:
91 		return EAFNOSUPPORT;
92 	}
93 
94 	return 0;
95 }
96 
97 
98 /**
99  * Set a Socket Address from an IPv4 address
100  *
101  * @param sa   Socket Address
102  * @param addr IPv4 address in host order
103  * @param port Port number
104  *
105  * @return 0 if success, otherwise errorcode
106  */
sa_set_in(struct sa * sa,uint32_t addr,uint16_t port)107 void sa_set_in(struct sa *sa, uint32_t addr, uint16_t port)
108 {
109 	if (!sa)
110 		return;
111 
112 	sa->u.in.sin_family = AF_INET;
113 	sa->u.in.sin_addr.s_addr = htonl(addr);
114 	sa->u.in.sin_port = htons(port);
115 	sa->len = sizeof(struct sockaddr_in);
116 }
117 
118 
119 /**
120  * Set a Socket Address from an IPv6 address
121  *
122  * @param sa   Socket Address
123  * @param addr IPv6 address
124  * @param port Port number
125  *
126  * @return 0 if success, otherwise errorcode
127  */
sa_set_in6(struct sa * sa,const uint8_t * addr,uint16_t port)128 void sa_set_in6(struct sa *sa, const uint8_t *addr, uint16_t port)
129 {
130 	if (!sa)
131 		return;
132 
133 #ifdef HAVE_INET6
134 	sa->u.in6.sin6_family = AF_INET6;
135 	memcpy(&sa->u.in6.sin6_addr, addr, 16);
136 	sa->u.in6.sin6_port = htons(port);
137 	sa->len = sizeof(struct sockaddr_in6);
138 #else
139 	(void)addr;
140 	(void)port;
141 #endif
142 }
143 
144 
145 /**
146  * Set a Socket Address from a sockaddr
147  *
148  * @param sa Socket Address
149  * @param s  Sockaddr
150  *
151  * @return 0 if success, otherwise errorcode
152  */
sa_set_sa(struct sa * sa,const struct sockaddr * s)153 int sa_set_sa(struct sa *sa, const struct sockaddr *s)
154 {
155 	if (!sa || !s)
156 		return EINVAL;
157 
158 	switch (s->sa_family) {
159 
160 	case AF_INET:
161 		memcpy(&sa->u.in, s, sizeof(struct sockaddr_in));
162 		sa->len = sizeof(struct sockaddr_in);
163 		break;
164 
165 #ifdef HAVE_INET6
166 	case AF_INET6:
167 		memcpy(&sa->u.in6, s, sizeof(struct sockaddr_in6));
168 		sa->len = sizeof(struct sockaddr_in6);
169 		break;
170 #endif
171 
172 	default:
173 		return EAFNOSUPPORT;
174 	}
175 
176 	sa->u.sa.sa_family = s->sa_family;
177 
178 	return 0;
179 }
180 
181 
182 /**
183  * Set the port number on a Socket Address
184  *
185  * @param sa   Socket Address
186  * @param port Port number
187  */
sa_set_port(struct sa * sa,uint16_t port)188 void sa_set_port(struct sa *sa, uint16_t port)
189 {
190 	if (!sa)
191 		return;
192 
193 	switch (sa->u.sa.sa_family) {
194 
195 	case AF_INET:
196 		sa->u.in.sin_port = htons(port);
197 		break;
198 
199 #ifdef HAVE_INET6
200 	case AF_INET6:
201 		sa->u.in6.sin6_port = htons(port);
202 		break;
203 #endif
204 
205 	default:
206 		DEBUG_WARNING("sa_set_port: no af %d (port %u)\n",
207 			      sa->u.sa.sa_family, port);
208 		break;
209 	}
210 }
211 
212 
213 /**
214  * Set a socket address from a string of type "address:port"
215  * IPv6 addresses must be encapsulated in square brackets.
216  *
217  * @param sa   Socket Address
218  * @param str  Address and port string
219  * @param len  Length of string
220  *
221  * @return 0 if success, otherwise errorcode
222  *
223  * Example strings:
224  *
225  * <pre>
226  *   1.2.3.4:1234
227  *   [::1]:1234
228  *   [::]:5060
229  * </pre>
230  */
sa_decode(struct sa * sa,const char * str,size_t len)231 int sa_decode(struct sa *sa, const char *str, size_t len)
232 {
233 	struct pl addr, port, pl;
234 	const char *c;
235 
236 	if (!sa || !str || !len)
237 		return EINVAL;
238 
239 	pl.p = str;
240 	pl.l = len;
241 
242 	if ('[' == str[0] && (c = pl_strchr(&pl, ']'))) {
243 		addr.p = str + 1;
244 		addr.l = c - str - 1;
245 		++c;
246 	}
247 	else if (NULL != (c = pl_strchr(&pl, ':'))) {
248 		addr.p = str;
249 		addr.l = c - str;
250 	}
251 	else {
252 		return EINVAL;
253 	}
254 
255 	if (len < (size_t)(c - str + 2))
256 		return EINVAL;
257 
258 	if (':' != *c)
259 		return EINVAL;
260 
261 	port.p = ++c;
262 	port.l = len + str - c;
263 
264 	return sa_set(sa, &addr, pl_u32(&port));
265 }
266 
267 
268 /**
269  * Get the Address Family of a Socket Address
270  *
271  * @param sa Socket Address
272  *
273  * @return Address Family
274  */
sa_af(const struct sa * sa)275 int sa_af(const struct sa *sa)
276 {
277 	return sa ? sa->u.sa.sa_family : AF_UNSPEC;
278 }
279 
280 
281 /**
282  * Get the IPv4-address of a Socket Address
283  *
284  * @param sa Socket Address
285  *
286  * @return IPv4 address in host order
287  */
sa_in(const struct sa * sa)288 uint32_t sa_in(const struct sa *sa)
289 {
290 	return sa ? ntohl(sa->u.in.sin_addr.s_addr) : 0;
291 }
292 
293 
294 /**
295  * Get the IPv6-address of a Socket Address
296  *
297  * @param sa   Socket Address
298  * @param addr On return, contains the IPv6-address
299  */
sa_in6(const struct sa * sa,uint8_t * addr)300 void sa_in6(const struct sa *sa, uint8_t *addr)
301 {
302 	if (!sa || !addr)
303 		return;
304 
305 #ifdef HAVE_INET6
306 	memcpy(addr, &sa->u.in6.sin6_addr, 16);
307 #endif
308 }
309 
310 
311 /**
312  * Convert a Socket Address to Presentation format
313  *
314  * @param sa   Socket Address
315  * @param buf  Buffer to store presentation format
316  * @param size Buffer size
317  *
318  * @return 0 if success, otherwise errorcode
319  */
sa_ntop(const struct sa * sa,char * buf,int size)320 int sa_ntop(const struct sa *sa, char *buf, int size)
321 {
322 	return net_inet_ntop(sa, buf, size);
323 }
324 
325 
326 /**
327  * Get the port number from a Socket Address
328  *
329  * @param sa Socket Address
330  *
331  * @return Port number  in host order
332  */
sa_port(const struct sa * sa)333 uint16_t sa_port(const struct sa *sa)
334 {
335 	if (!sa)
336 		return 0;
337 
338 	switch (sa->u.sa.sa_family) {
339 
340 	case AF_INET:
341 		return ntohs(sa->u.in.sin_port);
342 
343 #ifdef HAVE_INET6
344 	case AF_INET6:
345 		return ntohs(sa->u.in6.sin6_port);
346 #endif
347 
348 	default:
349 		return 0;
350 	}
351 }
352 
353 
354 /**
355  * Check if a Socket Address is set
356  *
357  * @param sa   Socket Address
358  * @param flag Flags specifying which fields to check
359  *
360  * @return true if set, false if not set
361  */
sa_isset(const struct sa * sa,int flag)362 bool sa_isset(const struct sa *sa, int flag)
363 {
364 	if (!sa)
365 		return false;
366 
367 	switch (sa->u.sa.sa_family) {
368 
369 	case AF_INET:
370 		if (flag & SA_ADDR)
371 			if (INADDR_ANY == sa->u.in.sin_addr.s_addr)
372 				return false;
373 		if (flag & SA_PORT)
374 			if (0 == sa->u.in.sin_port)
375 				return false;
376 		break;
377 
378 #ifdef HAVE_INET6
379 	case AF_INET6:
380 		if (flag & SA_ADDR)
381 			if (IN6_IS_ADDR_UNSPECIFIED(&sa->u.in6.sin6_addr))
382 				return false;
383 		if (flag & SA_PORT)
384 			if (0 == sa->u.in6.sin6_port)
385 				return false;
386 		break;
387 #endif
388 
389 	default:
390 		return false;
391 	}
392 
393 	return true;
394 }
395 
396 
397 /**
398  * Calculate the hash value of a Socket Address
399  *
400  * @param sa   Socket Address
401  * @param flag Flags specifying which fields to use
402  *
403  * @return Hash value
404  */
sa_hash(const struct sa * sa,int flag)405 uint32_t sa_hash(const struct sa *sa, int flag)
406 {
407 	uint32_t v = 0;
408 
409 	if (!sa)
410 		return 0;
411 
412 	switch (sa->u.sa.sa_family) {
413 
414 	case AF_INET:
415 		if (flag & SA_ADDR)
416 			v += ntohl(sa->u.in.sin_addr.s_addr);
417 		if (flag & SA_PORT)
418 			v += ntohs(sa->u.in.sin_port);
419 		break;
420 
421 #ifdef HAVE_INET6
422 	case AF_INET6:
423 		if (flag & SA_ADDR) {
424 			uint32_t *a = (uint32_t *)&sa->u.in6.sin6_addr;
425 			v += a[0] ^ a[1] ^ a[2] ^ a[3];
426 		}
427 		if (flag & SA_PORT)
428 			v += ntohs(sa->u.in6.sin6_port);
429 		break;
430 #endif
431 
432 	default:
433 		DEBUG_WARNING("sa_hash: unknown af %d\n", sa->u.sa.sa_family);
434 		return 0;
435 	}
436 
437 	return v;
438 }
439 
440 
441 /**
442  * Copy a Socket Address
443  *
444  * @param dst Socket Address to be written
445  * @param src Socket Address to be copied
446  */
sa_cpy(struct sa * dst,const struct sa * src)447 void sa_cpy(struct sa *dst, const struct sa *src)
448 {
449 	if (!dst || !src)
450 		return;
451 
452 	memcpy(dst, src, sizeof(*dst));
453 }
454 
455 
456 /**
457  * Compare two Socket Address objects
458  *
459  * @param l    Socket Address number one
460  * @param r    Socket Address number two
461  * @param flag Flags specifying which fields to use
462  *
463  * @return true if match, false if no match
464  */
sa_cmp(const struct sa * l,const struct sa * r,int flag)465 bool sa_cmp(const struct sa *l, const struct sa *r, int flag)
466 {
467 	if (!l || !r)
468 		return false;
469 
470 	if (l == r)
471 		return true;
472 
473 	if (l->u.sa.sa_family != r->u.sa.sa_family)
474 		return false;
475 
476 	switch (l->u.sa.sa_family) {
477 
478 	case AF_INET:
479 		if (flag & SA_ADDR)
480 			if (l->u.in.sin_addr.s_addr != r->u.in.sin_addr.s_addr)
481 				return false;
482 		if (flag & SA_PORT)
483 			if (l->u.in.sin_port != r->u.in.sin_port)
484 				return false;
485 		break;
486 
487 #ifdef HAVE_INET6
488 	case AF_INET6:
489 		if (flag & SA_ADDR)
490 			if (memcmp(&l->u.in6.sin6_addr,
491 				   &r->u.in6.sin6_addr, 16))
492 				return false;
493 		if (flag & SA_PORT)
494 			if (l->u.in6.sin6_port != r->u.in6.sin6_port)
495 				return false;
496 		break;
497 #endif
498 
499 	default:
500 		return false;
501 	}
502 
503 	return true;
504 }
505 
506 
507 /** IPv4 Link-local test */
508 #define IN_IS_ADDR_LINKLOCAL(a)					\
509 	(((a) & htonl(0xffff0000)) == htonl (0xa9fe0000))
510 
511 
512 /**
513  * Check if socket address is a link-local address
514  *
515  * @param sa Socket address
516  *
517  * @return true if link-local address, otherwise false
518  */
sa_is_linklocal(const struct sa * sa)519 bool sa_is_linklocal(const struct sa *sa)
520 {
521 	if (!sa)
522 		return false;
523 
524 	switch (sa_af(sa)) {
525 
526 	case AF_INET:
527 		return IN_IS_ADDR_LINKLOCAL(sa->u.in.sin_addr.s_addr);
528 
529 #ifdef HAVE_INET6
530 	case AF_INET6:
531 		return IN6_IS_ADDR_LINKLOCAL(&sa->u.in6.sin6_addr);
532 #endif
533 
534 	default:
535 		return false;
536 	}
537 }
538 
539 
540 /**
541  * Check if socket address is a loopback address
542  *
543  * @param sa Socket address
544  *
545  * @return true if loopback address, otherwise false
546  */
sa_is_loopback(const struct sa * sa)547 bool sa_is_loopback(const struct sa *sa)
548 {
549 	if (!sa)
550 		return false;
551 
552 	switch (sa_af(sa)) {
553 
554 	case AF_INET:
555 		return INADDR_LOOPBACK == ntohl(sa->u.in.sin_addr.s_addr);
556 
557 #ifdef HAVE_INET6
558 	case AF_INET6:
559 		return IN6_IS_ADDR_LOOPBACK(&sa->u.in6.sin6_addr);
560 #endif
561 
562 	default:
563 		return false;
564 	}
565 }
566 
567 
568 /**
569  * Check if socket address is any/unspecified address
570  *
571  * @param sa Socket address
572  *
573  * @return true if any address, otherwise false
574  */
sa_is_any(const struct sa * sa)575 bool sa_is_any(const struct sa *sa)
576 {
577 	if (!sa)
578 		return false;
579 
580 	switch (sa_af(sa)) {
581 
582 	case AF_INET:
583 		return INADDR_ANY == ntohl(sa->u.in.sin_addr.s_addr);
584 
585 #ifdef HAVE_INET6
586 	case AF_INET6:
587 		return IN6_IS_ADDR_UNSPECIFIED(&sa->u.in6.sin6_addr);
588 #endif
589 
590 	default:
591 		return false;
592 	}
593 }
594