Interface flags now defined with INTERFACE, inherited by TUN

This commit is contained in:
Gerhard Rieger 2023-10-26 19:08:26 +02:00
parent 8c9b185890
commit 47af17dbf2
16 changed files with 312 additions and 142 deletions

View file

@ -83,6 +83,9 @@ Corrections:
Now Socat handles EPIPE and ECONNRESET as errors to indicate possible
failure of data transfer.
INTERFACE addresses did not accept options of INTERFACE group (for
historical reasons they were only available with TUN addresses).
Coding:
Introduced groups_t instead of uint32_t, for more flexibility.

View file

@ -312,6 +312,7 @@ AC_ARG_ENABLE(genericsocket, [ --disable-genericsocket disable generic socket s
*) AC_DEFINE(WITH_GENERICSOCKET) AC_MSG_RESULT(yes);;
esac],
[AC_DEFINE(WITH_GENERICSOCKET) AC_MSG_RESULT(yes)])
AC_MSG_CHECKING(whether to include generic network interface support)
AC_ARG_ENABLE(interface, [ --disable-interface disable network interface support],
[case "$enableval" in

View file

@ -1084,7 +1084,7 @@ label(ADDRESS_TUN)dit(bf(tt(TUN[:<if-addr>/<bits>])))
Note: If you intend to transfer packets between two Socat "wire sides" you
need a protocol that keeps packet boundaries, e.g.UDP; TCP might work with
option link(nodelay)(OPTION_TCP_NODELAY).nl()
Option groups: link(FD)(GROUP_FD),link(NAMED)(GROUP_NAMED),link(OPEN)(GROUP_OPEN),link(TUN)(GROUP_TUN) nl()
Option groups: link(FD)(GROUP_FD),link(NAMED)(GROUP_NAMED),link(OPEN)(GROUP_OPEN),link(TUN)(GROUP_INTERFACE) nl()
Useful options:
link(iff-up)(OPTION_IFF_UP),
link(tun-device)(OPTION_TUN_DEVICE),
@ -3002,27 +3002,11 @@ enddit()
startdit()enddit()nl()
label(GROUP_TUN)em(bf(TUN option group))
label(GROUP_INTERFACE)em(bf(INTERFACE option group))
Options that control Linux TUN/TAP interface device addresses.
Options that control Linux INTERFACE addresses.
startdit()
label(OPTION_TUN_DEVICE)dit(bf(tt(tun-device=<device-file>)))
Instructs socat to take another path for the TUN clone device. Default is
tt(/dev/net/tun).
label(OPTION_TUN_NAME)dit(bf(tt(tun-name=<if-name>)))
Gives the resulting network interface a specific name instead of the system
generated (tun0, tun1, etc.)
label(OPTION_TUN_TYPE)dit(bf(tt(tun-type=[tun|tap])))
Sets the type of the TUN device; use this option to generate a TAP
device. See the Linux docu for the difference between these types.
When you try to establish a tunnel between two TUN devices, their types
should be the same.
label(OPTION_IFF_NO_PI)dit(bf(tt(iff-no-pi)))
Sets the IFF_NO_PI flag which controls if the device includes additional
packet information in the tunnel.
When you try to establish a tunnel between two TUN devices, these flags
should have the same values.
label(OPTION_IFF_UP)dit(bf(tt(iff-up)))
Sets the TUN network interface status UP. Strongly recommended.
label(OPTION_IFF_BROADCAST)dit(bf(tt(iff-broadcast)))
@ -3060,6 +3044,32 @@ enddit()
startdit()enddit()nl()
label(GROUP_TUN)em(bf(TUN option group))
Options that control Linux TUN/TAP interface device addresses.
startdit()
label(OPTION_TUN_DEVICE)dit(bf(tt(tun-device=<device-file>)))
Instructs socat to take another path for the TUN clone device. Default is
tt(/dev/net/tun).
label(OPTION_TUN_NAME)dit(bf(tt(tun-name=<if-name>)))
Gives the resulting network interface a specific name instead of the system
generated (tun0, tun1, etc.)
label(OPTION_TUN_TYPE)dit(bf(tt(tun-type=[tun|tap])))
Sets the type of the TUN device; use this option to generate a TAP
device. See the Linux docu for the difference between these types.
When you try to establish a tunnel between two TUN devices, their types
should be the same.
label(OPTION_IFF_NO_PI)dit(bf(tt(iff-no-pi)))
Sets the IFF_NO_PI flag which controls if the device includes additional
packet information in the tunnel.
When you try to establish a tunnel between two TUN devices, these flags
should have the same values.
enddit()
startdit()enddit()nl()
label(VALUES)
manpagesection(DATA VALUES)

View file

@ -5,6 +5,11 @@
#ifndef __sysincludes_h_included
#define __sysincludes_h_included 1
/* Sorry for this... */
#if defined(__sun) || defined(__sun__) || defined(__SunOS)
# define BSD_COMP 1 /* for SIOCGIFFLAGS */
#endif
#include <stddef.h> /* ptrdiff_t */
#if HAVE_STDBOOL_H
#include <stdbool.h> /* bool, true, false */

View file

@ -16,6 +16,10 @@
#include "utils.h"
#include "sysutils.h"
#if _WITH_INTERFACE
const int one = 1;
#endif
/* Substitute for Write():
Try to write all bytes before returning; this handles EINTR,
EAGAIN/EWOULDBLOCK, and partial write situations. The drawback is that this

View file

@ -43,6 +43,10 @@ struct xiorange {
} ;
#endif /* _WITH_SOCKET */
#if _WITH_INTERFACE
extern const int one;
#endif
extern ssize_t writefull(int fd, const void *buff, size_t bytes);
#if _WITH_SOCKET

40
test.sh
View file

@ -8395,34 +8395,42 @@ tl="$td/test$N.lock"
da="$(date) $RANDOM"
TUNNET=10.255.255
TUNNAME=tun9
CMD1="$TRACE $SOCAT $opts -L $tl TUN:$TUNNET.1/24,iff-up=1,tun-type=tun,tun-name=$TUNNAME echo"
CMD="$TRACE $SOCAT $opts - INTERFACE:$TUNNAME"
CMD0="$TRACE $SOCAT $opts -L $tl TUN:$TUNNET.1/24,iff-up=1,tun-type=tun,tun-name=$TUNNAME PIPE"
CMD1="$TRACE $SOCAT $opts - INTERFACE:$TUNNAME"
printf "test $F_n $TEST... " $N
$CMD1 2>"${te}1" &
pid1="$!"
$CMD0 2>"${te}1" &
pid0="$!"
#waitinterface "$TUNNAME"
sleep 1
echo "$da" |$CMD >"$tf" 2>"${te}"
kill $pid1 2>/dev/null
usleep $MICROS
{ echo "$da"; usleep $MICROS ; } |$CMD1 >"$tf" 2>"${te}"
rc1=$?
usleep $MICROS
kill $pid0 2>/dev/null
wait
if [ $? -ne 0 ]; then
$PRINTF "$FAILED: $TRACE $SOCAT:\n"
echo "$CMD &"
if [ "$rc1" -ne 0 ]; then
$PRINTF "$FAILED (rc1=$rc1):\n"
echo "$CMD0 &"
cat "${te}0" >&2
echo "$CMD1"
cat "${te}" "${te}1"
cat "${te}1" >&2
numFAIL=$((numFAIL+1))
listFAIL="$listFAIL $N"
elif ! echo "$da" |diff - "$tf" >"$tdiff"; then
$PRINTF "$FAILED\n"
echo "$CMD &"
$PRINTF "$FAILED (diff)\n"
echo "$CMD0 &"
cat "${te}0" >&2
echo "$CMD1"
cat "${te}1" >&2
echo "// diff:"
cat "$tdiff"
cat "${te}" "${te}1"
numFAIL=$((numFAIL+1))
listFAIL="$listFAIL $N"
else
$PRINTF "$OK\n"
if [ -n "$debug" ]; then cat "${te}" "${te}1"; 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))
fi
fi ;; # NUMCOND, feats
@ -13720,7 +13728,7 @@ elif [ $rc1 -ne 0 ]; then
cat "${te}1" >&2
numFAIL=$((numFAIL+1))
listFAIL="$listFAIL $N"
elif echo "$da" |diff - ${tf}1 >${tfdiff}$N; then
elif echo "$da" |diff - ${tf}1 >${tdiff}$N; then
$PRINTF "$OK\n"
numOK=$((numOK+1))
else

