2008-01-28 21:37:16 +00:00
/* source: xio-ip.c */
2016-07-22 06:54:31 +00:00
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
2008-01-27 12:00:08 +00:00
/* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for IP related functions */
# include "xiosysincludes.h"
# if _WITH_IP4 || _WITH_IP6
# include "xioopen.h"
2008-09-22 20:17:55 +00:00
# include "xio-ascii.h"
2008-01-27 12:00:08 +00:00
# include "xio-socket.h"
# include "xio-ip.h"
# include "xio-ip6.h"
2020-12-13 21:21:06 +00:00
# include "nestlex.h"
2008-01-27 12:00:08 +00:00
# if WITH_IP4 || WITH_IP6
# ifdef IP_OPTIONS
const struct optdesc opt_ip_options = { " ip-options " , " ipoptions " , OPT_IP_OPTIONS , GROUP_SOCK_IP , PH_PASTSOCKET , TYPE_BIN , OFUNC_SOCKOPT_APPEND , SOL_IP , IP_OPTIONS } ;
# endif
# ifdef IP_PKTINFO
const struct optdesc opt_ip_pktinfo = { " ip-pktinfo " , " pktinfo " , OPT_IP_PKTINFO , GROUP_SOCK_IP , PH_PASTSOCKET , TYPE_INT , OFUNC_SOCKOPT , SOL_IP , IP_PKTINFO } ;
# endif
# ifdef IP_RECVTOS
const struct optdesc opt_ip_recvtos = { " ip-recvtos " , " recvtos " , OPT_IP_RECVTOS , GROUP_SOCK_IP , PH_PASTSOCKET , TYPE_INT , OFUNC_SOCKOPT , SOL_IP , IP_RECVTOS } ;
# endif
2008-09-22 20:17:55 +00:00
# ifdef IP_RECVTTL /* -Cygwin */
2008-01-27 12:00:08 +00:00
const struct optdesc opt_ip_recvttl = { " ip-recvttl " , " recvttl " , OPT_IP_RECVTTL , GROUP_SOCK_IP , PH_PASTSOCKET , TYPE_INT , OFUNC_SOCKOPT , SOL_IP , IP_RECVTTL } ;
# endif
# ifdef IP_RECVOPTS
const struct optdesc opt_ip_recvopts = { " ip-recvopts " , " recvopts " , OPT_IP_RECVOPTS , GROUP_SOCK_IP , PH_PASTSOCKET , TYPE_INT , OFUNC_SOCKOPT , SOL_IP , IP_RECVOPTS } ;
# endif
# ifdef IP_RETOPTS
const struct optdesc opt_ip_retopts = { " ip-retopts " , " retopts " , OPT_IP_RETOPTS , GROUP_SOCK_IP , PH_PASTSOCKET , TYPE_INT , OFUNC_SOCKOPT , SOL_IP , IP_RETOPTS } ;
# endif
const struct optdesc opt_ip_tos = { " ip-tos " , " tos " , OPT_IP_TOS , GROUP_SOCK_IP , PH_PASTSOCKET , TYPE_INT , OFUNC_SOCKOPT , SOL_IP , IP_TOS } ;
const struct optdesc opt_ip_ttl = { " ip-ttl " , " ttl " , OPT_IP_TTL , GROUP_SOCK_IP , PH_PASTSOCKET , TYPE_INT , OFUNC_SOCKOPT , SOL_IP , IP_TTL } ;
# ifdef IP_HDRINCL
const struct optdesc opt_ip_hdrincl = { " ip-hdrincl " , " hdrincl " , OPT_IP_HDRINCL , GROUP_SOCK_IP , PH_PASTSOCKET , TYPE_INT , OFUNC_SOCKOPT , SOL_IP , IP_HDRINCL } ;
# endif
# ifdef IP_RECVERR
const struct optdesc opt_ip_recverr = { " ip-recverr " , " recverr " , OPT_IP_RECVERR , GROUP_SOCK_IP , PH_PASTSOCKET , TYPE_INT , OFUNC_SOCKOPT , SOL_IP , IP_RECVERR } ;
# endif
# ifdef IP_MTU_DISCOVER
const struct optdesc opt_ip_mtu_discover = { " ip-mtu-discover " , " mtudiscover " , OPT_IP_MTU_DISCOVER , GROUP_SOCK_IP , PH_PASTSOCKET , TYPE_INT , OFUNC_SOCKOPT , SOL_IP , IP_MTU_DISCOVER } ;
# endif
# ifdef IP_MTU
const struct optdesc opt_ip_mtu = { " ip-mtu " , " mtu " , OPT_IP_MTU , GROUP_SOCK_IP , PH_PASTSOCKET , TYPE_INT , OFUNC_SOCKOPT , SOL_IP , IP_MTU } ;
# endif
2020-12-12 12:47:40 +00:00
# ifdef IP_TRANSPARENT
const struct optdesc opt_ip_transparent = { " ip-transparent " , " transparent " , OPT_IP_TRANSPARENT , GROUP_SOCK_IP , PH_PREBIND , TYPE_BOOL , OFUNC_SOCKOPT , SOL_IP , IP_TRANSPARENT } ;
# endif
2008-01-27 12:00:08 +00:00
# ifdef IP_FREEBIND
const struct optdesc opt_ip_freebind = { " ip-freebind " , " freebind " , OPT_IP_FREEBIND , GROUP_SOCK_IP , PH_PASTSOCKET , TYPE_INT , OFUNC_SOCKOPT , SOL_IP , IP_FREEBIND } ;
# endif
# ifdef IP_ROUTER_ALERT
const struct optdesc opt_ip_router_alert = { " ip-router-alert " , " routeralert " , OPT_IP_ROUTER_ALERT , GROUP_SOCK_IP , PH_PASTSOCKET , TYPE_INT , OFUNC_SOCKOPT , SOL_IP , IP_ROUTER_ALERT } ;
# endif
/* following: Linux allows int but OpenBSD reqs char/byte */
const struct optdesc opt_ip_multicast_ttl = { " ip-multicast-ttl " , " multicastttl " , OPT_IP_MULTICAST_TTL , GROUP_SOCK_IP , PH_PASTSOCKET , TYPE_BYTE , OFUNC_SOCKOPT , SOL_IP , IP_MULTICAST_TTL } ;
2008-09-14 16:33:28 +00:00
/* following: Linux allows int but OpenBSD reqs char/byte */
const struct optdesc opt_ip_multicast_loop = { " ip-multicast-loop " , " multicastloop " , OPT_IP_MULTICAST_LOOP , GROUP_SOCK_IP , PH_PASTSOCKET , TYPE_BYTE , OFUNC_SOCKOPT , SOL_IP , IP_MULTICAST_LOOP } ;
2008-01-27 12:00:08 +00:00
const struct optdesc opt_ip_multicast_if = { " ip-multicast-if " , " multicast-if " , OPT_IP_MULTICAST_IF , GROUP_SOCK_IP , PH_PASTSOCKET , TYPE_IP4NAME , OFUNC_SOCKOPT , SOL_IP , IP_MULTICAST_IF } ;
# ifdef IP_PKTOPTIONS
const struct optdesc opt_ip_pktoptions = { " ip-pktoptions " , " pktopts " , OPT_IP_PKTOPTIONS , GROUP_SOCK_IP , PH_PASTSOCKET , TYPE_INT , OFUNC_SOCKOPT , SOL_IP , IP_PKTOPTIONS } ;
# endif
# 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
2022-09-15 08:09:05 +00:00
# if defined(HAVE_STRUCT_IP_MREQ_SOURCE) && defined(IP_ADD_SOURCE_MEMBERSHIP)
2020-12-13 21:21:06 +00:00
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
2008-09-22 20:17:55 +00:00
# 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
# ifdef IP_RECVIF
const struct optdesc opt_ip_recvif = { " ip-recvif " , " recvdstaddrif " , OPT_IP_RECVIF , GROUP_SOCK_IP , PH_PASTSOCKET , TYPE_INT , OFUNC_SOCKOPT , SOL_IP , IP_RECVIF } ;
# endif
2008-01-27 12:00:08 +00:00
2023-11-05 12:56:58 +00:00
# ifdef AI_ADDRCONFIG
const struct optdesc opt_ai_addrconfig = { " ai-addrconfig " , " addrconfig " , OPT_AI_ADDRCONFIG , GROUP_SOCK_IP , PH_INIT , TYPE_BOOL , OFUNC_OFFSET_MASKS , XIO_OFFSETOF ( para . socket . ip . ai_flags ) , XIO_SIZEOF ( para . socket . ip . ai_flags ) , AI_ADDRCONFIG } ;
# endif
2023-11-05 12:58:07 +00:00
# ifdef AI_PASSIVE
const struct optdesc opt_ai_passive = { " ai-passive " , " passive " , OPT_AI_PASSIVE , GROUP_SOCK_IP , PH_INIT , TYPE_BOOL , OFUNC_OFFSET_MASKS , XIO_OFFSETOF ( para . socket . ip . ai_flags ) , XIO_SIZEOF ( para . socket . ip . ai_flags ) , AI_PASSIVE } ;
# endif
2023-11-05 12:56:58 +00:00
2019-03-03 14:57:08 +00:00
# if WITH_RES_DEPRECATED
# define WITH_RES_AAONLY 1
# define WITH_RES_PRIMARY 1
# endif /* WITH_RES_DEPRECATED */
2008-01-27 12:00:08 +00:00
# if HAVE_RESOLV_H
2010-01-09 12:32:23 +00:00
const struct optdesc opt_res_debug = { " res-debug " , NULL , OPT_RES_DEBUG , GROUP_SOCK_IP , PH_INIT , TYPE_BOOL , OFUNC_OFFSET_MASKS , XIO_OFFSETOF ( para . socket . ip . res_opts ) , XIO_SIZEOF ( para . socket . ip . res_opts ) , RES_DEBUG } ;
2019-03-03 14:57:08 +00:00
# if WITH_RES_AAONLY
2010-01-09 12:32:23 +00:00
const struct optdesc opt_res_aaonly = { " res-aaonly " , " aaonly " , OPT_RES_AAONLY , GROUP_SOCK_IP , PH_INIT , TYPE_BOOL , OFUNC_OFFSET_MASKS , XIO_OFFSETOF ( para . socket . ip . res_opts ) , XIO_SIZEOF ( para . socket . ip . res_opts ) , RES_AAONLY } ;
2019-03-03 14:57:08 +00:00
# endif
2010-01-09 12:32:23 +00:00
const struct optdesc opt_res_usevc = { " res-usevc " , " usevc " , OPT_RES_USEVC , GROUP_SOCK_IP , PH_INIT , TYPE_BOOL , OFUNC_OFFSET_MASKS , XIO_OFFSETOF ( para . socket . ip . res_opts ) , XIO_SIZEOF ( para . socket . ip . res_opts ) , RES_USEVC } ;
2019-03-03 14:57:08 +00:00
# if WITH_RES_PRIMARY
2010-01-09 12:32:23 +00:00
const struct optdesc opt_res_primary = { " res-primary " , " primary " , OPT_RES_PRIMARY , GROUP_SOCK_IP , PH_INIT , TYPE_BOOL , OFUNC_OFFSET_MASKS , XIO_OFFSETOF ( para . socket . ip . res_opts ) , XIO_SIZEOF ( para . socket . ip . res_opts ) , RES_PRIMARY } ;
2019-03-03 14:57:08 +00:00
# endif
2010-01-09 12:32:23 +00:00
const struct optdesc opt_res_igntc = { " res-igntc " , " igntc " , OPT_RES_IGNTC , GROUP_SOCK_IP , PH_INIT , TYPE_BOOL , OFUNC_OFFSET_MASKS , XIO_OFFSETOF ( para . socket . ip . res_opts ) , XIO_SIZEOF ( para . socket . ip . res_opts ) , RES_IGNTC } ;
const struct optdesc opt_res_recurse = { " res-recurse " , " recurse " , OPT_RES_RECURSE , GROUP_SOCK_IP , PH_INIT , TYPE_BOOL , OFUNC_OFFSET_MASKS , XIO_OFFSETOF ( para . socket . ip . res_opts ) , XIO_SIZEOF ( para . socket . ip . res_opts ) , RES_RECURSE } ;
const struct optdesc opt_res_defnames = { " res-defnames " , " defnames " , OPT_RES_DEFNAMES , GROUP_SOCK_IP , PH_INIT , TYPE_BOOL , OFUNC_OFFSET_MASKS , XIO_OFFSETOF ( para . socket . ip . res_opts ) , XIO_SIZEOF ( para . socket . ip . res_opts ) , RES_DEFNAMES } ;
const struct optdesc opt_res_stayopen = { " res-stayopen " , " stayopen " , OPT_RES_STAYOPEN , GROUP_SOCK_IP , PH_INIT , TYPE_BOOL , OFUNC_OFFSET_MASKS , XIO_OFFSETOF ( para . socket . ip . res_opts ) , XIO_SIZEOF ( para . socket . ip . res_opts ) , RES_STAYOPEN } ;
const struct optdesc opt_res_dnsrch = { " res-dnsrch " , " dnsrch " , OPT_RES_DNSRCH , GROUP_SOCK_IP , PH_INIT , TYPE_BOOL , OFUNC_OFFSET_MASKS , XIO_OFFSETOF ( para . socket . ip . res_opts ) , XIO_SIZEOF ( para . socket . ip . res_opts ) , RES_DNSRCH } ;
2008-01-27 12:00:08 +00:00
# endif /* HAVE_RESOLV_H */
# endif /* WITH_IP4 || WITH_IP6 */
2023-10-26 20:16:21 +00:00
int xioinit_ip (
2023-11-05 12:59:14 +00:00
int * pf ,
char ipv )
2023-10-26 20:16:21 +00:00
{
if ( * pf = = PF_UNSPEC ) {
2023-11-05 12:59:14 +00:00
switch ( ipv ) {
2023-10-26 20:16:21 +00:00
case ' 0 ' : * pf = PF_UNSPEC ; break ;
# if WITH_IP4
case ' 4 ' : * pf = PF_INET ; break ;
# endif
# if WITH_IP6
case ' 6 ' : * pf = PF_INET6 ; break ;
# endif
}
}
return 0 ;
}
2008-01-27 12:00:08 +00:00
# if HAVE_RESOLV_H
int Res_init ( void ) {
int result ;
Debug ( " res_init() " ) ;
result = res_init ( ) ;
Debug1 ( " res_init() -> %d " , result ) ;
return result ;
}
# endif /* HAVE_RESOLV_H */
# if HAVE_RESOLV_H
unsigned long res_opts ( ) {
return _res . options ;
}
# endif /* HAVE_RESOLV_H */
/* the ultimate(?) socat resolver function
node : the address to be resolved ; supported forms :
1.2 .3 .4 ( IPv4 address )
[ : : 2 ] ( IPv6 address )
hostname ( hostname resolving to IPv4 or IPv6 address )
hostname . domain ( fq hostname resolving to IPv4 or IPv6 address )
service : the port specification ; may be numeric or symbolic
family : PF_INET , PF_INET6 , or PF_UNSPEC permitting both
2020-01-01 13:50:29 +00:00
socktype : SOCK_STREAM , SOCK_DGRAM , . . .
2008-01-27 12:00:08 +00:00
protocol : IPPROTO_UDP , IPPROTO_TCP
sau : an uninitialized storage for the resulting socket address
2023-06-24 08:21:44 +00:00
returns : STAT_OK , STAT_RETRYLATER , STAT_NORETRY , prints message
2008-01-27 12:00:08 +00:00
*/
int xiogetaddrinfo ( const char * node , const char * service ,
int family , int socktype , int protocol ,
2023-11-05 12:56:58 +00:00
struct addrinfo * * res , const int ai_flags [ 2 ] ,
const unsigned long res_opts [ 2 ] ) {
2008-01-27 12:00:08 +00:00
char * numnode = NULL ;
size_t nodelen ;
unsigned long save_res_opts = 0 ;
# if HAVE_GETADDRINFO
struct addrinfo hints = { 0 } ;
2014-03-01 14:58:06 +00:00
# else /* HAVE_PROTOTYPE_LIB_getipnodebyname || nothing */
2008-01-27 12:00:08 +00:00
struct hostent * host ;
# endif
int error_num ;
# if HAVE_RESOLV_H
2023-11-05 12:56:58 +00:00
if ( res_opts [ 0 ] | res_opts [ 1 ] ) {
2008-01-27 12:00:08 +00:00
if ( ! ( _res . options & RES_INIT ) ) {
Res_init ( ) ; /*!!! returns -1 on error */
}
save_res_opts = _res . options ;
2023-11-05 12:56:58 +00:00
_res . options | = res_opts [ 0 ] ;
_res . options & = ~ res_opts [ 1 ] ;
2008-01-27 12:00:08 +00:00
Debug2 ( " changed _res.options from 0x%lx to 0x%lx " ,
save_res_opts , _res . options ) ;
}
# endif /* HAVE_RESOLV_H */
2015-01-12 21:21:36 +00:00
if ( service & & service [ 0 ] = = ' \0 ' ) {
Error ( " empty port/service " ) ;
}
2020-12-26 21:46:36 +00:00
2023-10-22 21:15:49 +00:00
# if LATER
2020-12-26 21:46:36 +00:00
# ifdef WITH_VSOCK
if ( family = = AF_VSOCK ) {
error_num = sockaddr_vm_parse ( & sau - > vm , node , service ) ;
if ( error_num < 0 )
return STAT_NORETRY ;
return STAT_OK ;
}
# endif /* WITH_VSOCK */
2023-10-22 21:15:49 +00:00
# endif /* LATER */
2008-01-27 12:00:08 +00:00
/* the resolver functions might handle numeric forms of node names by
reverse lookup , that ' s not what we want .
So we detect these and handle them specially */
2018-07-29 09:30:40 +00:00
if ( 0 ) { /* for canonical reasons */
;
2008-01-27 12:00:08 +00:00
# if WITH_IP6
} else if ( node & & node [ 0 ] = = ' [ ' & & node [ ( nodelen = strlen ( node ) ) - 1 ] = = ' ] ' ) {
if ( ( numnode = Malloc ( nodelen - 1 ) ) = = NULL ) {
# if HAVE_RESOLV_H
2023-11-05 12:56:58 +00:00
if ( res_opts [ 0 ] | res_opts [ 1 ] ) {
_res . options = save_res_opts ;
2008-01-27 12:00:08 +00:00
}
# endif
return STAT_NORETRY ;
}
2014-01-19 13:35:23 +00:00
strncpy ( numnode , node + 1 , nodelen - 2 ) ; /* ok */
2008-01-27 12:00:08 +00:00
numnode [ nodelen - 2 ] = ' \0 ' ;
node = numnode ;
# if HAVE_GETADDRINFO
hints . ai_flags | = AI_NUMERICHOST ;
# endif /* HAVE_GETADDRINFO */
if ( family = = PF_UNSPEC ) family = PF_INET6 ;
# endif /* WITH_IP6 */
}
2023-11-05 12:56:58 +00:00
if ( family = = 0 )
hints . ai_flags | = AI_ADDRCONFIG ;
hints . ai_flags | = AI_PASSIVE /* important for IPv4+IPv6 listen */ ;
2008-01-27 12:00:08 +00:00
# if HAVE_GETADDRINFO
if ( node ! = NULL | | service ! = NULL ) {
struct addrinfo * record ;
2023-11-05 12:56:58 +00:00
if ( ai_flags ! = NULL ) {
hints . ai_flags | = ai_flags [ 0 ] ;
hints . ai_flags & = ~ ai_flags [ 1 ] ;
}
2008-01-27 12:00:08 +00:00
hints . ai_family = family ;
hints . ai_socktype = socktype ;
hints . ai_protocol = protocol ;
hints . ai_addrlen = 0 ;
hints . ai_addr = NULL ;
hints . ai_canonname = NULL ;
hints . ai_next = NULL ;
2020-12-11 21:13:08 +00:00
do {
2023-10-22 21:15:49 +00:00
error_num = Getaddrinfo ( node , service , & hints , res ) ;
2020-12-11 21:13:08 +00:00
if ( error_num = = 0 ) break ;
if ( error_num = = EAI_SOCKTYPE & & socktype ! = 0 ) {
/* there are systems where kernel goes SCTP but not getaddrinfo() */
hints . ai_socktype = 0 ;
continue ;
}
if ( error_num = = EAI_SERVICE & & protocol ! = 0 ) {
2021-10-26 11:34:38 +00:00
if ( hints . ai_protocol = = 0 ) {
2023-11-05 12:59:14 +00:00
Error7 ( " getaddrinfo \" %s \" , \" %s \" , {0x%02x,%d,%d,%d}, {}): %s " ,
2021-10-26 11:34:38 +00:00
node ? node : " NULL " , service ? service : " NULL " ,
hints . ai_flags , hints . ai_family ,
hints . ai_socktype , hints . ai_protocol ,
gai_strerror ( error_num ) ) ;
2023-10-22 21:15:49 +00:00
if ( res ! = NULL ) freeaddrinfo ( * res ) ;
2021-10-26 11:34:38 +00:00
if ( numnode ) free ( numnode ) ;
return STAT_NORETRY ;
}
2020-12-11 21:13:08 +00:00
hints . ai_protocol = 0 ;
continue ;
}
2023-10-22 21:15:49 +00:00
if ( ( error_num = Getaddrinfo ( node , service , & hints , res ) ) ! = 0 ) {
2023-11-05 12:56:58 +00:00
Error7 ( " getaddrinfo( \" %s \" , \" %s \" , {0x%02x,%d,%d,%d}, {}): %s " ,
2016-05-08 11:52:20 +00:00
node ? node : " NULL " , service ? service : " NULL " ,
hints . ai_flags , hints . ai_family ,
2008-01-27 12:00:08 +00:00
hints . ai_socktype , hints . ai_protocol ,
( error_num = = EAI_SYSTEM ) ?
strerror ( errno ) : gai_strerror ( error_num ) ) ;
if ( numnode ) free ( numnode ) ;
# if HAVE_RESOLV_H
2023-11-05 12:56:58 +00:00
if ( res_opts [ 0 ] | res_opts [ 1 ] ) {
_res . options = save_res_opts ;
2008-01-27 12:00:08 +00:00
}
# endif
return STAT_RETRYLATER ;
2020-12-11 21:13:08 +00:00
}
} while ( 1 ) ;
2008-01-29 22:08:52 +00:00
service = NULL ; /* do not resolve later again */
2008-01-27 12:00:08 +00:00
2023-10-22 21:15:49 +00:00
# if WITH_MSGLEVEL <= E_DEBUG
record = * res ;
while ( record ) {
char buff [ 256 /*!*/ ] ;
sockaddr_info ( record - > ai_addr , record - > ai_addrlen , buff , sizeof ( buff ) ) ;
2023-11-05 12:59:14 +00:00
Debug5 ( " getaddrinfo() -> flags=0x%02x family=%d socktype=%d protocol=%d addr=%s " , record - > ai_flags , record - > ai_family , record - > ai_socktype , record - > ai_protocol , buff ) ;
2023-10-22 21:15:49 +00:00
record = record - > ai_next ;
2008-01-27 12:00:08 +00:00
}
2023-10-22 21:15:49 +00:00
# endif /* WITH_MSGLEVEL <= E_DEBUG */
2008-01-27 12:00:08 +00:00
}
2014-03-01 14:58:06 +00:00
# elif HAVE_PROTOTYPE_LIB_getipnodebyname /* !HAVE_GETADDRINFO */
2008-01-27 12:00:08 +00:00
if ( node ! = NULL ) {
/* first fallback is getipnodebyname() */
if ( family = = PF_UNSPEC ) {
# if WITH_IP4 && WITH_IP6
2023-10-26 20:16:21 +00:00
switch ( xioparms . default_ip ) {
case ' 4 ' : pf = PF_INET ; break ;
case ' 6 ' : pf = PF_INET6 ; break ;
default : break ; /* includes \0 */
}
2008-01-27 12:00:08 +00:00
# elif WITH_IP6
family = PF_INET6 ;
# else
family = PF_INET ;
# endif
}
host = Getipnodebyname ( node , family , AI_V4MAPPED , & error_num ) ;
if ( host = = NULL ) {
const static char ai_host_not_found [ ] = " Host not found " ;
const static char ai_no_address [ ] = " No address " ;
const static char ai_no_recovery [ ] = " No recovery " ;
const static char ai_try_again [ ] = " Try again " ;
const char * error_msg = " Unknown error " ;
switch ( error_num ) {
case HOST_NOT_FOUND : error_msg = ai_host_not_found ; break ;
case NO_ADDRESS : error_msg = ai_no_address ;
case NO_RECOVERY : error_msg = ai_no_recovery ;
case TRY_AGAIN : error_msg = ai_try_again ;
}
Error2 ( " getipnodebyname( \" %s \" , ...): %s " , node , error_msg ) ;
} else {
switch ( family ) {
# if WITH_IP4
case PF_INET :
* socklen = sizeof ( sau - > ip4 ) ;
sau - > soa . sa_family = PF_INET ;
memcpy ( & sau - > ip4 . sin_addr , host - > h_addr_list [ 0 ] , 4 ) ;
break ;
# endif
# if WITH_IP6
case PF_INET6 :
* socklen = sizeof ( sau - > ip6 ) ;
sau - > soa . sa_family = PF_INET6 ;
memcpy ( & sau - > ip6 . sin6_addr , host - > h_addr_list [ 0 ] , 16 ) ;
break ;
# endif
}
}
freehostent ( host ) ;
}
2023-10-22 21:15:49 +00:00
# elsif 0 /* !HAVE_PROTOTYPE_LIB_getipnodebyname */
2008-01-27 12:00:08 +00:00
if ( node ! = NULL ) {
/* this is not a typical IP6 resolver function - but Linux
" man gethostbyname " says that the only supported address type with
this function is AF_INET _at present_ , so maybe this fallback will
2020-12-28 11:37:49 +00:00
be useful somewhere sometimes in a future even for IP6 */
2008-01-27 12:00:08 +00:00
if ( family = = PF_UNSPEC ) {
# if WITH_IP4 && WITH_IP6
2023-10-26 20:16:21 +00:00
switch ( xioparms . default_ip ) {
case ' 4 ' : pf = PF_INET ; break ;
case ' 6 ' : pf = PF_INET6 ; break ;
default : break ; /* includes \0 */
}
2008-01-27 12:00:08 +00:00
# elif WITH_IP6
family = PF_INET6 ;
# else
family = PF_INET ;
# endif
}
/*!!! try gethostbyname2 for IP6 */
if ( ( host = Gethostbyname ( node ) ) = = NULL ) {
Error2 ( " gethostbyname( \" %s \" ): %s " , node ,
h_errno = = NETDB_INTERNAL ? strerror ( errno ) :
hstrerror ( h_errno ) ) ;
# if HAVE_RESOLV_H
2023-11-05 12:56:58 +00:00
if ( res_opts [ 0 ] | res_opts [ 1 ] ) {
_res . options = save_res_opts ;
2008-01-27 12:00:08 +00:00
}
# endif
return STAT_RETRYLATER ;
}
if ( host - > h_addrtype ! = family ) {
2023-10-22 21:15:49 +00:00
Error2 ( " xiogetaddrinfo(): \" %s \" does not resolve to %s " ,
2008-01-27 12:00:08 +00:00
node , family = = PF_INET ? " IP4 " : " IP6 " ) ;
} else {
switch ( family ) {
# if WITH_IP4
case PF_INET :
* socklen = sizeof ( sau - > ip4 ) ;
sau - > soa . sa_family = PF_INET ;
memcpy ( & sau - > ip4 . sin_addr , host - > h_addr_list [ 0 ] , 4 ) ;
break ;
# endif /* WITH_IP4 */
# if WITH_IP6
case PF_INET6 :
* socklen = sizeof ( sau - > ip6 ) ;
sau - > soa . sa_family = PF_INET6 ;
memcpy ( & sau - > ip6 . sin6_addr , host - > h_addr_list [ 0 ] , 16 ) ;
break ;
# endif /* WITH_IP6 */
}
}
}
# endif
if ( numnode ) free ( numnode ) ;
# if HAVE_RESOLV_H
2023-11-05 12:56:58 +00:00
if ( res_opts [ 0 ] | res_opts [ 1 ] ) {
_res . options = save_res_opts ;
2008-01-27 12:00:08 +00:00
}
# endif /* HAVE_RESOLV_H */
return STAT_OK ;
}
2023-10-22 21:15:49 +00:00
void xiofreeaddrinfo ( struct addrinfo * res ) {
# if HAVE_GETADDRINFO
freeaddrinfo ( res ) ;
# else
;
# endif
}
/* A simple resolver interface that just returns one address,
the first found by calling xiogetaddrinfo ( ) .
2023-11-05 12:59:14 +00:00
family may be AF_INET , AF_INET6 , or AF_UNSPEC ;
2023-10-22 21:15:49 +00:00
Returns - 1 when an error occurred or when no result found .
*/
int xioresolve ( const char * node , const char * service ,
int family , int socktype , int protocol ,
union sockaddr_union * addr , socklen_t * addrlen ,
2023-11-05 12:56:58 +00:00
const int ai_flags [ 2 ] , const unsigned long res_opts [ 2 ] )
{
2023-10-22 21:15:49 +00:00
struct addrinfo * res = NULL ;
2023-11-05 12:59:14 +00:00
struct addrinfo * aip ;
2023-10-22 21:15:49 +00:00
int rc ;
rc = xiogetaddrinfo ( node , service , family , socktype , protocol ,
2023-11-05 12:56:58 +00:00
& res , ai_flags , res_opts ) ;
2023-10-22 21:15:49 +00:00
if ( rc ! = 0 ) {
xiofreeaddrinfo ( res ) ;
return - 1 ;
}
if ( res = = NULL ) {
Warn1 ( " xioresolve(node= \" %s \" , ...): No result " , node ) ;
xiofreeaddrinfo ( res ) ;
return - 1 ;
}
if ( res - > ai_addrlen > * addrlen ) {
Warn3 ( " xioresolve(node= \" %s \" , addrlen= " F_socklen " , ...): " F_socklen " bytes required " , node , * addrlen , res - > ai_addrlen ) ;
xiofreeaddrinfo ( res ) ;
return - 1 ;
}
if ( res - > ai_next ! = NULL ) {
Info4 ( " xioresolve(node= \" %s \" , service=%s%s%s, ...): More than one address found " , node ? node : " NULL " , service ? " \" " : " " , service ? service : " NULL " , service ? " \" " : " " ) ;
}
2023-11-05 12:59:14 +00:00
aip = res ;
if ( ai_flags [ 0 ] & AI_PASSIVE & & family = = PF_UNSPEC ) {
/* We select the first IPv6 address, if available,
because this might accept IPv4 connections too */
struct addrinfo * aip = res ;
while ( aip ! = NULL ) {
if ( aip - > ai_family = = PF_INET6 )
break ;
aip = aip - > ai_next ;
}
if ( aip = = NULL )
aip = res ;
}
memcpy ( addr , aip - > ai_addr , aip - > ai_addrlen ) ;
* addrlen = aip - > ai_addrlen ;
2023-10-22 21:15:49 +00:00
xiofreeaddrinfo ( res ) ;
return 0 ;
}
2008-01-27 12:00:08 +00:00
2008-09-22 20:17:55 +00:00
# if defined(HAVE_STRUCT_CMSGHDR) && defined(CMSG_DATA)
2021-10-28 19:21:07 +00:00
/* Converts the ancillary message in *cmsg into a form useable for further
2014-01-19 13:35:23 +00:00
processing . knows the specifics of common message types .
2021-10-28 19:21:07 +00:00
These are valid for IPv4 and IPv6
Returns the number of resulting syntax elements in * num
Returns a sequence of \ 0 terminated type strings in * typbuff
Returns a sequence of \ 0 terminated name strings in * nambuff
Returns a sequence of \ 0 terminated value strings in * valbuff
The respective len parameters specify the available space in the buffers
Returns STAT_OK on success
Returns STAT_WARNING if a buffer was too short and data truncated .
2014-01-19 13:35:23 +00:00
*/
2023-09-30 13:18:39 +00:00
int xiolog_ancillary_ip (
struct single * sfd ,
struct cmsghdr * cmsg ,
int * num ,
char * typbuff , int typlen ,
char * nambuff , int namlen ,
char * envbuff , int envlen ,
char * valbuff , int vallen )
{
2017-01-22 17:48:07 +00:00
int cmsgctr = 0 ;
const char * cmsgtype , * cmsgname = NULL , * cmsgenvn = NULL ;
2008-09-22 20:17:55 +00:00
size_t msglen ;
char scratch1 [ 16 ] ; /* can hold an IPv4 address in ASCII */
2011-11-22 12:37:23 +00:00
# if WITH_IP4 && defined(IP_PKTINFO) && HAVE_STRUCT_IN_PKTINFO
2008-09-22 20:17:55 +00:00
char scratch2 [ 16 ] ;
char scratch3 [ 16 ] ;
2011-11-22 12:37:23 +00:00
# endif
2014-01-19 13:35:23 +00:00
int rc = 0 ;
2008-09-22 20:17:55 +00:00
msglen = cmsg - > cmsg_len - ( ( char * ) CMSG_DATA ( cmsg ) - ( char * ) cmsg ) ;
envbuff [ 0 ] = ' \0 ' ;
switch ( cmsg - > cmsg_type ) {
default :
* num = 1 ;
2014-01-19 13:35:23 +00:00
typbuff [ 0 ] = ' \0 ' ; strncat ( typbuff , " IP " , typlen - 1 ) ;
2008-09-22 20:17:55 +00:00
snprintf ( nambuff , namlen , " type_%u " , cmsg - > cmsg_type ) ;
xiodump ( CMSG_DATA ( cmsg ) , msglen , valbuff , vallen , 0 ) ;
return STAT_OK ;
2008-09-24 14:14:42 +00:00
# if WITH_IP4
2008-09-26 10:30:04 +00:00
# if defined(IP_PKTINFO) && HAVE_STRUCT_IN_PKTINFO
2008-09-22 20:17:55 +00:00
case IP_PKTINFO : {
struct in_pktinfo * pktinfo = ( struct in_pktinfo * ) CMSG_DATA ( cmsg ) ;
* num = 3 ;
2014-01-19 13:35:23 +00:00
typbuff [ 0 ] = ' \0 ' ; strncat ( typbuff , " IP_PKTINFO " , typlen - 1 ) ;
2008-09-22 20:17:55 +00:00
snprintf ( nambuff , namlen , " %s%c%s%c%s " , " if " , ' \0 ' , " locaddr " , ' \0 ' , " dstaddr " ) ;
2023-06-12 21:01:54 +00:00
snprintf ( envbuff , envlen , " %s%c%s%c%s " , " IP_IF " , ' \0 ' ,
2008-09-22 20:17:55 +00:00
" IP_LOCADDR " , ' \0 ' , " IP_DSTADDR " ) ;
snprintf ( valbuff , vallen , " %s%c%s%c%s " ,
xiogetifname ( pktinfo - > ipi_ifindex , scratch1 , - 1 ) , ' \0 ' ,
2011-11-22 10:24:35 +00:00
# if HAVE_PKTINFO_IPI_SPEC_DST
inet4addr_info ( ntohl ( pktinfo - > ipi_spec_dst . s_addr ) ,
scratch2 , sizeof ( scratch2 ) ) ,
# else
" " ,
# endif
' \0 ' ,
inet4addr_info ( ntohl ( pktinfo - > ipi_addr . s_addr ) ,
scratch3 , sizeof ( scratch3 ) ) ) ;
2021-10-28 19:21:07 +00:00
Notice3 ( " Ancillary message: interface \" %s \" , locaddr=%s, dstaddr=%s " ,
xiogetifname ( pktinfo - > ipi_ifindex , scratch1 , - 1 ) ,
# if HAVE_PKTINFO_IPI_SPEC_DST
inet4addr_info ( ntohl ( pktinfo - > ipi_spec_dst . s_addr ) ,
scratch2 , sizeof ( scratch2 ) ) ,
# else
" " ,
# endif
inet4addr_info ( ntohl ( pktinfo - > ipi_addr . s_addr ) ,
scratch3 , sizeof ( scratch3 ) ) ) ;
2008-09-22 20:17:55 +00:00
}
return STAT_OK ;
2008-09-26 10:30:04 +00:00
# endif /* defined(IP_PKTINFO) && HAVE_STRUCT_IN_PKTINFO */
2008-09-24 14:14:42 +00:00
# endif /* WITH_IP4 */
2015-01-23 17:46:04 +00:00
# if defined(IP_RECVERR) && HAVE_STRUCT_SOCK_EXTENDED_ERR
2008-09-22 20:17:55 +00:00
case IP_RECVERR : {
2021-10-28 19:21:07 +00:00
struct xio_extended_err {
struct sock_extended_err see ;
__u32 data0 ;
__u32 data1 ;
__u32 data2 ;
__u32 data3 ;
} ;
struct xio_extended_err * err =
( struct xio_extended_err * ) CMSG_DATA ( cmsg ) ;
2008-09-22 20:17:55 +00:00
* num = 6 ;
2014-01-19 13:35:23 +00:00
typbuff [ 0 ] = ' \0 ' ; strncat ( typbuff , " IP_RECVERR " , typlen - 1 ) ;
2008-09-22 20:17:55 +00:00
snprintf ( nambuff , namlen , " %s%c%s%c%s%c%s%c%s%c%s " ,
" errno " , ' \0 ' , " origin " , ' \0 ' , " type " , ' \0 ' ,
" code " , ' \0 ' , " info " , ' \0 ' , " data " ) ;
snprintf ( envbuff , envlen , " %s%c%s%c%s%c%s%c%s%c%s " ,
" IP_RECVERR_ERRNO " , ' \0 ' , " IP_RECVERR_ORIGIN " , ' \0 ' ,
" IP_RECVERR_TYPE " , ' \0 ' , " IP_RECVERR_CODE " , ' \0 ' ,
" IP_RECVERR_INFO " , ' \0 ' , " IP_RECVERR_DATA " ) ;
snprintf ( valbuff , vallen , " %u%c%u%c%u%c%u%c%u%c%u " ,
2021-10-28 19:21:07 +00:00
err - > see . ee_errno , ' \0 ' , err - > see . ee_origin , ' \0 ' , err - > see . ee_type , ' \0 ' ,
err - > see . ee_code , ' \0 ' , err - > see . ee_info , ' \0 ' , err - > see . ee_data ) ;
/* semantic part */
switch ( err - > see . ee_origin ) {
char addrbuff [ 40 ] ;
# if WITH_IP4
case SO_EE_ORIGIN_ICMP :
if ( 1 ) {
inet4addr_info ( ntohl ( err - > data1 ) , addrbuff , sizeof ( addrbuff ) ) ;
Notice6 ( " received ICMP from %s, type %d, code %d, info %d, data %d, resulting in errno %d " ,
addrbuff , err - > see . ee_type , err - > see . ee_code , err - > see . ee_info , err - > see . ee_data , err - > see . ee_errno ) ;
}
break ;
# endif /* WITH_IP4 */
# if WITH_IP6
case SO_EE_ORIGIN_ICMP6 :
if ( 1 ) {
Notice5 ( " received ICMP type %d, code %d, info %d, data %d, resulting in errno %d " ,
err - > see . ee_type , err - > see . ee_code , err - > see . ee_info , err - > see . ee_data , err - > see . ee_errno ) ;
}
break ;
# endif /* WITH_IP6 */
default :
Notice6 ( " received error message origin %d, type %d, code %d, info %d, data %d, generating errno %d " ,
err - > see . ee_origin , err - > see . ee_type , err - > see . ee_code , err - > see . ee_info , err - > see . ee_data , err - > see . ee_errno ) ;
break ;
}
2008-09-22 20:17:55 +00:00
return STAT_OK ;
}
2015-01-23 17:46:04 +00:00
# endif /* defined(IP_RECVERR) && HAVE_STRUCT_SOCK_EXTENDED_ERR */
2008-09-22 20:17:55 +00:00
# ifdef IP_RECVIF
case IP_RECVIF : {
/* spec in FreeBSD: /usr/include/net/if_dl.h */
struct sockaddr_dl * sadl = ( struct sockaddr_dl * ) CMSG_DATA ( cmsg ) ;
* num = 1 ;
2014-01-19 13:35:23 +00:00
typbuff [ 0 ] = ' \0 ' ; strncat ( typbuff , " IP_RECVIF " , typlen - 1 ) ;
nambuff [ 0 ] = ' \0 ' ; strncat ( nambuff , " if " , namlen - 1 ) ;
envbuff [ 0 ] = ' \0 ' ; strncat ( envbuff , " IP_IF " , envlen - 1 ) ;
valbuff [ 0 ] = ' \0 ' ;
strncat ( valbuff ,
xiosubstr ( scratch1 , sadl - > sdl_data , 0 , sadl - > sdl_nlen ) , vallen - 1 ) ;
2021-10-28 19:21:07 +00:00
Notice1 ( " IP_RECVIF: %s " , valbuff ) ;
2008-09-22 20:17:55 +00:00
return STAT_OK ;
}
# endif /* defined(IP_RECVIF) */
2008-09-24 14:14:42 +00:00
# if WITH_IP4
2008-09-22 20:17:55 +00:00
# ifdef IP_RECVDSTADDR
case IP_RECVDSTADDR :
* num = 1 ;
2014-01-19 13:35:23 +00:00
typbuff [ 0 ] = ' \0 ' ; strncat ( typbuff , " IP_RECVDSTADDR " , typlen - 1 ) ;
nambuff [ 0 ] = ' \0 ' ; strncat ( nambuff , " dstaddr " , namlen - 1 ) ;
envbuff [ 0 ] = ' \0 ' ; strncat ( envbuff , " IP_DSTADDR " , envlen - 1 ) ;
2008-09-22 20:17:55 +00:00
inet4addr_info ( ntohl ( * ( uint32_t * ) CMSG_DATA ( cmsg ) ) , valbuff , vallen ) ;
2021-10-28 19:21:07 +00:00
Notice1 ( " IP_RECVDSTADDR: %s " , valbuff ) ;
2008-09-22 20:17:55 +00:00
return STAT_OK ;
# endif
2008-09-24 14:14:42 +00:00
# endif /* WITH_IP4 */
2008-09-22 20:17:55 +00:00
case IP_OPTIONS :
2008-09-26 09:54:08 +00:00
# ifdef IP_RECVOPTS
2008-09-22 20:17:55 +00:00
case IP_RECVOPTS :
2008-09-26 09:54:08 +00:00
# endif
2021-10-28 19:21:07 +00:00
cmsgtype = " IP_OPTIONS " ; cmsgname = " options " ; cmsgctr = - 1 ;
/*!!!*/
break ;
2022-09-26 19:56:21 +00:00
# if XIO_ANCILLARY_TYPE_SOLARIS
case IP_RECVTOS :
# else
2008-09-22 20:17:55 +00:00
case IP_TOS :
2022-09-26 19:56:21 +00:00
# endif
2021-10-28 19:21:07 +00:00
cmsgtype = " IP_TOS " ; cmsgname = " tos " ; cmsgctr = msglen ;
break ;
2008-09-22 20:17:55 +00:00
case IP_TTL : /* Linux */
# ifdef IP_RECVTTL
case IP_RECVTTL : /* FreeBSD */
# endif
2017-01-22 17:48:07 +00:00
cmsgtype = " IP_TTL " ; cmsgname = " ttl " ; cmsgctr = msglen ; break ;
2008-09-22 20:17:55 +00:00
}
/* when we come here we provide a single parameter
2021-10-28 19:21:07 +00:00
with name in cmsgname , value length in msglen */
2008-09-22 20:17:55 +00:00
* num = 1 ;
2014-01-19 13:35:23 +00:00
if ( strlen ( cmsgtype ) > = typlen ) rc = STAT_WARNING ;
typbuff [ 0 ] = ' \0 ' ; strncat ( typbuff , cmsgtype , typlen - 1 ) ;
if ( strlen ( cmsgname ) > = namlen ) rc = STAT_WARNING ;
nambuff [ 0 ] = ' \0 ' ; strncat ( nambuff , cmsgname , namlen - 1 ) ;
2008-09-22 20:17:55 +00:00
if ( cmsgenvn ) {
2014-01-19 13:35:23 +00:00
if ( strlen ( cmsgenvn ) > = envlen ) rc = STAT_WARNING ;
envbuff [ 0 ] = ' \0 ' ; strncat ( envbuff , cmsgenvn , envlen - 1 ) ;
2008-09-22 20:17:55 +00:00
} else {
envbuff [ 0 ] = ' \0 ' ;
}
2017-01-22 17:48:07 +00:00
switch ( cmsgctr ) {
case sizeof ( char ) :
2021-10-28 19:21:07 +00:00
snprintf ( valbuff , vallen , " %u " , * ( unsigned char * ) CMSG_DATA ( cmsg ) ) ;
Notice2 ( " Ancillary message: %s=%u " , cmsgname , * ( unsigned char * ) CMSG_DATA ( cmsg ) ) ;
break ;
2017-01-22 17:48:07 +00:00
case sizeof ( int ) :
2021-10-28 19:21:07 +00:00
snprintf ( valbuff , vallen , " %u " , ( * ( unsigned int * ) CMSG_DATA ( cmsg ) ) ) ;
Notice2 ( " Ancillary message: %s=%u " , cmsgname , * ( unsigned int * ) CMSG_DATA ( cmsg ) ) ;
break ;
2017-01-22 17:48:07 +00:00
case 0 :
xiodump ( CMSG_DATA ( cmsg ) , msglen , valbuff , vallen , 0 ) ; break ;
default : break ;
2008-09-22 20:17:55 +00:00
}
2014-01-19 13:35:23 +00:00
return rc ;
2008-09-22 20:17:55 +00:00
}
# endif /* defined(HAVE_STRUCT_CMSGHDR) && defined(CMSG_DATA) */
2020-12-13 21:21:06 +00:00
2023-06-24 08:21:44 +00:00
# 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 ) ;
2023-11-05 12:56:58 +00:00
/* First parameter is always multicast address */
2023-06-24 08:21:44 +00:00
/*! result */
2023-10-22 21:15:49 +00:00
xioresolve ( opt - > value . u_string /*multiaddr*/ , NULL ,
2023-11-05 12:56:58 +00:00
xfd - > para . socket . la . soa . sa_family ,
SOCK_DGRAM , IPPROTO_IP , & sockaddr1 , & socklen1 ,
xfd - > para . socket . ip . ai_flags , xfd - > para . socket . ip . res_opts ) ;
2023-06-24 08:21:44 +00:00
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 */
2023-10-22 21:15:49 +00:00
xioresolve ( opt - > value2 . u_string /*param2*/ , NULL ,
2023-11-05 12:56:58 +00:00
xfd - > para . socket . la . soa . sa_family ,
SOCK_DGRAM , IPPROTO_IP , & sockaddr2 , & socklen2 ,
xfd - > para . socket . ip . ai_flags ,
xfd - > para . socket . ip . res_opts ) ;
2023-06-24 08:21:44 +00:00
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 */
2023-10-22 21:15:49 +00:00
xioresolve ( opt - > value2 . u_string /*param2*/ , NULL ,
2023-11-05 12:56:58 +00:00
xfd - > para . socket . la . soa . sa_family ,
SOCK_DGRAM , IPPROTO_IP ,
& sockaddr2 , & socklen2 ,
xfd - > para . socket . ip . ai_flags ,
xfd - > para . socket . ip . res_opts ) ;
2023-06-24 08:21:44 +00:00
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) */
2020-12-13 21:21:06 +00:00
# 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 ' ;
2023-06-24 08:21:44 +00:00
if ( ( opt - > value . u_string /*mcaddr*/ = strdup ( buff ) ) = = NULL ) {
Error1 ( " strdup( \" %s \" ): out of memory " , buff ) ;
return - 1 ;
}
2020-12-13 21:21:06 +00:00
+ + 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 ' ;
2023-06-24 08:21:44 +00:00
if ( ( opt - > value2 . u_string /*ifaddr*/ = strdup ( buff ) ) = = NULL ) {
Error1 ( " strdup( \" %s \" ): out of memory " , buff ) ;
free ( opt - > value . u_string ) ;
return - 1 ;
}
2020-12-13 21:21:06 +00:00
+ + 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 ' ;
2023-06-24 08:21:44 +00:00
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 ;
}
2020-12-13 21:21:06 +00:00
2021-01-03 15:56:50 +00:00
Info4 ( " setting option \" %s \" to {0x%08x,0x%08x,0x%08x} " ,
2020-12-13 21:21:06 +00:00
ent - > desc - > defname ,
2023-06-24 08:21:44 +00:00
ntohl ( * ( unsigned int * ) opt - > value . u_string /*mcaddr*/ ) ,
ntohl ( * ( unsigned int * ) opt - > value2 . u_string /*ifaddr*/ ) ,
ntohl ( * ( unsigned int * ) opt - > value3 . u_string /*srcaddr*/ ) ) ;
2020-12-13 21:21:06 +00:00
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 ) ;
2023-10-22 21:15:49 +00:00
int rc ;
2020-12-13 21:21:06 +00:00
/* first parameter is always multicast address */
2023-10-22 21:15:49 +00:00
rc = xioresolve ( opt - > value . u_string /*mcaddr*/ , NULL ,
2023-11-05 12:56:58 +00:00
xfd - > para . socket . la . soa . sa_family ,
SOCK_DGRAM , IPPROTO_IP ,
& sockaddr1 , & socklen1 , xfd - > para . socket . ip . ai_flags ,
xfd - > para . socket . ip . res_opts ) ;
2023-10-22 21:15:49 +00:00
if ( rc < 0 ) {
return - 1 ;
}
2020-12-13 21:21:06 +00:00
ip4_mreq_src . imr_multiaddr = sockaddr1 . ip4 . sin_addr ;
/* second parameter is interface address */
2023-10-22 21:15:49 +00:00
rc = xioresolve ( opt - > value . u_string /*ifaddr*/ , NULL ,
2023-11-05 12:56:58 +00:00
xfd - > para . socket . la . soa . sa_family ,
SOCK_DGRAM , IPPROTO_IP ,
& sockaddr2 , & socklen2 , xfd - > para . socket . ip . ai_flags ,
xfd - > para . socket . ip . res_opts ) ;
2023-10-22 21:15:49 +00:00
if ( rc < 0 ) {
return - 1 ;
}
2020-12-13 21:21:06 +00:00
ip4_mreq_src . imr_interface = sockaddr2 . ip4 . sin_addr ;
/* third parameter is source address */
2023-10-22 21:15:49 +00:00
rc = xioresolve ( opt - > value . u_string /*srcaddr*/ , NULL ,
2023-11-05 12:56:58 +00:00
xfd - > para . socket . la . soa . sa_family ,
SOCK_DGRAM , IPPROTO_IP ,
& sockaddr3 , & socklen3 , xfd - > para . socket . ip . ai_flags ,
xfd - > para . socket . ip . res_opts ) ;
2023-10-22 21:15:49 +00:00
if ( rc < 0 ) {
return - 1 ;
}
2020-12-13 21:21:06 +00:00
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 ,
2021-01-03 15:56:50 +00:00
htonl ( ( uint32_t ) ip4_mreq_src . imr_multiaddr . s_addr ) ,
ip4_mreq_src . imr_interface . s_addr ,
ip4_mreq_src . imr_sourceaddr . s_addr ,
2020-12-13 21:21:06 +00:00
sizeof ( struct ip_mreq_source ) ,
strerror ( errno ) ) ;
opt - > desc = ODESC_ERROR ;
return - 1 ;
}
return 0 ;
}
# endif /* HAVE_STRUCT_IP_MREQ_SOURCE */
2008-01-27 12:00:08 +00:00
# endif /* _WITH_IP4 || _WITH_IP6 */