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
= XCALLOC (MTYPE_SOCKUNION
, sizeof (union sockunion
));
185 ret
= inet_pton (AF_INET
, str
, &su
->sin
.sin_addr
);
186 if (ret
> 0) /* Valid IPv4 address format. */
188 su
->sin
.sin_family
= AF_INET
;
189 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
190 su
->sin
.sin_len
= sizeof(struct sockaddr_in
);
191 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
195 ret
= inet_pton (AF_INET6
, str
, &su
->sin6
.sin6_addr
);
196 if (ret
> 0) /* Valid IPv6 address format. */
198 su
->sin6
.sin6_family
= AF_INET6
;
200 su
->sin6
.sin6_len
= sizeof(struct sockaddr_in6
);
201 #endif /* SIN6_LEN */
204 #endif /* HAVE_IPV6 */
206 XFREE (MTYPE_SOCKUNION
, su
);
211 sockunion_su2str (union sockunion
*su
)
213 char str
[SU_ADDRSTRLEN
];
215 switch (su
->sa
.sa_family
)
218 inet_ntop (AF_INET
, &su
->sin
.sin_addr
, str
, sizeof (str
));
222 inet_ntop (AF_INET6
, &su
->sin6
.sin6_addr
, str
, sizeof (str
));
224 #endif /* HAVE_IPV6 */
226 return XSTRDUP (MTYPE_TMP
, str
);
229 /* Convert IPv4 compatible IPv6 address to IPv4 address. */
231 sockunion_normalise_mapped (union sockunion
*su
)
233 struct sockaddr_in sin
;
236 if (su
->sa
.sa_family
== AF_INET6
237 && IN6_IS_ADDR_V4MAPPED (&su
->sin6
.sin6_addr
))
239 memset (&sin
, 0, sizeof (struct sockaddr_in
));
240 sin
.sin_family
= AF_INET
;
241 sin
.sin_port
= su
->sin6
.sin6_port
;
242 memcpy (&sin
.sin_addr
, ((char *)&su
->sin6
.sin6_addr
) + 12, 4);
243 memcpy (su
, &sin
, sizeof (struct sockaddr_in
));
245 #endif /* HAVE_IPV6 */
248 /* Return socket of sockunion. */
250 sockunion_socket (union sockunion
*su
)
254 sock
= socket (su
->sa
.sa_family
, SOCK_STREAM
, 0);
257 zlog (NULL
, LOG_WARNING
, "Can't make socket : %s", safe_strerror (errno
));
264 /* Return accepted new socket file descriptor. */
266 sockunion_accept (int sock
, union sockunion
*su
)
271 len
= sizeof (union sockunion
);
272 client_sock
= accept (sock
, (struct sockaddr
*) su
, &len
);
274 sockunion_normalise_mapped (su
);
278 /* Return sizeof union sockunion. */
280 sockunion_sizeof (union sockunion
*su
)
285 switch (su
->sa
.sa_family
)
288 ret
= sizeof (struct sockaddr_in
);
292 ret
= sizeof (struct sockaddr_in6
);
294 #endif /* AF_INET6 */
299 /* return sockunion structure : this function should be revised. */
301 sockunion_log (union sockunion
*su
)
303 static char buf
[SU_ADDRSTRLEN
];
305 switch (su
->sa
.sa_family
)
308 snprintf (buf
, SU_ADDRSTRLEN
, "%s", inet_ntoa (su
->sin
.sin_addr
));
312 snprintf (buf
, SU_ADDRSTRLEN
, "%s",
313 inet_ntop (AF_INET6
, &(su
->sin6
.sin6_addr
), buf
, SU_ADDRSTRLEN
));
315 #endif /* HAVE_IPV6 */
317 snprintf (buf
, SU_ADDRSTRLEN
, "af_unknown %d ", su
->sa
.sa_family
);
320 return (XSTRDUP (MTYPE_TMP
, buf
));
323 /* sockunion_connect returns
326 1 : connect is in progress */
328 sockunion_connect (int fd
, union sockunion
*peersu
, unsigned short port
,
329 unsigned int ifindex
)
335 memcpy (&su
, peersu
, sizeof (union sockunion
));
337 switch (su
.sa
.sa_family
)
340 su
.sin
.sin_port
= port
;
344 su
.sin6
.sin6_port
= port
;
346 if (IN6_IS_ADDR_LINKLOCAL(&su
.sin6
.sin6_addr
) && ifindex
)
348 #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
349 /* su.sin6.sin6_scope_id = ifindex; */
351 su
.sin6
.sin6_scope_id
= ifindex
;
353 #endif /* HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID */
355 SET_IN6_LINKLOCAL_IFINDEX (su
.sin6
.sin6_addr
, ifindex
);
360 #endif /* HAVE_IPV6 */
363 /* Make socket non-block. */
364 val
= fcntl (fd
, F_GETFL
, 0);
365 fcntl (fd
, F_SETFL
, val
|O_NONBLOCK
);
367 /* Call connect function. */
368 ret
= connect (fd
, (struct sockaddr
*) &su
, sockunion_sizeof (&su
));
370 /* Immediate success */
373 fcntl (fd
, F_SETFL
, val
);
374 return connect_success
;
377 /* If connect is in progress then return 1 else it's real error. */
380 if (errno
!= EINPROGRESS
)
382 zlog_info ("can't connect to %s fd %d : %s",
383 sockunion_log (&su
), fd
, safe_strerror (errno
));
384 return connect_error
;
388 fcntl (fd
, F_SETFL
, val
);
390 return connect_in_progress
;
393 /* Make socket from sockunion union. */
395 sockunion_stream_socket (union sockunion
*su
)
399 if (su
->sa
.sa_family
== 0)
400 su
->sa
.sa_family
= AF_INET_UNION
;
402 sock
= socket (su
->sa
.sa_family
, SOCK_STREAM
, 0);
405 zlog (NULL
, LOG_WARNING
, "can't make socket sockunion_stream_socket");
410 /* Bind socket to specified address. */
412 sockunion_bind (int sock
, union sockunion
*su
, unsigned short port
,
413 union sockunion
*su_addr
)
418 if (su
->sa
.sa_family
== AF_INET
)
420 size
= sizeof (struct sockaddr_in
);
421 su
->sin
.sin_port
= htons (port
);
422 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
423 su
->sin
.sin_len
= size
;
424 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
426 su
->sin
.sin_addr
.s_addr
= htonl (INADDR_ANY
);
429 else if (su
->sa
.sa_family
== AF_INET6
)
431 size
= sizeof (struct sockaddr_in6
);
432 su
->sin6
.sin6_port
= htons (port
);
434 su
->sin6
.sin6_len
= size
;
435 #endif /* SIN6_LEN */
438 #if defined(LINUX_IPV6) || defined(NRL)
439 memset (&su
->sin6
.sin6_addr
, 0, sizeof (struct in6_addr
));
441 su
->sin6
.sin6_addr
= in6addr_any
;
442 #endif /* LINUX_IPV6 */
445 #endif /* HAVE_IPV6 */
448 ret
= bind (sock
, (struct sockaddr
*)su
, size
);
450 zlog (NULL
, LOG_WARNING
, "can't bind socket : %s", safe_strerror (errno
));
456 sockopt_reuseaddr (int sock
)
461 ret
= setsockopt (sock
, SOL_SOCKET
, SO_REUSEADDR
,
462 (void *) &on
, sizeof (on
));
465 zlog (NULL
, LOG_WARNING
, "can't set sockopt SO_REUSEADDR to socket %d", sock
);
473 sockopt_reuseport (int sock
)
478 ret
= setsockopt (sock
, SOL_SOCKET
, SO_REUSEPORT
,
479 (void *) &on
, sizeof (on
));
482 zlog (NULL
, LOG_WARNING
, "can't set sockopt SO_REUSEPORT to socket %d", sock
);
489 sockopt_reuseport (int sock
)
496 sockopt_ttl (int family
, int sock
, int ttl
)
501 if (family
== AF_INET
)
503 ret
= setsockopt (sock
, IPPROTO_IP
, IP_TTL
,
504 (void *) &ttl
, sizeof (int));
507 zlog (NULL
, LOG_WARNING
, "can't set sockopt IP_TTL %d to socket %d", ttl
, sock
);
514 if (family
== AF_INET6
)
516 ret
= setsockopt (sock
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
,
517 (void *) &ttl
, sizeof (int));
520 zlog (NULL
, LOG_WARNING
, "can't set sockopt IPV6_UNICAST_HOPS %d to socket %d",
526 #endif /* HAVE_IPV6 */
530 /* If same family and same prefix return 1. */
532 sockunion_same (union sockunion
*su1
, union sockunion
*su2
)
536 if (su1
->sa
.sa_family
!= su2
->sa
.sa_family
)
539 switch (su1
->sa
.sa_family
)
542 ret
= memcmp (&su1
->sin
.sin_addr
, &su2
->sin
.sin_addr
,
543 sizeof (struct in_addr
));
547 ret
= memcmp (&su1
->sin6
.sin6_addr
, &su2
->sin6
.sin6_addr
,
548 sizeof (struct in6_addr
));
550 #endif /* HAVE_IPV6 */
558 /* After TCP connection is established. Get local address and port. */
560 sockunion_getsockname (int fd
)
567 struct sockaddr_in sin
;
569 struct sockaddr_in6 sin6
;
570 #endif /* HAVE_IPV6 */
571 char tmp_buffer
[128];
575 memset (&name
, 0, sizeof name
);
578 ret
= getsockname (fd
, (struct sockaddr
*)&name
, &len
);
581 zlog_warn ("Can't get local address and port by getsockname: %s",
582 safe_strerror (errno
));
586 if (name
.sa
.sa_family
== AF_INET
)
588 su
= XCALLOC (MTYPE_SOCKUNION
, sizeof (union sockunion
));
589 memcpy (su
, &name
, sizeof (struct sockaddr_in
));
593 if (name
.sa
.sa_family
== AF_INET6
)
595 su
= XCALLOC (MTYPE_SOCKUNION
, sizeof (union sockunion
));
596 memcpy (su
, &name
, sizeof (struct sockaddr_in6
));
597 sockunion_normalise_mapped (su
);
600 #endif /* HAVE_IPV6 */
604 /* After TCP connection is established. Get remote address and port. */
606 sockunion_getpeername (int fd
)
613 struct sockaddr_in sin
;
615 struct sockaddr_in6 sin6
;
616 #endif /* HAVE_IPV6 */
617 char tmp_buffer
[128];
621 memset (&name
, 0, sizeof name
);
623 ret
= getpeername (fd
, (struct sockaddr
*)&name
, &len
);
626 zlog (NULL
, LOG_WARNING
, "Can't get remote address and port: %s",
627 safe_strerror (errno
));
631 if (name
.sa
.sa_family
== AF_INET
)
633 su
= XCALLOC (MTYPE_SOCKUNION
, sizeof (union sockunion
));
634 memcpy (su
, &name
, sizeof (struct sockaddr_in
));
638 if (name
.sa
.sa_family
== AF_INET6
)
640 su
= XCALLOC (MTYPE_SOCKUNION
, sizeof (union sockunion
));
641 memcpy (su
, &name
, sizeof (struct sockaddr_in6
));
642 sockunion_normalise_mapped (su
);
645 #endif /* HAVE_IPV6 */
649 /* Print sockunion structure */
650 static void __attribute__ ((unused
))
651 sockunion_print (union sockunion
*su
)
656 switch (su
->sa
.sa_family
)
659 printf ("%s\n", inet_ntoa (su
->sin
.sin_addr
));
664 char buf
[SU_ADDRSTRLEN
];
666 printf ("%s\n", inet_ntop (AF_INET6
, &(su
->sin6
.sin6_addr
),
670 #endif /* HAVE_IPV6 */
675 struct sockaddr_dl
*sdl
;
677 sdl
= (struct sockaddr_dl
*)&(su
->sa
);
678 printf ("link#%d\n", sdl
->sdl_index
);
683 printf ("af_unknown %d\n", su
->sa
.sa_family
);
690 in6addr_cmp (struct in6_addr
*addr1
, struct in6_addr
*addr2
)
695 p1
= (u_char
*)addr1
;
696 p2
= (u_char
*)addr2
;
698 for (i
= 0; i
< sizeof (struct in6_addr
); i
++)
702 else if (p1
[i
] < p2
[i
])
707 #endif /* HAVE_IPV6 */
710 sockunion_cmp (union sockunion
*su1
, union sockunion
*su2
)
712 if (su1
->sa
.sa_family
> su2
->sa
.sa_family
)
714 if (su1
->sa
.sa_family
< su2
->sa
.sa_family
)
717 if (su1
->sa
.sa_family
== AF_INET
)
719 if (ntohl (su1
->sin
.sin_addr
.s_addr
) == ntohl (su2
->sin
.sin_addr
.s_addr
))
721 if (ntohl (su1
->sin
.sin_addr
.s_addr
) > ntohl (su2
->sin
.sin_addr
.s_addr
))
727 if (su1
->sa
.sa_family
== AF_INET6
)
728 return in6addr_cmp (&su1
->sin6
.sin6_addr
, &su2
->sin6
.sin6_addr
);
729 #endif /* HAVE_IPV6 */
733 /* Duplicate sockunion. */
735 sockunion_dup (union sockunion
*su
)
737 union sockunion
*dup
= XCALLOC (MTYPE_SOCKUNION
, sizeof (union sockunion
));
738 memcpy (dup
, su
, sizeof (union sockunion
));
743 sockunion_free (union sockunion
*su
)
745 XFREE (MTYPE_SOCKUNION
, su
);