1 /* Socket union related function.
2 * Copyright (c) 1997, 98 Kunihiro Ishiguro
4 * This file is part of GNU Zebra.
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
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.
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
26 #include "sockunion.h"
31 #ifndef HAVE_INET_ATON
33 inet_aton (const char *cp
, struct in_addr
*inaddr
)
36 register u_long addr
= 0;
37 register u_long val
= 0, base
= 10;
41 register char c
= *cp
;
45 case '0': case '1': case '2': case '3': case '4': case '5':
46 case '6': case '7': case '8': case '9':
47 val
= (val
* base
) + (c
- '0');
55 addr
= addr
<< 8 | val
;
64 addr
<<= 8 * (3 - dots
);
66 inaddr
->s_addr
= htonl (addr
);
69 #endif /* ! HAVE_INET_ATON */
72 #ifndef HAVE_INET_PTON
74 inet_pton (int family
, const char *strptr
, void *addrptr
)
76 if (family
== AF_INET
)
78 struct in_addr in_val
;
80 if (inet_aton (strptr
, &in_val
))
82 memcpy (addrptr
, &in_val
, sizeof (struct in_addr
));
90 #endif /* ! HAVE_INET_PTON */
92 #ifndef HAVE_INET_NTOP
94 inet_ntop (int family
, const void *addrptr
, char *strptr
, size_t len
)
96 unsigned char *p
= (unsigned char *) addrptr
;
98 if (family
== AF_INET
)
100 char temp
[INET_ADDRSTRLEN
];
102 snprintf(temp
, sizeof(temp
), "%d.%d.%d.%d", p
[0], p
[1], p
[2], p
[3]);
104 if (strlen(temp
) >= len
)
109 strcpy(strptr
, temp
);
113 errno
= EAFNOSUPPORT
;
116 #endif /* ! HAVE_INET_NTOP */
119 inet_sutop (union sockunion
*su
, char *str
)
121 switch (su
->sa
.sa_family
)
124 inet_ntop (AF_INET
, &su
->sin
.sin_addr
, str
, INET_ADDRSTRLEN
);
128 inet_ntop (AF_INET6
, &su
->sin6
.sin6_addr
, str
, INET6_ADDRSTRLEN
);
130 #endif /* HAVE_IPV6 */
136 str2sockunion (const char *str
, union sockunion
*su
)
140 memset (su
, 0, sizeof (union sockunion
));
142 ret
= inet_pton (AF_INET
, str
, &su
->sin
.sin_addr
);
143 if (ret
> 0) /* Valid IPv4 address format. */
145 su
->sin
.sin_family
= AF_INET
;
146 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
147 su
->sin
.sin_len
= sizeof(struct sockaddr_in
);
148 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
152 ret
= inet_pton (AF_INET6
, str
, &su
->sin6
.sin6_addr
);
153 if (ret
> 0) /* Valid IPv6 address format. */
155 su
->sin6
.sin6_family
= AF_INET6
;
157 su
->sin6
.sin6_len
= sizeof(struct sockaddr_in6
);
158 #endif /* SIN6_LEN */
161 #endif /* HAVE_IPV6 */
166 sockunion2str (union sockunion
*su
, char *buf
, size_t len
)
168 if (su
->sa
.sa_family
== AF_INET
)
169 return inet_ntop (AF_INET
, &su
->sin
.sin_addr
, buf
, len
);
171 else if (su
->sa
.sa_family
== AF_INET6
)
172 return inet_ntop (AF_INET6
, &su
->sin6
.sin6_addr
, buf
, len
);
173 #endif /* HAVE_IPV6 */
178 sockunion_str2su (const char *str
)
183 su
= XMALLOC (MTYPE_SOCKUNION
, sizeof (union sockunion
));
184 memset (su
, 0, sizeof (union sockunion
));
186 ret
= inet_pton (AF_INET
, str
, &su
->sin
.sin_addr
);
187 if (ret
> 0) /* Valid IPv4 address format. */
189 su
->sin
.sin_family
= AF_INET
;
190 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
191 su
->sin
.sin_len
= sizeof(struct sockaddr_in
);
192 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
196 ret
= inet_pton (AF_INET6
, str
, &su
->sin6
.sin6_addr
);
197 if (ret
> 0) /* Valid IPv6 address format. */
199 su
->sin6
.sin6_family
= AF_INET6
;
201 su
->sin6
.sin6_len
= sizeof(struct sockaddr_in6
);
202 #endif /* SIN6_LEN */
205 #endif /* HAVE_IPV6 */
207 XFREE (MTYPE_SOCKUNION
, su
);
212 sockunion_su2str (union sockunion
*su
)
214 char str
[SU_ADDRSTRLEN
];
216 switch (su
->sa
.sa_family
)
219 inet_ntop (AF_INET
, &su
->sin
.sin_addr
, str
, sizeof (str
));
223 inet_ntop (AF_INET6
, &su
->sin6
.sin6_addr
, str
, sizeof (str
));
225 #endif /* HAVE_IPV6 */
227 return XSTRDUP (MTYPE_TMP
, str
);
230 /* Return socket of sockunion. */
232 sockunion_socket (union sockunion
*su
)
236 sock
= socket (su
->sa
.sa_family
, SOCK_STREAM
, 0);
239 zlog (NULL
, LOG_WARNING
, "Can't make socket : %s", safe_strerror (errno
));
246 /* Return accepted new socket file descriptor. */
248 sockunion_accept (int sock
, union sockunion
*su
)
253 len
= sizeof (union sockunion
);
254 client_sock
= accept (sock
, (struct sockaddr
*) su
, &len
);
256 /* Convert IPv4 compatible IPv6 address to IPv4 address. */
258 if (su
->sa
.sa_family
== AF_INET6
)
260 if (IN6_IS_ADDR_V4MAPPED (&su
->sin6
.sin6_addr
))
262 struct sockaddr_in sin
;
264 memset (&sin
, 0, sizeof (struct sockaddr_in
));
265 sin
.sin_family
= AF_INET
;
266 memcpy (&sin
.sin_addr
, ((char *)&su
->sin6
.sin6_addr
) + 12, 4);
267 memcpy (su
, &sin
, sizeof (struct sockaddr_in
));
270 #endif /* HAVE_IPV6 */
275 /* Return sizeof union sockunion. */
277 sockunion_sizeof (union sockunion
*su
)
282 switch (su
->sa
.sa_family
)
285 ret
= sizeof (struct sockaddr_in
);
289 ret
= sizeof (struct sockaddr_in6
);
291 #endif /* AF_INET6 */
296 /* return sockunion structure : this function should be revised. */
298 sockunion_log (union sockunion
*su
)
300 static char buf
[SU_ADDRSTRLEN
];
302 switch (su
->sa
.sa_family
)
305 snprintf (buf
, SU_ADDRSTRLEN
, "%s", inet_ntoa (su
->sin
.sin_addr
));
309 snprintf (buf
, SU_ADDRSTRLEN
, "%s",
310 inet_ntop (AF_INET6
, &(su
->sin6
.sin6_addr
), buf
, SU_ADDRSTRLEN
));
312 #endif /* HAVE_IPV6 */
314 snprintf (buf
, SU_ADDRSTRLEN
, "af_unknown %d ", su
->sa
.sa_family
);
317 return (XSTRDUP (MTYPE_TMP
, buf
));
320 /* sockunion_connect returns
323 1 : connect is in progress */
325 sockunion_connect (int fd
, union sockunion
*peersu
, unsigned short port
,
326 unsigned int ifindex
)
332 memcpy (&su
, peersu
, sizeof (union sockunion
));
334 switch (su
.sa
.sa_family
)
337 su
.sin
.sin_port
= port
;
341 su
.sin6
.sin6_port
= port
;
343 if (IN6_IS_ADDR_LINKLOCAL(&su
.sin6
.sin6_addr
) && ifindex
)
345 #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
346 /* su.sin6.sin6_scope_id = ifindex; */
348 su
.sin6
.sin6_scope_id
= ifindex
;
350 #endif /* HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID */
352 SET_IN6_LINKLOCAL_IFINDEX (su
.sin6
.sin6_addr
, ifindex
);
357 #endif /* HAVE_IPV6 */
360 /* Make socket non-block. */
361 val
= fcntl (fd
, F_GETFL
, 0);
362 fcntl (fd
, F_SETFL
, val
|O_NONBLOCK
);
364 /* Call connect function. */
365 ret
= connect (fd
, (struct sockaddr
*) &su
, sockunion_sizeof (&su
));
367 /* Immediate success */
370 fcntl (fd
, F_SETFL
, val
);
371 return connect_success
;
374 /* If connect is in progress then return 1 else it's real error. */
377 if (errno
!= EINPROGRESS
)
379 zlog_info ("can't connect to %s fd %d : %s",
380 sockunion_log (&su
), fd
, safe_strerror (errno
));
381 return connect_error
;
385 fcntl (fd
, F_SETFL
, val
);
387 return connect_in_progress
;
390 /* Make socket from sockunion union. */
392 sockunion_stream_socket (union sockunion
*su
)
396 if (su
->sa
.sa_family
== 0)
397 su
->sa
.sa_family
= AF_INET_UNION
;
399 sock
= socket (su
->sa
.sa_family
, SOCK_STREAM
, 0);
402 zlog (NULL
, LOG_WARNING
, "can't make socket sockunion_stream_socket");
407 /* Bind socket to specified address. */
409 sockunion_bind (int sock
, union sockunion
*su
, unsigned short port
,
410 union sockunion
*su_addr
)
415 if (su
->sa
.sa_family
== AF_INET
)
417 size
= sizeof (struct sockaddr_in
);
418 su
->sin
.sin_port
= htons (port
);
419 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
420 su
->sin
.sin_len
= size
;
421 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
423 su
->sin
.sin_addr
.s_addr
= htonl (INADDR_ANY
);
426 else if (su
->sa
.sa_family
== AF_INET6
)
428 size
= sizeof (struct sockaddr_in6
);
429 su
->sin6
.sin6_port
= htons (port
);
431 su
->sin6
.sin6_len
= size
;
432 #endif /* SIN6_LEN */
435 #if defined(LINUX_IPV6) || defined(NRL)
436 memset (&su
->sin6
.sin6_addr
, 0, sizeof (struct in6_addr
));
438 su
->sin6
.sin6_addr
= in6addr_any
;
439 #endif /* LINUX_IPV6 */
442 #endif /* HAVE_IPV6 */
445 ret
= bind (sock
, (struct sockaddr
*)su
, size
);
447 zlog (NULL
, LOG_WARNING
, "can't bind socket : %s", safe_strerror (errno
));
453 sockopt_reuseaddr (int sock
)
458 ret
= setsockopt (sock
, SOL_SOCKET
, SO_REUSEADDR
,
459 (void *) &on
, sizeof (on
));
462 zlog (NULL
, LOG_WARNING
, "can't set sockopt SO_REUSEADDR to socket %d", sock
);
470 sockopt_reuseport (int sock
)
475 ret
= setsockopt (sock
, SOL_SOCKET
, SO_REUSEPORT
,
476 (void *) &on
, sizeof (on
));
479 zlog (NULL
, LOG_WARNING
, "can't set sockopt SO_REUSEPORT to socket %d", sock
);
486 sockopt_reuseport (int sock
)
493 sockopt_ttl (int family
, int sock
, int ttl
)
498 if (family
== AF_INET
)
500 ret
= setsockopt (sock
, IPPROTO_IP
, IP_TTL
,
501 (void *) &ttl
, sizeof (int));
504 zlog (NULL
, LOG_WARNING
, "can't set sockopt IP_TTL %d to socket %d", ttl
, sock
);
511 if (family
== AF_INET6
)
513 ret
= setsockopt (sock
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
,
514 (void *) &ttl
, sizeof (int));
517 zlog (NULL
, LOG_WARNING
, "can't set sockopt IPV6_UNICAST_HOPS %d to socket %d",
523 #endif /* HAVE_IPV6 */
527 /* If same family and same prefix return 1. */
529 sockunion_same (union sockunion
*su1
, union sockunion
*su2
)
533 if (su1
->sa
.sa_family
!= su2
->sa
.sa_family
)
536 switch (su1
->sa
.sa_family
)
539 ret
= memcmp (&su1
->sin
.sin_addr
, &su2
->sin
.sin_addr
,
540 sizeof (struct in_addr
));
544 ret
= memcmp (&su1
->sin6
.sin6_addr
, &su2
->sin6
.sin6_addr
,
545 sizeof (struct in6_addr
));
547 #endif /* HAVE_IPV6 */
555 /* After TCP connection is established. Get local address and port. */
557 sockunion_getsockname (int fd
)
564 struct sockaddr_in sin
;
566 struct sockaddr_in6 sin6
;
567 #endif /* HAVE_IPV6 */
568 char tmp_buffer
[128];
572 memset (&name
, 0, sizeof name
);
575 ret
= getsockname (fd
, (struct sockaddr
*)&name
, &len
);
578 zlog_warn ("Can't get local address and port by getsockname: %s",
579 safe_strerror (errno
));
583 if (name
.sa
.sa_family
== AF_INET
)
585 su
= XCALLOC (MTYPE_SOCKUNION
, sizeof (union sockunion
));
586 memcpy (su
, &name
, sizeof (struct sockaddr_in
));
590 if (name
.sa
.sa_family
== AF_INET6
)
592 su
= XCALLOC (MTYPE_SOCKUNION
, sizeof (union sockunion
));
593 memcpy (su
, &name
, sizeof (struct sockaddr_in6
));
595 if (IN6_IS_ADDR_V4MAPPED (&su
->sin6
.sin6_addr
))
597 struct sockaddr_in sin
;
599 sin
.sin_family
= AF_INET
;
600 memcpy (&sin
.sin_addr
, ((char *)&su
->sin6
.sin6_addr
) + 12, 4);
601 sin
.sin_port
= su
->sin6
.sin6_port
;
602 memcpy (su
, &sin
, sizeof (struct sockaddr_in
));
606 #endif /* HAVE_IPV6 */
610 /* After TCP connection is established. Get remote address and port. */
612 sockunion_getpeername (int fd
)
619 struct sockaddr_in sin
;
621 struct sockaddr_in6 sin6
;
622 #endif /* HAVE_IPV6 */
623 char tmp_buffer
[128];
627 memset (&name
, 0, sizeof name
);
629 ret
= getpeername (fd
, (struct sockaddr
*)&name
, &len
);
632 zlog (NULL
, LOG_WARNING
, "Can't get remote address and port: %s",
633 safe_strerror (errno
));
637 if (name
.sa
.sa_family
== AF_INET
)
639 su
= XCALLOC (MTYPE_SOCKUNION
, sizeof (union sockunion
));
640 memcpy (su
, &name
, sizeof (struct sockaddr_in
));
644 if (name
.sa
.sa_family
== AF_INET6
)
646 su
= XCALLOC (MTYPE_SOCKUNION
, sizeof (union sockunion
));
647 memcpy (su
, &name
, sizeof (struct sockaddr_in6
));
649 if (IN6_IS_ADDR_V4MAPPED (&su
->sin6
.sin6_addr
))
651 struct sockaddr_in sin
;
653 sin
.sin_family
= AF_INET
;
654 memcpy (&sin
.sin_addr
, ((char *)&su
->sin6
.sin6_addr
) + 12, 4);
655 sin
.sin_port
= su
->sin6
.sin6_port
;
656 memcpy (su
, &sin
, sizeof (struct sockaddr_in
));
660 #endif /* HAVE_IPV6 */
664 /* Print sockunion structure */
665 static void __attribute__ ((unused
))
666 sockunion_print (union sockunion
*su
)
671 switch (su
->sa
.sa_family
)
674 printf ("%s\n", inet_ntoa (su
->sin
.sin_addr
));
679 char buf
[SU_ADDRSTRLEN
];
681 printf ("%s\n", inet_ntop (AF_INET6
, &(su
->sin6
.sin6_addr
),
685 #endif /* HAVE_IPV6 */
690 struct sockaddr_dl
*sdl
;
692 sdl
= (struct sockaddr_dl
*)&(su
->sa
);
693 printf ("link#%d\n", sdl
->sdl_index
);
698 printf ("af_unknown %d\n", su
->sa
.sa_family
);
705 in6addr_cmp (struct in6_addr
*addr1
, struct in6_addr
*addr2
)
710 p1
= (u_char
*)addr1
;
711 p2
= (u_char
*)addr2
;
713 for (i
= 0; i
< sizeof (struct in6_addr
); i
++)
717 else if (p1
[i
] < p2
[i
])
722 #endif /* HAVE_IPV6 */
725 sockunion_cmp (union sockunion
*su1
, union sockunion
*su2
)
727 if (su1
->sa
.sa_family
> su2
->sa
.sa_family
)
729 if (su1
->sa
.sa_family
< su2
->sa
.sa_family
)
732 if (su1
->sa
.sa_family
== AF_INET
)
734 if (ntohl (su1
->sin
.sin_addr
.s_addr
) == ntohl (su2
->sin
.sin_addr
.s_addr
))
736 if (ntohl (su1
->sin
.sin_addr
.s_addr
) > ntohl (su2
->sin
.sin_addr
.s_addr
))
742 if (su1
->sa
.sa_family
== AF_INET6
)
743 return in6addr_cmp (&su1
->sin6
.sin6_addr
, &su2
->sin6
.sin6_addr
);
744 #endif /* HAVE_IPV6 */
748 /* Duplicate sockunion. */
750 sockunion_dup (union sockunion
*su
)
752 union sockunion
*dup
= XCALLOC (MTYPE_SOCKUNION
, sizeof (union sockunion
));
753 memcpy (dup
, su
, sizeof (union sockunion
));
758 sockunion_free (union sockunion
*su
)
760 XFREE (MTYPE_SOCKUNION
, su
);