New option ip-add-source-membership

This commit is contained in:
Gerhard Rieger 2020-12-13 22:21:06 +01:00
parent 13ac417410
commit 583e14d7fa
10 changed files with 195 additions and 2 deletions

View file

@ -155,6 +155,9 @@ New features:
Test: ACCEPTTIMEOUT
Proposed by Roland
New option ip-add-source-membership
Feature inspired by Brian (b f31415)
####################### V 1.7.3.4:
Corrections:

View file

@ -379,6 +379,9 @@
/* Define if you have struct ipv6_mreq */
#undef HAVE_STRUCT_IPV6_MREQ
/* Define if you have struct ip_mreq_source */
#undef HAVE_STRUCT_IP_MREQ_SOURCE
/* Define if you have struct ifreq */
#undef HAVE_STRUCT_IFREQ

View file

@ -1176,6 +1176,19 @@ if test $sc_cv_struct_ipv6_mreq = yes; then
fi
AC_MSG_RESULT($sc_cv_struct_ipv6_mreq)
# struct ip_mreq_source (for multicasting options)
AC_MSG_CHECKING(for struct ip_mreq_source)
AC_CACHE_VAL(sc_cv_struct_ip_mreq_source,
[AC_TRY_COMPILE([#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/ip.h>],[struct ip_mreq_source s;],
[sc_cv_struct_ip_mreq_source=yes],
[sc_cv_struct_ip_mreq_source=no])])
if test $sc_cv_struct_ip_mreq_source = yes; then
AC_DEFINE(HAVE_STRUCT_IP_MREQ_SOURCE)
fi
AC_MSG_RESULT($sc_cv_struct_ip_mreqn)
# struct ifreq (for network interfaces)
AC_MSG_CHECKING(for struct ifreq)

View file

@ -394,6 +394,7 @@ label(ADDRESS_IP_DATAGRAM)dit(bf(tt(IP-DATAGRAM:<address>:<protocol>)))
link(ip-multicast-ttl)(OPTION_IP_MULTICAST_TTL),
link(ip-multicast-if)(OPTION_IP_MULTICAST_IF),
link(ip-add-membership)(OPTION_IP_ADD_MEMBERSHIP),
link(ip-add-source-membership)(OPTION_IP_ADD_SOURCE_MEMBERSHIP),
link(ttl)(OPTION_TTL),
link(tos)(OPTION_TOS),
link(pf)(OPTION_PROTOCOL_FAMILY)nl()
@ -1101,6 +1102,7 @@ label(ADDRESS_UDP_DATAGRAM)dit(bf(tt(UDP-DATAGRAM:<address>:<port>)))
link(ip-multicast-ttl)(OPTION_IP_MULTICAST_TTL),
link(ip-multicast-if)(OPTION_IP_MULTICAST_IF),
link(ip-add-membership)(OPTION_IP_ADD_MEMBERSHIP),
link(ip-add-source-membership)(OPTION_IP_ADD_SOURCE_MEMBERSHIP),
link(ttl)(OPTION_TTL),
link(tos)(OPTION_TOS),
link(sourceport)(OPTION_SOURCEPORT),
@ -2108,6 +2110,11 @@ dit(bf(tt(ip-add-membership=<multicast-address:interface-address:interface-index
provide tt(struct mreqn) (Linux).nl()
The indices of active network interfaces can be shown using the utility
procan().
label(OPTION_IP_ADD_SOURCE_MEMBERSHIP)
dit(bf(tt(ip-add-source-membership=<multicast-address:interface-address:source-address>)))
Makes the socket member of the specified multicast group for the specified
source, i.e. only multicast traffic from this address is to be delivered.
This is currently only implemented for IPv4.nl()
label(OPTION_IP_MULTICAST_IF)
dit(bf(tt(ip-multicast-if=<hostname>)))
Specifies hostname or address of the network interface to be used for

128
xio-ip.c
View file

@ -14,6 +14,7 @@
#include "xio-socket.h"
#include "xio-ip.h"
#include "xio-ip6.h"
#include "nestlex.h"
#if WITH_IP4 || WITH_IP6
@ -70,6 +71,9 @@ const struct optdesc opt_ip_pktoptions = { "ip-pktoptions", "pktopts", OPT_IP_PK
#ifdef IP_ADD_MEMBERSHIP
const struct optdesc opt_ip_add_membership = { "ip-add-membership", "membership",OPT_IP_ADD_MEMBERSHIP, GROUP_SOCK_IP, PH_PASTSOCKET, TYPE_IP_MREQN, OFUNC_SOCKOPT, SOL_IP, IP_ADD_MEMBERSHIP };
#endif
#ifdef IP_ADD_SOURCE_MEMBERSHIP
const struct optdesc opt_ip_add_source_membership = { "ip-add-source-membership", "source-membership",OPT_IP_ADD_SOURCE_MEMBERSHIP, GROUP_SOCK_IP, PH_PASTSOCKET, TYPE_IP_MREQ_SOURCE, OFUNC_SOCKOPT, SOL_IP, IP_ADD_SOURCE_MEMBERSHIP };
#endif
#ifdef IP_RECVDSTADDR
const struct optdesc opt_ip_recvdstaddr = { "ip-recvdstaddr", "recvdstaddr",OPT_IP_RECVDSTADDR, GROUP_SOCK_IP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IP, IP_RECVDSTADDR };
#endif
@ -581,4 +585,128 @@ int xiolog_ancillary_ip(struct cmsghdr *cmsg, int *num,
}
#endif /* defined(HAVE_STRUCT_CMSGHDR) && defined(CMSG_DATA) */
#if HAVE_STRUCT_IP_MREQ_SOURCE
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
if we are coping with an IPv4 or IPv6 socat address */
const char *ends[] = { ":", NULL };
const char *nests[] = { "[","]", NULL };
char buff[512], *buffp=buff; size_t bufspc = sizeof(buff)-1;
char *tokp = token;
int parsres;
/* parse first IP address, expect ':' */
parsres =
nestlex((const char **)&tokp, &buffp, &bufspc,
ends, NULL, NULL, nests,
true, false, false);
if (parsres < 0) {
Error1("option too long: \"%s\"", token);
return -1;
} else if (parsres > 0) {
Error1("syntax error in \"%s\"", token);
return -1;
}
if (*tokp != ':') {
Error1("syntax in option %s: missing ':'", token);
}
*buffp++ = '\0';
opt->value.u_ip_mreq_source.mcaddr = 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\"", token);
return -1;
} else if (parsres > 0) {
Error1("syntax error in \"%s\"", token);
return -1;
}
if (*tokp != ':') {
Error1("syntax in option %s: missing ':'", token);
}
*buffp++ = '\0';
opt->value.u_ip_mreq_source.ifaddr = strdup(buff); /*!!! NULL */
++tokp;
/* parse third 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\"", token);
return -1;
} else if (parsres > 0) {
Error1("syntax error in \"%s\"", token);
return -1;
}
if (*tokp) {
Error1("syntax in option %s: trailing cruft", token);
}
*buffp++ = '\0';
opt->value.u_ip_mreq_source.srcaddr = strdup(buff); /*!!! NULL */
Info4("setting option \"%s\" to {0x%08x,0x%08x,0x08x}",
ent->desc->defname,
opt->value.u_ip_mreq_source.mcaddr,
opt->value.u_ip_mreq_source.ifaddr,
opt->value.u_ip_mreq_source.srcaddr);
return 0;
}
int xioapply_ip_add_source_membership(struct single *xfd, struct opt *opt) {
struct ip_mreq_source ip4_mreq_src = {{0}};
/* IPv6 not supported - seems to have different handling */
union sockaddr_union sockaddr1;
socklen_t socklen1 = sizeof(sockaddr1.ip4);
union sockaddr_union sockaddr2;
socklen_t socklen2 = sizeof(sockaddr2.ip4);
union sockaddr_union sockaddr3;
socklen_t socklen3 = sizeof(sockaddr3.ip4);
/* first parameter is always multicast address */
/*! result */
xiogetaddrinfo(opt->value.u_ip_mreq_source.mcaddr, NULL,
xfd->para.socket.la.soa.sa_family,
SOCK_DGRAM, IPPROTO_IP,
&sockaddr1, &socklen1, 0, 0);
ip4_mreq_src.imr_multiaddr = sockaddr1.ip4.sin_addr;
/* second parameter is interface address */
xiogetaddrinfo(opt->value.u_ip_mreq_source.ifaddr, NULL,
xfd->para.socket.la.soa.sa_family,
SOCK_DGRAM, IPPROTO_IP,
&sockaddr2, &socklen2, 0, 0);
ip4_mreq_src.imr_interface = sockaddr2.ip4.sin_addr;
/* third parameter is source address */
xiogetaddrinfo(opt->value.u_ip_mreq_source.srcaddr, NULL,
xfd->para.socket.la.soa.sa_family,
SOCK_DGRAM, IPPROTO_IP,
&sockaddr3, &socklen3, 0, 0);
ip4_mreq_src.imr_sourceaddr = sockaddr3.ip4.sin_addr;
if (Setsockopt(xfd->fd, opt->desc->major, opt->desc->minor,
&ip4_mreq_src, sizeof(ip4_mreq_src)) < 0) {
Error8("setsockopt(%d, %d, %d, {0x%08x,0x%08x,0x%08x}, "F_Zu"): %s",
xfd->fd, opt->desc->major, opt->desc->minor,
ip4_mreq_src.imr_multiaddr,
ip4_mreq_src.imr_interface,
ip4_mreq_src.imr_sourceaddr,
sizeof(struct ip_mreq_source),
strerror(errno));
opt->desc = ODESC_ERROR;
return -1;
}
return 0;
}
#endif /* HAVE_STRUCT_IP_MREQ_SOURCE */
#endif /* _WITH_IP4 || _WITH_IP6 */

View file

@ -24,6 +24,7 @@ extern const struct optdesc opt_ip_multicast_loop;
extern const struct optdesc opt_ip_multicast_if;
extern const struct optdesc opt_ip_pktoptions;
extern const struct optdesc opt_ip_add_membership;
extern const struct optdesc opt_ip_add_source_membership;
extern const struct optdesc opt_ip_recvdstaddr;
extern const struct optdesc opt_ip_recvif;
extern const struct optdesc opt_ip_transparent;
@ -48,5 +49,7 @@ int xiolog_ancillary_ip(struct cmsghdr *cmsg, int *num,
char *nambuff, int namlen,
char *envbuff, int envlen,
char *valbuff, int vallen);
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);
#endif /* !defined(__xio_ip_h_included) */

7
xio.h
View file

@ -354,6 +354,13 @@ union integral {
#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
struct in_addr u_ip4addr;
#endif

View file

@ -21,6 +21,7 @@ static const char *optiontypenames[] = {
"DOUBLE", "STRING-NULL", "LONG-LONG", "OFF_T",
"OFF64_T", "INT:INT", "INT:INTP", "INT:BIN",
"INT:STRING", "INT:INT:INT", "INT:INT:BIN", "INT:INT:STRING",
"INT:INT:GENERIC",
"IP4NAME",
#if HAVE_STRUCT_LINGER
@ -31,6 +32,10 @@ static const char *optiontypenames[] = {
#elif HAVE_STRUCT_IP_MREQ
"STRUCT-IP_MREQ",
#endif
#if HAVE_STRUCT_IP_MREQ_SOURCE
"IP-MREQ-SOURCE",
#endif
"GENERIC",
} ;

View file

@ -7,6 +7,7 @@
#include "xiosysincludes.h"
#include "xioopen.h"
#include "xio-unix.h"
#include "xio-ip.h"
#include "xiomodes.h"
#include "xiolockfile.h"
@ -156,6 +157,9 @@ const struct optname optionnames[] = {
#endif /* SO_ACCEPTCONN */
#ifdef IP_ADD_MEMBERSHIP
IF_IP ("add-membership", &opt_ip_add_membership)
#endif
#ifdef IP_ADD_SOURCE_MEMBERSHIP
IF_IP ("add-source-membership", &opt_ip_add_source_membership)
#endif
IF_TUN ("allmulti", &opt_iff_allmulti)
#if WITH_LIBWRAP && defined(HAVE_HOSTS_ALLOW_TABLE)
@ -668,6 +672,9 @@ const struct optname optionnames[] = {
#ifdef IP_ADD_MEMBERSHIP
IF_IP ("ip-add-membership", &opt_ip_add_membership)
#endif
#ifdef IP_ADD_SOURCE_MEMBERSHIP
IF_IP ("ip-add-source-membership", &opt_ip_add_source_membership)
#endif
#ifdef IP_FREEBIND
IF_IP ("ip-freebind", &opt_ip_freebind)
#endif
@ -1547,6 +1554,9 @@ const struct optname optionnames[] = {
IF_SOCKS4 ("socksport", &opt_socksport)
IF_SOCKS4 ("socksuser", &opt_socksuser)
IF_SOCKET ("socktype", &opt_so_type)
#ifdef IP_ADD_SOURCE_MEMBERSHIP
IF_IP ("source-membership", &opt_ip_add_source_membership)
#endif
IF_IPAPP ("sourceport", &opt_sourceport)
IF_IPAPP ("sp", &opt_sourceport)
IF_TERMIOS("start", &opt_vstart)
@ -2488,6 +2498,10 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
break;
#endif /* defined(HAVE_STRUCT_IP_MREQ) || defined (HAVE_STRUCT_IP_MREQN) */
case TYPE_IP_MREQ_SOURCE:
xiotype_ip_add_source_membership(token, ent, opt);
break;
#if WITH_IP4
case TYPE_IP4NAME:
{
@ -4057,7 +4071,13 @@ mc:addr
break;
#endif /* WITH_IP4 && (defined(HAVE_STRUCT_IP_MREQ) || defined (HAVE_STRUCT_IP_MREQN)) */
#if WITH_IP4 && defined(HAVE_STRUCT_IP_MREQ_SOURCE) && defined(IP_ADD_SOURCE_MEMBERSHIP)
case OPT_IP_ADD_SOURCE_MEMBERSHIP:
if (xioapply_ip_add_source_membership(xfd, opt) < 0) {
continue;
}
break;
#endif /* WITH_IP4 && defined(HAVE_STRUCT_IP_MREQ_SOURCE) && defined(IP_ADD_SOURCE_MEMBERSHIP) */
#if WITH_IP6 && defined(HAVE_STRUCT_IPV6_MREQ)
case OPT_IPV6_JOIN_GROUP:

View file

@ -73,8 +73,11 @@ enum e_types {
#if HAVE_STRUCT_IP_MREQ || HAVE_STRUCT_IP_MREQN
TYPE_IP_MREQN, /* for struct ip_mreq or struct ip_mreqn */
#endif
#if HAVE_STRUCT_IP_MREQ_SOURCE
TYPE_IP_MREQ_SOURCE, /* for struct ip_mreq_source */
#endif
TYPE_GENERIC, /* type is determined from (text) data provided */
TYPE_GENERIC, /* type is determined from (text) data provided (dalan syntax) */
} ;
enum e_func {
@ -380,6 +383,7 @@ enum e_optcode {
OPT_IOCTL_STRING, /* generic ioctl with integer value (pointed to) */
OPT_IOCTL_VOID, /* generic ioctl without value */
OPT_IP_ADD_MEMBERSHIP,
OPT_IP_ADD_SOURCE_MEMBERSHIP,
#ifdef IP_HDRINCL
OPT_IP_HDRINCL,
#endif