]>
git.proxmox.com Git - mirror_frr.git/blob - lib/sockunion.c
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 DEFINE_MTYPE_STATIC(LIB
, SOCKUNION
, "Socket union")
34 inet_sutop (const union sockunion
*su
, char *str
)
36 switch (su
->sa
.sa_family
)
39 inet_ntop (AF_INET
, &su
->sin
.sin_addr
, str
, INET_ADDRSTRLEN
);
42 inet_ntop (AF_INET6
, &su
->sin6
.sin6_addr
, str
, INET6_ADDRSTRLEN
);
49 str2sockunion (const char *str
, union sockunion
*su
)
53 memset (su
, 0, sizeof (union sockunion
));
55 ret
= inet_pton (AF_INET
, str
, &su
->sin
.sin_addr
);
56 if (ret
> 0) /* Valid IPv4 address format. */
58 su
->sin
.sin_family
= AF_INET
;
59 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
60 su
->sin
.sin_len
= sizeof(struct sockaddr_in
);
61 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
64 ret
= inet_pton (AF_INET6
, str
, &su
->sin6
.sin6_addr
);
65 if (ret
> 0) /* Valid IPv6 address format. */
67 su
->sin6
.sin6_family
= AF_INET6
;
69 su
->sin6
.sin6_len
= sizeof(struct sockaddr_in6
);
77 sockunion2str (const union sockunion
*su
, char *buf
, size_t len
)
79 switch (sockunion_family(su
))
82 snprintf (buf
, len
, "(unspec)");
85 return inet_ntop (AF_INET
, &su
->sin
.sin_addr
, buf
, len
);
87 return inet_ntop (AF_INET6
, &su
->sin6
.sin6_addr
, buf
, len
);
89 snprintf (buf
, len
, "(af %d)", sockunion_family(su
));
94 sockunion_str2su (const char *str
)
96 union sockunion
*su
= XCALLOC (MTYPE_SOCKUNION
, sizeof (union sockunion
));
98 if (!str2sockunion (str
, su
))
101 XFREE (MTYPE_SOCKUNION
, su
);
105 /* Convert IPv4 compatible IPv6 address to IPv4 address. */
107 sockunion_normalise_mapped (union sockunion
*su
)
109 struct sockaddr_in sin
;
111 if (su
->sa
.sa_family
== AF_INET6
112 && IN6_IS_ADDR_V4MAPPED (&su
->sin6
.sin6_addr
))
114 memset (&sin
, 0, sizeof (struct sockaddr_in
));
115 sin
.sin_family
= AF_INET
;
116 sin
.sin_port
= su
->sin6
.sin6_port
;
117 memcpy (&sin
.sin_addr
, ((char *)&su
->sin6
.sin6_addr
) + 12, 4);
118 memcpy (su
, &sin
, sizeof (struct sockaddr_in
));
122 /* return sockunion structure : this function should be revised. */
124 sockunion_log (const union sockunion
*su
, char *buf
, size_t len
)
126 switch (su
->sa
.sa_family
)
129 return inet_ntop(AF_INET
, &su
->sin
.sin_addr
, buf
, len
);
132 return inet_ntop(AF_INET6
, &(su
->sin6
.sin6_addr
), buf
, len
);
136 snprintf (buf
, len
, "af_unknown %d ", su
->sa
.sa_family
);
141 /* Return socket of sockunion. */
143 sockunion_socket (const union sockunion
*su
)
147 sock
= socket (su
->sa
.sa_family
, SOCK_STREAM
, 0);
150 char buf
[SU_ADDRSTRLEN
];
151 zlog (NULL
, LOG_WARNING
, "Can't make socket for %s : %s",
152 sockunion_log (su
, buf
, SU_ADDRSTRLEN
), safe_strerror (errno
));
159 /* Return accepted new socket file descriptor. */
161 sockunion_accept (int sock
, union sockunion
*su
)
166 len
= sizeof (union sockunion
);
167 client_sock
= accept (sock
, (struct sockaddr
*) su
, &len
);
169 sockunion_normalise_mapped (su
);
173 /* Return sizeof union sockunion. */
175 sockunion_sizeof (const union sockunion
*su
)
180 switch (su
->sa
.sa_family
)
183 ret
= sizeof (struct sockaddr_in
);
186 ret
= sizeof (struct sockaddr_in6
);
192 /* sockunion_connect returns
195 1 : connect is in progress */
197 sockunion_connect (int fd
, const union sockunion
*peersu
, unsigned short port
,
204 memcpy (&su
, peersu
, sizeof (union sockunion
));
206 switch (su
.sa
.sa_family
)
209 su
.sin
.sin_port
= port
;
212 su
.sin6
.sin6_port
= port
;
214 if (IN6_IS_ADDR_LINKLOCAL(&su
.sin6
.sin6_addr
) && ifindex
)
216 su
.sin6
.sin6_scope_id
= ifindex
;
217 SET_IN6_LINKLOCAL_IFINDEX (su
.sin6
.sin6_addr
, ifindex
);
223 /* Make socket non-block. */
224 val
= fcntl (fd
, F_GETFL
, 0);
225 fcntl (fd
, F_SETFL
, val
|O_NONBLOCK
);
227 /* Call connect function. */
228 ret
= connect (fd
, (struct sockaddr
*) &su
, sockunion_sizeof (&su
));
230 /* Immediate success */
233 fcntl (fd
, F_SETFL
, val
);
234 return connect_success
;
237 /* If connect is in progress then return 1 else it's real error. */
240 if (errno
!= EINPROGRESS
)
242 char str
[SU_ADDRSTRLEN
];
243 zlog_info ("can't connect to %s fd %d : %s",
244 sockunion_log (&su
, str
, sizeof str
),
245 fd
, safe_strerror (errno
));
246 return connect_error
;
250 fcntl (fd
, F_SETFL
, val
);
252 return connect_in_progress
;
255 /* Make socket from sockunion union. */
257 sockunion_stream_socket (union sockunion
*su
)
261 if (su
->sa
.sa_family
== 0)
262 su
->sa
.sa_family
= AF_INET_UNION
;
264 sock
= socket (su
->sa
.sa_family
, SOCK_STREAM
, 0);
267 zlog (NULL
, LOG_WARNING
, "can't make socket sockunion_stream_socket");
272 /* Bind socket to specified address. */
274 sockunion_bind (int sock
, union sockunion
*su
, unsigned short port
,
275 union sockunion
*su_addr
)
280 if (su
->sa
.sa_family
== AF_INET
)
282 size
= sizeof (struct sockaddr_in
);
283 su
->sin
.sin_port
= htons (port
);
284 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
285 su
->sin
.sin_len
= size
;
286 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
288 sockunion2ip (su
) = htonl (INADDR_ANY
);
290 else if (su
->sa
.sa_family
== AF_INET6
)
292 size
= sizeof (struct sockaddr_in6
);
293 su
->sin6
.sin6_port
= htons (port
);
295 su
->sin6
.sin6_len
= size
;
296 #endif /* SIN6_LEN */
300 memset (&su
->sin6
.sin6_addr
, 0, sizeof (struct in6_addr
));
302 su
->sin6
.sin6_addr
= in6addr_any
;
303 #endif /* LINUX_IPV6 */
307 ret
= bind (sock
, (struct sockaddr
*)su
, size
);
310 char buf
[SU_ADDRSTRLEN
];
311 zlog (NULL
, LOG_WARNING
, "can't bind socket for %s : %s",
312 sockunion_log (su
, buf
, SU_ADDRSTRLEN
), safe_strerror (errno
));
319 sockopt_reuseaddr (int sock
)
324 ret
= setsockopt (sock
, SOL_SOCKET
, SO_REUSEADDR
,
325 (void *) &on
, sizeof (on
));
328 zlog (NULL
, LOG_WARNING
, "can't set sockopt SO_REUSEADDR to socket %d", sock
);
336 sockopt_reuseport (int sock
)
341 ret
= setsockopt (sock
, SOL_SOCKET
, SO_REUSEPORT
,
342 (void *) &on
, sizeof (on
));
345 zlog (NULL
, LOG_WARNING
, "can't set sockopt SO_REUSEPORT to socket %d", sock
);
352 sockopt_reuseport (int sock
)
359 sockopt_ttl (int family
, int sock
, int ttl
)
364 if (family
== AF_INET
)
366 ret
= setsockopt (sock
, IPPROTO_IP
, IP_TTL
,
367 (void *) &ttl
, sizeof (int));
370 zlog (NULL
, LOG_WARNING
, "can't set sockopt IP_TTL %d to socket %d", ttl
, sock
);
376 if (family
== AF_INET6
)
378 ret
= setsockopt (sock
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
,
379 (void *) &ttl
, sizeof (int));
382 zlog (NULL
, LOG_WARNING
, "can't set sockopt IPV6_UNICAST_HOPS %d to socket %d",
392 sockopt_cork (int sock
, int onoff
)
395 return setsockopt (sock
, IPPROTO_TCP
, TCP_CORK
, &onoff
, sizeof(onoff
));
401 int sockopt_mark_default(int sock
, int mark
, struct zebra_privs_t
*cap
)
406 if ( cap
->change (ZPRIVS_RAISE
) )
407 zlog_err ("routing_socket: Can't raise privileges");
409 ret
= setsockopt(sock
, SOL_SOCKET
, SO_MARK
, &mark
, sizeof(mark
));
411 if ( cap
->change (ZPRIVS_LOWER
) )
412 zlog_err ("routing_socket: Can't lower privileges");
421 sockopt_minttl (int family
, int sock
, int minttl
)
424 if (family
== AF_INET
)
426 int ret
= setsockopt (sock
, IPPROTO_IP
, IP_MINTTL
, &minttl
, sizeof(minttl
));
428 zlog (NULL
, LOG_WARNING
,
429 "can't set sockopt IP_MINTTL to %d on socket %d: %s",
430 minttl
, sock
, safe_strerror (errno
));
433 #endif /* IP_MINTTL */
434 #ifdef IPV6_MINHOPCOUNT
435 if (family
== AF_INET6
)
437 int ret
= setsockopt (sock
, IPPROTO_IPV6
, IPV6_MINHOPCOUNT
, &minttl
, sizeof(minttl
));
439 zlog (NULL
, LOG_WARNING
,
440 "can't set sockopt IPV6_MINHOPCOUNT to %d on socket %d: %s",
441 minttl
, sock
, safe_strerror (errno
));
451 sockopt_v6only (int family
, int sock
)
456 if (family
== AF_INET6
)
458 ret
= setsockopt (sock
, IPPROTO_IPV6
, IPV6_V6ONLY
,
459 (void *) &on
, sizeof (int));
462 zlog (NULL
, LOG_WARNING
, "can't set sockopt IPV6_V6ONLY "
463 "to socket %d", sock
);
468 #endif /* IPV6_V6ONLY */
472 /* If same family and same prefix return 1. */
474 sockunion_same (const union sockunion
*su1
, const union sockunion
*su2
)
478 if (su1
->sa
.sa_family
!= su2
->sa
.sa_family
)
481 switch (su1
->sa
.sa_family
)
484 ret
= memcmp (&su1
->sin
.sin_addr
, &su2
->sin
.sin_addr
,
485 sizeof (struct in_addr
));
488 ret
= memcmp (&su1
->sin6
.sin6_addr
, &su2
->sin6
.sin6_addr
,
489 sizeof (struct in6_addr
));
490 if ((ret
== 0) && IN6_IS_ADDR_LINKLOCAL(&su1
->sin6
.sin6_addr
))
492 /* compare interface indices */
493 if (su1
->sin6
.sin6_scope_id
&& su2
->sin6
.sin6_scope_id
)
494 ret
= (su1
->sin6
.sin6_scope_id
== su2
->sin6
.sin6_scope_id
) ? 0 : 1;
505 sockunion_hash (const union sockunion
*su
)
507 switch (sockunion_family(su
))
510 return jhash_1word(su
->sin
.sin_addr
.s_addr
, 0);
512 return jhash2(su
->sin6
.sin6_addr
.s6_addr32
, ZEBRA_NUM_OF(su
->sin6
.sin6_addr
.s6_addr32
), 0);
518 family2addrsize(int family
)
523 return sizeof(struct in_addr
);
525 return sizeof(struct in6_addr
);
531 sockunion_get_addrlen(const union sockunion
*su
)
533 return family2addrsize(sockunion_family(su
));
537 sockunion_get_addr(const union sockunion
*su
)
539 switch (sockunion_family(su
))
542 return (const u_char
*) &su
->sin
.sin_addr
.s_addr
;
544 return (const u_char
*) &su
->sin6
.sin6_addr
;
550 sockunion_set(union sockunion
*su
, int family
, const u_char
*addr
, size_t bytes
)
552 if (family2addrsize(family
) != bytes
)
555 sockunion_family(su
) = family
;
559 memcpy(&su
->sin
.sin_addr
.s_addr
, addr
, bytes
);
562 memcpy(&su
->sin6
.sin6_addr
, addr
, bytes
);
567 /* After TCP connection is established. Get local address and port. */
569 sockunion_getsockname (int fd
)
576 struct sockaddr_in sin
;
577 struct sockaddr_in6 sin6
;
578 char tmp_buffer
[128];
582 memset (&name
, 0, sizeof name
);
585 ret
= getsockname (fd
, (struct sockaddr
*)&name
, &len
);
588 zlog_warn ("Can't get local address and port by getsockname: %s",
589 safe_strerror (errno
));
593 if (name
.sa
.sa_family
== AF_INET
)
595 su
= XCALLOC (MTYPE_SOCKUNION
, sizeof (union sockunion
));
596 memcpy (su
, &name
, sizeof (struct sockaddr_in
));
599 if (name
.sa
.sa_family
== AF_INET6
)
601 su
= XCALLOC (MTYPE_SOCKUNION
, sizeof (union sockunion
));
602 memcpy (su
, &name
, sizeof (struct sockaddr_in6
));
603 sockunion_normalise_mapped (su
);
609 /* After TCP connection is established. Get remote address and port. */
611 sockunion_getpeername (int fd
)
618 struct sockaddr_in sin
;
619 struct sockaddr_in6 sin6
;
620 char tmp_buffer
[128];
624 memset (&name
, 0, sizeof name
);
626 ret
= getpeername (fd
, (struct sockaddr
*)&name
, &len
);
629 zlog (NULL
, LOG_WARNING
, "Can't get remote address and port: %s",
630 safe_strerror (errno
));
634 if (name
.sa
.sa_family
== AF_INET
)
636 su
= XCALLOC (MTYPE_SOCKUNION
, sizeof (union sockunion
));
637 memcpy (su
, &name
, sizeof (struct sockaddr_in
));
640 if (name
.sa
.sa_family
== AF_INET6
)
642 su
= XCALLOC (MTYPE_SOCKUNION
, sizeof (union sockunion
));
643 memcpy (su
, &name
, sizeof (struct sockaddr_in6
));
644 sockunion_normalise_mapped (su
);
650 /* Print sockunion structure */
651 static void __attribute__ ((unused
))
652 sockunion_print (const union sockunion
*su
)
657 switch (su
->sa
.sa_family
)
660 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
),
674 struct sockaddr_dl
*sdl
;
676 sdl
= (struct sockaddr_dl
*)&(su
->sa
);
677 printf ("link#%d\n", sdl
->sdl_index
);
682 printf ("af_unknown %d\n", su
->sa
.sa_family
);
688 in6addr_cmp (const struct in6_addr
*addr1
, const struct in6_addr
*addr2
)
691 const u_char
*p1
, *p2
;
693 p1
= (const u_char
*)addr1
;
694 p2
= (const u_char
*)addr2
;
696 for (i
= 0; i
< sizeof (struct in6_addr
); i
++)
700 else if (p1
[i
] < p2
[i
])
707 sockunion_cmp (const union sockunion
*su1
, const union sockunion
*su2
)
709 if (su1
->sa
.sa_family
> su2
->sa
.sa_family
)
711 if (su1
->sa
.sa_family
< su2
->sa
.sa_family
)
714 if (su1
->sa
.sa_family
== AF_INET
)
716 if (ntohl (sockunion2ip (su1
)) == ntohl (sockunion2ip (su2
)))
718 if (ntohl (sockunion2ip (su1
)) > ntohl (sockunion2ip (su2
)))
723 if (su1
->sa
.sa_family
== AF_INET6
)
724 return in6addr_cmp (&su1
->sin6
.sin6_addr
, &su2
->sin6
.sin6_addr
);
728 /* Duplicate sockunion. */
730 sockunion_dup (const union sockunion
*su
)
732 union sockunion
*dup
= XCALLOC (MTYPE_SOCKUNION
, sizeof (union sockunion
));
733 memcpy (dup
, su
, sizeof (union sockunion
));
738 sockunion_free (union sockunion
*su
)
740 XFREE (MTYPE_SOCKUNION
, su
);
744 sockunion_init (union sockunion
*su
)
746 memset(su
, 0, sizeof(union sockunion
));