View file

@ -6,7 +6,7 @@
#include "xiosysincludes.h"
#if WITH_INTERFACE
#if _WITH_INTERFACE
#include "xioopen.h"
#include "xio-socket.h"
@ -19,7 +19,39 @@ int xioopen_interface(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *xfd, groups_t groups, int pf,
int dummy2, int dummy3);
const struct addrdesc xioaddr_interface= { "INTERFACE", 3, xioopen_interface, GROUP_FD|GROUP_SOCKET, PF_PACKET, 0, 0 HELP(":<interface>") };
/*0 const struct optdesc opt_interface_addr = { "interface-addr", "address", OPT_INTERFACE_ADDR, GROUP_INTERFACE, PH_FD, TYPE_STRING, OFUNC_SPEC };*/
/*0 const struct optdesc opt_interface_netmask = { "interface-netmask", "netmask", OPT_INTERFACE_NETMASK, GROUP_INTERFACE, PH_FD, TYPE_STRING, OFUNC_SPEC };*/
const struct optdesc opt_iff_up = { "iff-up", "up", OPT_IFF_UP, GROUP_INTERFACE, PH_INIT, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.interface.iff_opts), XIO_SIZEOF(para.interface.iff_opts), IFF_UP };
const struct optdesc opt_iff_broadcast = { "iff-broadcast", NULL, OPT_IFF_BROADCAST, GROUP_INTERFACE, PH_FD, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.interface.iff_opts), XIO_SIZEOF(para.interface.iff_opts), IFF_BROADCAST };
const struct optdesc opt_iff_debug = { "iff-debug" , NULL, OPT_IFF_DEBUG, GROUP_INTERFACE, PH_FD, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.interface.iff_opts), XIO_SIZEOF(para.interface.iff_opts), IFF_DEBUG };
const struct optdesc opt_iff_loopback = { "iff-loopback" , "loopback", OPT_IFF_LOOPBACK, GROUP_INTERFACE, PH_FD, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.interface.iff_opts), XIO_SIZEOF(para.interface.iff_opts), IFF_LOOPBACK };
const struct optdesc opt_iff_pointopoint = { "iff-pointopoint", "pointopoint",OPT_IFF_POINTOPOINT, GROUP_INTERFACE, PH_FD, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.interface.iff_opts), XIO_SIZEOF(para.interface.iff_opts), IFF_POINTOPOINT };
const struct optdesc opt_iff_notrailers = { "iff-notrailers", "notrailers", OPT_IFF_NOTRAILERS, GROUP_INTERFACE, PH_FD, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.interface.iff_opts), XIO_SIZEOF(para.interface.iff_opts), IFF_NOTRAILERS };
const struct optdesc opt_iff_running = { "iff-running", "running", OPT_IFF_RUNNING, GROUP_INTERFACE, PH_FD, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.interface.iff_opts), XIO_SIZEOF(para.interface.iff_opts), IFF_RUNNING };
const struct optdesc opt_iff_noarp = { "iff-noarp", "noarp", OPT_IFF_NOARP, GROUP_INTERFACE, PH_FD, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.interface.iff_opts), XIO_SIZEOF(para.interface.iff_opts), IFF_NOARP };
const struct optdesc opt_iff_promisc = { "iff-promisc", "promisc", OPT_IFF_PROMISC, GROUP_INTERFACE, PH_FD, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.interface.iff_opts), XIO_SIZEOF(para.interface.iff_opts), IFF_PROMISC };
const struct optdesc opt_iff_allmulti = { "iff-allmulti", "allmulti", OPT_IFF_ALLMULTI, GROUP_INTERFACE, PH_FD, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.interface.iff_opts), XIO_SIZEOF(para.interface.iff_opts), IFF_ALLMULTI };
#ifdef IFF_MASTER
const struct optdesc opt_iff_master = { "iff-master", "master", OPT_IFF_MASTER, GROUP_INTERFACE, PH_FD, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.interface.iff_opts), XIO_SIZEOF(para.interface.iff_opts), IFF_MASTER };
#endif
#ifdef IFF_SLAVE
const struct optdesc opt_iff_slave = { "iff-slave", "slave", OPT_IFF_SLAVE, GROUP_INTERFACE, PH_FD, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.interface.iff_opts), XIO_SIZEOF(para.interface.iff_opts), IFF_SLAVE };
#endif
const struct optdesc opt_iff_multicast = { "iff-multicast", NULL, OPT_IFF_MULTICAST, GROUP_INTERFACE, PH_FD, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.interface.iff_opts), XIO_SIZEOF(para.interface.iff_opts), IFF_MULTICAST };
#ifdef IFF_PORTSEL
const struct optdesc opt_iff_portsel = { "iff-portsel", "portsel", OPT_IFF_PORTSEL, GROUP_INTERFACE, PH_FD, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.interface.iff_opts), XIO_SIZEOF(para.interface.iff_opts), IFF_PORTSEL };
#endif
#ifdef IFF_AUTOMEDIA
const struct optdesc opt_iff_automedia = { "iff-automedia", "automedia", OPT_IFF_AUTOMEDIA, GROUP_INTERFACE, PH_FD, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.interface.iff_opts), XIO_SIZEOF(para.interface.iff_opts), IFF_AUTOMEDIA };
#endif
/*const struct optdesc opt_iff_dynamic = { "iff-dynamic", "dynamic", OPT_IFF_DYNAMIC, GROUP_INTERFACE, PH_FD, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.interface.iff_opts), XIO_SIZEOF(short), IFF_DYNAMIC };*/
#if LATER
const struct optdesc opt_route = { "route", NULL, OPT_ROUTE, GROUP_INTERFACE, PH_INIT, TYPE_STRING, OFUNC_SPEC };
#endif
#if WITH_INTERFACE
const struct addrdesc xioaddr_interface = { "INTERFACE", 3, xioopen_interface, GROUP_FD|GROUP_SOCKET|GROUP_INTERFACE, PF_PACKET, 0, 0 HELP(":<interface>") };
#endif /* WITH_INTERFACE */
static
@ -34,13 +66,14 @@ int _xioopen_interface(const char *ifname,
bool needbind = false;
char *bindstring = NULL;
struct sockaddr_ll sall = { 0 };
int rc;
if (ifindex(ifname, &ifidx, -1) < 0) {
Error1("unknown interface \"%s\"", ifname);
ifidx = 0; /* desparate attempt to continue */
}
xfd->howtoend = END_SHUTDOWN;
xfd->howtoend = END_INTERFACE;
retropt_int(opts, OPT_SO_TYPE, &socktype);
retropt_socket_pf(opts, &pf);
@ -67,9 +100,25 @@ int _xioopen_interface(const char *ifname,
needbind = true;
xfd->peersa = (union sockaddr_union)us;
return
rc =
_xioopen_dgram_sendto(needbind?&us:NULL, uslen,
opts, xioflags, xfd, groups, pf, socktype, 0, 0);
if (rc < 0)
return rc;
strncpy(xfd->para.interface.name, ifname, IFNAMSIZ);
_xiointerface_get_iff(xfd->fd, ifname, &xfd->para.interface.save_iff);
_xiointerface_apply_iff(xfd->fd, ifname, xfd->para.interface.iff_opts);
#ifdef PACKET_IGNORE_OUTGOING
/* Raw socket may even provide packets that are outbound - we are not
interested in these and disable this "feature" in kernel if possible */
if (Setsockopt(xfd->fd, SOL_PACKET, PACKET_IGNORE_OUTGOING, &one, sizeof(one)) < 0) {
Warn2("setsockopt(%d, SOL_PACKET, PACKET_IGNORE_OUTGOING, {1}): %s",
xfd->fd, strerror(errno));
}
#endif
return 0;
}
static
@ -102,4 +151,80 @@ int xioopen_interface(int argc, const char *argv[], struct opt *opts,
return STAT_OK;
}
#endif /* WITH_INTERFACE */
/* Retrieves the interface flags related to sockfd */
int _xiointerface_get_iff(
int sockfd,
const char *name,
short *save_iff)
{
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
if (Ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
Error3("ioctl(%d, SIOCGIFFLAGS, {\"%s\"}: %s",
sockfd, ifr.ifr_name, strerror(errno));
}
*save_iff = ifr.ifr_flags;
return 0;
}
/* Applies the interface flags to the socket FD.
Used by INTERFACE and TUN
*/
int _xiointerface_set_iff(
int sockfd,
const char *name,
short new_iff)
{
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
if (Ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
Error3("ioctl(%d, SIOCGIFFLAGS, {\"%s\"}: %s",
sockfd, ifr.ifr_name, strerror(errno));
}
ifr.ifr_flags = new_iff;
if (Ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) {
Error4("ioctl(%d, SIOCSIFFLAGS, {\"%s\", %hd}: %s",
sockfd, ifr.ifr_name, ifr.ifr_flags, strerror(errno));
}
return 0;
}
/* Applies the interface flags to the socket FD
Used by INTERFACE and TUN
*/
int _xiointerface_apply_iff(
int sockfd,
const char *name,
short iff_opts[2])
{
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
if (Ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
Error3("ioctl(%d, SIOCGIFFLAGS, {\"%s\"}: %s",
sockfd, ifr.ifr_name, strerror(errno));
}
Debug2("\"%s\": system set flags: 0x%hx", ifr.ifr_name, ifr.ifr_flags);
ifr.ifr_flags |= iff_opts[0];
ifr.ifr_flags &= ~iff_opts[1];
Debug2("\"%s\": xio merged flags: 0x%hx", ifr.ifr_name, ifr.ifr_flags);
if (Ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) {
Error4("ioctl(%d, SIOCSIFFLAGS, {\"%s\", %hd}: %s",
sockfd, ifr.ifr_name, ifr.ifr_flags, strerror(errno));
}
ifr.ifr_flags = 0;
if (Ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
Error3("ioctl(%d, SIOCGIFFLAGS, {\"%s\"}: %s",
sockfd, ifr.ifr_name, strerror(errno));
}
Debug2("\"%s\": resulting flags: 0x%hx", ifr.ifr_name, ifr.ifr_flags);
return 0;
}
#endif /* _WITH_INTERFACE */

View file

@ -7,4 +7,29 @@
extern const struct addrdesc xioaddr_interface;
extern const struct optdesc opt_interface_addr;
extern const struct optdesc opt_interface_netmask;
extern const struct optdesc opt_iff_up;
extern const struct optdesc opt_iff_broadcast;
extern const struct optdesc opt_iff_debug;
extern const struct optdesc opt_iff_loopback;
extern const struct optdesc opt_iff_pointopoint;
extern const struct optdesc opt_iff_notrailers;
extern const struct optdesc opt_iff_running;
extern const struct optdesc opt_iff_noarp;
extern const struct optdesc opt_iff_promisc;
extern const struct optdesc opt_iff_allmulti;
extern const struct optdesc opt_iff_master;
extern const struct optdesc opt_iff_slave;
extern const struct optdesc opt_iff_multicast;
extern const struct optdesc opt_iff_portsel;
extern const struct optdesc opt_iff_automedia;
/*extern const struct optdesc opt_iff_dynamic;*/
extern int xiolog_ancillary_packet(struct single *sfd, struct cmsghdr *cmsg, int *num, char *typbuff, int typlen, char *nambuff, int namlen, char *envbuff, int envlen, char *valbuff, int vallen);
extern int _xiointerface_get_iff(int sockfd, const char *name, short *save_iff);
extern int _xiointerface_set_iff(int sockfd, const char *name, short new_iff);
extern int _xiointerface_apply_iff(int sockfd, const char *name, short iff_opts[2]);
#endif /* !defined(__xio_interface_h_included) */

View file

@ -1055,6 +1055,7 @@ int _xioopen_dgram_sendto(/* them is already in xfd->peersa */
applyopts_offset(xfd, opts);
applyopts_single(xfd, opts, PH_PASTSOCKET);
applyopts(xfd->fd, opts, PH_PASTSOCKET);
applyopts_single(xfd, opts, PH_FD);
applyopts(xfd->fd, opts, PH_FD);
applyopts_cloexec(xfd->fd, opts);

View file

@ -11,40 +11,21 @@
#include "xio-named.h"
#include "xio-socket.h"
#include "xio-ip.h"
#include "xio-interface.h"
#include "xio-tun.h"
static int xioopen_tun(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, groups_t groups, int dummy1, int dummy2, int dummy3);
/****** TUN addresses ******/
/****** TUN options ******/
const struct optdesc opt_tun_device = { "tun-device", NULL, OPT_TUN_DEVICE, GROUP_TUN, PH_OPEN, TYPE_FILENAME, OFUNC_SPEC };
const struct optdesc opt_tun_name = { "tun-name", NULL, OPT_TUN_NAME, GROUP_INTERFACE, PH_FD, TYPE_STRING, OFUNC_SPEC };
const struct optdesc opt_tun_type = { "tun-type", NULL, OPT_TUN_TYPE, GROUP_INTERFACE, PH_FD, TYPE_STRING, OFUNC_SPEC };
const struct optdesc opt_iff_no_pi = { "iff-no-pi", "no-pi", OPT_IFF_NO_PI, GROUP_TUN, PH_FD, TYPE_BOOL, OFUNC_SPEC };
/*0 const struct optdesc opt_interface_addr = { "interface-addr", "address", OPT_INTERFACE_ADDR, GROUP_INTERFACE, PH_FD, TYPE_STRING, OFUNC_SPEC };*/
/*0 const struct optdesc opt_interface_netmask = { "interface-netmask", "netmask", OPT_INTERFACE_NETMASK, GROUP_INTERFACE, PH_FD, TYPE_STRING, OFUNC_SPEC };*/
const struct optdesc opt_iff_up = { "iff-up", "up", OPT_IFF_UP, GROUP_INTERFACE, PH_FD, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.tun.iff_opts), XIO_SIZEOF(para.tun.iff_opts), IFF_UP };
const struct optdesc opt_iff_broadcast = { "iff-broadcast", NULL, OPT_IFF_BROADCAST, GROUP_INTERFACE, PH_FD, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.tun.iff_opts), XIO_SIZEOF(para.tun.iff_opts), IFF_BROADCAST };
const struct optdesc opt_iff_debug = { "iff-debug" , NULL, OPT_IFF_DEBUG, GROUP_INTERFACE, PH_FD, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.tun.iff_opts), XIO_SIZEOF(para.tun.iff_opts), IFF_DEBUG };
const struct optdesc opt_iff_loopback = { "iff-loopback" , "loopback", OPT_IFF_LOOPBACK, GROUP_INTERFACE, PH_FD, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.tun.iff_opts), XIO_SIZEOF(para.tun.iff_opts), IFF_LOOPBACK };
const struct optdesc opt_iff_pointopoint = { "iff-pointopoint", "pointopoint",OPT_IFF_POINTOPOINT, GROUP_INTERFACE, PH_FD, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.tun.iff_opts), XIO_SIZEOF(para.tun.iff_opts), IFF_POINTOPOINT };
const struct optdesc opt_iff_notrailers = { "iff-notrailers", "notrailers", OPT_IFF_NOTRAILERS, GROUP_INTERFACE, PH_FD, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.tun.iff_opts), XIO_SIZEOF(para.tun.iff_opts), IFF_NOTRAILERS };
const struct optdesc opt_iff_running = { "iff-running", "running", OPT_IFF_RUNNING, GROUP_INTERFACE, PH_FD, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.tun.iff_opts), XIO_SIZEOF(para.tun.iff_opts), IFF_RUNNING };
const struct optdesc opt_iff_noarp = { "iff-noarp", "noarp", OPT_IFF_NOARP, GROUP_INTERFACE, PH_FD, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.tun.iff_opts), XIO_SIZEOF(para.tun.iff_opts), IFF_NOARP };
const struct optdesc opt_iff_promisc = { "iff-promisc", "promisc", OPT_IFF_PROMISC, GROUP_INTERFACE, PH_FD, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.tun.iff_opts), XIO_SIZEOF(para.tun.iff_opts), IFF_PROMISC };
const struct optdesc opt_iff_allmulti = { "iff-allmulti", "allmulti", OPT_IFF_ALLMULTI, GROUP_INTERFACE, PH_FD, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.tun.iff_opts), XIO_SIZEOF(para.tun.iff_opts), IFF_ALLMULTI };
const struct optdesc opt_iff_master = { "iff-master", "master", OPT_IFF_MASTER, GROUP_INTERFACE, PH_FD, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.tun.iff_opts), XIO_SIZEOF(para.tun.iff_opts), IFF_MASTER };
const struct optdesc opt_iff_slave = { "iff-slave", "slave", OPT_IFF_SLAVE, GROUP_INTERFACE, PH_FD, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.tun.iff_opts), XIO_SIZEOF(para.tun.iff_opts), IFF_SLAVE };
const struct optdesc opt_iff_multicast = { "iff-multicast", NULL, OPT_IFF_MULTICAST, GROUP_INTERFACE, PH_FD, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.tun.iff_opts), XIO_SIZEOF(para.tun.iff_opts), IFF_MULTICAST };
const struct optdesc opt_iff_portsel = { "iff-portsel", "portsel", OPT_IFF_PORTSEL, GROUP_INTERFACE, PH_FD, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.tun.iff_opts), XIO_SIZEOF(para.tun.iff_opts), IFF_PORTSEL };
const struct optdesc opt_iff_automedia = { "iff-automedia", "automedia", OPT_IFF_AUTOMEDIA, GROUP_INTERFACE, PH_FD, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.tun.iff_opts), XIO_SIZEOF(para.tun.iff_opts), IFF_AUTOMEDIA };
/*const struct optdesc opt_iff_dynamic = { "iff-dynamic", "dynamic", OPT_IFF_DYNAMIC, GROUP_INTERFACE, PH_FD, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.tun.iff_opts), XIO_SIZEOF(short), IFF_DYNAMIC };*/
#if LATER
const struct optdesc opt_route = { "route", NULL, OPT_ROUTE, GROUP_INTERFACE, PH_INIT, TYPE_STRING, OFUNC_SPEC };
#endif
const struct optdesc opt_iff_no_pi = { "iff-no-pi", "no-pi", OPT_IFF_NO_PI, GROUP_TUN, PH_FD, TYPE_BOOL, OFUNC_SPEC };
const struct addrdesc xioaddr_tun = { "TUN", 3, xioopen_tun, GROUP_FD|GROUP_CHR|GROUP_NAMED|GROUP_OPEN|GROUP_TUN, 0, 0, 0 HELP("[:<ip-addr>/<bits>]") };
/****** TUN addresses ******/
const struct addrdesc xioaddr_tun = { "TUN", 3, xioopen_tun, GROUP_FD|GROUP_CHR|GROUP_OPEN|GROUP_TUN, 0, 0, 0 HELP("[:<ip-addr>/<bits>]") };
/* "if-name"=tun3
// "route"=address/netmask
// "ip6-route"=address/netmask
@ -103,7 +84,7 @@ static int xioopen_tun(int argc, const char *argv[], struct opt *opts, int xiofl
xfd->stream.fd = result;
/* prepare configuration of the new network interface */
memset(&ifr, 0,sizeof(ifr));
memset(&ifr, 0, sizeof(ifr));
if (retropt_string(opts, OPT_TUN_NAME, &tunname) == 0) {
strncpy(ifr.ifr_name, tunname, IFNAMSIZ); /* ok */
@ -136,6 +117,7 @@ static int xioopen_tun(int argc, const char *argv[], struct opt *opts, int xiofl
xfd->stream.fd, ifr.ifr_name, strerror(errno));
Close(xfd->stream.fd);
}
Notice1("TUN: new device \"%s\"", ifr.ifr_name);
/*===================== setting interface properties =====================*/
@ -174,29 +156,8 @@ static int xioopen_tun(int argc, const char *argv[], struct opt *opts, int xiofl
/*--------------------- setting interface flags --------------------------*/
applyopts_single(&xfd->stream, opts, PH_FD);
if (Ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
Error3("ioctl(%d, SIOCGIFFLAGS, {\"%s\"}: %s",
sockfd, ifr.ifr_name, strerror(errno));
}
Debug2("\"%s\": system set flags: 0x%hx", ifr.ifr_name, ifr.ifr_flags);
ifr.ifr_flags |= xfd->stream.para.tun.iff_opts[0];
ifr.ifr_flags &= ~xfd->stream.para.tun.iff_opts[1];
Debug2("\"%s\": xio merged flags: 0x%hx", ifr.ifr_name, ifr.ifr_flags);
if (Ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) {
Error4("ioctl(%d, SIOCSIFFLAGS, {\"%s\", %hd}: %s",
sockfd, ifr.ifr_name, ifr.ifr_flags, strerror(errno));
}
ifr.ifr_flags = 0;
if (Ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
Error3("ioctl(%d, SIOCGIFFLAGS, {\"%s\"}: %s",
sockfd, ifr.ifr_name, strerror(errno));
}
Debug2("\"%s\": resulting flags: 0x%hx", ifr.ifr_name, ifr.ifr_flags);
_xiointerface_apply_iff(sockfd, ifr.ifr_name, xfd->stream.para.interface.iff_opts);
#if LATER
applyopts_named(tundevice, opts, PH_FD);
#endif
applyopts(xfd->stream.fd, opts, PH_FD);
applyopts_cloexec(xfd->stream.fd, opts);

View file

@ -9,24 +9,6 @@ extern const struct optdesc opt_tun_device;
extern const struct optdesc opt_tun_name;
extern const struct optdesc opt_tun_type;
extern const struct optdesc opt_iff_no_pi;
extern const struct optdesc opt_interface_addr;
extern const struct optdesc opt_interface_netmask;
extern const struct optdesc opt_iff_up;
extern const struct optdesc opt_iff_broadcast;
extern const struct optdesc opt_iff_debug;
extern const struct optdesc opt_iff_loopback;
extern const struct optdesc opt_iff_pointopoint;
extern const struct optdesc opt_iff_notrailers;
extern const struct optdesc opt_iff_running;
extern const struct optdesc opt_iff_noarp;
extern const struct optdesc opt_iff_promisc;
extern const struct optdesc opt_iff_allmulti;
extern const struct optdesc opt_iff_master;
extern const struct optdesc opt_iff_slave;
extern const struct optdesc opt_iff_multicast;
extern const struct optdesc opt_iff_portsel;
extern const struct optdesc opt_iff_automedia;
/*extern const struct optdesc opt_iff_dynamic;*/
extern const struct addrdesc xioaddr_tun;

11
xio.h
View file

@ -192,7 +192,8 @@ typedef struct single {
END_SHUTDOWN, /* shutdown() */
END_KILL, /* has subprocess */
END_CLOSE_KILL, /* first close fd, then kill subprocess */
END_SHUTDOWN_KILL /* first shutdown fd, then kill subprocess */
END_SHUTDOWN_KILL,/* first shutdown fd, then kill subprocess */
END_INTERFACE /* restore interface flags, then close fd */
} howtoend;
#if _WITH_SOCKET
union sockaddr_union peersa;
@ -276,11 +277,13 @@ typedef struct single {
#endif
} openssl;
#endif /* WITH_OPENSSL */
#if WITH_TUN
#if _WITH_INTERFACE
struct {
char name[IFNAMSIZ]; /* name of interface */
short save_iff; /* for restoring old settings on exit */
short iff_opts[2]; /* ifr flags, using OFUNC_OFFSET_MASKS */
} tun;
#endif /* WITH_TUN */
} interface;
#endif /* _WITH_INTERFACE */
} para;
#if WITH_STATS
unsigned long long blocks_read;

