]> git.proxmox.com Git - mirror_frr.git/blame - lib/sockunion.c
lib: migrate to new memory-type handling
[mirror_frr.git] / lib / sockunion.c
CommitLineData
718e3744 1/* Socket union related function.
2 * Copyright (c) 1997, 98 Kunihiro Ishiguro
3 *
4 * This file is part of GNU Zebra.
5 *
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with GNU Zebra; see the file COPYING. If not, write to the Free
18 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 * 02111-1307, USA.
20 */
21
22#include <zebra.h>
23
24#include "prefix.h"
25#include "vty.h"
26#include "sockunion.h"
27#include "memory.h"
28#include "str.h"
29#include "log.h"
7cb5cdbb 30#include "jhash.h"
718e3744 31
32#ifndef HAVE_INET_ATON
33int
34inet_aton (const char *cp, struct in_addr *inaddr)
35{
36 int dots = 0;
37 register u_long addr = 0;
38 register u_long val = 0, base = 10;
39
40 do
41 {
42 register char c = *cp;
43
44 switch (c)
45 {
46 case '0': case '1': case '2': case '3': case '4': case '5':
47 case '6': case '7': case '8': case '9':
48 val = (val * base) + (c - '0');
49 break;
50 case '.':
51 if (++dots > 3)
52 return 0;
53 case '\0':
54 if (val > 255)
55 return 0;
56 addr = addr << 8 | val;
57 val = 0;
58 break;
59 default:
60 return 0;
61 }
62 } while (*cp++) ;
63
64 if (dots < 3)
65 addr <<= 8 * (3 - dots);
66 if (inaddr)
67 inaddr->s_addr = htonl (addr);
68 return 1;
69}
70#endif /* ! HAVE_INET_ATON */
71
72
73#ifndef HAVE_INET_PTON
74int
75inet_pton (int family, const char *strptr, void *addrptr)
76{
77 if (family == AF_INET)
78 {
79 struct in_addr in_val;
80
81 if (inet_aton (strptr, &in_val))
82 {
83 memcpy (addrptr, &in_val, sizeof (struct in_addr));
84 return 1;
85 }
86 return 0;
87 }
88 errno = EAFNOSUPPORT;
89 return -1;
90}
91#endif /* ! HAVE_INET_PTON */
92
93#ifndef HAVE_INET_NTOP
94const char *
95inet_ntop (int family, const void *addrptr, char *strptr, size_t len)
96{
97 unsigned char *p = (unsigned char *) addrptr;
98
99 if (family == AF_INET)
100 {
101 char temp[INET_ADDRSTRLEN];
102
103 snprintf(temp, sizeof(temp), "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
104
105 if (strlen(temp) >= len)
106 {
107 errno = ENOSPC;
108 return NULL;
109 }
110 strcpy(strptr, temp);
111 return strptr;
112 }
113
114 errno = EAFNOSUPPORT;
115 return NULL;
116}
117#endif /* ! HAVE_INET_NTOP */
118
119const char *
c0d8db4d 120inet_sutop (const union sockunion *su, char *str)
718e3744 121{
122 switch (su->sa.sa_family)
123 {
124 case AF_INET:
125 inet_ntop (AF_INET, &su->sin.sin_addr, str, INET_ADDRSTRLEN);
126 break;
127#ifdef HAVE_IPV6
128 case AF_INET6:
129 inet_ntop (AF_INET6, &su->sin6.sin6_addr, str, INET6_ADDRSTRLEN);
130 break;
131#endif /* HAVE_IPV6 */
132 }
133 return str;
134}
135
136int
a149411b 137str2sockunion (const char *str, union sockunion *su)
718e3744 138{
139 int ret;
140
141 memset (su, 0, sizeof (union sockunion));
142
143 ret = inet_pton (AF_INET, str, &su->sin.sin_addr);
144 if (ret > 0) /* Valid IPv4 address format. */
145 {
146 su->sin.sin_family = AF_INET;
6f0e3f6e 147#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
718e3744 148 su->sin.sin_len = sizeof(struct sockaddr_in);
6f0e3f6e 149#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
718e3744 150 return 0;
151 }
152#ifdef HAVE_IPV6
153 ret = inet_pton (AF_INET6, str, &su->sin6.sin6_addr);
154 if (ret > 0) /* Valid IPv6 address format. */
155 {
156 su->sin6.sin6_family = AF_INET6;
157#ifdef SIN6_LEN
158 su->sin6.sin6_len = sizeof(struct sockaddr_in6);
159#endif /* SIN6_LEN */
160 return 0;
161 }
162#endif /* HAVE_IPV6 */
163 return -1;
164}
165
166const char *
c0d8db4d 167sockunion2str (const union sockunion *su, char *buf, size_t len)
718e3744 168{
67e2b6f0
TT
169 switch (sockunion_family(su))
170 {
171 case AF_UNSPEC:
172 snprintf (buf, len, "(unspec)");
173 return buf;
174 case AF_INET:
175 return inet_ntop (AF_INET, &su->sin.sin_addr, buf, len);
718e3744 176#ifdef HAVE_IPV6
67e2b6f0
TT
177 case AF_INET6:
178 return inet_ntop (AF_INET6, &su->sin6.sin6_addr, buf, len);
718e3744 179#endif /* HAVE_IPV6 */
67e2b6f0
TT
180 }
181 snprintf (buf, len, "(af %d)", sockunion_family(su));
182 return buf;
718e3744 183}
184
2fb2a455
PJ
185union sockunion *
186sockunion_str2su (const char *str)
187{
188 union sockunion *su = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion));
189
190 if (!str2sockunion (str, su))
191 return su;
192
193 XFREE (MTYPE_SOCKUNION, su);
194 return NULL;
195}
196
1a7dcf42
PJ
197/* Convert IPv4 compatible IPv6 address to IPv4 address. */
198static void
199sockunion_normalise_mapped (union sockunion *su)
200{
201 struct sockaddr_in sin;
202
203#ifdef HAVE_IPV6
204 if (su->sa.sa_family == AF_INET6
205 && IN6_IS_ADDR_V4MAPPED (&su->sin6.sin6_addr))
206 {
207 memset (&sin, 0, sizeof (struct sockaddr_in));
208 sin.sin_family = AF_INET;
3fa3f957 209 sin.sin_port = su->sin6.sin6_port;
1a7dcf42
PJ
210 memcpy (&sin.sin_addr, ((char *)&su->sin6.sin6_addr) + 12, 4);
211 memcpy (su, &sin, sizeof (struct sockaddr_in));
212 }
213#endif /* HAVE_IPV6 */
214}
215
fc9707c3
DW
216/* return sockunion structure : this function should be revised. */
217static const char *
c0d8db4d 218sockunion_log (const union sockunion *su, char *buf, size_t len)
fc9707c3
DW
219{
220 switch (su->sa.sa_family)
221 {
222 case AF_INET:
223 return inet_ntop(AF_INET, &su->sin.sin_addr, buf, len);
224
225 case AF_INET6:
226 return inet_ntop(AF_INET6, &(su->sin6.sin6_addr), buf, len);
227 break;
228
229 default:
230 snprintf (buf, len, "af_unknown %d ", su->sa.sa_family);
231 return buf;
232 }
233}
234
718e3744 235/* Return socket of sockunion. */
236int
c0d8db4d 237sockunion_socket (const union sockunion *su)
718e3744 238{
239 int sock;
240
241 sock = socket (su->sa.sa_family, SOCK_STREAM, 0);
242 if (sock < 0)
243 {
fc9707c3
DW
244 char buf[SU_ADDRSTRLEN];
245 zlog (NULL, LOG_WARNING, "Can't make socket for %s : %s",
246 sockunion_log (su, buf, SU_ADDRSTRLEN), safe_strerror (errno));
718e3744 247 return -1;
248 }
249
250 return sock;
251}
252
253/* Return accepted new socket file descriptor. */
254int
255sockunion_accept (int sock, union sockunion *su)
256{
257 socklen_t len;
258 int client_sock;
259
260 len = sizeof (union sockunion);
261 client_sock = accept (sock, (struct sockaddr *) su, &len);
262
84152ee6 263 sockunion_normalise_mapped (su);
718e3744 264 return client_sock;
265}
266
267/* Return sizeof union sockunion. */
8cc4198f 268static int
c0d8db4d 269sockunion_sizeof (const union sockunion *su)
718e3744 270{
271 int ret;
272
273 ret = 0;
274 switch (su->sa.sa_family)
275 {
276 case AF_INET:
277 ret = sizeof (struct sockaddr_in);
278 break;
279#ifdef HAVE_IPV6
280 case AF_INET6:
281 ret = sizeof (struct sockaddr_in6);
282 break;
283#endif /* AF_INET6 */
284 }
285 return ret;
286}
287
718e3744 288/* sockunion_connect returns
289 -1 : error occured
290 0 : connect success
291 1 : connect is in progress */
292enum connect_result
c0d8db4d 293sockunion_connect (int fd, const union sockunion *peersu, unsigned short port,
b892f1dd 294 ifindex_t ifindex)
718e3744 295{
296 int ret;
297 int val;
298 union sockunion su;
299
300 memcpy (&su, peersu, sizeof (union sockunion));
301
302 switch (su.sa.sa_family)
303 {
304 case AF_INET:
305 su.sin.sin_port = port;
306 break;
307#ifdef HAVE_IPV6
308 case AF_INET6:
309 su.sin6.sin6_port = port;
310#ifdef KAME
311 if (IN6_IS_ADDR_LINKLOCAL(&su.sin6.sin6_addr) && ifindex)
312 {
6f0e3f6e 313#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
f2345335 314 su.sin6.sin6_scope_id = ifindex;
6f0e3f6e 315#endif /* HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID */
718e3744 316 SET_IN6_LINKLOCAL_IFINDEX (su.sin6.sin6_addr, ifindex);
317 }
318#endif /* KAME */
319 break;
320#endif /* HAVE_IPV6 */
321 }
322
323 /* Make socket non-block. */
324 val = fcntl (fd, F_GETFL, 0);
325 fcntl (fd, F_SETFL, val|O_NONBLOCK);
326
327 /* Call connect function. */
328 ret = connect (fd, (struct sockaddr *) &su, sockunion_sizeof (&su));
329
330 /* Immediate success */
331 if (ret == 0)
332 {
333 fcntl (fd, F_SETFL, val);
334 return connect_success;
335 }
336
337 /* If connect is in progress then return 1 else it's real error. */
338 if (ret < 0)
339 {
340 if (errno != EINPROGRESS)
341 {
b24b19f7 342 char str[SU_ADDRSTRLEN];
718e3744 343 zlog_info ("can't connect to %s fd %d : %s",
b24b19f7
SH
344 sockunion_log (&su, str, sizeof str),
345 fd, safe_strerror (errno));
718e3744 346 return connect_error;
347 }
348 }
349
350 fcntl (fd, F_SETFL, val);
351
352 return connect_in_progress;
353}
354
355/* Make socket from sockunion union. */
356int
357sockunion_stream_socket (union sockunion *su)
358{
359 int sock;
360
361 if (su->sa.sa_family == 0)
362 su->sa.sa_family = AF_INET_UNION;
363
364 sock = socket (su->sa.sa_family, SOCK_STREAM, 0);
365
366 if (sock < 0)
367 zlog (NULL, LOG_WARNING, "can't make socket sockunion_stream_socket");
368
369 return sock;
370}
371
372/* Bind socket to specified address. */
373int
374sockunion_bind (int sock, union sockunion *su, unsigned short port,
375 union sockunion *su_addr)
376{
377 int size = 0;
378 int ret;
379
380 if (su->sa.sa_family == AF_INET)
381 {
382 size = sizeof (struct sockaddr_in);
383 su->sin.sin_port = htons (port);
6f0e3f6e 384#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
718e3744 385 su->sin.sin_len = size;
6f0e3f6e 386#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
718e3744 387 if (su_addr == NULL)
12829328 388 sockunion2ip (su) = htonl (INADDR_ANY);
718e3744 389 }
390#ifdef HAVE_IPV6
391 else if (su->sa.sa_family == AF_INET6)
392 {
393 size = sizeof (struct sockaddr_in6);
394 su->sin6.sin6_port = htons (port);
395#ifdef SIN6_LEN
396 su->sin6.sin6_len = size;
397#endif /* SIN6_LEN */
398 if (su_addr == NULL)
399 {
1cbb5dfc 400#ifdef LINUX_IPV6
718e3744 401 memset (&su->sin6.sin6_addr, 0, sizeof (struct in6_addr));
402#else
403 su->sin6.sin6_addr = in6addr_any;
404#endif /* LINUX_IPV6 */
405 }
406 }
407#endif /* HAVE_IPV6 */
408
409
410 ret = bind (sock, (struct sockaddr *)su, size);
411 if (ret < 0)
fc9707c3
DW
412 {
413 char buf[SU_ADDRSTRLEN];
414 zlog (NULL, LOG_WARNING, "can't bind socket for %s : %s",
415 sockunion_log (su, buf, SU_ADDRSTRLEN), safe_strerror (errno));
416 }
718e3744 417
418 return ret;
419}
420
421int
422sockopt_reuseaddr (int sock)
423{
424 int ret;
425 int on = 1;
426
427 ret = setsockopt (sock, SOL_SOCKET, SO_REUSEADDR,
428 (void *) &on, sizeof (on));
429 if (ret < 0)
430 {
431 zlog (NULL, LOG_WARNING, "can't set sockopt SO_REUSEADDR to socket %d", sock);
432 return -1;
433 }
434 return 0;
435}
436
437#ifdef SO_REUSEPORT
438int
439sockopt_reuseport (int sock)
440{
441 int ret;
442 int on = 1;
443
444 ret = setsockopt (sock, SOL_SOCKET, SO_REUSEPORT,
445 (void *) &on, sizeof (on));
446 if (ret < 0)
447 {
e7fe8c88 448 zlog (NULL, LOG_WARNING, "can't set sockopt SO_REUSEPORT to socket %d", sock);
718e3744 449 return -1;
450 }
451 return 0;
452}
453#else
454int
455sockopt_reuseport (int sock)
456{
457 return 0;
458}
459#endif /* 0 */
460
461int
462sockopt_ttl (int family, int sock, int ttl)
463{
464 int ret;
465
466#ifdef IP_TTL
467 if (family == AF_INET)
468 {
469 ret = setsockopt (sock, IPPROTO_IP, IP_TTL,
470 (void *) &ttl, sizeof (int));
471 if (ret < 0)
472 {
473 zlog (NULL, LOG_WARNING, "can't set sockopt IP_TTL %d to socket %d", ttl, sock);
474 return -1;
475 }
476 return 0;
477 }
478#endif /* IP_TTL */
479#ifdef HAVE_IPV6
480 if (family == AF_INET6)
481 {
482 ret = setsockopt (sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
483 (void *) &ttl, sizeof (int));
484 if (ret < 0)
485 {
486 zlog (NULL, LOG_WARNING, "can't set sockopt IPV6_UNICAST_HOPS %d to socket %d",
487 ttl, sock);
488 return -1;
489 }
490 return 0;
491 }
492#endif /* HAVE_IPV6 */
493 return 0;
494}
495
58192df7
SH
496int
497sockopt_cork (int sock, int onoff)
498{
499#ifdef TCP_CORK
500 return setsockopt (sock, IPPROTO_TCP, TCP_CORK, &onoff, sizeof(onoff));
501#else
502 return 0;
ed40466a
DS
503#endif
504}
505
506int sockopt_mark_default(int sock, int mark, struct zebra_privs_t *cap)
507{
508#ifdef SO_MARK
509 int ret;
510
511 if ( cap->change (ZPRIVS_RAISE) )
512 zlog_err ("routing_socket: Can't raise privileges");
513
514 ret = setsockopt(sock, SOL_SOCKET, SO_MARK, &mark, sizeof(mark));
515
516 if ( cap->change (ZPRIVS_LOWER) )
517 zlog_err ("routing_socket: Can't lower privileges");
518
519 return ret;
520#else
521 return 0;
58192df7
SH
522#endif
523}
524
fa411a21
NH
525int
526sockopt_minttl (int family, int sock, int minttl)
527{
89b6d1f8 528#ifdef IP_MINTTL
d876bdf4 529 if (family == AF_INET)
fa411a21 530 {
d876bdf4
SH
531 int ret = setsockopt (sock, IPPROTO_IP, IP_MINTTL, &minttl, sizeof(minttl));
532 if (ret < 0)
533 zlog (NULL, LOG_WARNING,
534 "can't set sockopt IP_MINTTL to %d on socket %d: %s",
535 minttl, sock, safe_strerror (errno));
536 return ret;
fa411a21 537 }
d876bdf4 538#endif /* IP_MINTTL */
d8dc5257 539#ifdef IPV6_MINHOPCOUNT
d876bdf4
SH
540 if (family == AF_INET6)
541 {
d8dc5257 542 int ret = setsockopt (sock, IPPROTO_IPV6, IPV6_MINHOPCOUNT, &minttl, sizeof(minttl));
d876bdf4
SH
543 if (ret < 0)
544 zlog (NULL, LOG_WARNING,
d8dc5257 545 "can't set sockopt IPV6_MINHOPCOUNT to %d on socket %d: %s",
d876bdf4
SH
546 minttl, sock, safe_strerror (errno));
547 return ret;
548 }
549#endif
fa411a21 550
89b6d1f8
SH
551 errno = EOPNOTSUPP;
552 return -1;
fa411a21
NH
553}
554
ca051269
DL
555int
556sockopt_v6only (int family, int sock)
557{
558 int ret, on = 1;
559
560#ifdef HAVE_IPV6
561#ifdef IPV6_V6ONLY
562 if (family == AF_INET6)
563 {
564 ret = setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY,
565 (void *) &on, sizeof (int));
566 if (ret < 0)
567 {
568 zlog (NULL, LOG_WARNING, "can't set sockopt IPV6_V6ONLY "
569 "to socket %d", sock);
570 return -1;
571 }
572 return 0;
573 }
574#endif /* IPV6_V6ONLY */
575#endif /* HAVE_IPV6 */
576 return 0;
577}
578
718e3744 579/* If same family and same prefix return 1. */
580int
3f9c7369 581sockunion_same (const union sockunion *su1, const union sockunion *su2)
718e3744 582{
583 int ret = 0;
584
585 if (su1->sa.sa_family != su2->sa.sa_family)
586 return 0;
587
588 switch (su1->sa.sa_family)
589 {
590 case AF_INET:
591 ret = memcmp (&su1->sin.sin_addr, &su2->sin.sin_addr,
592 sizeof (struct in_addr));
593 break;
594#ifdef HAVE_IPV6
595 case AF_INET6:
596 ret = memcmp (&su1->sin6.sin6_addr, &su2->sin6.sin6_addr,
597 sizeof (struct in6_addr));
f2345335
DS
598 if ((ret == 0) && IN6_IS_ADDR_LINKLOCAL(&su1->sin6.sin6_addr))
599 {
600 /* compare interface indices */
601 if (su1->sin6.sin6_scope_id && su2->sin6.sin6_scope_id)
602 ret = (su1->sin6.sin6_scope_id == su2->sin6.sin6_scope_id) ? 0 : 1;
603 }
718e3744 604 break;
605#endif /* HAVE_IPV6 */
606 }
607 if (ret == 0)
608 return 1;
609 else
610 return 0;
611}
612
7cb5cdbb
TT
613unsigned int
614sockunion_hash (const union sockunion *su)
615{
616 switch (sockunion_family(su))
617 {
618 case AF_INET:
619 return jhash_1word(su->sin.sin_addr.s_addr, 0);
620#ifdef HAVE_IPV6
621 case AF_INET6:
622 return jhash2(su->sin6.sin6_addr.s6_addr32, ZEBRA_NUM_OF(su->sin6.sin6_addr.s6_addr32), 0);
623#endif /* HAVE_IPV6 */
624 }
625 return 0;
626}
627
95e0999c
TT
628size_t
629family2addrsize(int family)
630{
631 switch (family)
632 {
633 case AF_INET:
634 return sizeof(struct in_addr);
635#ifdef HAVE_IPV6
636 case AF_INET6:
637 return sizeof(struct in6_addr);
638#endif /* HAVE_IPV6 */
639 }
640 return 0;
641}
642
643size_t
644sockunion_get_addrlen(const union sockunion *su)
645{
646 return family2addrsize(sockunion_family(su));
647}
648
649const u_char *
650sockunion_get_addr(const union sockunion *su)
651{
652 switch (sockunion_family(su))
653 {
654 case AF_INET:
655 return (const u_char *) &su->sin.sin_addr.s_addr;
656#ifdef HAVE_IPV6
657 case AF_INET6:
658 return (const u_char *) &su->sin6.sin6_addr;
659#endif /* HAVE_IPV6 */
660 }
661 return NULL;
662}
663
664void
665sockunion_set(union sockunion *su, int family, const u_char *addr, size_t bytes)
666{
667 if (family2addrsize(family) != bytes)
668 return;
669
670 sockunion_family(su) = family;
671 switch (family)
672 {
673 case AF_INET:
674 memcpy(&su->sin.sin_addr.s_addr, addr, bytes);
675 break;
676#ifdef HAVE_IPV6
677 case AF_INET6:
678 memcpy(&su->sin6.sin6_addr, addr, bytes);
679 break;
680#endif /* HAVE_IPV6 */
681 }
682}
683
718e3744 684/* After TCP connection is established. Get local address and port. */
685union sockunion *
686sockunion_getsockname (int fd)
687{
688 int ret;
22528299 689 socklen_t len;
718e3744 690 union
691 {
692 struct sockaddr sa;
693 struct sockaddr_in sin;
694#ifdef HAVE_IPV6
695 struct sockaddr_in6 sin6;
696#endif /* HAVE_IPV6 */
697 char tmp_buffer[128];
698 } name;
699 union sockunion *su;
700
701 memset (&name, 0, sizeof name);
702 len = sizeof name;
703
704 ret = getsockname (fd, (struct sockaddr *)&name, &len);
705 if (ret < 0)
706 {
707 zlog_warn ("Can't get local address and port by getsockname: %s",
6099b3b5 708 safe_strerror (errno));
718e3744 709 return NULL;
710 }
711
712 if (name.sa.sa_family == AF_INET)
713 {
2ba9a37a 714 su = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion));
718e3744 715 memcpy (su, &name, sizeof (struct sockaddr_in));
716 return su;
717 }
718#ifdef HAVE_IPV6
719 if (name.sa.sa_family == AF_INET6)
720 {
2ba9a37a 721 su = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion));
718e3744 722 memcpy (su, &name, sizeof (struct sockaddr_in6));
1a7dcf42 723 sockunion_normalise_mapped (su);
718e3744 724 return su;
725 }
726#endif /* HAVE_IPV6 */
727 return NULL;
728}
729
730/* After TCP connection is established. Get remote address and port. */
731union sockunion *
732sockunion_getpeername (int fd)
733{
734 int ret;
22528299 735 socklen_t len;
718e3744 736 union
737 {
738 struct sockaddr sa;
739 struct sockaddr_in sin;
740#ifdef HAVE_IPV6
741 struct sockaddr_in6 sin6;
742#endif /* HAVE_IPV6 */
743 char tmp_buffer[128];
744 } name;
745 union sockunion *su;
746
747 memset (&name, 0, sizeof name);
748 len = sizeof name;
749 ret = getpeername (fd, (struct sockaddr *)&name, &len);
750 if (ret < 0)
751 {
752 zlog (NULL, LOG_WARNING, "Can't get remote address and port: %s",
6099b3b5 753 safe_strerror (errno));
718e3744 754 return NULL;
755 }
756
757 if (name.sa.sa_family == AF_INET)
758 {
2ba9a37a 759 su = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion));
718e3744 760 memcpy (su, &name, sizeof (struct sockaddr_in));
761 return su;
762 }
763#ifdef HAVE_IPV6
764 if (name.sa.sa_family == AF_INET6)
765 {
2ba9a37a 766 su = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion));
718e3744 767 memcpy (su, &name, sizeof (struct sockaddr_in6));
1a7dcf42 768 sockunion_normalise_mapped (su);
718e3744 769 return su;
770 }
771#endif /* HAVE_IPV6 */
772 return NULL;
773}
774
775/* Print sockunion structure */
8cc4198f 776static void __attribute__ ((unused))
c0d8db4d 777sockunion_print (const union sockunion *su)
718e3744 778{
779 if (su == NULL)
780 return;
781
782 switch (su->sa.sa_family)
783 {
784 case AF_INET:
785 printf ("%s\n", inet_ntoa (su->sin.sin_addr));
786 break;
787#ifdef HAVE_IPV6
788 case AF_INET6:
789 {
42d49865 790 char buf [SU_ADDRSTRLEN];
718e3744 791
792 printf ("%s\n", inet_ntop (AF_INET6, &(su->sin6.sin6_addr),
793 buf, sizeof (buf)));
794 }
795 break;
796#endif /* HAVE_IPV6 */
797
798#ifdef AF_LINK
799 case AF_LINK:
800 {
801 struct sockaddr_dl *sdl;
802
803 sdl = (struct sockaddr_dl *)&(su->sa);
804 printf ("link#%d\n", sdl->sdl_index);
805 }
806 break;
807#endif /* AF_LINK */
808 default:
809 printf ("af_unknown %d\n", su->sa.sa_family);
810 break;
811 }
812}
813
814#ifdef HAVE_IPV6
8cc4198f 815static int
c0d8db4d 816in6addr_cmp (const struct in6_addr *addr1, const struct in6_addr *addr2)
718e3744 817{
8c328f11 818 unsigned int i;
35dece84 819 const u_char *p1, *p2;
718e3744 820
35dece84
DS
821 p1 = (const u_char *)addr1;
822 p2 = (const u_char *)addr2;
718e3744 823
824 for (i = 0; i < sizeof (struct in6_addr); i++)
825 {
826 if (p1[i] > p2[i])
827 return 1;
828 else if (p1[i] < p2[i])
829 return -1;
830 }
831 return 0;
832}
833#endif /* HAVE_IPV6 */
834
835int
c0d8db4d 836sockunion_cmp (const union sockunion *su1, const union sockunion *su2)
718e3744 837{
838 if (su1->sa.sa_family > su2->sa.sa_family)
839 return 1;
840 if (su1->sa.sa_family < su2->sa.sa_family)
841 return -1;
842
843 if (su1->sa.sa_family == AF_INET)
844 {
12829328 845 if (ntohl (sockunion2ip (su1)) == ntohl (sockunion2ip (su2)))
718e3744 846 return 0;
12829328 847 if (ntohl (sockunion2ip (su1)) > ntohl (sockunion2ip (su2)))
718e3744 848 return 1;
849 else
850 return -1;
851 }
852#ifdef HAVE_IPV6
853 if (su1->sa.sa_family == AF_INET6)
854 return in6addr_cmp (&su1->sin6.sin6_addr, &su2->sin6.sin6_addr);
855#endif /* HAVE_IPV6 */
856 return 0;
857}
858
859/* Duplicate sockunion. */
860union sockunion *
c0d8db4d 861sockunion_dup (const union sockunion *su)
718e3744 862{
863 union sockunion *dup = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion));
864 memcpy (dup, su, sizeof (union sockunion));
865 return dup;
866}
867
868void
869sockunion_free (union sockunion *su)
870{
871 XFREE (MTYPE_SOCKUNION, su);
872}
dd793e4a
DW
873
874void
875sockunion_init (union sockunion *su)
876{
877 memset(su, 0, sizeof(union sockunion));
878}