1
0
mirror of https://github.com/moparisthebest/socat synced 2024-12-22 06:58:47 -05:00

merged feature raw network interface

This commit is contained in:
Gerhard Rieger 2008-09-23 00:09:19 +02:00
commit 784e378ede
18 changed files with 293 additions and 25 deletions

View File

@ -2,7 +2,11 @@
new features:
new address types SCTP-CONNECT and SCTP-LISTEN implement SCTP stream
mode for IPv4 and IPv6; new address options sctp-maxseg and
sctp-nodelay
sctp-nodelay (suggested by David A. Madore; thanks to Jonathan Brennan
for providing an initial patch)
new address "interface" for transparent network interface handling
(suggested by Stuart Nicholson)
added generic socket addresses: SOCKET-CONNECT, SOCKET-LISTEN,
SOCKET-SENDTO, SOCKET-RECVFROM, SOCKET-RECV, SOCKET-DATAGRAM allow

View File

@ -45,8 +45,11 @@ XIOSRCS = xioinitialize.c xiohelp.c xioparam.c xiodiag.c xioopen.c xioopts.c \
xiolayer.c xioshutdown.c xioclose.c xioexit.c \
xio-process.c xio-fd.c xio-fdnum.c xio-stdio.c xio-pipe.c \
xio-gopen.c xio-creat.c xio-file.c xio-named.c \
xio-socket.c xio-listen.c xio-unix.c xio-ip.c xio-ip4.c xio-ip6.c xio-ipapp.c xio-tcp.c xio-socks.c xio-proxy.c xio-udp.c \
xio-socket.c xio-interface.c xio-listen.c xio-unix.c \
xio-ip.c xio-ip4.c xio-ip6.c xio-ipapp.c xio-tcp.c \
xio-sctp.c xio-rawip.c \
xio-socks.c xio-proxy.c xio-udp.c \
xio-rawip.c \
xio-progcall.c xio-exec.c xio-system.c xio-termios.c xio-readline.c \
xio-pty.c xio-openssl.c \
xio-ascii.c xiolockfile.c xio-tcpwrap.c xio-ext2.c xio-tun.c
@ -60,10 +63,11 @@ PROGS = socat procan filan
HFILES = sycls.h sslcls.h error.h dalan.h procan.h filan.h hostan.h sysincludes.h xio.h xioopen.h sysutils.h utils.h nestlex.h compat.h \
xioconfig.h mytypes.h xioopts.h xiodiag.h xiohelp.h xiosysincludes.h \
xiomodes.h xiolayer.h xio-process.h xio-fd.h xio-fdnum.h xio-stdio.h \
xio-named.h xio-file.h xio-creat.h xio-gopen.h xio-pipe.h xio-socket.h \
xio-listen.h xio-unix.h xio-rawip.h xio-ip.h xio-ip4.h xio-ip6.h \
xio-ipapp.h xio-tcp.h xio-udp.h xio-socks.h xio-proxy.h xio-progcall.h xio-exec.h \
xio-sctp.h \
xio-named.h xio-file.h xio-creat.h xio-gopen.h xio-pipe.h \
xio-socket.h xio-interface.h xio-listen.h xio-unix.h \
xio-ip.h xio-ip4.h xio-ip6.h xio-rawip.h \
xio-ipapp.h xio-tcp.h xio-udp.h xio-sctp.h \
xio-socks.h xio-proxy.h xio-progcall.h xio-exec.h \
xio-system.h xio-termios.h xio-readline.h \
xio-pty.h xio-openssl.h \
xio-ascii.h xiolockfile.h xio-tcpwrap.h xio-ext2.h xio-tun.h

View File

@ -1 +1 @@
"1.6.0.1+ip4bind+recvfromfork+x64+execstderr+execspaces+cosmetics+poll+udplistencont+ignoreeofunblock+escape+timestamp+ancillary+envvar+protocol+ioctl+setsockopt+genericsocket+sctp"
"1.6.0.1+ip4bind+recvfromfork+x64+execstderr+execspaces+cosmetics+poll+udplistencont+ignoreeofunblock+escape+timestamp+ancillary+envvar+protocol+ioctl+setsockopt+genericsocket+sctp+interface"

View File

@ -236,6 +236,12 @@
/* Define if you have the <linux/if_tun.h> header file. */
#undef HAVE_LINUX_IF_TUN_H
/* Define if you have the <netpacket/packet.h> header file. */
#undef HAVE_NETPACKET_PACKET_H
/* Define if you have the <netinet/if_ether.h> header file. */
#undef HAVE_NETINET_IF_ETHER_H
/* Define if you have the <sys/utsname.h> header file. */
#undef HAVE_SYS_UTSNAME_H
@ -469,6 +475,7 @@
#undef WITH_IP6
#undef WITH_RAWIP
#undef WITH_GENERICSOCKET
#undef WITH_INTERFACE
#undef WITH_TCP
#undef WITH_UDP
#undef WITH_SCTP

