mirror of
https://repo.or.cz/socat.git
synced 2024-12-22 23:42:34 +00:00
Moved multicast related code from xioopts.c to xio-ip.c and xio-ip6.c
This commit is contained in:
parent
d36f78d854
commit
282596dc9d
8 changed files with 297 additions and 235 deletions
2
CHANGES
2
CHANGES
|
@ -47,6 +47,8 @@ Coding:
|
||||||
|
|
||||||
Renamed xioopts_t to xioparms_t to avoid confusion with xioopts module.
|
Renamed xioopts_t to xioparms_t to avoid confusion with xioopts module.
|
||||||
|
|
||||||
|
Moved multicast related code from xioopts.c to xio-ip.c and xio-ip6.c
|
||||||
|
|
||||||
Porting:
|
Porting:
|
||||||
Removed Config/ because its contents have not been maintained for many
|
Removed Config/ because its contents have not been maintained for many
|
||||||
years.
|
years.
|
||||||
|
|
23
test.sh
23
test.sh
|
@ -7991,6 +7991,14 @@ elif ! feat=$(testfeats ip4 udp) || ! runsip4 >/dev/null; then
|
||||||
$PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N
|
$PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N
|
||||||
numCANT=$((numCANT+1))
|
numCANT=$((numCANT+1))
|
||||||
listCANT="$listCANT $N"
|
listCANT="$listCANT $N"
|
||||||
|
elif ! a=$(testaddrs UDP4-RECV UDP4-SENDTO); then
|
||||||
|
$PRINTF "test $F_n $TEST... ${YELLOW}Address $a not available${NORMAL}\n" $N
|
||||||
|
numCANT=$((numCANT+1))
|
||||||
|
listCANT="$listCANT $N"
|
||||||
|
elif ! o=$(testoptions ip-add-membership bind) >/dev/null; then
|
||||||
|
$PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available${NORMAL}\n" $N
|
||||||
|
numCANT=$((numCANT+1))
|
||||||
|
listCANT="$listCANT $N"
|
||||||
else
|
else
|
||||||
tf="$td/test$N.stdout"
|
tf="$td/test$N.stdout"
|
||||||
te="$td/test$N.stderr"
|
te="$td/test$N.stderr"
|
||||||
|
@ -8012,19 +8020,26 @@ kill "$pid1" 2>/dev/null; wait;
|
||||||
if [ "$rc2" -ne 0 ]; then
|
if [ "$rc2" -ne 0 ]; then
|
||||||
$PRINTF "$FAILED: $TRACE $SOCAT:\n"
|
$PRINTF "$FAILED: $TRACE $SOCAT:\n"
|
||||||
echo "$CMD1 &"
|
echo "$CMD1 &"
|
||||||
|
cat "${te}1" >&2
|
||||||
echo "$CMD2"
|
echo "$CMD2"
|
||||||
cat "${te}1"
|
cat "${te}2" >&2
|
||||||
cat "${te}2"
|
|
||||||
numFAIL=$((numFAIL+1))
|
numFAIL=$((numFAIL+1))
|
||||||
listFAIL="$listFAIL $N"
|
listFAIL="$listFAIL $N"
|
||||||
elif ! echo "$da" |diff - "$tf" >"$tdiff"; then
|
elif ! echo "$da" |diff - "$tf" >"$tdiff"; then
|
||||||
$PRINTF "$FAILED\n"
|
$PRINTF "$FAILED\n"
|
||||||
|
echo "$CMD1 &"
|
||||||
|
cat "${te}1" >&2
|
||||||
|
echo "$CMD2"
|
||||||
|
cat "${te}2" >&2
|
||||||
cat "$tdiff"
|
cat "$tdiff"
|
||||||
numFAIL=$((numFAIL+1))
|
numFAIL=$((numFAIL+1))
|
||||||
listFAIL="$listFAIL $N"
|
listFAIL="$listFAIL $N"
|
||||||
else
|
else
|
||||||
$PRINTF "$OK\n"
|
$PRINTF "$OK\n"
|
||||||
if [ -n "$debug" ]; then cat $te; fi
|
if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi
|
||||||
|
if [ "$DEBUG" ]; then cat "${te}0" >&2; fi
|
||||||
|
if [ "$VERBOSE" ]; then echo "$CMD1"; fi
|
||||||
|
if [ "$DEBUG" ]; then cat "${te}1" >&2; fi
|
||||||
numOK=$((numOK+1))
|
numOK=$((numOK+1))
|
||||||
fi
|
fi
|
||||||
fi ;; # NUMCOND, feats
|
fi ;; # NUMCOND, feats
|
||||||
|
@ -12580,7 +12595,7 @@ N=$((N+1))
|
||||||
# fixed in 1.7.3.2
|
# fixed in 1.7.3.2
|
||||||
NAME=USE_IPV6_JOIN_GROUP
|
NAME=USE_IPV6_JOIN_GROUP
|
||||||
case "$TESTS" in
|
case "$TESTS" in
|
||||||
*%$N%*|*%functions%*|*%bugs%*|*%socket%*|*%ip6%*|*%udp%*|*%udp6%*|*%dgram%*|*%$NAME%*)
|
*%$N%*|*%functions%*|*%bugs%*|*%socket%*|*%ip6%*|*%udp%*|*%udp6%*|*%dgram%*|*%multicast%*|*%$NAME%*)
|
||||||
TEST="$NAME: is option ipv6-join-group used"
|
TEST="$NAME: is option ipv6-join-group used"
|
||||||
# Invoke socat with option ipv6-join-group on UDP6 address.
|
# Invoke socat with option ipv6-join-group on UDP6 address.
|
||||||
# Terminate immediately, do not transfer data.
|
# Terminate immediately, do not transfer data.
|
||||||
|
|
227
xio-ip.c
227
xio-ip.c
|
@ -131,7 +131,7 @@ unsigned long res_opts() {
|
||||||
socktype: SOCK_STREAM, SOCK_DGRAM, ...
|
socktype: SOCK_STREAM, SOCK_DGRAM, ...
|
||||||
protocol: IPPROTO_UDP, IPPROTO_TCP
|
protocol: IPPROTO_UDP, IPPROTO_TCP
|
||||||
sau: an uninitialized storage for the resulting socket address
|
sau: an uninitialized storage for the resulting socket address
|
||||||
returns: STAT_OK, STAT_RETRYLATER
|
returns: STAT_OK, STAT_RETRYLATER, STAT_NORETRY, prints message
|
||||||
*/
|
*/
|
||||||
int xiogetaddrinfo(const char *node, const char *service,
|
int xiogetaddrinfo(const char *node, const char *service,
|
||||||
int family, int socktype, int protocol,
|
int family, int socktype, int protocol,
|
||||||
|
@ -662,6 +662,201 @@ int xiolog_ancillary_ip(struct cmsghdr *cmsg, int *num,
|
||||||
#endif /* defined(HAVE_STRUCT_CMSGHDR) && defined(CMSG_DATA) */
|
#endif /* defined(HAVE_STRUCT_CMSGHDR) && defined(CMSG_DATA) */
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(HAVE_STRUCT_IP_MREQ) || defined (HAVE_STRUCT_IP_MREQN)
|
||||||
|
int xiotype_ip_add_membership(
|
||||||
|
char *tokp,
|
||||||
|
const struct optname *ent,
|
||||||
|
struct opt *opt)
|
||||||
|
{
|
||||||
|
/* we do not resolve the addresses here because we do not yet know
|
||||||
|
if we are coping with a IPv4 or IPv6 socat address */
|
||||||
|
const char *ends[] = { ":", NULL };
|
||||||
|
const char *nests[] = { "[","]", NULL };
|
||||||
|
char buff[512], *buffp=buff; size_t bufspc = sizeof(buff)-1;
|
||||||
|
int parsres;
|
||||||
|
|
||||||
|
/* parse first IP address, expect ':' */
|
||||||
|
/*! result= */
|
||||||
|
parsres =
|
||||||
|
nestlex((const char **)&tokp, &buffp, &bufspc,
|
||||||
|
ends, NULL, NULL, nests,
|
||||||
|
true, false, false);
|
||||||
|
if (parsres < 0) {
|
||||||
|
Error1("option too long: \"%s\"", tokp);
|
||||||
|
return -1;
|
||||||
|
} else if (parsres > 0) {
|
||||||
|
Error1("syntax error in \"%s\"", tokp);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (*tokp != ':') {
|
||||||
|
Error1("syntax in option %s: missing ':'", tokp);
|
||||||
|
}
|
||||||
|
*buffp++ = '\0';
|
||||||
|
if ((opt->value.u_string/*multiaddr*/ = strdup(buff)) == NULL) {
|
||||||
|
Error1("strdup(\"%s\"): out of memory", buff);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
++tokp;
|
||||||
|
/* parse second IP address, expect ':' or '\0'' */
|
||||||
|
buffp = buff;
|
||||||
|
/*! result= */
|
||||||
|
parsres =
|
||||||
|
nestlex((const char **)&tokp, &buffp, &bufspc,
|
||||||
|
ends, NULL, NULL, nests,
|
||||||
|
true, false, false);
|
||||||
|
if (parsres < 0) {
|
||||||
|
Error1("option too long: \"%s\"", tokp);
|
||||||
|
return -1;
|
||||||
|
} else if (parsres > 0) {
|
||||||
|
Error1("syntax error in \"%s\"", tokp);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
*buffp++ = '\0';
|
||||||
|
if ((opt->value2.u_string/*param2*/ = strdup(buff)) == NULL) {
|
||||||
|
Error1("strdup(\"%s\"): out of memory", buff);
|
||||||
|
free(opt->value.u_string);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if HAVE_STRUCT_IP_MREQN
|
||||||
|
if (*tokp++ == ':') {
|
||||||
|
strncpy(opt->value3.u_string/*ifindex*/, tokp, IF_NAMESIZE); /* ok */
|
||||||
|
Info4("setting option \"%s\" to {\"%s\",\"%s\",\"%s\"}",
|
||||||
|
ent->desc->defname,
|
||||||
|
opt->value.u_string/*multiaddr*/,
|
||||||
|
opt->value2.u_string/*param2*/,
|
||||||
|
opt->value3.u_string/*ifindex*/);
|
||||||
|
} else {
|
||||||
|
/*0 opt->value3.u_string = NULL; / * is NULL from init */
|
||||||
|
Info3("setting option \"%s\" to {\"%s\",\"%s\"}",
|
||||||
|
ent->desc->defname,
|
||||||
|
opt->value.u_string/*multiaddr*/,
|
||||||
|
opt->value2.u_string/*param2*/);
|
||||||
|
}
|
||||||
|
#else /* !HAVE_STRUCT_IP_MREQN */
|
||||||
|
Info3("setting option \"%s\" to {\"%s\",\"%s\"}",
|
||||||
|
ent->desc->defname,
|
||||||
|
opt->value.u_string/*multiaddr*/,
|
||||||
|
opt->value2.u_string/*param2*/);
|
||||||
|
#endif /* !HAVE_STRUCT_IP_MREQN */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* defined(HAVE_STRUCT_IP_MREQ) || defined (HAVE_STRUCT_IP_MREQN) */
|
||||||
|
|
||||||
|
#if defined(HAVE_STRUCT_IP_MREQ) || defined (HAVE_STRUCT_IP_MREQN)
|
||||||
|
int xioapply_ip_add_membership(
|
||||||
|
xiosingle_t *xfd,
|
||||||
|
struct opt *opt)
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
#if HAVE_STRUCT_IP_MREQN
|
||||||
|
struct ip_mreqn mreqn;
|
||||||
|
#endif
|
||||||
|
struct ip_mreq mreq;
|
||||||
|
} ip4_mreqn = {{{0}}};
|
||||||
|
/* IPv6 not supported - seems to have different handling */
|
||||||
|
/*
|
||||||
|
mc:addr:ifname|ifind
|
||||||
|
mc:ifname|ifind
|
||||||
|
mc:addr
|
||||||
|
*/
|
||||||
|
union sockaddr_union sockaddr1;
|
||||||
|
socklen_t socklen1 = sizeof(sockaddr1.ip4);
|
||||||
|
union sockaddr_union sockaddr2;
|
||||||
|
socklen_t socklen2 = sizeof(sockaddr2.ip4);
|
||||||
|
|
||||||
|
/* first parameter is alway multicast address */
|
||||||
|
/*! result */
|
||||||
|
xiogetaddrinfo(opt->value.u_string/*multiaddr*/, NULL,
|
||||||
|
xfd->para.socket.la.soa.sa_family,
|
||||||
|
SOCK_DGRAM, IPPROTO_IP,
|
||||||
|
&sockaddr1, &socklen1, 0, 0);
|
||||||
|
ip4_mreqn.mreq.imr_multiaddr = sockaddr1.ip4.sin_addr;
|
||||||
|
if (0) {
|
||||||
|
; /* for canonical reasons */
|
||||||
|
#if HAVE_STRUCT_IP_MREQN
|
||||||
|
} else if (opt->value3.u_string/*ifindex*/ != NULL) {
|
||||||
|
/* three parameters */
|
||||||
|
/* second parameter is interface address */
|
||||||
|
xiogetaddrinfo(opt->value2.u_string/*param2*/, NULL,
|
||||||
|
xfd->para.socket.la.soa.sa_family,
|
||||||
|
SOCK_DGRAM, IPPROTO_IP,
|
||||||
|
&sockaddr2, &socklen2, 0, 0);
|
||||||
|
ip4_mreqn.mreq.imr_interface = sockaddr2.ip4.sin_addr;
|
||||||
|
/* third parameter is interface */
|
||||||
|
if (ifindex(opt->value3.u_string/*ifindex*/,
|
||||||
|
(unsigned int *)&ip4_mreqn.mreqn.imr_ifindex, -1)
|
||||||
|
< 0) {
|
||||||
|
Error1("cannot resolve interface \"%s\"",
|
||||||
|
opt->value3.u_string/*ifindex*/);
|
||||||
|
}
|
||||||
|
#endif /* HAVE_STRUCT_IP_MREQN */
|
||||||
|
} else {
|
||||||
|
/* two parameters */
|
||||||
|
if (0) {
|
||||||
|
; /* for canonical reasons */
|
||||||
|
#if HAVE_STRUCT_IP_MREQN
|
||||||
|
/* there is a form with two parameters that uses mreqn */
|
||||||
|
} else if (ifindex(opt->value2.u_string/*param2*/,
|
||||||
|
(unsigned int *)&ip4_mreqn.mreqn.imr_ifindex,
|
||||||
|
-1)
|
||||||
|
>= 0) {
|
||||||
|
/* yes, second param converts to interface */
|
||||||
|
ip4_mreqn.mreq.imr_interface.s_addr = htonl(0);
|
||||||
|
#endif /* HAVE_STRUCT_IP_MREQN */
|
||||||
|
} else {
|
||||||
|
/*! result */
|
||||||
|
xiogetaddrinfo(opt->value2.u_string/*param2*/, NULL,
|
||||||
|
xfd->para.socket.la.soa.sa_family,
|
||||||
|
SOCK_DGRAM, IPPROTO_IP,
|
||||||
|
&sockaddr2, &socklen2, 0, 0);
|
||||||
|
ip4_mreqn.mreq.imr_interface = sockaddr2.ip4.sin_addr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if LATER
|
||||||
|
if (0) {
|
||||||
|
; /* for canonical reasons */
|
||||||
|
} else if (xfd->para.socket.la.soa.sa_family == PF_INET) {
|
||||||
|
} else if (xfd->para.socket.la.soa.sa_family == PF_INET6) {
|
||||||
|
ip6_mreqn.mreq.imr_multiaddr = sockaddr1.ip6.sin6_addr;
|
||||||
|
ip6_mreqn.mreq.imr_interface = sockaddr2.ip6.sin6_addr;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if HAVE_STRUCT_IP_MREQN
|
||||||
|
if (Setsockopt(xfd->fd, opt->desc->major, opt->desc->minor,
|
||||||
|
&ip4_mreqn.mreqn, sizeof(ip4_mreqn.mreqn)) < 0) {
|
||||||
|
Error8("setsockopt(%d, %d, %d, {0x%08x,0x%08x,%d}, "F_Zu"): %s",
|
||||||
|
xfd->fd, opt->desc->major, opt->desc->minor,
|
||||||
|
ip4_mreqn.mreqn.imr_multiaddr.s_addr,
|
||||||
|
ip4_mreqn.mreqn.imr_address.s_addr,
|
||||||
|
ip4_mreqn.mreqn.imr_ifindex,
|
||||||
|
sizeof(ip4_mreqn.mreqn),
|
||||||
|
strerror(errno));
|
||||||
|
opt->desc = ODESC_ERROR;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (Setsockopt(xfd->fd, opt->desc->major, opt->desc->minor,
|
||||||
|
&ip4_mreqn.mreq, sizeof(ip4_mreqn.mreq)) < 0) {
|
||||||
|
Error7("setsockopt(%d, %d, %d, {0x%08x,0x%08x}, "F_Zu"): %s",
|
||||||
|
xfd->fd, opt->desc->major, opt->desc->minor,
|
||||||
|
ip4_mreqn.mreq.imr_multiaddr,
|
||||||
|
ip4_mreqn.mreq.imr_interface,
|
||||||
|
sizeof(ip4_mreqn.mreq),
|
||||||
|
strerror(errno));
|
||||||
|
opt->desc = ODESC_ERROR;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* defined(HAVE_STRUCT_IP_MREQ) || defined (HAVE_STRUCT_IP_MREQN) */
|
||||||
|
|
||||||
|
|
||||||
#if HAVE_STRUCT_IP_MREQ_SOURCE
|
#if HAVE_STRUCT_IP_MREQ_SOURCE
|
||||||
int xiotype_ip_add_source_membership(char *token, const struct optname *ent, struct opt *opt) {
|
int xiotype_ip_add_source_membership(char *token, const struct optname *ent, struct opt *opt) {
|
||||||
/* we do not resolve the addresses here because we do not yet know
|
/* we do not resolve the addresses here because we do not yet know
|
||||||
|
@ -688,7 +883,10 @@ int xiotype_ip_add_source_membership(char *token, const struct optname *ent, str
|
||||||
Error1("syntax in option %s: missing ':'", token);
|
Error1("syntax in option %s: missing ':'", token);
|
||||||
}
|
}
|
||||||
*buffp++ = '\0';
|
*buffp++ = '\0';
|
||||||
opt->value.u_ip_mreq_source.mcaddr = strdup(buff); /*!!! NULL */
|
if ((opt->value.u_string/*mcaddr*/ = strdup(buff)) == NULL) {
|
||||||
|
Error1("strdup(\"%s\"): out of memory", buff);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
++tokp;
|
++tokp;
|
||||||
/* parse second IP address, expect ':' or '\0'' */
|
/* parse second IP address, expect ':' or '\0'' */
|
||||||
|
@ -709,7 +907,11 @@ int xiotype_ip_add_source_membership(char *token, const struct optname *ent, str
|
||||||
Error1("syntax in option %s: missing ':'", token);
|
Error1("syntax in option %s: missing ':'", token);
|
||||||
}
|
}
|
||||||
*buffp++ = '\0';
|
*buffp++ = '\0';
|
||||||
opt->value.u_ip_mreq_source.ifaddr = strdup(buff); /*!!! NULL */
|
if ((opt->value2.u_string/*ifaddr*/ = strdup(buff)) == NULL) {
|
||||||
|
Error1("strdup(\"%s\"): out of memory", buff);
|
||||||
|
free(opt->value.u_string);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
++tokp;
|
++tokp;
|
||||||
/* parse third IP address, expect ':' or '\0'' */
|
/* parse third IP address, expect ':' or '\0'' */
|
||||||
|
@ -730,13 +932,18 @@ int xiotype_ip_add_source_membership(char *token, const struct optname *ent, str
|
||||||
Error1("syntax in option %s: trailing cruft", token);
|
Error1("syntax in option %s: trailing cruft", token);
|
||||||
}
|
}
|
||||||
*buffp++ = '\0';
|
*buffp++ = '\0';
|
||||||
opt->value.u_ip_mreq_source.srcaddr = strdup(buff); /*!!! NULL */
|
if ((opt->value3.u_string/*srcaddr*/ = strdup(buff)) == NULL) {
|
||||||
|
Error1("strdup(\"%s\"): out of memory", buff);
|
||||||
|
free(opt->value.u_string);
|
||||||
|
free(opt->value2.u_string);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
Info4("setting option \"%s\" to {0x%08x,0x%08x,0x%08x}",
|
Info4("setting option \"%s\" to {0x%08x,0x%08x,0x%08x}",
|
||||||
ent->desc->defname,
|
ent->desc->defname,
|
||||||
ntohl(*(unsigned int *)opt->value.u_ip_mreq_source.mcaddr),
|
ntohl(*(unsigned int *)opt->value.u_string/*mcaddr*/),
|
||||||
ntohl(*(unsigned int *)opt->value.u_ip_mreq_source.ifaddr),
|
ntohl(*(unsigned int *)opt->value2.u_string/*ifaddr*/),
|
||||||
ntohl(*(unsigned int *)opt->value.u_ip_mreq_source.srcaddr));
|
ntohl(*(unsigned int *)opt->value3.u_string/*srcaddr*/));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -752,19 +959,19 @@ int xioapply_ip_add_source_membership(struct single *xfd, struct opt *opt) {
|
||||||
|
|
||||||
/* first parameter is always multicast address */
|
/* first parameter is always multicast address */
|
||||||
/*! result */
|
/*! result */
|
||||||
xiogetaddrinfo(opt->value.u_ip_mreq_source.mcaddr, NULL,
|
xiogetaddrinfo(opt->value.u_string/*mcaddr*/, NULL,
|
||||||
xfd->para.socket.la.soa.sa_family,
|
xfd->para.socket.la.soa.sa_family,
|
||||||
SOCK_DGRAM, IPPROTO_IP,
|
SOCK_DGRAM, IPPROTO_IP,
|
||||||
&sockaddr1, &socklen1, 0, 0);
|
&sockaddr1, &socklen1, 0, 0);
|
||||||
ip4_mreq_src.imr_multiaddr = sockaddr1.ip4.sin_addr;
|
ip4_mreq_src.imr_multiaddr = sockaddr1.ip4.sin_addr;
|
||||||
/* second parameter is interface address */
|
/* second parameter is interface address */
|
||||||
xiogetaddrinfo(opt->value.u_ip_mreq_source.ifaddr, NULL,
|
xiogetaddrinfo(opt->value2.u_string/*ifaddr*/, NULL,
|
||||||
xfd->para.socket.la.soa.sa_family,
|
xfd->para.socket.la.soa.sa_family,
|
||||||
SOCK_DGRAM, IPPROTO_IP,
|
SOCK_DGRAM, IPPROTO_IP,
|
||||||
&sockaddr2, &socklen2, 0, 0);
|
&sockaddr2, &socklen2, 0, 0);
|
||||||
ip4_mreq_src.imr_interface = sockaddr2.ip4.sin_addr;
|
ip4_mreq_src.imr_interface = sockaddr2.ip4.sin_addr;
|
||||||
/* third parameter is source address */
|
/* third parameter is source address */
|
||||||
xiogetaddrinfo(opt->value.u_ip_mreq_source.srcaddr, NULL,
|
xiogetaddrinfo(opt->value3.u_string/*srcaddr*/, NULL,
|
||||||
xfd->para.socket.la.soa.sa_family,
|
xfd->para.socket.la.soa.sa_family,
|
||||||
SOCK_DGRAM, IPPROTO_IP,
|
SOCK_DGRAM, IPPROTO_IP,
|
||||||
&sockaddr3, &socklen3, 0, 0);
|
&sockaddr3, &socklen3, 0, 0);
|
||||||
|
|
2
xio-ip.h
2
xio-ip.h
|
@ -49,6 +49,8 @@ int xiolog_ancillary_ip(struct cmsghdr *cmsg, int *num,
|
||||||
char *nambuff, int namlen,
|
char *nambuff, int namlen,
|
||||||
char *envbuff, int envlen,
|
char *envbuff, int envlen,
|
||||||
char *valbuff, int vallen);
|
char *valbuff, int vallen);
|
||||||
|
extern int xiotype_ip_add_membership(char *token, const struct optname *ent, struct opt *opt);
|
||||||
|
extern int xioapply_ip_add_membership(xiosingle_t *xfd, struct opt *opt);
|
||||||
extern int xiotype_ip_add_source_membership(char* token, const struct optname *ent, struct opt *opt);
|
extern int xiotype_ip_add_source_membership(char* token, const struct optname *ent, struct opt *opt);
|
||||||
extern int xioapply_ip_add_source_membership(struct single *xfd, struct opt *opt);
|
extern int xioapply_ip_add_source_membership(struct single *xfd, struct opt *opt);
|
||||||
|
|
||||||
|
|
49
xio-ip6.c
49
xio-ip6.c
|
@ -81,6 +81,7 @@ const struct optdesc opt_ipv6_recvpathmtu = { "ipv6-recvpathmtu", "recvpathmtu",
|
||||||
int xioip6_pton(const char *src, struct in6_addr *dst) {
|
int xioip6_pton(const char *src, struct in6_addr *dst) {
|
||||||
union sockaddr_union sockaddr;
|
union sockaddr_union sockaddr;
|
||||||
socklen_t sockaddrlen = sizeof(sockaddr);
|
socklen_t sockaddrlen = sizeof(sockaddr);
|
||||||
|
int res;
|
||||||
|
|
||||||
if (src[0] == '[') {
|
if (src[0] == '[') {
|
||||||
char plainaddr[INET6_ADDRSTRLEN];
|
char plainaddr[INET6_ADDRSTRLEN];
|
||||||
|
@ -92,8 +93,9 @@ int xioip6_pton(const char *src, struct in6_addr *dst) {
|
||||||
*clos = '\0';
|
*clos = '\0';
|
||||||
return xioip6_pton(plainaddr, dst);
|
return xioip6_pton(plainaddr, dst);
|
||||||
}
|
}
|
||||||
if (xiogetaddrinfo(src, NULL, PF_INET6, 0, 0, &sockaddr, &sockaddrlen,
|
if ((res =
|
||||||
0, 0)
|
xiogetaddrinfo(src, NULL, PF_INET6, 0, 0, &sockaddr, &sockaddrlen,
|
||||||
|
0, 0))
|
||||||
!= STAT_OK) {
|
!= STAT_OK) {
|
||||||
return STAT_NORETRY;
|
return STAT_NORETRY;
|
||||||
}
|
}
|
||||||
|
@ -457,4 +459,47 @@ xiosetsockaddrenv_ip6(int idx, char *namebuff, size_t namelen,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(HAVE_STRUCT_IPV6_MREQ)
|
||||||
|
int xioapply_ipv6_join_group(
|
||||||
|
xiosingle_t *xfd,
|
||||||
|
struct opt *opt)
|
||||||
|
{
|
||||||
|
struct ipv6_mreq ip6_mreq = {{{{0}}}};
|
||||||
|
union sockaddr_union sockaddr1;
|
||||||
|
socklen_t socklen1 = sizeof(sockaddr1.ip6);
|
||||||
|
int res;
|
||||||
|
|
||||||
|
/* Always two parameters */
|
||||||
|
/* First parameter is multicast address */
|
||||||
|
if ((res =
|
||||||
|
xiogetaddrinfo(opt->value.u_string/*multiaddr*/, NULL,
|
||||||
|
xfd->para.socket.la.soa.sa_family,
|
||||||
|
SOCK_DGRAM, IPPROTO_IP,
|
||||||
|
&sockaddr1, &socklen1, 0, 0)) != STAT_OK) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
ip6_mreq.ipv6mr_multiaddr = sockaddr1.ip6.sin6_addr;
|
||||||
|
if (ifindex(opt->value2.u_string/*param2*/,
|
||||||
|
&ip6_mreq.ipv6mr_interface, -1)
|
||||||
|
< 0) {
|
||||||
|
Error1("interface \"%s\" not found",
|
||||||
|
opt->value2.u_string/*param2*/);
|
||||||
|
ip6_mreq.ipv6mr_interface = htonl(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Setsockopt(xfd->fd, opt->desc->major, opt->desc->minor,
|
||||||
|
&ip6_mreq, sizeof(ip6_mreq)) < 0) {
|
||||||
|
Error6("setsockopt(%d, %d, %d, {...,0x%08x}, "F_Zu"): %s",
|
||||||
|
xfd->fd, opt->desc->major, opt->desc->minor,
|
||||||
|
ip6_mreq.ipv6mr_interface,
|
||||||
|
sizeof(ip6_mreq),
|
||||||
|
strerror(errno));
|
||||||
|
opt->desc = ODESC_ERROR;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* defined(HAVE_STRUCT_IPV6_MREQ) */
|
||||||
|
|
||||||
#endif /* WITH_IP6 */
|
#endif /* WITH_IP6 */
|
||||||
|
|
|
@ -48,6 +48,7 @@ extern int
|
||||||
xiosetsockaddrenv_ip6(int idx, char *namebuff, size_t namelen,
|
xiosetsockaddrenv_ip6(int idx, char *namebuff, size_t namelen,
|
||||||
char *valuebuff, size_t valuelen,
|
char *valuebuff, size_t valuelen,
|
||||||
struct sockaddr_in6 *sa, int ipproto);
|
struct sockaddr_in6 *sa, int ipproto);
|
||||||
|
extern int xioapply_ipv6_join_group(xiosingle_t *xfd, struct opt *opt);
|
||||||
|
|
||||||
#endif /* WITH_IP6 */
|
#endif /* WITH_IP6 */
|
||||||
|
|
||||||
|
|
16
xio.h
16
xio.h
|
@ -375,22 +375,6 @@ union integral {
|
||||||
#if HAVE_STRUCT_TIMESPEC
|
#if HAVE_STRUCT_TIMESPEC
|
||||||
struct timespec u_timespec;
|
struct timespec u_timespec;
|
||||||
#endif /* HAVE_STRUCT_TIMESPEC */
|
#endif /* HAVE_STRUCT_TIMESPEC */
|
||||||
#if HAVE_STRUCT_IP_MREQ || HAVE_STRUCT_IP_MREQN
|
|
||||||
struct {
|
|
||||||
char *multiaddr;
|
|
||||||
char *param2; /* address, interface */
|
|
||||||
#if HAVE_STRUCT_IP_MREQN
|
|
||||||
char ifindex[IF_NAMESIZE+1];
|
|
||||||
#endif
|
|
||||||
} u_ip_mreq;
|
|
||||||
#endif
|
|
||||||
#if HAVE_STRUCT_IP_MREQ_SOURCE
|
|
||||||
struct {
|
|
||||||
char *mcaddr;
|
|
||||||
char *ifaddr; /* address, interface */
|
|
||||||
char *srcaddr; /* source address */
|
|
||||||
} u_ip_mreq_source;
|
|
||||||
#endif
|
|
||||||
#if WITH_IP4
|
#if WITH_IP4
|
||||||
struct in_addr u_ip4addr;
|
struct in_addr u_ip4addr;
|
||||||
#endif
|
#endif
|
||||||
|
|
206
xioopts.c
206
xioopts.c
|
@ -2477,76 +2477,10 @@ int parseopts_table(const char **a, groups_t groups, struct opt **opts,
|
||||||
(*opts)[i].value.u_int, (*opts)[i].value2.u_int,
|
(*opts)[i].value.u_int, (*opts)[i].value2.u_int,
|
||||||
(*opts)[i].value3.u_string);
|
(*opts)[i].value3.u_string);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#if defined(HAVE_STRUCT_IP_MREQ) || defined (HAVE_STRUCT_IP_MREQN)
|
#if defined(HAVE_STRUCT_IP_MREQ) || defined (HAVE_STRUCT_IP_MREQN)
|
||||||
|
|
||||||
case TYPE_IP_MREQN:
|
case TYPE_IP_MREQN:
|
||||||
{
|
xiotype_ip_add_membership(token, ent, opt);
|
||||||
/* we do not resolve the addresses here because we do not yet know
|
|
||||||
if we are coping with a IPv4 or IPv6 socat address */
|
|
||||||
const char *ends[] = { ":", NULL };
|
|
||||||
const char *nests[] = { "[","]", NULL };
|
|
||||||
char buff[512], *buffp=buff; size_t bufspc = sizeof(buff)-1;
|
|
||||||
|
|
||||||
/* parse first IP address, expect ':' */
|
|
||||||
tokp = token;
|
|
||||||
/*! result= */
|
|
||||||
parsres =
|
|
||||||
nestlex((const char **)&tokp, &buffp, &bufspc,
|
|
||||||
ends, NULL, NULL, nests,
|
|
||||||
true, false, false);
|
|
||||||
if (parsres < 0) {
|
|
||||||
Error1("option too long: \"%s\"", *a);
|
|
||||||
return -1;
|
|
||||||
} else if (parsres > 0) {
|
|
||||||
Error1("syntax error in \"%s\"", *a);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (*tokp != ':') {
|
|
||||||
Error1("syntax in option %s: missing ':'", token);
|
|
||||||
}
|
|
||||||
*buffp++ = '\0';
|
|
||||||
(*opts)[i].value.u_ip_mreq.multiaddr = strdup(buff); /*!!! NULL */
|
|
||||||
|
|
||||||
++tokp;
|
|
||||||
/* parse second IP address, expect ':' or '\0'' */
|
|
||||||
buffp = buff;
|
|
||||||
/*! result= */
|
|
||||||
parsres =
|
|
||||||
nestlex((const char **)&tokp, &buffp, &bufspc,
|
|
||||||
ends, NULL, NULL, nests,
|
|
||||||
true, false, false);
|
|
||||||
if (parsres < 0) {
|
|
||||||
Error1("option too long: \"%s\"", *a);
|
|
||||||
return -1;
|
|
||||||
} else if (parsres > 0) {
|
|
||||||
Error1("syntax error in \"%s\"", *a);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
*buffp++ = '\0';
|
|
||||||
(*opts)[i].value.u_ip_mreq.param2 = strdup(buff); /*!!! NULL */
|
|
||||||
|
|
||||||
#if HAVE_STRUCT_IP_MREQN
|
|
||||||
if (*tokp++ == ':') {
|
|
||||||
strncpy((*opts)[i].value.u_ip_mreq.ifindex, tokp, IF_NAMESIZE); /* ok */
|
|
||||||
Info4("setting option \"%s\" to {\"%s\",\"%s\",\"%s\"}",
|
|
||||||
ent->desc->defname,
|
|
||||||
(*opts)[i].value.u_ip_mreq.multiaddr,
|
|
||||||
(*opts)[i].value.u_ip_mreq.param2,
|
|
||||||
(*opts)[i].value.u_ip_mreq.ifindex);
|
|
||||||
} else {
|
|
||||||
(*opts)[i].value.u_ip_mreq.ifindex[0] = '\0';
|
|
||||||
Info3("setting option \"%s\" to {\"%s\",\"%s\"}",
|
|
||||||
ent->desc->defname,
|
|
||||||
(*opts)[i].value.u_ip_mreq.multiaddr,
|
|
||||||
(*opts)[i].value.u_ip_mreq.param2);
|
|
||||||
}
|
|
||||||
#else /* !HAVE_STRUCT_IP_MREQN */
|
|
||||||
Info3("setting option \"%s\" to {0x%08x,0x%08x}",
|
|
||||||
ent->desc->defname,
|
|
||||||
(*opts)[i].value.u_ip_mreq.multiaddr,
|
|
||||||
(*opts)[i].value.u_ip_mreq.param2);
|
|
||||||
#endif /* !HAVE_STRUCT_IP_MREQN */
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
#endif /* defined(HAVE_STRUCT_IP_MREQ) || defined (HAVE_STRUCT_IP_MREQN) */
|
#endif /* defined(HAVE_STRUCT_IP_MREQ) || defined (HAVE_STRUCT_IP_MREQN) */
|
||||||
|
|
||||||
|
@ -4029,108 +3963,8 @@ int applyopts_single(struct single *xfd, struct opt *opts, enum e_phase phase) {
|
||||||
switch (opt->desc->optcode) {
|
switch (opt->desc->optcode) {
|
||||||
#if WITH_IP4 && (defined(HAVE_STRUCT_IP_MREQ) || defined (HAVE_STRUCT_IP_MREQN))
|
#if WITH_IP4 && (defined(HAVE_STRUCT_IP_MREQ) || defined (HAVE_STRUCT_IP_MREQN))
|
||||||
case OPT_IP_ADD_MEMBERSHIP:
|
case OPT_IP_ADD_MEMBERSHIP:
|
||||||
{
|
if (xioapply_ip_add_membership(xfd, opt) < 0) {
|
||||||
union {
|
continue;
|
||||||
#if HAVE_STRUCT_IP_MREQN
|
|
||||||
struct ip_mreqn mreqn;
|
|
||||||
#endif
|
|
||||||
struct ip_mreq mreq;
|
|
||||||
} ip4_mreqn = {{{0}}};
|
|
||||||
/* IPv6 not supported - seems to have different handling */
|
|
||||||
/*
|
|
||||||
mc:addr:ifname|ifind
|
|
||||||
mc:ifname|ifind
|
|
||||||
mc:addr
|
|
||||||
*/
|
|
||||||
union sockaddr_union sockaddr1;
|
|
||||||
socklen_t socklen1 = sizeof(sockaddr1.ip4);
|
|
||||||
union sockaddr_union sockaddr2;
|
|
||||||
socklen_t socklen2 = sizeof(sockaddr2.ip4);
|
|
||||||
|
|
||||||
/* first parameter is alway multicast address */
|
|
||||||
/*! result */
|
|
||||||
xiogetaddrinfo(opt->value.u_ip_mreq.multiaddr, NULL,
|
|
||||||
xfd->para.socket.la.soa.sa_family,
|
|
||||||
SOCK_DGRAM, IPPROTO_IP,
|
|
||||||
&sockaddr1, &socklen1, 0, 0);
|
|
||||||
ip4_mreqn.mreq.imr_multiaddr = sockaddr1.ip4.sin_addr;
|
|
||||||
if (0) {
|
|
||||||
; /* for canonical reasons */
|
|
||||||
#if HAVE_STRUCT_IP_MREQN
|
|
||||||
} else if (opt->value.u_ip_mreq.ifindex[0] != '\0') {
|
|
||||||
/* three parameters */
|
|
||||||
/* second parameter is interface address */
|
|
||||||
xiogetaddrinfo(opt->value.u_ip_mreq.param2, NULL,
|
|
||||||
xfd->para.socket.la.soa.sa_family,
|
|
||||||
SOCK_DGRAM, IPPROTO_IP,
|
|
||||||
&sockaddr2, &socklen2, 0, 0);
|
|
||||||
ip4_mreqn.mreq.imr_interface = sockaddr2.ip4.sin_addr;
|
|
||||||
/* third parameter is interface */
|
|
||||||
if (ifindex(opt->value.u_ip_mreq.ifindex,
|
|
||||||
(unsigned int *)&ip4_mreqn.mreqn.imr_ifindex, -1)
|
|
||||||
< 0) {
|
|
||||||
Error1("cannot resolve interface \"%s\"",
|
|
||||||
opt->value.u_ip_mreq.ifindex);
|
|
||||||
}
|
|
||||||
#endif /* HAVE_STRUCT_IP_MREQN */
|
|
||||||
} else {
|
|
||||||
/* two parameters */
|
|
||||||
if (0) {
|
|
||||||
; /* for canonical reasons */
|
|
||||||
#if HAVE_STRUCT_IP_MREQN
|
|
||||||
/* there is a form with two parameters that uses mreqn */
|
|
||||||
} else if (ifindex(opt->value.u_ip_mreq.param2,
|
|
||||||
(unsigned int *)&ip4_mreqn.mreqn.imr_ifindex,
|
|
||||||
-1)
|
|
||||||
>= 0) {
|
|
||||||
/* yes, second param converts to interface */
|
|
||||||
ip4_mreqn.mreq.imr_interface.s_addr = htonl(0);
|
|
||||||
#endif /* HAVE_STRUCT_IP_MREQN */
|
|
||||||
} else {
|
|
||||||
/*! result */
|
|
||||||
xiogetaddrinfo(opt->value.u_ip_mreq.param2, NULL,
|
|
||||||
xfd->para.socket.la.soa.sa_family,
|
|
||||||
SOCK_DGRAM, IPPROTO_IP,
|
|
||||||
&sockaddr2, &socklen2, 0, 0);
|
|
||||||
ip4_mreqn.mreq.imr_interface = sockaddr2.ip4.sin_addr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if LATER
|
|
||||||
if (0) {
|
|
||||||
; /* for canonical reasons */
|
|
||||||
} else if (xfd->para.socket.la.soa.sa_family == PF_INET) {
|
|
||||||
} else if (xfd->para.socket.la.soa.sa_family == PF_INET6) {
|
|
||||||
ip6_mreqn.mreq.imr_multiaddr = sockaddr1.ip6.sin6_addr;
|
|
||||||
ip6_mreqn.mreq.imr_interface = sockaddr2.ip6.sin6_addr;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if HAVE_STRUCT_IP_MREQN
|
|
||||||
if (Setsockopt(xfd->fd, opt->desc->major, opt->desc->minor,
|
|
||||||
&ip4_mreqn.mreqn, sizeof(ip4_mreqn.mreqn)) < 0) {
|
|
||||||
Error8("setsockopt(%d, %d, %d, {0x%08x,0x%08x,%d}, "F_Zu"): %s",
|
|
||||||
xfd->fd, opt->desc->major, opt->desc->minor,
|
|
||||||
ip4_mreqn.mreqn.imr_multiaddr.s_addr,
|
|
||||||
ip4_mreqn.mreqn.imr_address.s_addr,
|
|
||||||
ip4_mreqn.mreqn.imr_ifindex,
|
|
||||||
sizeof(ip4_mreqn.mreqn),
|
|
||||||
strerror(errno));
|
|
||||||
opt->desc = ODESC_ERROR; continue;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if (Setsockopt(xfd->fd, opt->desc->major, opt->desc->minor,
|
|
||||||
&ip4_mreqn.mreq, sizeof(ip4_mreqn.mreq)) < 0) {
|
|
||||||
Error7("setsockopt(%d, %d, %d, {0x%08x,0x%08x}, "F_Zu"): %s",
|
|
||||||
xfd->fd, opt->desc->major, opt->desc->minor,
|
|
||||||
ip4_mreqn.mreq.imr_multiaddr,
|
|
||||||
ip4_mreqn.mreq.imr_interface,
|
|
||||||
sizeof(ip4_mreqn.mreq),
|
|
||||||
strerror(errno));
|
|
||||||
opt->desc = ODESC_ERROR; continue;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif /* WITH_IP4 && (defined(HAVE_STRUCT_IP_MREQ) || defined (HAVE_STRUCT_IP_MREQN)) */
|
#endif /* WITH_IP4 && (defined(HAVE_STRUCT_IP_MREQ) || defined (HAVE_STRUCT_IP_MREQN)) */
|
||||||
|
@ -4145,36 +3979,8 @@ mc:addr
|
||||||
|
|
||||||
#if WITH_IP6 && defined(HAVE_STRUCT_IPV6_MREQ)
|
#if WITH_IP6 && defined(HAVE_STRUCT_IPV6_MREQ)
|
||||||
case OPT_IPV6_JOIN_GROUP:
|
case OPT_IPV6_JOIN_GROUP:
|
||||||
{
|
if (xioapply_ipv6_join_group(xfd, opt) < 0) {
|
||||||
struct ipv6_mreq ip6_mreq = {{{{0}}}};
|
continue;
|
||||||
union sockaddr_union sockaddr1;
|
|
||||||
socklen_t socklen1 = sizeof(sockaddr1.ip6);
|
|
||||||
|
|
||||||
/* always two parameters */
|
|
||||||
/* first parameter is multicast address */
|
|
||||||
/*! result */
|
|
||||||
xiogetaddrinfo(opt->value.u_ip_mreq.multiaddr, NULL,
|
|
||||||
xfd->para.socket.la.soa.sa_family,
|
|
||||||
SOCK_DGRAM, IPPROTO_IP,
|
|
||||||
&sockaddr1, &socklen1, 0, 0);
|
|
||||||
ip6_mreq.ipv6mr_multiaddr = sockaddr1.ip6.sin6_addr;
|
|
||||||
if (ifindex(opt->value.u_ip_mreq.param2,
|
|
||||||
&ip6_mreq.ipv6mr_interface, -1)
|
|
||||||
< 0) {
|
|
||||||
Error1("interface \"%s\" not found",
|
|
||||||
opt->value.u_ip_mreq.param2);
|
|
||||||
ip6_mreq.ipv6mr_interface = htonl(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Setsockopt(xfd->fd, opt->desc->major, opt->desc->minor,
|
|
||||||
&ip6_mreq, sizeof(ip6_mreq)) < 0) {
|
|
||||||
Error6("setsockopt(%d, %d, %d, {...,0x%08x}, "F_Zu"): %s",
|
|
||||||
xfd->fd, opt->desc->major, opt->desc->minor,
|
|
||||||
ip6_mreq.ipv6mr_interface,
|
|
||||||
sizeof(ip6_mreq),
|
|
||||||
strerror(errno));
|
|
||||||
opt->desc = ODESC_ERROR; continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif /* WITH_IP6 && defined(HAVE_STRUCT_IPV6_MREQ) */
|
#endif /* WITH_IP6 && defined(HAVE_STRUCT_IPV6_MREQ) */
|
||||||
|
|
Loading…
Reference in a new issue