View file

@ -10,6 +10,7 @@
#include "xiolockfile.h"
#include "xio-termios.h"
#include "xio-interface.h"
/* close the xio fd; must be valid and "simple" (not dual) */
@ -77,6 +78,15 @@ int xioclose1(struct single *pipe) {
Info3("shutdown(%d, %d): %s", pipe->fd, 2, strerror(errno)); }
break;
#endif /* _WITH_SOCKET */
#if WITH_INTERFACE
case END_INTERFACE:
{
_xiointerface_set_iff(pipe->fd, pipe->para.interface.name, pipe->para.interface.save_iff);
if (Close(pipe->fd) < 0) {
Info2("close(%d): %s", pipe->fd, strerror(errno)); } break;
}
break;
#endif /* WITH_INTERFACE */
case END_NONE: default: break;
}
}

View file

@ -67,7 +67,13 @@
# undef WITH_LIBWRAP
#endif
#if WITH_GENERICSOCKET || WITH_TUN
#if WITH_INTERFACE || WITH_TUN
# define _WITH_INTERFACE 1
#else
# define _WITH_INTERFACE 0
#endif
#if WITH_GENERICSOCKET || _WITH_INTERFACE
# define _WITH_SOCKET 1
#endif
@ -79,11 +85,11 @@
# define _WITH_IP6 1
#endif
#if WITH_NAMED || WITH_TUN
#if WITH_NAMED
# define _WITH_NAMED 1
#endif
#if WITH_FILE || WITH_TUN
#if WITH_FILE
# define _WITH_FILE 1
#endif