View File

@ -220,6 +220,28 @@ AC_ARG_ENABLE(rawsocket, [ --disable-genericsocket disable generic socket suppo
*) AC_DEFINE(WITH_GENERICSOCKET) AC_MSG_RESULT(yes);;
esac],
[AC_DEFINE(WITH_GENERICSOCKET) AC_MSG_RESULT(yes)])
AC_MSG_CHECKING(whether to include raw network INTERFACE support)
AC_ARG_ENABLE(interface, [ --disable-interface disable network interface support],
[case "$enableval" in
no) AC_MSG_RESULT(no); WITH_INTERFACE= ;;
*) AC_MSG_RESULT(yes); WITH_INTERFACE=1 ;;
esac],
[AC_MSG_RESULT(yes); WITH_INTERFACE=1 ])
if test "$WITH_INTERFACE"; then
AC_CHECK_HEADER(netpacket/packet.h,
AC_DEFINE(HAVE_NETPACKET_PACKET_H),
[WITH_INTERFACE=;
AC_MSG_WARN([include file netpacket/packet.h not found, disabling INTERFACE])])
fi
if test "$WITH_INTERFACE"; then
AC_CHECK_HEADER(netinet/if_ether.h,
AC_DEFINE(HAVE_NETINET_IF_ETHER_H),
[WITH_INTERFACE=;
AC_MSG_WARN([include file netinet/if_ether.h not found, disabling INTERFACE])])
fi
if test "$WITH_INTERFACE"; then
AC_DEFINE(WITH_INTERFACE)
fi
AC_MSG_CHECKING(whether to include TCP support)
AC_ARG_ENABLE(tcp, [ --disable-tcp disable TCP support],

View File

@ -541,6 +541,15 @@ label(ADDRESS_NAMED_PIPE)dit(bf(tt(PIPE:<filename>)))
link(mode)(OPTION_MODE),
link(unlink-early)(OPTION_UNLINK_EARLY)nl()
See also: link(unnamed pipe)(ADDRESS_UNNAMED_PIPE)
label(ADDRESS_INTERFACE)dit(bf(tt(INTERFACE:<interface>)))
Communicate with a network connected on an interface using raw packets
including link level data. link(<interface>)(TYPE_INTERFACE) is the name of
the network interface. Currently only available on Linux.
Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET) nl()
Useful options:
link(pf)(OPTION_PROTOCOL_FAMILY)
link(so-type)(OPTION_SO_TYPE)nl()
See also: link(ip-recv)(ADDRESS_IP_RECV)
label(ADDRESS_UNNAMED_PIPE)dit(bf(tt(PIPE)))
Creates an unnamed pipe and uses it for reading and writing. It works as an
echo, because everything written
@ -2741,7 +2750,8 @@ label(TYPE_INT)dit(int)
"0", i.e. decimal number, octal number with leading "0", or hexadecimal
number with leading "0x". The value must fit into a C int.
label(TYPE_INTERFACE)dit(interface)
A string specifying the device name of a network interface, e.g. "eth0".
A string specifying the device name of a network interface
as shown by ifconfig or procan, e.g. "eth0".
label(TYPE_IP_ADDRESS)dit(IP address)
An IPv4 address in numbers-and-dots notation, an IPv6 address in hex
notation enclosed in brackets, or a hostname that resolves to an IPv4 or an
@ -3193,6 +3203,17 @@ client and server authentication (see OpenSSL
link(client)(EXAMPLE_ADDRESS_OPENSSL_CONNECT) and
link(server)(EXAMPLE_ADDRESS_OPENSSL_LISTEN)).
label(EXAMPLE_INTERFACE)
dit(bf(tt(socat PTY,link=/var/run/ppp,raw,echo=0 INTERFACE:hdlc0)))
circumvents the problem that pppd requires a serial device and thus might not
be able to work on a synchronous line that is represented by a network device.
socat creates a PTY to make pppd happy, binds to the network interface hdlc0,
and can transfer data between both devices. Use pppd on device /var/run/ppp
then.
enddit()

View File

