summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/prefix.h52
-rw-r--r--lib/qafi_safi.h5
-rw-r--r--lib/qfstring.c234
-rw-r--r--lib/qfstring.h11
-rw-r--r--lib/smux.c9
-rw-r--r--lib/sockopt.c1145
-rw-r--r--lib/sockopt.h41
-rw-r--r--lib/sockunion.c403
-rw-r--r--lib/sockunion.h47
-rw-r--r--lib/thread.c8
-rw-r--r--lib/vty_io.c1
-rw-r--r--lib/vty_io_term.c38
12 files changed, 1349 insertions, 645 deletions
diff --git a/lib/prefix.h b/lib/prefix.h
index bc44244c..7944fd69 100644
--- a/lib/prefix.h
+++ b/lib/prefix.h
@@ -40,8 +40,8 @@ typedef const union sockunion* const_sockunion ;
/* IPv4 and IPv6 unified prefix structure. */
struct prefix
{
- u_char family;
- u_char prefixlen;
+ sa_family_t family;
+ u_char prefixlen;
union
{
u_char prefix;
@@ -61,36 +61,66 @@ struct prefix
/* IPv4 prefix structure. */
struct prefix_ipv4
{
- u_char family;
- u_char prefixlen;
+ sa_family_t family;
+ u_char prefixlen;
struct in_addr prefix __attribute__ ((aligned (8)));
};
+CONFIRM(offsetof(struct prefix_ipv4, family)
+ == offsetof(struct prefix, family)) ;
+CONFIRM(offsetof(struct prefix_ipv4, prefixlen)
+ == offsetof(struct prefix, prefixlen)) ;
+CONFIRM(offsetof(struct prefix_ipv4, prefix)
+ == offsetof(struct prefix, u.prefix4)) ;
+CONFIRM(sizeof(struct prefix_ipv4) <= sizeof(struct prefix)) ;
/* IPv6 prefix structure. */
#ifdef HAVE_IPV6
struct prefix_ipv6
{
- u_char family;
- u_char prefixlen;
+ sa_family_t family;
+ u_char prefixlen;
struct in6_addr prefix __attribute__ ((aligned (8)));
};
+CONFIRM(offsetof(struct prefix_ipv6, family)
+ == offsetof(struct prefix, family)) ;
+CONFIRM(offsetof(struct prefix_ipv6, prefixlen)
+ == offsetof(struct prefix, prefixlen)) ;
+CONFIRM(offsetof(struct prefix_ipv6, prefix)
+ == offsetof(struct prefix, u.prefix6)) ;
+CONFIRM(sizeof(struct prefix_ipv6) <= sizeof(struct prefix)) ;
#endif /* HAVE_IPV6 */
struct prefix_ls
{
- u_char family;
- u_char prefixlen;
+ sa_family_t family;
+ u_char prefixlen;
struct in_addr id __attribute__ ((aligned (8)));
struct in_addr adv_router;
};
+CONFIRM(offsetof(struct prefix_ls, family)
+ == offsetof(struct prefix, family)) ;
+CONFIRM(offsetof(struct prefix_ls, prefixlen)
+ == offsetof(struct prefix, prefixlen)) ;
+CONFIRM(offsetof(struct prefix_ls, id)
+ == offsetof(struct prefix, u.lp.id)) ;
+CONFIRM(offsetof(struct prefix_ls, adv_router)
+ == offsetof(struct prefix, u.lp.adv_router)) ;
+CONFIRM(sizeof(struct prefix_ls) <= sizeof(struct prefix)) ;
/* Prefix for routing distinguisher. */
struct prefix_rd
{
- u_char family;
- u_char prefixlen;
- u_char val[8] __attribute__ ((aligned (8)));
+ sa_family_t family;
+ u_char prefixlen;
+ u_char val[8] __attribute__ ((aligned (8)));
};
+CONFIRM(offsetof(struct prefix_rd, family)
+ == offsetof(struct prefix, family)) ;
+CONFIRM(offsetof(struct prefix_rd, prefixlen)
+ == offsetof(struct prefix, prefixlen)) ;
+CONFIRM(offsetof(struct prefix_rd, val)
+ == offsetof(struct prefix, u.val)) ;
+CONFIRM(sizeof(struct prefix_rd) <= sizeof(struct prefix)) ;
#ifndef INET_ADDRSTRLEN
#define INET_ADDRSTRLEN 16
diff --git a/lib/qafi_safi.h b/lib/qafi_safi.h
index c93b741e..5559097d 100644
--- a/lib/qafi_safi.h
+++ b/lib/qafi_safi.h
@@ -139,11 +139,6 @@ typedef struct qAFI_SAFI qAFI_SAFI_t ;
typedef struct qAFI_SAFI* qAFI_SAFI ;
/*==============================================================================
- * POSIX address family type
- */
-typedef int pAF_t ;
-
-/*==============================================================================
* Quagga AFI/SAFI values -- original macro definitions
*/
diff --git a/lib/qfstring.c b/lib/qfstring.c
index 9f2e2e9c..eda2aa9a 100644
--- a/lib/qfstring.c
+++ b/lib/qfstring.c
@@ -20,6 +20,8 @@
*/
#include "misc.h"
+#include <stdio.h>
+
#include "qfstring.h"
/*==============================================================================
@@ -397,7 +399,9 @@ qfs_pointer(qf_str qfs, void* p_val, enum pf_flags flags,
* pf_plus -- requires '+' or '-'
* pf_space -- requires space or '-'
* pf_zeros -- zero fill to width
- * pf_alt -- add '0x' or '0X' if hex (no effect on decimal)
+ * pf_alt -- add '0x' or '0X' if hex -- depending on pf_uc
+ * add '0' if octal and not zero.
+ * no effect otherwise
*
* pf_precision -- explicit precision (needed if precision == 0)
*
@@ -430,7 +434,11 @@ qfs_pointer(qf_str qfs, void* p_val, enum pf_flags flags,
*
* * pf_unsigned or sign == 0 takes precedence over pf_plus and pf_space.
*
- * For hex output, pf_commas groups digits in 4's, separated by '_'.
+ * For decimal output, pf_commas groups digits in 3's, separated by ','.
+ * For hex output, pf_commas groups digits in 4's, separated by '_'.
+ * For oct output, pf_commas is ignored.
+ *
+ * Note that pf_commas is a glibc extension, which does not apply to hex !
*
* For hex output if precision is:
*
@@ -521,6 +529,9 @@ qfs_number(qf_str qfs, uintmax_t val, int sign, enum pf_flags flags,
if ((flags & pf_precision) || (width <= 0))
flags &= ~pf_zeros ; /* turn off zero fill */
+ if (flags & pf_oct)
+ flags &= ~pf_commas ; /* turn off commas */
+
/* Set up any required sign and radix prefix */
if ((flags & pf_unsigned) || (sign == 0))
{
@@ -548,15 +559,22 @@ qfs_number(qf_str qfs, uintmax_t val, int sign, enum pf_flags flags,
sign_len = 0 ;
} ;
- if ((flags & (pf_hex | pf_alt)) == (pf_hex | pf_alt))
- {
- radix_str = (flags & pf_uc) ? "0X" : "0x" ;
- radix_len = 2 ;
- }
- else
+ radix_str = "" ;
+ radix_len = 0 ;
+
+ if (flags & pf_alt)
{
- radix_str = "" ;
- radix_len = 0 ;
+ if (flags & pf_hex)
+ {
+ confirm(pf_uc != 0) ;
+ radix_str = (flags & pf_uc) ? "0X" : "0x" ;
+ radix_len = 2 ;
+ }
+ else if ((flags & pf_oct) && (val != 0))
+ {
+ radix_str = "0" ;
+ radix_len = 1 ;
+ } ;
} ;
/* Turn off zero fill if left justify (width < 0) */
@@ -574,8 +592,14 @@ qfs_number(qf_str qfs, uintmax_t val, int sign, enum pf_flags flags,
} ;
/* Start with the basic digit conversion. */
- base = (flags & pf_hex) ? 16 : 10 ;
+ base = 10 ;
+ if (flags & pf_hex)
+ base = 16 ;
+ else if (flags & pf_oct)
+ base = 8 ;
+
digits = (flags & pf_uc) ? uc : lc ;
+ confirm(pf_uc != 0) ;
e = p = num + sizeof(num) ;
v = val ;
@@ -734,12 +758,15 @@ enum pf_phase
pfp_flags,
pfp_width,
pfp_precision,
- pfp_num_type,
+ pfp_int_type,
+ pfp_float_type,
pfp_done,
pfp_failed
} ;
+CONFIRM(pfp_float_type > pfp_int_type) ;
+
/* Number types for printing */
enum arg_num_type
{
@@ -750,7 +777,8 @@ enum arg_num_type
ant_long_long, /* ll */
ant_intmax_t, /* j */
ant_size_t, /* z */
- ant_ptr_t, /* %p */
+ ant_ptr_t, /* void* */
+ ant_long_double, /* L for float */
ant_default = ant_int,
};
@@ -759,14 +787,16 @@ static enum pf_phase qfs_arg_string(qf_str qfs, const char* src,
enum pf_flags flags, int width, int precision) ;
static enum pf_phase qfs_arg_char(qf_str qfs, char ch,
enum pf_flags flags, int width, int precision) ;
-static enum pf_phase qfs_arg_number(qf_str qfs, va_list* p_va,
+static enum pf_phase qfs_arg_integer(qf_str qfs, va_list* p_va,
enum pf_flags flags, int width, int precision, enum arg_num_type ant) ;
+static enum pf_phase qfs_arg_float(qf_str qfs, va_list* p_va,
+ const char* start, size_t flen, enum arg_num_type ant) ;
/*------------------------------------------------------------------------------
* Formatted print to qf_str -- cf printf() -- appends to the qf_str.
*
- * This operation is async-signal-safe. Takes into account the offset, and
- * adds up any overflow.
+ * This operation is async-signal-safe -- EXCEPT for floating point values.
+ * Takes into account the offset, and adds up any overflow.
*
* Returns: the resulting length of the qf_str.
*/
@@ -786,8 +816,8 @@ qfs_printf(qf_str qfs, const char* format, ...)
/*------------------------------------------------------------------------------
* Formatted print to qf_str -- cf vprintf() -- appends to the qf_str.
*
- * This operation is async-signal-safe. Takes into account the offset, and
- * adds up any overflow
+ * This operation is async-signal-safe -- EXCEPT for floating point values.
+ * Takes into account the offset, and adds up any overflow.
*
* Operates on a copy of the va_list -- so the original is *unchanged*.
*
@@ -851,6 +881,11 @@ qfs_vprintf(qf_str qfs, const char *format, va_list va)
phase = (phase <= pfp_flags) ? pfp_flags : pfp_failed ;
break ;
+ case '#':
+ flags |= pf_alt ;
+ phase = (phase <= pfp_flags) ? pfp_flags : pfp_failed ;
+ break ;
+
case ' ':
flags |= pf_space ;
phase = (phase <= pfp_flags) ? pfp_flags : pfp_failed ;
@@ -909,13 +944,13 @@ qfs_vprintf(qf_str qfs, const char *format, va_list va)
break ;
case '.':
- phase = (phase <= pfp_precision) ? pfp_precision : pfp_failed;
+ phase = (phase < pfp_precision) ? pfp_precision : pfp_failed ;
flags |= pf_precision ;
precision = 0 ;
break ;
case 'l': /* 1 or 2 'l', not 'h', 'j' or 'z' */
- phase = pfp_num_type ;
+ phase = (phase <= pfp_int_type) ? pfp_int_type : pfp_failed ;
if (ant == ant_default)
ant = ant_long ;
else if (ant == ant_long)
@@ -925,7 +960,7 @@ qfs_vprintf(qf_str qfs, const char *format, va_list va)
break ;
case 'h': /* 1 or 2 'h', not 'l', 'j' or 'z' */
- phase = pfp_num_type ;
+ phase = (phase <= pfp_int_type) ? pfp_int_type : pfp_failed ;
if (ant == ant_default)
ant = ant_short ;
else if (ant == ant_short)
@@ -935,17 +970,22 @@ qfs_vprintf(qf_str qfs, const char *format, va_list va)
break ;
case 'j': /* 1 'j', not 'h', 'l' or 'z' */
- phase = (phase <= pfp_num_type) ? pfp_num_type : pfp_failed ;
+ phase = (phase <= pfp_int_type) ? pfp_int_type : pfp_failed ;
ant = ant_intmax_t ;
break ;
case 'z': /* 1 'z', not 'h', 'l' or 'j' */
- phase = (phase <= pfp_num_type) ? pfp_num_type : pfp_failed ;
+ phase = (phase <= pfp_int_type) ? pfp_int_type : pfp_failed ;
ant = ant_size_t ;
break ;
+ case 'L': /* 1 'L', not for integers ! */
+ phase = (phase < pfp_int_type) ? pfp_float_type : pfp_failed ;
+ ant = ant_long_double ;
+ break ;
+
case 's':
- if (phase == pfp_num_type)
+ if (phase == pfp_int_type)
phase = pfp_failed ; /* don't do 'l' etc. */
else
phase = qfs_arg_string(qfs, va_arg(vac, char*),
@@ -953,7 +993,7 @@ qfs_vprintf(qf_str qfs, const char *format, va_list va)
break ;
case 'c':
- if (phase == pfp_num_type)
+ if (phase == pfp_int_type)
phase = pfp_failed ; /* don't do 'l' etc. */
else
phase = qfs_arg_char(qfs, (char)va_arg(vac, int),
@@ -962,33 +1002,53 @@ qfs_vprintf(qf_str qfs, const char *format, va_list va)
case 'd':
case 'i':
- phase = qfs_arg_number(qfs, &vac, flags, width, precision,
+ phase = qfs_arg_integer(qfs, &vac, flags, width, precision,
ant) ;
break ;
case 'u':
- phase = qfs_arg_number(qfs, &vac, flags | pf_unsigned, width,
+ phase = qfs_arg_integer(qfs, &vac, flags | pf_unsigned, width,
+ precision, ant) ;
+ break ;
+
+ case 'o':
+ phase = qfs_arg_integer(qfs, &vac, flags | pf_oct, width,
precision, ant) ;
break ;
case 'x':
- phase = qfs_arg_number(qfs, &vac, flags | pf_hex_x, width,
+ phase = qfs_arg_integer(qfs, &vac, flags | pf_hex_x, width,
precision, ant) ;
break ;
case 'X':
- phase = qfs_arg_number(qfs, &vac, flags | pf_hex_X, width,
+ phase = qfs_arg_integer(qfs, &vac, flags | pf_hex_X, width,
precision, ant) ;
break ;
case 'p':
- if (phase == pfp_num_type)
+ if (phase == pfp_int_type)
phase = pfp_failed ;
else
- phase = qfs_arg_number(qfs, &vac, flags | pf_void_p, width,
+ phase = qfs_arg_integer(qfs, &vac, flags | pf_void_p, width,
precision, ant_ptr_t) ;
break ;
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'F':
+ case 'g':
+ case 'G':
+ case 'a':
+ case 'A':
+ if (phase == pfp_int_type)
+ phase = pfp_failed ;
+ else
+ phase = qfs_arg_float(qfs, &vac, start, format - start,
+ ant) ;
+ break ;
+
default: /* unrecognised format */
phase = pfp_failed ;
break ;
@@ -1089,14 +1149,16 @@ qfs_arg_char(qf_str qfs, char ch, enum pf_flags flags, int width, int precision)
} ;
/*------------------------------------------------------------------------------
- * %d, %i, %u, %x, %X and %p handler
+ * %d, %i, %u, %o, %x, %X and %p handler
*
- * Accepts: pf_commas -- format with commas
+ * Accepts: pf_commas -- format with commas or '_' for hex (non-standard)
+ * ignored for octal.
* pf_minus -- left justify (any width will be -ve)
* pf_plus -- requires sign
* pf_space -- requires space or '-'
* pf_zeros -- zero fill to width
* pf_alt -- '0x' or '0X' for hex
+ * '0' for octal
*
* pf_precision -- precision specified
*
@@ -1107,16 +1169,24 @@ qfs_arg_char(qf_str qfs, char ch, enum pf_flags flags, int width, int precision)
*
* and: all the number argument types.
*
+ * Rejects: ant == ant_long_double -- which is how the parser spots an
+ * erroneous %Ld for example.
+ *
* This operation is async-signal-safe. Takes into account the offset, and
* adds up any overflow
*/
static enum pf_phase
-qfs_arg_number(qf_str qfs, va_list* p_va, enum pf_flags flags,
+qfs_arg_integer(qf_str qfs, va_list* p_va, enum pf_flags flags,
int width, int precision, enum arg_num_type ant)
{
uintmax_t u_val ;
intmax_t s_val ;
+ /* Reject if seen an 'L'
+ */
+ if (ant == ant_long_double)
+ return pfp_failed ;
+
/* Special for hex with '0... if no explicit precision, set -1 for byte
* and -2 for everything else -- see qfs_number().
*/
@@ -1208,3 +1278,99 @@ qfs_arg_number(qf_str qfs, va_list* p_va, enum pf_flags flags,
return pfp_done ;
} ;
+/*------------------------------------------------------------------------------
+ * %e, %E, %f, %F, %g, %G, %a and %A handler
+ *
+ * This uses the standard library sprintf() to do the business, so this is
+ * NOT async-signal-safe. This means that we get the full precision supported
+ * by the system ! Attempting to construct async-signal-safe conversion is
+ * doomed to failure, because any floating point operation may affect flags
+ * and other state in the processor :-(
+ *
+ * This operation is *NOT* async-signal-safe. Takes into account the offset,
+ * and adds up any overflow
+ */
+
+union float_value
+{
+ double d ;
+ long double ld ;
+} ;
+
+static int
+qfs_arg_float_snprintf(void* buf, int have, const char* format,
+ union float_value* p_val, enum arg_num_type ant)
+{
+ if (ant == ant_default)
+ return snprintf(buf, have, format, p_val->d) ;
+ else
+ return snprintf(buf, have, format, p_val->ld) ;
+} ;
+
+static enum pf_phase
+qfs_arg_float(qf_str qfs, va_list* p_va, const char* start, size_t flen,
+ enum arg_num_type ant)
+{
+ union float_value val ;
+ char format[flen + 1] ;
+ int want ;
+
+ if (ant == ant_default)
+ val.d = va_arg(*p_va, double) ;
+ else
+ val.ld = va_arg(*p_va, long double) ;
+
+ memcpy(format, start, flen) ;
+ format[flen + 1] = '\0' ;
+
+ if (qfs->offset == 0)
+ {
+ /* No offset, so can use the qfs directly.
+ */
+ int have ;
+
+ have = qfs_left(qfs) ;
+ want = qfs_arg_float_snprintf(qfs->ptr, have + 1, format, &val, ant) ;
+
+ if (want > 0)
+ {
+ if (want <= have)
+ qfs->ptr += want ;
+ else
+ {
+ qfs->ptr = qfs->end ;
+ qfs->overflow += (want - have) ;
+ } ;
+ } ;
+ }
+ else
+ {
+ /* Because the offset is not zero, need to use an intermediate
+ * buffer and then copy part after the offset.
+ *
+ * First, discover full extent of the formatted value, then if that
+ * exceeds the offset, construct buffer and copy what we can to the
+ * qps; otherwise, reduce the offset.
+ */
+ want = qfs_arg_float_snprintf(NULL, 0, format, &val, ant) ;
+
+ if (want > 0)
+ {
+ int take ;
+
+ take = qfs->offset + qfs_left(qfs) ;
+ if (take > want)
+ take = want ;
+
+ {
+ char tmp[take + 1] ;
+ want = qfs_arg_float_snprintf(tmp, take + 1, format, &val, ant) ;
+
+ if (want > 0)
+ qfs_append_n(qfs, tmp, want) ;
+ } ;
+ } ;
+ } ;
+
+ return (want >= 0) ? pfp_done : pfp_failed ;
+} ;
diff --git a/lib/qfstring.h b/lib/qfstring.h
index 03204c3d..be858899 100644
--- a/lib/qfstring.h
+++ b/lib/qfstring.h
@@ -26,11 +26,15 @@
#include "vargs.h"
/*==============================================================================
- * These "qfstrings" address the issues of dealing with *fixed* length
+ * These "qfstring" address the issues of dealing with *fixed* length
* strings, particularly where the string handling must be async-signal-safe.
*
* Are also used to support snprintf() style printing, but to one or more
* fixed length buffers.
+ *
+ * All operations that can possibly be async-signal-safe, are. Notable
+ * exception is anything involving floating point values -- because of the
+ * state contain in floating point status/option registers !
*/
/* When initialised a qf_string is set:
@@ -75,8 +79,9 @@ enum pf_flags
pf_precision = BIT( 7), /* '.' seen */
/* The following signal how to render the value */
- pf_hex = BIT( 8), /* hex */
- pf_uc = BIT( 9), /* upper-case */
+ pf_oct = BIT( 8), /* octal */
+ pf_hex = BIT( 9), /* hex */
+ pf_uc = BIT(10), /* upper-case */
/* The following signal the type of value */
pf_ptr = BIT(14), /* is a pointer */
diff --git a/lib/smux.c b/lib/smux.c
index df02dd44..cd3d2edf 100644
--- a/lib/smux.c
+++ b/lib/smux.c
@@ -38,6 +38,7 @@
#include <lib/version.h>
#include "memory.h"
#include "sockunion.h"
+#include "sockopt.h"
#include "smux.h"
#define min(A,B) ((A) < (B) ? (A) : (B))
@@ -215,8 +216,8 @@ smux_socket (void)
sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (sock < 0)
continue;
- sockopt_reuseaddr (sock);
- sockopt_reuseport (sock);
+ setsockopt_reuseaddr (sock);
+ setsockopt_reuseport (sock);
ret = connect (sock, res->ai_addr, res->ai_addrlen);
if (ret < 0)
{
@@ -251,8 +252,8 @@ smux_socket (void)
serv.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
- sockopt_reuseaddr (sock);
- sockopt_reuseport (sock);
+ setsockopt_reuseaddr (sock);
+ setsockopt_reuseport (sock);
ret = connect (sock, (struct sockaddr *) &serv, sizeof (struct sockaddr_in));
if (ret < 0)
diff --git a/lib/sockopt.c b/lib/sockopt.c
index aa747429..083cafc2 100644
--- a/lib/sockopt.c
+++ b/lib/sockopt.c
@@ -1,4 +1,4 @@
-/* setsockopt functions
+/* Setting and getting socket options -- utility functions.
* Copyright (C) 1999 Kunihiro Ishiguro
*
* This file is part of GNU Zebra.
@@ -20,218 +20,585 @@
*/
#include <zebra.h>
+
#include "log.h"
#include "sockopt.h"
#include "sockunion.h"
#include "pthread_safe.h"
-int
-setsockopt_so_recvbuf (int sock_fd, int size)
+/*------------------------------------------------------------------------------
+ * Set socket SO_REUSEADDR option
+ *
+ * Returns: >= 0 => OK
+ * < 0 => failed -- see errno
+ *
+ * Logs a LOG_WARNING message if fails.
+ */
+extern int
+setsockopt_reuseaddr (int sock_fd)
{
int ret;
+ int on = 1;
- ret = setsockopt (sock_fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)) ;
+ ret = setsockopt (sock_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
if (ret < 0)
{
int err = errno ;
- zlog_err ("socket %d: cannot setsockopt SO_RCVBUF to %d: %s",
- sock_fd, size, errtoa(err, 0).str) ;
+ zlog_warn ("cannot set sockopt SO_REUSEADDR on socket %d: %s", sock_fd,
+ errtoa(err, 0).str) ;
errno = err ;
} ;
- return ret;
+ return ret ;
}
-int
-setsockopt_so_sendbuf (const int sock_fd, int size)
+/*------------------------------------------------------------------------------
+ * Set socket SO_REUSEPORT option -- if it is locally supported.
+ *
+ * Returns: >= 0 => OK -- or not supported
+ * < 0 => failed -- see errno
+ *
+ * Logs a LOG_WARNING message if fails.
+ */
+extern int
+setsockopt_reuseport (int sock_fd)
{
- int ret ;
+ int ret;
- ret = setsockopt (sock_fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
+#ifdef SO_REUSEPORT
+ int on = 1;
+ ret = setsockopt (sock_fd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
+#else
+ ret = 0 ;
+#endif
if (ret < 0)
{
int err = errno ;
- zlog_err ("socket %d: cannot setsockopt SO_SNDBUF to %d: %s",
- sock_fd, size, errtoa(err, 0).str) ;
+ zlog_warn ("cannot set sockopt SO_REUSEPORT on socket %d: %s", sock_fd,
+ errtoa(err, 0).str) ;
errno = err ;
} ;
- return ret;
+ return ret ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Set socket SO_BROADCAST option
+ *
+ * Returns: >= 0 => OK
+ * < 0 => failed -- see errno
+ *
+ * Logs a LOG_WARNING message if fails.
+ */
+extern int
+setsockopt_broadcast (int sock_fd)
+{
+ int ret;
+ int on = 1;
+
+ ret = setsockopt (sock_fd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));
+ if (ret < 0)
+ {
+ int err = errno ;
+ zlog_warn ("cannot set sockopt SO_BROADCAST on socket %d: %s", sock_fd,
+ errtoa(err, 0).str) ;
+ errno = err ;
+ }
+ return ret ;
}
-int
-getsockopt_so_sendbuf (const int sock_fd)
+/*------------------------------------------------------------------------------
+ * Set TCP_CORK, if available.
+ *
+ * Returns: >= 0 => OK -- or not supported
+ * < 0 => failed -- see errno
+ *
+ * Logs a LOG_WARNING message if fails.
+ */
+extern int
+setsockopt_cork (int sock_fd, int onoff)
{
- u_int32_t optval;
- socklen_t optlen = sizeof (optval);
+#ifdef TCP_CORK
+ int ret;
- int ret = getsockopt (sock_fd, SOL_SOCKET, SO_SNDBUF, &optval, &optlen);
+ ret = setsockopt (sock_fd, IPPROTO_TCP, TCP_CORK, &onoff, sizeof(onoff));
if (ret < 0)
- {
- int err = errno ;
- zlog_err ("socket %d: cannot getsockopt SO_SNDBUF: %s",
+ {
+ int err = errno ;
+ zlog_warn ("cannot set sockopt TCP_CORK to %d on socket %d: %s", onoff,
sock_fd, errtoa(err, 0).str) ;
- errno = err ;
- return ret;
- }
-
- return optval;
+ errno = err ;
+ }
+ return ret ;
+#else
+ return 0;
+#endif
}
-static void *
-getsockopt_cmsg_data (struct msghdr *msgh, int level, int type)
+/*------------------------------------------------------------------------------
+ * Set IP_TTL/IPV6_UNICAST_HOPS for socket, if available
+ *
+ * The ttl given is the maximum number of hops to allow -- so will generally
+ * be 1 or 255 or some small number.
+ *
+ * NB: This code treats any ttl outside the range 1..MAXTTL as MAXTTL.
+ *
+ * Returns: >= 0 => OK -- or not supported
+ * < 0 => failed, see errno.
+ *
+ * Logs a LOG_WARNING message if fails.
+ *
+ * NB: for AF_INET6 where have: IN6_IS_ADDR_V4MAPPED, there is the question
+ * of whether to use IPPROTO_IP/IP_TTL or IPPROTO_IPV6/IPV6_UNICAST_HOPS.
+ *
+ * Here we try first to use the socket family, and if that fails on
+ * AF_INET6, then if the protocol family is AF_INET, then tries that.
+ */
+extern int
+setsockopt_ttl (int sock_fd, int ttl)
{
- struct cmsghdr *cmsg;
- void *ptr = NULL;
+ const char* name ;
+ int af ;
+ int ret ;
- for (cmsg = ZCMSG_FIRSTHDR(msgh);
- cmsg != NULL;
- cmsg = CMSG_NXTHDR(msgh, cmsg))
- if (cmsg->cmsg_level == level && cmsg->cmsg_type)
- return (ptr = CMSG_DATA(cmsg));
+ af = sockunion_getsockfamily(sock_fd) ;
+ if (af < 0)
+ return af ;
- return NULL;
-}
+ if ((ttl < 1) || (ttl > MAXTTL))
+ ttl = MAXTTL ;
-#ifdef HAVE_IPV6
-/* Set IPv6 packet info to the socket. */
-int
-setsockopt_ipv6_pktinfo (int sock_fd, int val)
-{
- int ret;
+ ret = 0 ;
+ name = NULL ;
-#ifdef IPV6_RECVPKTINFO /*2292bis-01*/
- ret = setsockopt(sock_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &val, sizeof(val));
- if (ret < 0)
+ while (1)
{
- int err = errno ;
- zlog_warn ("cannot setsockopt IPV6_RECVPKTINFO: %s", errtoa(err, 0).str);
- errno = err ;
+ switch (af)
+ {
+ case AF_INET:
+#ifdef IP_TTL
+ ret = setsockopt (sock_fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
+ name = "IP_TTL" ;
+#endif /* IP_TTL */
+ break ;
+
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ ret = setsockopt (sock_fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
+ &ttl, sizeof(ttl));
+ name = "IPV6_UNICAST_HOPS" ;
+
+ if (ret < 0)
+ {
+ af = sockunion_getprotofamily(sock_fd) ;
+ if (af == AF_INET)
+ continue ;
+ } ;
+ break ;
+#endif
+
+ default: /* ignore unknown family */
+ break ;
+ } ;
+
+ break ;
} ;
-#else /*RFC2292*/
- ret = setsockopt(sock_fd, IPPROTO_IPV6, IPV6_PKTINFO, &val, sizeof(val));
+
if (ret < 0)
{
int err = errno ;
- zlog_warn ("cannot setsockopt IPV6_PKTINFO: %s", errtoa(err, 0).str);
+ zlog_warn("cannot set sockopt %s to %d on socket %d: %s", name, ttl,
+ sock_fd, errtoa(err, 0).str) ;
errno = err ;
} ;
-#endif /* INIA_IPV6 */
- return ret;
-}
-/* Set multicast hops val to the socket. */
-int
-setsockopt_ipv6_checksum (int sock_fd, int val)
+ return ret ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Set IP_MINTTL/IPV6_MINHOPCOUNT (GTSM), if available.
+ *
+ * The ttl given is the maximum number of hops to allow -- so will generally
+ * be 1 -- which is the same as IP_TTL/IPV6_UNICAST_HOPS.
+ *
+ * NB: to turn off GTSM, need to set ttl = MAXTTL. This code treats any ttl
+ * outside the range 1..MAXTTL as MAXTTL.
+ *
+ * The underlying mechanics want MAX_TTL - (ttl - 1) -- and may not
+ * accept a value of zero.
+ *
+ * Returns: >= 0 => OK
+ * < 0 => failed or not supported -- see errno
+ * EOPNOTSUPP if not supported
+ *
+ * Logs a LOG_WARNING message if fails (and is supported).
+ *
+ * NB: for AF_INET6 where have: IN6_IS_ADDR_V4MAPPED, there is the question
+ * of whether to use IPPROTO_IP/IP_TTL or IPPROTO_IPV6/IPV6_UNICAST_HOPS.
+ *
+ * Here we try first to use the socket family, and if that fails on
+ * AF_INET6, then if the protocol family is AF_INET, then tries that.
+ */
+extern int
+setsockopt_minttl (int sock_fd, int ttl)
{
- int ret;
+ const char* name ;
+ int af ;
+ int minttl ;
+ int ret ;
-#ifdef GNU_LINUX
- ret = setsockopt(sock_fd, IPPROTO_RAW, IPV6_CHECKSUM, &val, sizeof(val));
+ af = sockunion_getsockfamily(sock_fd) ;
+ if (af < 0)
+ return af ;
+
+ ret = 0 ;
+ name = NULL ;
+
+ if ((ttl < 1) || (ttl > MAXTTL))
+ ttl = MAXTTL ;
+
+ minttl = MAXTTL - (ttl - 1) ;
+
+ while (1)
+ {
+ enum
+ {
+#ifdef IP_MINTTL
+ have_ip_minttl = true,
#else
- ret = setsockopt(sock_fd, IPPROTO_IPV6, IPV6_CHECKSUM, &val, sizeof(val));
-#endif /* GNU_LINUX */
+ have_ip_minttl = false,
+#endif
+ ip_minttl = IP_MINTTL + 0
+ } ;
+
+#ifdef HAVE_IPV6
+
+# ifdef GNU_LINUX
+ /* The #include to bring in IPV6_MINHOPCOUNT is buried more or less as
+ * deep as we can get it, because it also redefines a number of things
+ * that we do not want redefined.
+ */
+ #include <linux/in6.h>
+# endif
+
+ enum
+ {
+# ifdef IPV6_MINHOPCOUNT
+ have_ipv6_minhopcount = true,
+# else
+ have_ipv6_minhopcount = false,
+# endif
+ ipv6_minhopcount = IPV6_MINHOPCOUNT + 0
+ } ;
+#endif /* HAVE_IPV6 */
+
+ switch (af)
+ {
+ case AF_INET:
+ name = "IP_MINTTL" ;
+ if (have_ip_minttl)
+ ret = setsockopt (sock_fd, IPPROTO_IP, ip_minttl,
+ &minttl, sizeof(minttl));
+ else
+ {
+ ret = -1 ;
+ errno = EOPNOTSUPP ;
+ } ;
+
+ break ;
+
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ name = "IPV6_MINHOPCOUNT" ;
+ if (have_ipv6_minhopcount)
+ ret = setsockopt (sock_fd, IPPROTO_IPV6, ipv6_minhopcount,
+ &minttl, sizeof(minttl));
+ else
+ {
+ ret = -1 ;
+ errno = EOPNOTSUPP ;
+ } ;
+
+ if (ret < 0)
+ {
+ af = sockunion_getprotofamily(sock_fd) ;
+ if (af == AF_INET)
+ continue ;
+ } ;
+
+ break ;
+#endif /* HAVE_IPV6 */
+
+ default: /* ignore unknown family */
+ break ;
+ } ;
+
+ break ;
+ } ;
+
if (ret < 0)
{
int err = errno ;
- zlog_warn ("cannot setsockopt IPV6_CHECKSUM: %s", errtoa(err, 0).str);
+ zlog_warn("cannot set sockopt %s to %d on socket %d: %s", name, minttl,
+ sock_fd, errtoa(err, 0).str) ;
errno = err ;
} ;
- return ret;
-}
-/* Set multicast hops val to the socket. */
-int
-setsockopt_ipv6_multicast_hops (int sock_fd, int val)
+ return ret ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Set TCP MD5 signature socket option, if available.
+ *
+ * A NULL password or an empty password both signify unsetting the MD5
+ * signature.
+ *
+ * Returns: >= 0 => OK (or not supported, but password NULL or empty)
+ * < 0 => failed or not supported, see errno.
+ *
+ * NB: returns EOPNOTSUPP if TCP MD5 is not supported and password is not NULL
+ * and is not empty.
+ *
+ * Logs a LOG_ERR message if fails (and is supported).
+ */
+extern int
+setsockopt_tcp_signature (int sock_fd, sockunion su, const char *password)
{
- int ret;
+ int ret ;
- ret = setsockopt(sock_fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val,
- sizeof(val));
+ if ((password != NULL) && (*password == '\0'))
+ password = NULL ;
+
+ ret = 0 ; /* so far, so good */
+
+#if defined(HAVE_TCP_MD5_LINUX24) && defined(GNU_LINUX)
+ /* Support for the old Linux 2.4 TCP-MD5 patch, taken from Hasso Tepper's
+ * version of the Quagga patch (based on work by Rick Payne, and Bruce
+ * Simpson)
+ */
+#define TCP_MD5_AUTH 13
+#define TCP_MD5_AUTH_ADD 1
+#define TCP_MD5_AUTH_DEL 2
+ struct tcp_rfc2385_cmd {
+ u_int8_t command; /* Command - Add/Delete */
+ u_int32_t address; /* IPV4 address associated */
+ u_int8_t keylen; /* MD5 Key len (do NOT assume 0 terminated ascii) */
+ void *key; /* MD5 Key */
+ } cmd;
+ struct in_addr *addr = &su->sin.sin_addr;
+
+ cmd.command = (password != NULL ? TCP_MD5_AUTH_ADD : TCP_MD5_AUTH_DEL);
+ cmd.address = addr->s_addr;
+ cmd.keylen = (password != NULL ? strlen (password) : 0);
+ cmd.key = password;
+
+ ret = setsockopt (sock_fd, IPPROTO_TCP, TCP_MD5_AUTH, &cmd, sizeof cmd) ;
if (ret < 0)
{
int err = errno ;
- zlog_warn ("cannot setsockopt IPV6_MULTICAST_HOPS: %s",
- errtoa(err, 0).str);
+ zlog_err("sockopt_tcp_signature: setsockopt(%d): %s",
+ sock_fd, errtoa(err, 0).str) ;
errno = err ;
+ }
+
+#elif HAVE_DECL_TCP_MD5SIG
+
+# ifdef GNU_LINUX
+ struct tcp_md5sig md5sig ;
+# ifdef HAVE_IPV6
+ int saf ;
+ union sockunion sux[1] ;
+# endif
+
+ /* Testing reveals that in order to set an MD5 password for an AF_INET6
+ * socket, the address passed in must be AF_INET6, even if what we are
+ * dealing with here is an IN6_IS_ADDR_V4MAPPED socket.
+ */
+# ifdef HAVE_IPV6
+ saf = sockunion_getsockfamily(sock_fd) ;
+ if (saf < 0)
+ return saf ;
+
+ if ((saf == AF_INET6) && (sockunion_family(su) == AF_INET))
+ {
+ sockunion_copy (sux, su) ;
+ sockunion_map_ipv4 (sux) ;
+ su = sux ; /* substitute v4 mapped address */
} ;
- return ret;
-}
+# endif
-/* Set multicast hops val to the socket. */
-int
-setsockopt_ipv6_unicast_hops (int sock_fd, int val)
-{
- int ret;
+ /* Set address to AF_UNSPEC and key length and everything else to zero,
+ * then copy in the address and the key.
+ */
+ memset (&md5sig, 0, sizeof (md5sig)) ;
+ confirm(AF_UNSPEC == 0) ;
- ret = setsockopt(sock_fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &val, sizeof(val));
- if (ret < 0)
+ memcpy (&md5sig.tcpm_addr, &su->sa, sockunion_get_len(su)) ;
+
+ if (password != NULL)
{
- int err = errno ;
- zlog_warn("cannot setsockopt IPV6_UNICAST_HOPS: %s", errtoa(err, 0).str);
- errno = err ;
+ size_t keylen = strlen(password) ;
+
+ if (md5sig.tcpm_keylen <= TCP_MD5SIG_MAXKEYLEN)
+ {
+ md5sig.tcpm_keylen = keylen ;
+ memcpy (md5sig.tcpm_key, password, keylen);
+ }
+ else
+ {
+ errno = EINVAL ; /* manufactured error */
+ ret = -1 ;
+ } ;
} ;
- return ret;
-}
-int
-setsockopt_ipv6_hoplimit (int sock_fd, int val)
-{
- int ret;
+# else
+ /*
+ * XXX Need to do PF_KEY operation here to add/remove an SA entry,
+ * and add/remove an SP entry for this peer's packet flows also.
+ */
+ int md5sig = (password != NULL) ? 1 : 0;
+
+# endif /* GNU_LINUX */
+
+ if (ret >= 0)
+ {
+ ret = setsockopt(sock_fd, IPPROTO_TCP, TCP_MD5SIG,
+ &md5sig, sizeof(md5sig)) ;
+ if (ret < 0)
+ /* ENOENT is harmless. It is returned when we clear a password where
+ * one was not previously set.
+ */
+ if ((errno == ENOENT) && (password == NULL))
+ ret = 0 ;
+ } ;
+
+#else
+
+ /* TCP MD5 is not supported */
+
+ if (password != NULL)
+ {
+ errno = EOPNOTSUPP ; /* manufactured error */
+ ret = -1 ;
+ } ;
+
+#endif /* !HAVE_TCP_MD5SIG */
-#ifdef IPV6_RECVHOPLIMIT /*2292bis-01*/
- ret = setsockopt (sock_fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &val,
- sizeof(val));
if (ret < 0)
{
int err = errno ;
- zlog_warn("cannot setsockopt IPV6_RECVHOPLIMIT: %s", errtoa(err, 0).str);
+ zlog_err("sockopt_tcp_signature: setsockopt(%d): %s",
+ sock_fd, errtoa(err, 0).str) ;
errno = err ;
} ;
-#else /*RFC2292*/
- ret = setsockopt (sock_fd, IPPROTO_IPV6, IPV6_HOPLIMIT, &val, sizeof(val));
+
+ return ret ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Set SO_RCVBUF option on socket.
+ *
+ * Returns: >= 0 => OK
+ * < 0 => failed, see errno.
+ *
+ * Logs a LOG_ERR message if fails
+ */
+extern int
+setsockopt_so_recvbuf (int sock_fd, int size)
+{
+ int ret;
+
+ ret = setsockopt (sock_fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)) ;
if (ret < 0)
{
int err = errno ;
- zlog_warn ("cannot setsockopt IPV6_HOPLIMIT: %s", errtoa(err, 0).str);
+ zlog_err ("cannot set sockopt SO_RCVBUF to %d on socket %d: %s",
+ size, sock_fd, errtoa(err, 0).str) ;
errno = err ;
} ;
-#endif
+
return ret;
}
-/* Set multicast loop zero to the socket. */
-int
-setsockopt_ipv6_multicast_loop (int sock_fd, int val)
+/*------------------------------------------------------------------------------
+ * Set SO_SNDBUF option on socket.
+ *
+ * Returns: >= 0 => OK
+ * < 0 => failed, see errno.
+ *
+ * Logs a LOG_ERR message if fails
+ */
+extern int
+setsockopt_so_sendbuf (int sock_fd, int size)
{
- int ret;
+ int ret ;
+
+ ret = setsockopt (sock_fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
- ret = setsockopt (sock_fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &val,
- sizeof (val));
if (ret < 0)
{
int err = errno ;
- zlog_warn ("cannot setsockopt IPV6_MULTICAST_LOOP: %s",
- errtoa(err, 0).str);
+ zlog_err("cannot set sockopt SO_SNDBUF to %d on socket %d: %s",
+ size, sock_fd, errtoa(err, 0).str) ;
errno = err ;
} ;
+
return ret;
}
-static int
-getsockopt_ipv6_ifindex (struct msghdr *msgh)
+/*------------------------------------------------------------------------------
+ * Get SO_SNDBUF option value from socket.
+ *
+ * Returns: >= 0 => OK == value of option
+ * < 0 => failed, see errno.
+ *
+ * Logs a LOG_ERR message if fails
+ */
+extern int
+getsockopt_so_sendbuf (int sock_fd)
{
- struct in6_pktinfo *pktinfo;
+ u_int32_t optval;
+ socklen_t optlen = sizeof (optval);
- pktinfo = getsockopt_cmsg_data (msgh, IPPROTO_IPV6, IPV6_PKTINFO);
+ int ret = getsockopt (sock_fd, SOL_SOCKET, SO_SNDBUF, &optval, &optlen);
+ if (ret < 0)
+ {
+ int err = errno ;
+ zlog_err ("cannot get sockopt SO_SNDBUF on socket %d: %s",
+ sock_fd, errtoa(err, 0).str) ;
+ errno = err ;
+ return ret;
+ }
- return pktinfo->ipi6_ifindex;
+ return optval;
}
-#endif /* HAVE_IPV6 */
+/*------------------------------------------------------------------------------
+ * Set IP_TOS option for AF_INET socket.
+ *
+ * Returns: >= 0 => OK
+ * < 0 => failed, see errno.
+ *
+ * Logs a LOG_ERR message if fails
+ */
+extern int
+setsockopt_ipv4_tos(int sock_fd, int tos)
+{
+ int ret;
-/*
+ ret = setsockopt (sock_fd, IPPROTO_IP, IP_TOS, &tos, sizeof (tos));
+ if (ret < 0)
+ {
+ int err = errno ;
+ zlog_err("cannot set sockopt IP_TOS option %#x on socket %d: %s",
+ tos, sock_fd, errtoa(err, 0).str) ;
+ errno = err ;
+ } ;
+ return ret;
+} ;
+
+/*------------------------------------------------------------------------------
* Process multicast socket options for IPv4 in an OS-dependent manner.
* Supported options are IP_MULTICAST_IF and IP_{ADD,DROP}_MEMBERSHIP.
*
@@ -252,7 +619,7 @@ getsockopt_ipv6_ifindex (struct msghdr *msgh)
* but this behavior should not be harmful if they behave the same way,
* allow leaves, or implicitly leave all groups joined to down interfaces.
*/
-int
+extern int
setsockopt_multicast_ipv4(int sock_fd,
int optname,
struct in_addr if_addr /* required */,
@@ -365,27 +732,83 @@ setsockopt_multicast_ipv4(int sock_fd,
}
+/*==============================================================================
+ * Set pktinfo and get ifindex etc
+ */
+
+static int setsockopt_ipv4_pktinfo (int sock_fd, int val) ;
+static int getsockopt_ipv4_ifindex (struct msghdr *msgh) ;
+
+#ifdef HAVE_IPV6
+static int getsockopt_ipv6_ifindex (struct msghdr *msgh) ;
+#endif
+
+static void * getsockopt_cmsg_data (struct msghdr *msgh, int level, int type) ;
+
+/*------------------------------------------------------------------------------
+ * Set IP_PKTINFO/IP_RECVIF or IPV6_RECVPKTINFO/IPV6_PKTINFO -- if available.
+ *
+ * Returns: >= 0 => OK
+ * < 0 => failed -- see errno
+ *
+ * Logs a LOG_ERR message if fails.
+ */
+extern int
+setsockopt_pktinfo (int af, int sock_fd, int val)
+{
+ int ret = -1;
+
+ switch (af)
+ {
+ case AF_INET:
+ ret = setsockopt_ipv4_pktinfo (sock_fd, val);
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ ret = setsockopt_ipv6_pktinfo (sock_fd, val);
+ break;
+#endif
+ default:
+ zlog_warn("setsockopt_ifindex: unknown address family %d", af) ;
+ ret = -1 ;
+ errno = EINVAL;
+ break ;
+ }
+ return ret;
+}
+
+/*------------------------------------------------------------------------------
+ * Set IP_PKTINFO or IP_RECVIF -- if available.
+ *
+ * Returns: >= 0 => OK
+ * < 0 => failed -- see errno
+ *
+ * Logs a LOG_ERR message if fails.
+ */
static int
-setsockopt_ipv4_ifindex (int sock_fd, int val)
+setsockopt_ipv4_pktinfo (int sock_fd, int val)
{
int ret;
-#if defined (IP_PKTINFO)
- ret = setsockopt (sock_fd, IPPROTO_IP, IP_PKTINFO, &val, sizeof (val)) ;
- if (ret < 0)
- {
- int err = errno ;
- zlog_warn ("Can't set IP_PKTINFO option for fd %d to %d: %s",
- sock_fd, val, errtoa(err, 0).str);
- errno = err ;
- } ;
-#elif defined (IP_RECVIF)
- ret = setsockopt (sock_fd, IPPROTO_IP, IP_RECVIF, &val, sizeof (val)) ;
+#if defined(IP_PKTINFO) || defined(IP_RECVIF)
+
+ int opt ;
+ const char* name ;
+
+# if defined(IP_PKTINFO)
+ opt = IP_PKTINFO ;
+ name = "IP_PKTINFO" ;
+# else
+ opt = IP_RECVIF ;
+ name = "IP_RECVIF" ;
+# endif
+
+ ret = setsockopt (sock_fd, IPPROTO_IP, opt, &val, sizeof (val)) ;
if (ret < 0)
{
int err = errno ;
- zlog_warn ("Can't set IP_RECVIF option for fd %d to %d: %s",
- sock_fd, val, errtoa(err, 0).str);
+ zlog_err("cannot set sockopt %s to %d on socket %d: %s", name,
+ val, sock_fd, errtoa(err, 0).str);
errno = err ;
} ;
#else
@@ -393,53 +816,82 @@ setsockopt_ipv4_ifindex (int sock_fd, int val)
#warning "Will not be able to receive link info."
#warning "Things might be seriously broken.."
/* XXX Does this ever happen? Should there be a zlog_warn message here? */
- ret = -1;
+ ret = -1;
+ errno = EOPNOTSUPP ; /* manufactured error */
#endif
return ret;
}
-int
-setsockopt_ipv4_tos(int sock_fd, int tos)
+/*------------------------------------------------------------------------------
+ * Set IPV6_RECVPKTINFO (RFC3542) or IPV6_RECVIF (RFC2292) -- if available.
+ *
+ * Returns: >= 0 => OK
+ * < 0 => failed -- see errno
+ *
+ * Logs a LOG_ERR message if fails.
+ */
+#ifdef HAVE_IPV6
+extern int
+setsockopt_ipv6_pktinfo (int sock_fd, int val)
{
int ret;
+ int opt ;
+ const char* name ;
- ret = setsockopt (sock_fd, IPPROTO_IP, IP_TOS, &tos, sizeof (tos));
+# ifdef IPV6_RECVPKTINFO
+ opt = IPV6_RECVPKTINFO ; /* RFC3542 == RFC2292-bis */
+ name = "IPV6_RECVPKTINFO" ;
+# else
+ opt = IPV6_PKTINFO ; /* RFC2292 */
+ name = "IPV6_PKTINFO" ;
+# endif
+
+ ret = setsockopt(sock_fd, IPPROTO_IPV6, opt, &val, sizeof(val));
if (ret < 0)
{
int err = errno ;
- zlog_warn ("Can't set IP_TOS option for fd %d to %#x: %s",
- sock_fd, tos, errtoa(err, 0).str);
+ zlog_err("cannot set sockopt %s to %d on socket %d: %s", name,
+ val, sock_fd, errtoa(err, 0).str);
errno = err ;
} ;
+
return ret;
}
+#endif
-
-int
-setsockopt_ifindex (int af, int sock_fd, int val)
+/*------------------------------------------------------------------------------
+ * Given a struct msghdr*, extract and return ifindex.
+ *
+ * Returns: > 0 => OK == ifindex
+ * 0 => none found or error
+ *
+ * Note: this is badly named, since it is not really a getsockopt() operation,
+ * but extracting data from a sendmsg/recvmsg struct msghdr.
+ *
+ * To have the ifindex returned, need to have setsockopt_pktinfo().
+ */
+extern int
+getsockopt_ifindex (int af, struct msghdr *msgh)
{
- int ret = -1;
-
switch (af)
{
case AF_INET:
- ret = setsockopt_ipv4_ifindex (sock_fd, val);
- break;
+ return (getsockopt_ipv4_ifindex (msgh));
+
#ifdef HAVE_IPV6
case AF_INET6:
- ret = setsockopt_ipv6_pktinfo (sock_fd, val);
- break;
+ return (getsockopt_ipv6_ifindex (msgh));
#endif
+
default:
- zlog_warn ("setsockopt_ifindex: unknown address family %d", af);
- ret = -1 ;
- errno = EINVAL;
- break ;
+ zlog_warn ("getsockopt_ifindex: unknown address family %d", af);
+ return 0 ;
}
- return ret;
}
-/*
+/*------------------------------------------------------------------------------
+ * AF_INET: extract ifindex from struct msghdr, if can
+ *
* Requires: msgh is not NULL and points to a valid struct msghdr, which
* may or may not have control data about the incoming interface.
*
@@ -449,17 +901,17 @@ setsockopt_ifindex (int af, int sock_fd, int val)
static int
getsockopt_ipv4_ifindex (struct msghdr *msgh)
{
- /* XXX: initialize to zero? (Always overwritten, so just cosmetic.) */
- int ifindex = -1;
+ int ifindex ;
#if defined(IP_PKTINFO)
/* Linux pktinfo based ifindex retrieval */
struct in_pktinfo *pktinfo;
- pktinfo =
- (struct in_pktinfo *)getsockopt_cmsg_data (msgh, IPPROTO_IP, IP_PKTINFO);
- /* XXX Can pktinfo be NULL? Clean up post 0.98. */
- ifindex = pktinfo->ipi_ifindex;
+ pktinfo = getsockopt_cmsg_data (msgh, IPPROTO_IP, IP_PKTINFO);
+ if (pktinfo != NULL)
+ ifindex = pktinfo->ipi_ifindex ;
+ else
+ ifindex = 0 ;
#elif defined(IP_RECVIF)
@@ -510,34 +962,73 @@ getsockopt_ipv4_ifindex (struct msghdr *msgh)
return ifindex;
}
-/* return ifindex, 0 if none found */
-int
-getsockopt_ifindex (int af, struct msghdr *msgh)
+/*------------------------------------------------------------------------------
+ * AF_INET6: extract ifindex from struct msghdr, if can
+ *
+ * Requires: msgh is not NULL and points to a valid struct msghdr, which
+ * may or may not have control data about the incoming interface.
+ *
+ * Returns the interface index (small integer >= 1) if it can be
+ * determined, or else 0.
+ */
+#ifdef HAVE_IPV6
+static int
+getsockopt_ipv6_ifindex (struct msghdr *msgh)
{
- int ifindex = 0;
+ struct in6_pktinfo *pktinfo;
- switch (af)
- {
- case AF_INET:
- return (getsockopt_ipv4_ifindex (msgh));
- break;
-#ifdef HAVE_IPV6
- case AF_INET6:
- return (getsockopt_ipv6_ifindex (msgh));
- break;
+ pktinfo = getsockopt_cmsg_data (msgh, IPPROTO_IPV6, IPV6_PKTINFO);
+
+ if (pktinfo != NULL)
+ return pktinfo->ipi6_ifindex;
+ else
+ return 0 ;
+}
#endif
- default:
- zlog_warn ("getsockopt_ifindex: unknown address family %d", af);
- return (ifindex = 0);
- }
+
+/*------------------------------------------------------------------------------
+ * Scan msg_control portion of struct msghdr, looking for a cmsg with the given
+ * level and type.
+ *
+ * Requires: msgh is not NULL and points to a valid struct msghdr, which
+ * may or may not have control data about the incoming interface.
+ *
+ * Returns: address of data part of cmsg
+ * or: NULL => not found
+ */
+static void *
+getsockopt_cmsg_data (struct msghdr *msgh, int level, int type)
+{
+ struct cmsghdr *cmsg;
+
+ for (cmsg = ZCMSG_FIRSTHDR(msgh);
+ cmsg != NULL;
+ cmsg = CMSG_NXTHDR(msgh, cmsg))
+ if ((cmsg->cmsg_level == level) && (cmsg->cmsg_type == type))
+ return (void*)CMSG_DATA(cmsg);
+
+ return NULL;
}
-/* swab iph between order system uses for IP_HDRINCL and host order */
-void
+/*------------------------------------------------------------------------------
+ * swab iph between order system uses for IP_HDRINCL and host order
+ *
+ * This is done before handing struct ip to the system.
+ *
+ * There are four u_short fields in the IPv4 header:
+ *
+ * u_short ip_len -- convert to network order, except as noted below
+ * u_short ip_id -- convert to network order
+ * u_short ip_off -- convert to network order, except as noted below
+ * u_short ip_sum -- which we don't touch -- set by kernel
+ */
+extern void
sockopt_iphdrincl_swab_htosys (struct ip *iph)
{
- /* BSD and derived take iph in network order, except for
- * ip_len and ip_off
+ /* BSD and derived take iph in network order, except for ip_len and ip_off.
+ *
+ * So if *not* BSD-like, then need to convert ip_len and ip_off to network
+ * order.
*/
#ifndef HAVE_IP_HDRINCL_BSD_ORDER
iph->ip_len = htons(iph->ip_len);
@@ -547,7 +1038,12 @@ sockopt_iphdrincl_swab_htosys (struct ip *iph)
iph->ip_id = htons(iph->ip_id);
}
-void
+/*------------------------------------------------------------------------------
+ * swab iph between order system uses for IP_HDRINCL and host order
+ *
+ * This is done after receiving struct ip from the system -- see notes above.
+ */
+extern void
sockopt_iphdrincl_swab_systoh (struct ip *iph)
{
#ifndef HAVE_IP_HDRINCL_BSD_ORDER
@@ -559,190 +1055,171 @@ sockopt_iphdrincl_swab_systoh (struct ip *iph)
}
/*==============================================================================
- * Set TCP MD5 signature socket option.
+ * IPv6 Stuff
+ */
+#ifdef HAVE_IPV6
+
+/*------------------------------------------------------------------------------
+ * Set IPV6_V6ONLY.
*
* Returns: >= 0 => OK
- * < 0 => failed, see errno.
+ * < 0 => failed -- see errno
*
- * NB: returns ENOSYS if TCP MD5 is not supported
+ * Logs a LOG_ERR message if fails.
*/
-int
-sockopt_tcp_signature (int sock_fd, union sockunion *su, const char *password)
+extern int
+setsockopt_ipv6_v6only(int sock_fd)
{
-#if defined(HAVE_TCP_MD5_LINUX24) && defined(GNU_LINUX)
- int ret ;
-
- /* Support for the old Linux 2.4 TCP-MD5 patch, taken from Hasso Tepper's
- * version of the Quagga patch (based on work by Rick Payne, and Bruce
- * Simpson)
- */
-#define TCP_MD5_AUTH 13
-#define TCP_MD5_AUTH_ADD 1
-#define TCP_MD5_AUTH_DEL 2
- struct tcp_rfc2385_cmd {
- u_int8_t command; /* Command - Add/Delete */
- u_int32_t address; /* IPV4 address associated */
- u_int8_t keylen; /* MD5 Key len (do NOT assume 0 terminated ascii) */
- void *key; /* MD5 Key */
- } cmd;
- struct in_addr *addr = &su->sin.sin_addr;
-
- cmd.command = (password != NULL ? TCP_MD5_AUTH_ADD : TCP_MD5_AUTH_DEL);
- cmd.address = addr->s_addr;
- cmd.keylen = (password != NULL ? strlen (password) : 0);
- cmd.key = password;
-
- ret = setsockopt (sock_fd, IPPROTO_TCP, TCP_MD5_AUTH, &cmd, sizeof cmd) ;
-
- return (ret >= 0) ? 0 : -1 ;
-
-#elif HAVE_DECL_TCP_MD5SIG
- int ret, err ;
-# ifndef GNU_LINUX
- /*
- * XXX Need to do PF_KEY operation here to add/remove an SA entry,
- * and add/remove an SP entry for this peer's packet flows also.
- */
- int md5sig = password && *password ? 1 : 0;
-# else
- int keylen = password ? strlen (password) : 0 ;
- struct tcp_md5sig md5sig ;
- union sockunion *su2 ;
- union sockunion susock ;
+ int ret;
+ int on = 1 ;
- /* Figure out whether the socket and the sockunion are the same family..
- * adding AF_INET to AF_INET6 needs to be v4 mapped, you'd think..
- */
- ret = sockunion_getsockname(sock_fd, &susock) ;
+ ret = setsockopt (sock_fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
if (ret < 0)
- return ret ;
-
- if (susock.sa.sa_family == su->sa.sa_family)
- su2 = su ;
- else
{
- /* oops.. */
- su2 = &susock ;
-
- if (su2->sa.sa_family == AF_INET)
- return 0 ; /* TODO: find out what this is doing ?? */
-
-# ifdef HAVE_IPV6
- /* If this does not work, then all users of this sockopt will need to
- * differentiate between IPv4 and IPv6, and keep separate sockets for
- * each.
- *
- * Sadly, it doesn't seem to work at present. It's unknown whether
- * this is a bug or not.
- */
- if (su2->sa.sa_family == AF_INET6
- && su->sa.sa_family == AF_INET)
- {
- su2->sin6.sin6_family = AF_INET6;
- /* V4Map the address */
- memset (&su2->sin6.sin6_addr, 0, sizeof (struct in6_addr));
- su2->sin6.sin6_addr.s6_addr[10] = 0xff ;
- su2->sin6.sin6_addr.s6_addr[11] = 0xff ;
-# ifdef s6_addr32
- su2->sin6.sin6_addr.s6_addr32[3] = su->sin.sin_addr.s_addr ;
-# else
- memcpy (&su2->sin6.sin6_addr.s6_addr[12], &su->sin.sin_addr, 4);
-# endif
- }
-# endif
+ int err = errno ;
+ zlog_err ("cannot set sockopt IPV6_V6ONLY on socket %d: %s",
+ sock_fd, errtoa(err, 0).str) ;
+ errno = err ;
}
+ return ret ;
+} ;
- memset (&md5sig, 0, sizeof (md5sig));
- memcpy (&md5sig.tcpm_addr, su2, sizeof (*su2));
- md5sig.tcpm_keylen = keylen;
- if (keylen)
- memcpy (md5sig.tcpm_key, password, keylen);
-
-# endif /* GNU_LINUX */
+/*------------------------------------------------------------------------------
+ * Set IPV6_CHECKSUM
+ *
+ * Returns: >= 0 => OK
+ * < 0 => failed -- see errno
+ *
+ * Logs a LOG_ERR message if fails.
+ */
+extern int
+setsockopt_ipv6_checksum (int sock_fd, int val)
+{
+ int ret;
- err = 0 ;
- ret = setsockopt(sock_fd, IPPROTO_TCP, TCP_MD5SIG, &md5sig, sizeof(md5sig)) ;
+#ifdef GNU_LINUX
+ ret = setsockopt(sock_fd, IPPROTO_RAW, IPV6_CHECKSUM, &val, sizeof(val));
+#else
+ ret = setsockopt(sock_fd, IPPROTO_IPV6, IPV6_CHECKSUM, &val, sizeof(val));
+#endif /* GNU_LINUX */
if (ret < 0)
{
- err = errno ;
- /* ENOENT is harmless. It is returned when we clear a password for which
- one was not previously set. */
- if (err == ENOENT)
- err = 0 ;
- else
- {
- zlog_err ("sockopt_tcp_signature: setsockopt(%d): %s",
+ int err = errno ;
+ zlog_err("cannot set sockopt IPV6_CHECKSUM to %d on socket %d: %s", val,
sock_fd, errtoa(err, 0).str) ;
- errno = err ;
- } ;
- }
-
- return (err == 0) ? 0 : -1 ;
-
-#else
+ errno = err ;
+ } ;
+ return ret;
+}
- /* TCP MD5 is not supported */
+/*------------------------------------------------------------------------------
+ * Set unicast hops val to the socket (cf IP_TTL).
+ *
+ * Returns: >= 0 => OK
+ * < 0 => failed -- see errno
+ *
+ * Logs a LOG_ERR message if fails.
+ */
+extern int
+setsockopt_ipv6_unicast_hops (int sock_fd, int val)
+{
+ int ret;
- if ((password == NULL) || (*password == '\0'))
- return 0 ; /* OK if not required ! */
+ ret = setsockopt(sock_fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &val, sizeof(val));
+ if (ret < 0)
+ {
+ int err = errno ;
+ zlog_err("cannot set sockopt IPV6_UNICAST_HOPS to %d on socket %d: %s",
+ val, sock_fd, errtoa(err, 0).str) ;
+ errno = err ;
+ } ;
+ return ret;
+}
- errno = ENOSYS ; /* manufactured error */
- return -1 ;
+/*------------------------------------------------------------------------------
+ * Set multicast hops val to the socket.
+ *
+ * Returns: >= 0 => OK
+ * < 0 => failed -- see errno
+ *
+ * Logs a LOG_ERR message if fails.
+ */
+extern int
+setsockopt_ipv6_multicast_hops (int sock_fd, int val)
+{
+ int ret;
-#endif /* !HAVE_TCP_MD5SIG */
-} ;
+ ret = setsockopt(sock_fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val,
+ sizeof(val));
+ if (ret < 0)
+ {
+ int err = errno ;
+ zlog_err("cannot set sockopt IPV6_MULTICAST_HOPS to %d on socket %d: %s",
+ val, sock_fd, errtoa(err, 0).str) ;
+ errno = err ;
+ } ;
+ return ret;
+}
-/*==============================================================================
- * Set TTL for socket
+/*------------------------------------------------------------------------------
+ * Set IPV6_RECVHOPLIMIT option (or IPV6_HOPLIMIT)
*
* Returns: >= 0 => OK
- * < 0 => failed, see errno.
+ * < 0 => failed -- see errno
+ *
+ * Logs a LOG_ERR message if fails.
*/
-int
-sockopt_ttl (int sock_fd, int ttl)
+extern int
+setsockopt_ipv6_hoplimit (int sock_fd, int val)
{
- const char* msg ;
- int ret ;
- int family ;
-
- ret = 0 ;
- msg = NULL ;
+ int ret;
+ int opt ;
+ const char* name ;
- family = sockunion_getsockfamily(sock_fd) ;
- if (family < 0)
- return -1 ;
+# ifdef IPV6_RECVHOPLIMIT
+ opt = IPV6_RECVHOPLIMIT ; /* RFC3542 == RFC2292-bis */
+ name = "IPV6_RECVHOPLIMIT" ;
+# else
+ opt = IPV6_HOPLIMIT ; /* RFC2292 */
+ name = "IPV6_HOPLIMIT" ;
+# endif
- switch (family)
- {
- case AF_INET:
-#ifdef IP_TTL
- ret = setsockopt (sock_fd, IPPROTO_IP, IP_TTL,(void*)&ttl, sizeof(int));
- msg = "IP_TTL" ;
-#endif /* IP_TTL */
- break ;
+ ret = setsockopt(sock_fd, IPPROTO_IPV6, opt, &val, sizeof(val));
+ if (ret < 0)
+ {
+ int err = errno ;
+ zlog_err("cannot set sockopt %s to %d on socket %d: %s", name,
+ val, sock_fd, errtoa(err, 0).str);
+ errno = err ;
+ } ;
-#ifdef HAVE_IPV6
- case AF_INET6:
- ret = setsockopt (sock_fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
- (void*)&ttl, sizeof(int));
- msg = "IPV6_UNICAST_HOPS" ;
- break ;
-#endif
+ return ret;
+}
- default: /* ignore unknown family */
- ret = 0 ;
- break ;
- } ;
+/*------------------------------------------------------------------------------
+ * Set IPV6_MULTICAST_LOOP option
+ *
+ * Returns: >= 0 => OK
+ * < 0 => failed -- see errno
+ *
+ * Logs a LOG_ERR message if fails.
+ */
+extern int
+setsockopt_ipv6_multicast_loop (int sock_fd, int val)
+{
+ int ret;
- if (ret != 0)
+ ret = setsockopt (sock_fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &val,
+ sizeof (val));
+ if (ret < 0)
{
int err = errno ;
- zlog (NULL, LOG_WARNING,
- "cannot set sockopt %s %d to socket %d: %s", msg, ttl, sock_fd,
- errtoa(err, 0).str) ;
+ zlog_err("cannot set sockopt IPV6_MULTICAST_LOOP to %d on socket %d: %s",
+ val, sock_fd, errtoa(err, 0).str);
errno = err ;
- return -1 ;
} ;
+ return ret;
+}
+#endif /* HAVE_IPV6 */
+
- return 0 ;
-} ;
diff --git a/lib/sockopt.h b/lib/sockopt.h
index ad86f053..c706a74f 100644
--- a/lib/sockopt.h
+++ b/lib/sockopt.h
@@ -1,4 +1,4 @@
-/* Router advertisement
+/* Setting and getting socket options -- utility functions.
* Copyright (C) 1999 Kunihiro Ishiguro
*
* This file is part of GNU Zebra.
@@ -24,18 +24,20 @@
#include "sockunion.h"
+extern int setsockopt_reuseaddr (int sock_fd) ;
+extern int setsockopt_reuseport (int sock_fd) ;
+extern int setsockopt_broadcast (int sock_fd) ;
+
+extern int setsockopt_ttl (int sock_fd, int ttl);
+extern int setsockopt_minttl (int sock_fd, int ttl);
+extern int setsockopt_cork (int sock_fd, int onoff);
+
extern int setsockopt_so_recvbuf (int sock_fd, int size);
-extern int setsockopt_so_sendbuf (const int sock_fd, int size);
-extern int getsockopt_so_sendbuf (const int sock_fd);
+extern int setsockopt_so_sendbuf (int sock_fd, int size);
+extern int getsockopt_so_sendbuf (int sock_fd);
-#ifdef HAVE_IPV6
-extern int setsockopt_ipv6_pktinfo (int, int);
-extern int setsockopt_ipv6_checksum (int, int);
-extern int setsockopt_ipv6_multicast_hops (int, int);
-extern int setsockopt_ipv6_unicast_hops (int, int);
-extern int setsockopt_ipv6_hoplimit (int, int);
-extern int setsockopt_ipv6_multicast_loop (int, int);
-#endif /* HAVE_IPV6 */
+extern int setsockopt_tcp_signature(int sock_fd, union sockunion *su,
+ const char *password);
/*
* It is OK to reference in6_pktinfo here without a protecting #if
@@ -92,7 +94,7 @@ extern int setsockopt_multicast_ipv4(int sock_fd, int optname,
extern int setsockopt_ipv4_tos(int sock_fd, int tos);
/* Ask for, and get, ifindex, by whatever method is supported. */
-extern int setsockopt_ifindex (int, int, int);
+extern int setsockopt_pktinfo (int, int, int);
extern int getsockopt_ifindex (int, struct msghdr *);
/* swab the fields in iph between the host order and system order expected
@@ -101,7 +103,16 @@ extern int getsockopt_ifindex (int, struct msghdr *);
extern void sockopt_iphdrincl_swab_htosys (struct ip *iph);
extern void sockopt_iphdrincl_swab_systoh (struct ip *iph);
-extern int sockopt_ttl (int sock_fd, int ttl);
-extern int sockopt_tcp_signature(int sock_fd, union sockunion *su,
- const char *password);
+#ifdef HAVE_IPV6
+
+extern int setsockopt_ipv6_v6only(int sock_fd) ;
+extern int setsockopt_ipv6_pktinfo (int, int);
+extern int setsockopt_ipv6_checksum (int, int);
+extern int setsockopt_ipv6_multicast_hops (int, int);
+extern int setsockopt_ipv6_unicast_hops (int, int);
+extern int setsockopt_ipv6_hoplimit (int, int);
+extern int setsockopt_ipv6_multicast_loop (int, int);
+
+#endif /* HAVE_IPV6 */
+
#endif /*_ZEBRA_SOCKOPT_H */
diff --git a/lib/sockunion.c b/lib/sockunion.c
index deac292c..9084c27e 100644
--- a/lib/sockunion.c
+++ b/lib/sockunion.c
@@ -249,11 +249,36 @@ sockunion_init_new(sockunion su, sa_family_t family)
if (family != AF_UNSPEC)
sockunion_set_family(su, family) ;
+ else
+ confirm(AF_UNSPEC == 0) ;
return su ;
} ;
/*------------------------------------------------------------------------------
+ * Get the length of the address in the given sockunion.
+ *
+ * Returns zero if AF_UNSPEC or not any known address family.
+ */
+extern int
+sockunion_get_len(sockunion su)
+{
+ switch (su->sa.sa_family)
+ {
+ case AF_INET:
+ return sizeof(struct sockaddr_in) ;
+
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ return sizeof(struct sockaddr_in6) ;
+#endif
+
+ default:
+ return 0 ;
+ } ;
+} ;
+
+/*------------------------------------------------------------------------------
* From the given string, fill in the given sockunion.
*
* Returns: 0 => OK -- sockunion filled in
@@ -357,20 +382,19 @@ sockunion_su2str (union sockunion *su, enum MTYPE type)
* If have an IPv6 mapped IPv4 address, convert it to an IPv4 address.
*/
extern void
-sockunion_unmap_ipv4 (union sockunion *su)
+sockunion_unmap_ipv4 (sockunion su)
{
#ifdef HAVE_IPV6
- union sockunion sux ;
- struct sockaddr_in* su_in = &sux.sin ;
-
- if ( (su->sa.sa_family == AF_INET6)
- && IN6_IS_ADDR_V4MAPPED (&su->sin6.sin6_addr) )
+ if ( (sockunion_family(su) == AF_INET6)
+ && IN6_IS_ADDR_V4MAPPED (&su->sin6.sin6_addr) )
{
- sockunion_init_new(&sux, AF_INET) ;
- memcpy (&su_in->sin_addr, ((char *)&su->sin6.sin6_addr) + 12, 4) ;
- su_in->sin_port = su->sin6.sin6_port ;
- memcpy (su, &sux, sizeof(sux)) ;
- confirm(sizeof(*su) == sizeof(sux)) ;
+ union sockunion sux[1] ;
+
+ sockunion_init_new(sux, AF_INET) ;
+ memcpy (&sux->sin.sin_addr, &su->sin6.sin6_addr.s6_addr[12], 4) ;
+ sux->sin.sin_port = su->sin6.sin6_port ;
+ memcpy (su, sux, sizeof(*sux)) ;
+ confirm(sizeof(*su) == sizeof(*sux)) ;
}
#endif /* HAVE_IPV6 */
}
@@ -379,20 +403,19 @@ sockunion_unmap_ipv4 (union sockunion *su)
* If have an IPv4 address, convert it to an IPv6 mapped IPv4 address.
*/
extern void
-sockunion_map_ipv4 (union sockunion *su)
+sockunion_map_ipv4 (sockunion su)
{
#ifdef HAVE_IPV6
- union sockunion sux ;
- struct sockaddr_in6* su_in6 = &sux.sin6 ;
-
- if (su->sa.sa_family == AF_INET)
+ if (sockunion_family(su) == AF_INET)
{
- sockunion_init_new(&sux, AF_INET6) ;
- memset (((char *)&su_in6->sin6_addr) + 10, 0xFF, 2) ;
- memcpy (((char *)&su_in6->sin6_addr) + 12, &su->sin.sin_addr, 4) ;
- su_in6->sin6_port = su->sin.sin_port ;
- memcpy (su, &sux, sizeof(sux)) ;
- confirm(sizeof(*su) == sizeof(sux)) ;
+ union sockunion sux[1] ;
+
+ sockunion_init_new(sux, AF_INET6) ;
+ memset (&sux->sin6.sin6_addr.s6_addr[10], 0xFF, 2) ;
+ memcpy (&sux->sin6.sin6_addr.s6_addr[12], &su->sin.sin_addr, 4) ;
+ sux->sin6.sin6_port = su->sin.sin_port ;
+ memcpy (su, sux, sizeof(*sux)) ;
+ confirm(sizeof(*su) == sizeof(*sux)) ;
}
#endif /* HAVE_IPV6 */
}
@@ -414,7 +437,7 @@ sockunion_map_ipv4 (union sockunion *su)
* -1 -- error -- not one of the above
* -2 -- error -- one of the above
*/
-int
+extern int
sockunion_accept (int sock_fd, union sockunion *su)
{
socklen_t len;
@@ -443,23 +466,22 @@ sockunion_accept (int sock_fd, union sockunion *su)
* Returns: -1 : failed -- see errno
* otherwise : socket
*
- * Logs a LOG_WARNING message if fails.
+ * Logs a LOG_ERR message if fails.
*/
extern int
-sockunion_socket(sa_family_t family, int type, int protocol)
+sockunion_socket(sockunion su, int type, int protocol)
{
int sock_fd ;
int err ;
- sock_fd = socket(family, type, protocol);
+ sock_fd = socket(sockunion_family(su), type, protocol);
if (sock_fd >= 0)
return sock_fd ;
err = errno ;
- zlog (NULL, LOG_WARNING,
- "Cannot make socket family=%d, type=%d, protocol=%d: %s",
- (int)family, type, protocol, errtoa(err, 0).str) ;
+ zlog_err("Cannot make socket family=%d, type=%d, protocol=%d: %s",
+ (int)sockunion_family(su), type, protocol, errtoa(err, 0).str) ;
errno = err ;
return -1;
}
@@ -470,15 +492,15 @@ sockunion_socket(sa_family_t family, int type, int protocol)
* Returns: -1 : failed -- see errno
* otherwise : socket
*
- * Logs a LOG_WARNING message if fails.
+ * Logs a LOG_ERR message if fails.
*/
-int
-sockunion_stream_socket (union sockunion *su)
+extern int
+sockunion_stream_socket (sockunion su)
{
if (su->sa.sa_family == 0)
su->sa.sa_family = AF_INET_UNION;
- return sockunion_socket (su->sa.sa_family, SOCK_STREAM, 0);
+ return sockunion_socket (su, SOCK_STREAM, 0);
}
/*------------------------------------------------------------------------------
@@ -541,25 +563,24 @@ sockunion_connect(int sock_fd, union sockunion* peer_su, unsigned short port,
/*------------------------------------------------------------------------------
* Start listening on given socket
*
- * Returns: 0 : OK (so far so good)
- * < 0 : failed -- see errno
+ * Returns: >= 0 : OK (so far so good)
+ * < 0 : failed -- see errno
*
- * Logs a LOG_WARNING message if fails.
+ * Logs a LOG_ERR message if fails.
*/
extern int
sockunion_listen(int sock_fd, int backlog)
{
- int ret, err ;
+ int ret ;
ret = listen(sock_fd, backlog) ;
- if (ret == 0)
- return 0 ;
-
- err = errno ;
- zlog (NULL, LOG_WARNING, "cannot listen on socket %d: %s",
- sock_fd, errtoa(err, 0).str) ;
- errno = err ;
+ if (ret < 0)
+ {
+ int err = errno ;
+ zlog_err("cannot listen on socket %d: %s", sock_fd, errtoa(err, 0).str) ;
+ errno = err ;
+ } ;
return ret ;
} ;
@@ -567,28 +588,72 @@ sockunion_listen(int sock_fd, int backlog)
/*------------------------------------------------------------------------------
* Bind socket to address/port.
*
- * Sets the given port into the sockunion su.
+ * If the 'any' parameter is true, sets the given sockunion to INADDR_ANY or
+ * the *socket* address family equivalent.
*
- * If the 'any' parameter is NULL, set the address part of sockunion to
- * INADDR_ANY or the family equivalent. Note that for IPv6 this does not
- * affect the flow/scope in the su.
+ * Sets the given port into the sockunion su.
*
* For good measure, sets sin_len or family equivalent if required.
*
+ * If not 'any', and the given su does not have the same address family as the
+ * socket, then attempts to convert the su to the same family as the socket,
+ * by mapping or unmapping IPv4.
+ *
* Performs bind() and logs a LOG_WARNING message if fails.
*
* Returns: >= 0 => OK
* < 0 => failed -- see errno
*/
-int
-sockunion_bind (int sock_fd, union sockunion *su, unsigned short port,
- void* any)
+extern int
+sockunion_bind(int sock_fd, sockunion su, unsigned short port, bool any)
{
int sa_len ;
int ret ;
+ int sock_family ;
- if (any == NULL)
- sockunion_set_addr_any(su) ;
+ sock_family = sockunion_getsockfamily(sock_fd) ;
+
+ if (any)
+ {
+ /* Create an "any" -- of same family as the socket */
+ sockunion_init_new(su, sock_family) ;
+ sockunion_set_addr_any(su) ;
+ }
+ else
+ {
+ /* Want to bind to a specific address.
+ *
+ * We provide bind with an address which matches the address family of
+ * the *socket*.
+ *
+ * If the socket is AF_INET, address may be AF_INET, or an AF_INET6
+ * *provided* it is an IPv4 mapped address.
+ *
+ * If the socket is AF_INET6, address may be AF_INET or AF_NET6, and
+ * will map any IPv4 address.
+ *
+ * If we don't HAVE_IPV6, or we don't recognise an address family,
+ * then do nothing and let bind() return some sort of error.
+ */
+#ifdef HAVE_IPV6
+ if (sock_family != sockunion_family(su))
+ {
+ switch (sock_family)
+ {
+ case AF_INET:
+ sockunion_unmap_ipv4(su) ; /* unmap if AF_INET6 mapped IPv4 */
+ break ;
+
+ case AF_INET6:
+ sockunion_map_ipv4(su) ; /* map if AF_INET */
+ break ;
+
+ default:
+ break ;
+ } ;
+ } ;
+#endif
+ } ;
sa_len = sockunion_set_port(su, port) ;
@@ -596,7 +661,7 @@ sockunion_bind (int sock_fd, union sockunion *su, unsigned short port,
if (ret < 0)
{
int err = errno ;
- zlog (NULL, LOG_WARNING, "cannot bind to %s port %d socket %d: %s",
+ zlog_warn("cannot bind to %s port %d socket %d: %s",
sutoa(su).str, port, sock_fd, errtoa(err, 0).str) ;
errno = err ;
} ;
@@ -605,72 +670,11 @@ sockunion_bind (int sock_fd, union sockunion *su, unsigned short port,
}
/*------------------------------------------------------------------------------
- * Set socket SO_REUSEADDR option
- *
- * Returns: >= 0 => OK
- * < 0 => failed -- see errno
- *
- * Logs a LOG_WARNING message if fails.
- */
-int
-sockopt_reuseaddr (int sock_fd)
-{
- int ret;
- int on = 1;
-
- ret = setsockopt (sock_fd, SOL_SOCKET, SO_REUSEADDR, (void *) &on,
- sizeof (on));
- if (ret < 0)
- {
- int err = errno ;
- zlog (NULL, LOG_WARNING,
- "cannot set sockopt SO_REUSEADDR to socket %d: %s", sock_fd,
- errtoa(err, 0).str) ;
- errno = err ;
- } ;
-
- return ret ;
-}
-
-/*------------------------------------------------------------------------------
- * Set socket SO_REUSEPORT option -- if it is locally supported.
- *
- * Returns: >= 0 => OK
- * < 0 => failed -- see errno
- *
- * Logs a LOG_WARNING message if fails.
- */
-int
-sockopt_reuseport (int sock_fd)
-{
- int ret;
-
-#ifdef SO_REUSEPORT
- int on = 1;
- ret = setsockopt (sock_fd, SOL_SOCKET, SO_REUSEPORT,
- (void *) &on, sizeof (on));
-#else
- ret = 0 ;
-#endif
-
- if (ret < 0)
- {
- int err = errno ;
- zlog (NULL, LOG_WARNING,
- "cannot set sockopt SO_REUSEPORT to socket %d: %s", sock_fd,
- errtoa(err, 0).str) ;
- errno = err ;
- } ;
-
- return ret ;
-} ;
-
-/*------------------------------------------------------------------------------
- * If same family and same prefix return 1.
+ * If same (known) family and same prefix return 1, otherwise return 0.
*
* Returns 0 if same family, but not a known family.
*/
-int
+extern int
sockunion_same (union sockunion *su1, union sockunion *su2)
{
int ret = 0;
@@ -686,7 +690,7 @@ sockunion_same (union sockunion *su1, union sockunion *su2)
#ifdef HAVE_IPV6
case AF_INET6:
ret = memcmp (&su1->sin6.sin6_addr, &su2->sin6.sin6_addr,
- sizeof (struct in6_addr));
+ sizeof (struct in6_addr));
return (ret == 0) ;
#endif /* HAVE_IPV6 */
@@ -696,125 +700,142 @@ sockunion_same (union sockunion *su1, union sockunion *su2)
} ;
/*------------------------------------------------------------------------------
- * Get the address family the given socket is set to.
+ * Get local (getsockname) or remote (getpeername) address and port.
*
* Returns: >= 0 == the address family (AF_UNSPEC if fd sock_fd < 0)
* < 0 => failed -- see errno
*
- * NB: gets the actual address family -- does NOT look for mapped IPv4.
- */
-extern int
-sockunion_getsockfamily(int sock_fd)
-{
- union sockunion su ;
- int ret ;
- socklen_t len ;
-
- if (sock_fd < 0)
- return AF_UNSPEC ;
-
- sockunion_init_new(&su, AF_UNSPEC) ;
- len = sizeof(su) ;
-
- ret = getsockname(sock_fd, (struct sockaddr *)&su, &len) ;
- if (ret < 0)
- {
- int err = errno ;
- zlog_warn ("Failed in getsockname for socket %d: %s",
- sock_fd, errtoa(err, 0).str) ;
- errno = err ;
- return -1 ;
- } ;
-
- return su.sa.sa_family ;
-} ;
-
-/*------------------------------------------------------------------------------
- * Get local or remote address and port.
- *
- * Returns: >= 0 => OK
- * < 0 => failed (or unknown family) -- see errno
- *
- * If address is an IPv4 mapped IPv6 address, returns the IPv4 address.
+ * If "unmap": if address is an IPv4 mapped IPv6 address, returns AF_INET.
*
* NB: returns EAFNOSUPPORT if don't recognise the address family.
+ *
+ * Logs a LOG_ERR message if fails in getsockname/getpeername.
*/
static int
-sockunion_get_name(int sock_fd, union sockunion* su, int local)
+sockunion_get_name(int sock_fd, union sockunion* su, bool local, bool unmap)
{
int ret ;
-
+ socklen_t len ;
union
{
- struct sockaddr sa;
- struct sockaddr_in sin;
-#ifdef HAVE_IPV6
- struct sockaddr_in6 sin6;
-#endif /* HAVE_IPV6 */
+ union sockunion su ;
char tmp_buffer[128];
} name ;
- socklen_t len = sizeof(name) ;
+ memset(su, 0, sizeof(union sockunion)) ;
+
+ confirm(AF_UNSPEC == 0) ;
+ if (sock_fd < 0)
+ return AF_UNSPEC ;
+
+ len = sizeof(name) ;
memset(&name, 0, len);
- memset(su, 0, sizeof(union sockunion)) ;
- if (local)
- ret = getsockname(sock_fd, (struct sockaddr *)&name, &len) ;
+ if (local)
+ ret = getsockname(sock_fd, &name.su.sa, &len) ;
else
- ret = getpeername(sock_fd, (struct sockaddr *)&name, &len) ;
+ ret = getpeername(sock_fd, &name.su.sa, &len) ;
if (ret < 0)
{
int err = errno ;
- zlog_warn ("Cannot get %s address and port: %s",
- local ? "local" : "remote", errtoa(err, 0).str) ;
+ zlog_err("failed in %s for socket %d: %s",
+ local ? "getsockname" : "getpeername",
+ sock_fd, errtoa(err, 0).str) ;
errno = err ;
- return ret ;
}
+ else
+ {
+ ret = name.su.sa.sa_family ;
- ret = 0 ; /* assume all will be well */
- switch (name.sa.sa_family)
- {
- case AF_INET:
- memcpy(su, &name, sizeof (struct sockaddr_in)) ;
- break ;
+ switch (ret)
+ {
+ case AF_INET:
+ su->sin = name.su.sin ;
+ break ;
#ifdef HAVE_IPV6
- case AF_INET6:
- memcpy(su, &name, sizeof (struct sockaddr_in6)) ;
- sockunion_unmap_ipv4(su) ;
- break ;
+ case AF_INET6:
+ su->sin6 = name.su.sin6 ;
+ if (unmap)
+ sockunion_unmap_ipv4(su) ;
+ break ;
#endif /* HAVE_IPV6 */
- default:
- errno = EAFNOSUPPORT ;
- ret = -1 ;
- } ;
+ default:
+ errno = EAFNOSUPPORT ;
+ ret = -1 ;
+ } ;
+ } ;
return ret ;
} ;
/*------------------------------------------------------------------------------
- * Get local address and port -- ie getsockname().
+ * Get the address family the given socket is set to.
+ *
+ * Returns: >= 0 == the address family (AF_UNSPEC if fd sock_fd < 0)
+ * < 0 => failed -- see errno
+ *
+ * NB: gets the actual address family -- does NOT look for mapped IPv4.
+ */
+extern int
+sockunion_getsockfamily(int sock_fd)
+{
+ union sockunion su[1] ;
+ int ret ;
+
+ ret = sockunion_get_name(sock_fd, su, true, /* true => local */
+ false) ; /* false => don't unmap */
+ return (ret >= 0) ? sockunion_family(su) : ret ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Get the address family the given socket's protocol is set to.
+ *
+ * If this is an AF_INET, that's easy.
+ *
+ * If this is an AF_INET6, then needs to look out for IN6_IS_ADDR_V4MAPPED.
+ *
+ * Returns: >= 0 == the address family (AF_UNSPEC if fd sock_fd < 0)
+ * < 0 => failed -- see errno
+ *
+ * NB: gets the underlying address family -- ie: looks for mapped IPv4.
+ */
+extern int
+sockunion_getprotofamily(int sock_fd)
+{
+ union sockunion su[1] ;
+ int ret ;
+
+ ret = sockunion_get_name(sock_fd, su, true, /* true => local */
+ true) ; /* true => unmap */
+ return (ret >= 0) ? sockunion_family(su) : ret ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Get local address and port -- ie getsockname(), except unmaps IPv4 mapped.
*
* See: sockunion_get_name()
*/
-int
-sockunion_getsockname(int sock_fd, union sockunion* su_local)
+extern int
+sockunion_getsockname(int sock_fd, sockunion su_local)
{
- return sockunion_get_name(sock_fd, su_local, 1) ;
+ return sockunion_get_name(sock_fd, su_local, true, /* true => local */
+ true) ; /* true => unmap */
} ;
/*------------------------------------------------------------------------------
- * Get remote address and port -- ie getpeername().
+ * Get remote address and port -- ie getpeername(), except unmaps IPv4 mapped.
*
* See: sockunion_get_name()
*/
-int
-sockunion_getpeername (int sock_fd, union sockunion* su_remote)
+extern int
+sockunion_getpeername (int sock_fd, sockunion su_remote)
{
- return sockunion_get_name(sock_fd, su_remote, 0) ;
+ return sockunion_get_name(sock_fd, su_remote, false, /* false => remote */
+ true) ; /* true => unmap */
} ;
/*------------------------------------------------------------------------------
diff --git a/lib/sockunion.h b/lib/sockunion.h
index 0b23ae63..eeae72d5 100644
--- a/lib/sockunion.h
+++ b/lib/sockunion.h
@@ -24,6 +24,7 @@
#define _ZEBRA_SOCKUNION_H
#include "zebra.h"
+#include <stdbool.h>
#include "symtab.h"
#include "prefix.h"
#include "memory.h"
@@ -101,36 +102,36 @@ struct sockunion_string
/* Prototypes. */
extern sockunion sockunion_init_new(sockunion su, sa_family_t family) ;
+extern int sockunion_get_len(sockunion su) ;
extern int sockunion_set_port(sockunion su, in_port_t port) ;
-extern int str2sockunion (const char *, union sockunion *);
-extern const char *sockunion2str (union sockunion *, char *, size_t);
+extern int str2sockunion (const char * str, sockunion su);
+extern const char *sockunion2str (sockunion su, char* buf, size_t size);
extern sockunion_string_t sutoa(sockunion su) ;
-extern int sockunion_cmp (union sockunion *, union sockunion *);
-extern int sockunion_same (union sockunion *, union sockunion *);
-
-extern char* sockunion_su2str (union sockunion* su, enum MTYPE type) ;
-extern union sockunion *sockunion_str2su (const char *str);
-extern struct in_addr sockunion_get_in_addr (union sockunion *su);
-extern int sockunion_accept (int sock_fd, union sockunion *);
-extern int sockunion_stream_socket (union sockunion *);
-extern int sockopt_reuseaddr (int);
-extern int sockopt_reuseport (int);
-extern int sockunion_bind (int sock_fd, union sockunion *,
- unsigned short, void* any);
-extern int sockunion_socket (sa_family_t family, int type, int protocol) ;
-extern int sockunion_connect (int sock_fd, union sockunion *su,
- unsigned short port, unsigned int) ;
+extern int sockunion_cmp (sockunion su1, sockunion su2);
+extern int sockunion_same (sockunion su1, sockunion su2);
+
+extern char* sockunion_su2str (sockunion su, enum MTYPE type) ;
+extern sockunion sockunion_str2su (const char *str);
+extern struct in_addr sockunion_get_in_addr (sockunion su);
+extern int sockunion_accept (int sock_fd, sockunion su);
+extern int sockunion_stream_socket (sockunion su);
+extern int sockunion_bind (int sock_fd, sockunion su,
+ unsigned short port, bool any) ;
+extern int sockunion_socket (sockunion su, int type, int protocol) ;
+extern int sockunion_connect (int sock_fd, sockunion su,
+ unsigned short port, unsigned int ifindex) ;
extern int sockunion_listen(int sock_fd, int backlog) ;
extern int sockunion_getsockfamily(int sock_fd) ;
-extern int sockunion_getsockname (int, union sockunion*);
-extern int sockunion_getpeername (int, union sockunion*);
-extern void sockunion_unmap_ipv4 (union sockunion *su) ;
-extern void sockunion_map_ipv4 (union sockunion *su) ;
+extern int sockunion_getprotofamily(int sock_fd) ;
+extern int sockunion_getsockname (int sock_fd, sockunion su);
+extern int sockunion_getpeername (int sock_fd, sockunion su);
+extern void sockunion_unmap_ipv4 (sockunion su) ;
+extern void sockunion_map_ipv4 (sockunion su) ;
-extern union sockunion *sockunion_dup (union sockunion *);
+extern sockunion sockunion_dup (sockunion src);
extern void sockunion_copy (sockunion dst, sockunion src) ;
-extern void sockunion_free (union sockunion *);
+extern void sockunion_free (sockunion su);
extern sockunion sockunion_new_prefix(sockunion su, prefix p) ;
extern sockunion sockunion_new_sockaddr(sockunion su, struct sockaddr* sa) ;
diff --git a/lib/thread.c b/lib/thread.c
index 7f8ff5f6..c130d876 100644
--- a/lib/thread.c
+++ b/lib/thread.c
@@ -438,8 +438,7 @@ DEFUN_CALL(show_thread_cpu,
}
static void
-cpu_record_hash_clear (struct hash_backet *bucket,
- void *args)
+cpu_record_hash_clear (struct hash_backet *bucket, void *args)
{
thread_type *filter = args;
struct cpu_thread_history *a = bucket->data;
@@ -1217,7 +1216,6 @@ thread_timer_process (struct thread_list *list, struct timeval *timenow)
/*------------------------------------------------------------------------------
* Move the given list of threads to the back of the THREAD_READY queue.
*/
-/* process a list en masse, e.g. for event thread lists */
static unsigned int
thread_process (struct thread_list *list)
{
@@ -1246,9 +1244,9 @@ thread_fetch (struct thread_master *m, struct thread *fetch)
fd_set readfd;
fd_set writefd;
fd_set exceptfd;
- struct timeval timer_val;
+ struct timeval timer_val ;
struct timeval timer_val_bg;
- struct timeval *timer_wait;
+ struct timeval *timer_wait ;
struct timeval *timer_wait_bg;
while (1)
diff --git a/lib/vty_io.c b/lib/vty_io.c
index 33947342..81af4e5e 100644
--- a/lib/vty_io.c
+++ b/lib/vty_io.c
@@ -40,6 +40,7 @@
#include "filter.h"
#include "privs.h"
#include "sockunion.h"
+#include "sockopt.h"
#include "network.h"
#include <arpa/telnet.h>
diff --git a/lib/vty_io_term.c b/lib/vty_io_term.c
index 61f35761..0660afb6 100644
--- a/lib/vty_io_term.c
+++ b/lib/vty_io_term.c
@@ -41,6 +41,7 @@
#include "filter.h"
#include "privs.h"
#include "sockunion.h"
+#include "sockopt.h"
#include "network.h"
#include <arpa/telnet.h>
@@ -1173,8 +1174,8 @@ static int
uty_term_listen_open(sa_family_t family, int type, int protocol,
struct sockaddr* sa, unsigned short port)
{
- union sockunion su ;
- int sock ;
+ union sockunion su[1] ;
+ int sock_fd ;
int ret ;
VTY_ASSERT_LOCKED() ;
@@ -1182,55 +1183,52 @@ uty_term_listen_open(sa_family_t family, int type, int protocol,
/* Is there an address and is it for this family ? */
if ((sa != NULL) || (sa->sa_family == family))
/* Set up sockunion containing required family and address */
- sockunion_new_sockaddr(&su, sa) ;
+ sockunion_new_sockaddr(su, sa) ;
else
{
/* no address or wrong family -- set up empty sockunion of
* required family */
- sockunion_init_new(&su, family) ;
+ sockunion_init_new(su, family) ;
sa = NULL ;
} ;
/* Open the socket and set its properties */
- sock = sockunion_socket(family, type, protocol) ;
- if (sock < 0)
+ sock_fd = sockunion_socket(su, type, protocol) ;
+ if (sock_fd < 0)
return -1 ;
- ret = sockopt_reuseaddr (sock);
+ ret = setsockopt_reuseaddr (sock_fd);
if (ret >= 0)
- ret = sockopt_reuseport (sock);
+ ret = setsockopt_reuseport (sock_fd);
if (ret >= 0)
- ret = set_nonblocking(sock);
+ ret = set_nonblocking(sock_fd);
-#if defined(HAVE_IPV6) && defined(IPV6_V6ONLY)
- /* Want only IPV6 on ipv6 socket (not mapped addresses)
+#ifdef HAVE_IPV6
+ /* Want only IPv6 on AF_INET6 socket (not mapped addresses)
*
* This distinguishes 0.0.0.0 from :: -- without this, bind() will reject the
* attempt to bind to :: after binding to 0.0.0.0.
*/
- if ((ret >= 0) && (sa->sa_family == AF_INET6))
- {
- int on = 1;
- ret = setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&on, sizeof(on));
- }
+ if ((ret >= 0) && (family == AF_INET6))
+ ret = setsockopt_ipv6_v6only(sock_fd) ;
#endif
if (ret >= 0)
- ret = sockunion_bind (sock, &su, port, sa) ;
+ ret = sockunion_bind (sock_fd, su, port, (sa == NULL)) ;
if (ret >= 0)
- ret = sockunion_listen (sock, 3);
+ ret = sockunion_listen (sock_fd, 3);
if (ret < 0)
{
- close (sock);
+ close (sock_fd);
return -1 ;
}
/* Socket is open -- set VTY_TERMINAL listener going */
- uty_add_listener(sock, uty_term_accept) ;
+ uty_add_listener(sock_fd, uty_term_accept) ;
/* Return OK and signal whether used address or not */
return (sa != NULL) ? 1 : 0 ;