View file

@ -125,6 +125,12 @@ bool xioopts_ignoregroups;
# define IF_OPENSSL(a,b)
#endif
#if WITH_INTERFACE
# define IF_INTERFACE(a,b) {a,b},
#else
# define IF_INTERFACE(a,b)
#endif
#if WITH_TUN
# define IF_TUN(a,b) {a,b},
#else
@ -167,7 +173,7 @@ const struct optname optionnames[] = {
#if defined(HAVE_STRUCT_IP_MREQ_SOURCE) && defined(IP_ADD_SOURCE_MEMBERSHIP)
IF_IP ("add-source-membership", &opt_ip_add_source_membership)
#endif
IF_TUN ("allmulti", &opt_iff_allmulti)
IF_INTERFACE("allmulti", &opt_iff_allmulti)
#if WITH_LIBWRAP && defined(HAVE_HOSTS_ALLOW_TABLE)
IF_IPAPP ("allow-table", &opt_tcpwrap_hosts_allow_table)
#endif
@ -185,7 +191,9 @@ const struct optname optionnames[] = {
#ifdef IPV6_AUTHHDR
IF_IP6 ("authhdr", &opt_ipv6_authhdr)
#endif
IF_TUN ("automedia", &opt_iff_automedia)
#ifdef IFF_AUTOMEDIA
IF_INTERFACE("automedia", &opt_iff_automedia)
#endif
#ifdef CBAUD
IF_TERMIOS("b0", &opt_b0)
#ifdef B1000000
@ -629,23 +637,31 @@ const struct optname optionnames[] = {
#ifdef SO_BINDTODEVICE
IF_SOCKET ("if", &opt_so_bindtodevice)
#endif
IF_TUN ("iff-allmulti", &opt_iff_allmulti)
IF_TUN ("iff-automedia", &opt_iff_automedia)
IF_TUN ("iff-broadcast", &opt_iff_broadcast)
IF_TUN ("iff-debug", &opt_iff_debug)
/*IF_TUN ("iff-dynamic", &opt_iff_dynamic)*/
IF_TUN ("iff-loopback", &opt_iff_loopback)
IF_TUN ("iff-master", &opt_iff_master)
IF_TUN ("iff-multicast", &opt_iff_multicast)
IF_INTERFACE("iff-allmulti", &opt_iff_allmulti)
#ifdef IFF_AUTOMEDIA
IF_INTERFACE("iff-automedia", &opt_iff_automedia)
#endif
IF_INTERFACE("iff-broadcast", &opt_iff_broadcast)
IF_INTERFACE("iff-debug", &opt_iff_debug)
/*IF_INTERFACE("iff-dynamic", &opt_iff_dynamic)*/
IF_INTERFACE("iff-loopback", &opt_iff_loopback)
#ifdef IFF_MASTER
IF_INTERFACE("iff-master", &opt_iff_master)
#endif
IF_INTERFACE("iff-multicast", &opt_iff_multicast)
IF_TUN ("iff-no-pi", &opt_iff_no_pi)
IF_TUN ("iff-noarp", &opt_iff_noarp)
IF_TUN ("iff-notrailers", &opt_iff_notrailers)
IF_TUN ("iff-pointopoint", &opt_iff_pointopoint)
IF_TUN ("iff-portsel", &opt_iff_portsel)
IF_TUN ("iff-promisc", &opt_iff_promisc)
IF_TUN ("iff-running", &opt_iff_running)
IF_TUN ("iff-slave", &opt_iff_slave)
IF_TUN ("iff-up", &opt_iff_up)
IF_INTERFACE("iff-noarp", &opt_iff_noarp)
IF_INTERFACE("iff-notrailers", &opt_iff_notrailers)
IF_INTERFACE("iff-pointopoint", &opt_iff_pointopoint)
#ifdef IFF_PORTSEL
IF_INTERFACE("iff-portsel", &opt_iff_portsel)
#endif
IF_INTERFACE("iff-promisc", &opt_iff_promisc)
IF_INTERFACE("iff-running", &opt_iff_running)
#ifdef IFF_SLAVE
IF_INTERFACE("iff-slave", &opt_iff_slave)
#endif
IF_INTERFACE("iff-up", &opt_iff_up)
IF_TERMIOS("ignbrk", &opt_ignbrk)
IF_TERMIOS("igncr", &opt_igncr)
/* you might need to terminate socat manually if you use this option: */
@ -914,7 +930,7 @@ const struct optname optionnames[] = {
IF_ANY ("lockw", &opt_flock_ex_nb) /* BSD, fallback */
#endif
IF_EXEC ("login", &opt_dash)
IF_TUN ("loopback", &opt_iff_loopback)
IF_INTERFACE("loopback", &opt_iff_loopback)
IF_IPAPP ("lowport", &opt_lowport)
#if HAVE_LSEEK64
IF_ANY ("lseek", &opt_lseek64_set)
@ -931,7 +947,9 @@ const struct optname optionnames[] = {
IF_ANY ("lseek64-end", &opt_lseek64_end)
IF_ANY ("lseek64-set", &opt_lseek64_set)
#endif
IF_TUN ("master", &opt_iff_master)
#ifdef IFF_MASTER
IF_INTERFACE("master", &opt_iff_master)
#endif
IF_LISTEN ("max-children", &opt_max_children)
#if HAVE_SSL_set_max_proto_version || defined(SSL_set_max_proto_version)
IF_OPENSSL("max-version", &opt_openssl_max_proto_version)
@ -971,7 +989,7 @@ const struct optname optionnames[] = {
#ifdef IP_MTU_DISCOVER
IF_IP ("mtudiscover", &opt_ip_mtu_discover)
#endif
IF_TUN ("multicast", &opt_iff_multicast)
IF_INTERFACE("multicast", &opt_iff_multicast)
IF_IP ("multicast-if", &opt_ip_multicast_if)
IF_IP ("multicast-loop", &opt_ip_multicast_loop)
IF_IP ("multicast-ttl", &opt_ip_multicast_ttl)
@ -999,7 +1017,7 @@ const struct optname optionnames[] = {
#if defined(HAVE_SSL_set_tlsext_host_name) || defined(SSL_set_tlsext_host_name)
IF_OPENSSL("no-sni", &opt_openssl_no_sni)
#endif
IF_TUN ("noarp", &opt_iff_noarp)
IF_INTERFACE("noarp", &opt_iff_noarp)
#ifdef O_NOATIME
IF_OPEN ("noatime", &opt_o_noatime)
#endif
@ -1038,7 +1056,7 @@ const struct optname optionnames[] = {
#if defined(HAVE_SSL_set_tlsext_host_name) || defined(SSL_set_tlsext_host_name)
IF_OPENSSL("nosni", &opt_openssl_no_sni)
#endif
IF_TUN ("notrailers", &opt_iff_notrailers)
IF_INTERFACE("notrailers", &opt_iff_notrailers)
#ifdef O_NSHARE
IF_OPEN ("nshare", &opt_o_nshare)
#endif
@ -1251,12 +1269,14 @@ const struct optname optionnames[] = {
IF_IP ("pktoptions", &opt_ip_pktoptions)
IF_IP ("pktopts", &opt_ip_pktoptions)
#endif
IF_TUN ("pointopoint", &opt_iff_pointopoint)
IF_INTERFACE("pointopoint", &opt_iff_pointopoint)
#ifdef I_POP
IF_ANY ("pop-all", &opt_streams_i_pop_all)
#endif
/*IF_IPAPP("port", &opt_port)*/
IF_TUN ("portsel", &opt_iff_portsel)
#ifdef IFF_PORTSEL
IF_INTERFACE("portsel", &opt_iff_portsel)
#endif
#if HAVE_RESOLV_H && WITH_RES_PRIMARY
IF_IP ("primary", &opt_res_primary)
#endif
@ -1266,7 +1286,7 @@ const struct optname optionnames[] = {
#ifdef O_PRIV
IF_OPEN ("priv", &opt_o_priv)
#endif
IF_TUN ("promisc", &opt_iff_promisc)
IF_INTERFACE("promisc", &opt_iff_promisc)
IF_READLINE("prompt", &opt_prompt)
#ifdef SO_PROTOTYPE
IF_SOCKET ("protocol", &opt_so_prototype)
@ -1401,7 +1421,7 @@ const struct optname optionnames[] = {
#ifdef IPV6_RTHDR
IF_IP6 ("rthdr", &opt_ipv6_rthdr)
#endif
IF_TUN ("running", &opt_iff_running)
IF_INTERFACE("running", &opt_iff_running)
#ifdef TCP_SACK_DISABLE
IF_TCP ("sack-disable", &opt_tcp_sack_disable)
#endif
@ -1484,7 +1504,9 @@ const struct optname optionnames[] = {
IF_SOCKET ("siocspgrp", &opt_siocspgrp)
#endif
IF_PTY ("sitout-eio", &opt_sitout_eio)
IF_TUN ("slave", &opt_iff_slave)
#ifdef IFF_SLAVE
IF_INTERFACE("slave", &opt_iff_slave)
#endif
IF_SOCKET ("sndbuf", &opt_so_sndbuf)
IF_SOCKET ("sndbuf-late", &opt_so_sndbuf_late)
#ifdef SO_SNDLOWAT
@ -1797,7 +1819,7 @@ const struct optname optionnames[] = {
#if WITH_FS && defined(FS_UNRM_FL)
IF_ANY ("unrm", &opt_fs_unrm)
#endif
IF_TUN ("up", &opt_iff_up)
IF_INTERFACE("up", &opt_iff_up)
#ifdef SO_USE_IFBUFS
IF_SOCKET ("use-ifbufs", &opt_so_use_ifbufs)
IF_SOCKET ("useifbufs", &opt_so_use_ifbufs)
@ -3745,7 +3767,7 @@ int applyopts(int fd, struct opt *opts, enum e_phase phase) {
/*Error1("applyopts(): function %d not implemented",
opt->desc->func);*/
if (opt->desc->func != OFUNC_EXT && opt->desc->func != OFUNC_SIGNAL) {
Error1("applyopts(): option \"%s\" does not apply",
Error1("applyopts(): internal error: option \"%s\" does not apply",
opt->desc->defname);
opt->desc = ODESC_ERROR;
++opt;