@ -428,6 +428,11 @@ void socat_version(FILE *fd) {
#else
fputs(" #undef WITH_RAWIP\n", fd);
#endif
#ifdef WITH_INTERFACE
fprintf(fd, " #define WITH_INTERFACE %d\n", WITH_INTERFACE);
#else
fputs(" #undef WITH_INTERFACE\n", fd);
#endif
#ifdef WITH_TCP
fprintf(fd, " #define WITH_TCP %d\n", WITH_TCP);
#else

View File

@ -125,6 +125,12 @@
#if HAVE_LINUX_ERRQUEUE_H
#include <linux/errqueue.h> /* struct sock_extended_err */
#endif
#if HAVE_NETPACKET_PACKET_H
#include <netpacket/packet.h>
#endif
#if HAVE_NETINET_IF_ETHER_H
#include <netinet/if_ether.h>
#endif
#if HAVE_LINUX_IF_TUN_H
#include <linux/if_tun.h>
#endif

View File

@ -116,7 +116,7 @@ socklen_t socket_init(int af, union sockaddr_union *sa) {
#if WITH_IP6
case AF_INET6: socket_in6_init(&sa->ip6); return sizeof(sa->ip6);
#endif
default: Error1("socket_init(): unknown address family %d", af);
default: Info1("socket_init(): unknown address family %d", af);
memset(sa, 0, sizeof(union sockaddr_union));
sa->soa.sa_family = af;
return 0;
@ -452,8 +452,12 @@ int parseport(const char *portname, int ipproto) {
#if WITH_IP4 || WITH_IP6
/* check the systems interfaces for ifname and return its index
or -1 if no interface with this name was found */
int ifindexbyname(const char *ifname) {
or -1 if no interface with this name was found
The system calls require an arbitrary socket; the calling program may
provide one in anysock to avoid creation of a dummy socket. anysock must be
<0 if it does not specify a socket fd.
*/
int ifindexbyname(const char *ifname, int anysock) {
/* Linux: man 7 netdevice */
/* FreeBSD: man 4 networking */
/* Solaris: man 7 if_tcp */
@ -461,29 +465,35 @@ int ifindexbyname(const char *ifname) {
#if defined(HAVE_STRUCT_IFREQ) && defined(SIOCGIFCONF) && defined(SIOCGIFINDEX)
/* currently we support Linux, FreeBSD; not Solaris */
#define IFBUFSIZ 1024
#define IFBUFSIZ 32*sizeof(struct ifreq) /*1024*/
int s;
struct ifreq ifr;
if (ifname[0] == '\0') {
return -1;
}
if ((s = Socket(PF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0) {
if (anysock >= 0) {
s = anysock;
} else if ((s = Socket(PF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0) {
Error1("socket(PF_INET, SOCK_DGRAM, IPPROTO_IP): %s", strerror(errno));
return -1;
}
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
if (Ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
Close(s);
Info3("ioctl(%d, SIOCGIFINDEX, {%s}): %s",
Info3("ioctl(%d, SIOCGIFINDEX, {\"%s\"}): %s",
s, ifr.ifr_name, strerror(errno));
Close(s);
return -1;
}
Close(s);
#if HAVE_STRUCT_IFREQ_IFR_INDEX
Info3("ioctl(%d, SIOCGIFINDEX, {\"%s\"}) -> { %d }",
s, ifname, ifr.ifr_index);
return ifr.ifr_index;
#elif HAVE_STRUCT_IFREQ_IFR_IFINDEX
Info3("ioctl(%d, SIOCGIFINDEX, {\"%s\"}) -> { %d }",
s, ifname, ifr.ifr_ifindex);
return ifr.ifr_ifindex;
#endif /* HAVE_STRUCT_IFREQ_IFR_IFINDEX */
@ -493,10 +503,11 @@ int ifindexbyname(const char *ifname) {
}
/* like ifindexbyname(), but allows an index number as input.
/* like ifindexbyname(), but also allows the index number as input - in this
case it does not lookup the index.
writes the resulting index to *ifindex and returns 0,
or returns -1 on error */
int ifindex(const char *ifname, unsigned int *ifindex) {
int ifindex(const char *ifname, unsigned int *ifindex, int anysock) {
char *endptr;
long int val;
@ -509,7 +520,7 @@ int ifindex(const char *ifname, unsigned int *ifindex) {
return 0;
}
if ((val = ifindexbyname(ifname)) < 0) {
if ((val = ifindexbyname(ifname, anysock)) < 0) {
return -1;
}
*ifindex = val;

View File

@ -78,8 +78,8 @@ extern int xiopoll(struct pollfd fds[], nfds_t nfds, int timeout);
extern int parseport(const char *portname, int proto);
extern int ifindexbyname(const char *ifname);
extern int ifindex(const char *ifname, unsigned int *ifindex);
extern int ifindexbyname(const char *ifname, int anysock);
extern int ifindex(const char *ifname, unsigned int *ifindex, int anysock);
extern int xiosetenv(const char *varname, const char *value, int overwrite);
extern int

55
test.sh
View File

@ -7851,6 +7851,61 @@ PORT=$((PORT+1))
N=$((N+1))
# use the INTERFACE address on a tun/tap device and transfer data fully
# transparent
NAME=TUNINTERFACE
case "$TESTS" in
*%functions%*|*%tun%*|*%interface%*|*%root%*|*%$NAME%*)
TEST="$NAME: pass data through tun interface using INTERFACE"
#idea: create a TUN interface and send a raw packet on the interface side.
# It should arrive unmodified on the tunnel side.
if ! feat=$(testaddrs ip4 tun interface) || ! runsip4 >/dev/null; then
$PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N
numCANT=$((numCANT+1))
elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then
$PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N
numCANT=$((numCANT+1))
else
tf="$td/test$N.stdout"
te="$td/test$N.stderr"
tdiff="$td/test$N.diff"
tl="$td/test$N.lock"
da="$(date) $RANDOM"
dalen=$((${#da}+1))
TUNNET=10.255.255
TUNNAME=tun9
CMD1="$SOCAT $opts -L $tl TUN:$TUNNET.1/24,iff-up=1,tun-type=tun,tun-name=$TUNNAME echo"
CMD="$SOCAT $opts - INTERFACE:$TUNNAME"
printf "test $F_n $TEST... " $N
$CMD1 2>"${te}1" &
pid1="$!"
#waitinterface "$TUNNAME"
sleep 1
echo "$da" |$CMD 2>"${te}1" >"$tf" 2>"${te}"
kill $pid1 2>/dev/null
wait
if [ $? -ne 0 ]; then
$PRINTF "$FAILED: $SOCAT:\n"
echo "$CMD &"
echo "$CMD1"
cat "${te}" "${te}1"
numFAIL=$((numFAIL+1))
elif ! echo "$da" |diff - "$tf" >"$tdiff"; then
$PRINTF "$FAILED\n"
cat "$tdiff"
cat "${te}" "${te}1"
numFAIL=$((numFAIL+1))
else
$PRINTF "$OK\n"
if [ -n "$debug" ]; then cat "${te}" "${te}1"; fi
numOK=$((numOK+1))
fi
fi ;; # not feats, not root
esac
PORT=$((PORT+1))
N=$((N+1))
NAME=ABSTRACTSTREAM
case "$TESTS" in
*%functions%*|*%unix%*|*%abstract%*|*%connect%*|*%listen%*|*%$NAME%*)

105
xio-interface.c Normal file
View File

@ -0,0 +1,105 @@
/* source: xio-interface.c */
/* Copyright Gerhard Rieger 2008 */
/* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for opening addresses of raw socket type */
#include "xiosysincludes.h"
#if WITH_INTERFACE
#include "xioopen.h"
#include "xio-socket.h"
#include "xio-interface.h"
static
int xioopen_interface(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *xfd, unsigned 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>") };
static
int _xioopen_interface(const char *ifname,
struct opt *opts, int xioflags, xiofile_t *xxfd,
unsigned groups, int pf) {
xiosingle_t *xfd = &xxfd->stream;
union sockaddr_union us = {{0}};
socklen_t uslen;
int socktype = SOCK_RAW;
unsigned int ifidx;
bool needbind = false;
char *bindstring = NULL;
struct sockaddr_ll sall = { 0 };
if (ifindex(ifname, &ifidx, -1) < 0) {
Error1("unknown interface \"%s\"", ifname);
ifidx = 0; /* desparate attempt to continue */
}
xfd->howtoend = END_SHUTDOWN;
retropt_int(opts, OPT_SO_TYPE, &socktype);
retropt_socket_pf(opts, &pf);
/* ...res_opts[] */
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
applyopts(-1, opts, PH_INIT);
xfd->salen = sizeof(xfd->peersa);
if (pf == PF_UNSPEC) {
pf = xfd->peersa.soa.sa_family;
}
xfd->dtype = XIODATA_RECVFROM_SKIPIP;
if (retropt_string(opts, OPT_BIND, &bindstring)) {
needbind = true;
}
/*!!! parse by ':' */
((struct sockaddr_ll *)&us)->sll_family = pf;
((struct sockaddr_ll *)&us)->sll_protocol = htons(ETH_P_ALL);
((struct sockaddr_ll *)&us)->sll_ifindex = ifidx;
uslen = sizeof(sall);
needbind = true;
xfd->peersa = (union sockaddr_union)us;
return
_xioopen_dgram_sendto(needbind?&us:NULL, uslen,
opts, xioflags, xfd, groups, pf, socktype, 0);
}
static
int xioopen_interface(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *xxfd, unsigned groups,
int pf, int dummy2, int dummy3) {
xiosingle_t *xfd = &xxfd->stream;
int result;
if (argc != 2) {
Error2("%s: wrong number of parameters (%d instead of 1)",
argv[0], argc-1);
return STAT_NORETRY;
}
if ((result =
_xioopen_interface(argv[1], opts, xioflags, xxfd, groups, pf))
!= STAT_OK) {
return result;
}
xfd->dtype = XIOREAD_RECV|XIOWRITE_SENDTO;
if (pf == PF_INET) {
xfd->dtype |= XIOREAD_RECV_SKIPIP;
}
xfd->para.socket.la.soa.sa_family = xfd->peersa.soa.sa_family;
_xio_openlate(xfd, opts);
return STAT_OK;
}
#endif /* WITH_INTERFACE */

10
xio-interface.h Normal file
View File

@ -0,0 +1,10 @@
/* source: xio-interface.h */
/* Copyright Gerhard Rieger 2008 */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_interface_h_included
#define __xio_interface_h_included 1
extern const struct addrdesc xioaddr_interface;
#endif /* !defined(__xio_interface_h_included) */

View File

@ -1500,8 +1500,8 @@ int retropt_socket_pf(struct opt *opts, int *pf) {
char *pfname;
if (retropt_string(opts, OPT_PROTOCOL_FAMILY, &pfname) >= 0) {
if (false) {
;
if (isdigit(pfname[0])) {
*pf = strtoul(pfname, NULL /*!*/, 0);
#if WITH_IP4
} else if (!strcasecmp("inet", pfname) ||
!strcasecmp("inet4", pfname) ||

View File

@ -20,6 +20,7 @@
#include "xio-listen.h"
#include "xio-unix.h"
#include "xio-rawip.h"
#include "xio-interface.h"
#include "xio-ip.h"
#if WITH_IP4
#include "xio-ip4.h"

View File

@ -59,6 +59,9 @@ const struct addrname addressnames[] = {
#if WITH_GOPEN
{ "gopen", &addr_gopen },
#endif
#if WITH_INTERFACE
{ "if", &xioaddr_interface },
#endif
#if (WITH_IP4 || WITH_IP6) && WITH_TCP
{ "inet", &addr_tcp_connect },
#endif
@ -80,6 +83,9 @@ const struct addrname addressnames[] = {
{ "inet6-l", &addr_tcp6_listen },
{ "inet6-listen", &addr_tcp6_listen },
#endif
#if WITH_INTERFACE
{ "interface", &xioaddr_interface },
#endif
#if WITH_RAWIP
#if (WITH_IP4 || WITH_IP6)
{ "ip", &addr_rawip_sendto },

View File

@ -3876,7 +3876,7 @@ mc:addr
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)
(unsigned int *)&ip4_mreqn.mreqn.imr_ifindex, -1)
< 0) {
Error1("cannot resolve interface \"%s\"",
opt->value.u_ip_mreq.ifindex);
@ -3889,7 +3889,8 @@ mc:addr
#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)
(unsigned int *)&ip4_mreqn.mreqn.imr_ifindex,
-1)
>= 0) {
/* yes, second param converts to interface */
ip4_mreqn.mreq.imr_interface.s_addr = htonl(0);
@ -3961,7 +3962,8 @@ mc:addr
&sockaddr1, &socklen1, 0, 0);
ip6_mreq.ipv6mr_multiaddr = sockaddr1.ip6.sin6_addr;
if (ifindex(opt->value.u_ip_mreq.param2,
&ip6_mreq.ipv6mr_interface) < 0) {
&ip6_mreq.ipv6mr_interface, -1)
< 0) {
Error1("interface \"%s\" not found",
opt->value.u_ip_mreq.param2);
ip6_mreq.ipv6mr_interface = htonl(0);

View File

@ -144,6 +144,15 @@ ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) {
errno = _errno;
return -1;
}
/* on packet type we also receive outgoing packets, this is not desired
*/
if (from.soa.sa_family == PF_PACKET) {
if ((((struct sockaddr_ll *)&from.soa)->sll_pkttype & PACKET_OUTGOING)
== 0) {
errno = EAGAIN; return -1;
}
}
Notice2("received packet with "F_Zu" bytes from %s",
bytes,
sockaddr_info(&from.soa, fromlen, infobuff, sizeof(infobuff)));