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