socat/xio-rawip.c
2008-02-24 11:09:01 +01:00

316 lines
13 KiB
C

/* $Id: xio-rawip.c,v 1.32 2007/02/05 19:56:34 gerhard Exp $ */
/* Copyright Gerhard Rieger 2001-2007 */
/* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for opening addresses of raw IP type */
#include "xiosysincludes.h"
#if (WITH_IP4 || WITH_IP6) && WITH_RAWIP
#include "xioopen.h"
#include "xio-socket.h"
#include "xio-ip.h"
#include "xio-ip6.h"
#include "xio-tcpwrap.h"
#include "xio-rawip.h"
static
int xioopen_rawip_sendto(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *fd, unsigned groups, int pf,
int dummy2, int dummy3);
static
int xioopen_rawip_datagram(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *fd, unsigned groups, int pf,
int dummy2, int dummy3);
static
int xioopen_rawip_recvfrom(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *xfd, unsigned groups,
int pf, int dummy2, int dummy3);
static
int xioopen_rawip_recv(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *xfd, unsigned groups,
int pf, int socktype, int ipproto);
static
int _xioopen_rawip_sendto(const char *hostname, const char *protname,
struct opt *opts, int xioflags,
xiofile_t *xxfd, unsigned groups, int pf);
static const struct xioaddr_endpoint_desc xioaddr_rawip_sendto2 = { XIOADDR_SYS, "ip-sendto", 2, XIOBIT_WRONLY|XIOBIT_RDWR, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6, XIOSHUT_DOWN, XIOCLOSE_NONE, xioopen_rawip_sendto, PF_UNSPEC, 0, 0 HELP(":<host>:<protocol>") };
const union xioaddr_desc *xioaddrs_rawip_sendto[] = { (union xioaddr_desc *)&xioaddr_rawip_sendto2, NULL };
static const struct xioaddr_endpoint_desc xioaddr_rawip_datagram2= { XIOADDR_SYS, "ip-datagram", 2, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_RANGE, XIOSHUT_DOWN, XIOCLOSE_NONE, xioopen_rawip_datagram, PF_UNSPEC, 0, 0 HELP(":<host>:<protocol>") };
const union xioaddr_desc *xioaddrs_rawip_datagram[] = { (union xioaddr_desc *)&xioaddr_rawip_datagram2, NULL };
static const struct xioaddr_endpoint_desc xioaddr_rawip_recvfrom1= { XIOADDR_SYS, "ip-recvfrom", 1, XIOBIT_RDONLY|XIOBIT_RDWR, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_CHILD|GROUP_RANGE, XIOSHUT_DOWN, XIOCLOSE_NONE, xioopen_rawip_recvfrom, PF_UNSPEC, SOCK_RAW, 0 HELP(":<protocol>") };
const union xioaddr_desc *xioaddrs_rawip_recvfrom[] = { (union xioaddr_desc *)&xioaddr_rawip_recvfrom1, NULL };
static const struct xioaddr_endpoint_desc xioaddr_rawip_recv1 = { XIOADDR_SYS, "ip-recv", 1, XIOBIT_RDONLY, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_RANGE, XIOSHUT_DOWN, XIOCLOSE_NONE, xioopen_rawip_recv, PF_UNSPEC, SOCK_RAW, 0 HELP(":<protocol>") };
const union xioaddr_desc *xioaddrs_rawip_recv[] = { (union xioaddr_desc *)&xioaddr_rawip_recv1, NULL };
#if WITH_IP4
static const struct xioaddr_endpoint_desc xioaddr_rawip4_sendto2 = { XIOADDR_SYS, "ip4-sendto", 2, XIOBIT_WRONLY|XIOBIT_RDWR, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4, XIOSHUT_DOWN, XIOCLOSE_NONE, xioopen_rawip_sendto, PF_INET, 0, 0 HELP(":<host>:<protocol>") };
const union xioaddr_desc *xioaddrs_rawip4_sendto[] = { (union xioaddr_desc *)&xioaddr_rawip4_sendto2, NULL };
static const struct xioaddr_endpoint_desc xioaddr_rawip4_datagram2= { XIOADDR_SYS, "ip4-datagram", 2, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_RANGE, XIOSHUT_DOWN, XIOCLOSE_NONE, xioopen_rawip_datagram, PF_INET, 0, 0 HELP(":<host>:<protocol>") };
const union xioaddr_desc *xioaddrs_rawip4_datagram[] = { (union xioaddr_desc *)&xioaddr_rawip4_datagram2, NULL };
static const struct xioaddr_endpoint_desc xioaddr_rawip4_recvfrom1= { XIOADDR_SYS, "ip4-recvfrom", 1, XIOBIT_RDONLY|XIOBIT_RDWR, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_CHILD|GROUP_RANGE, XIOSHUT_DOWN, XIOCLOSE_NONE, xioopen_rawip_recvfrom, PF_INET, SOCK_RAW, 0 HELP(":<protocol>") };
const union xioaddr_desc *xioaddrs_rawip4_recvfrom[] = { (union xioaddr_desc *)&xioaddr_rawip4_recvfrom1, NULL };
static const struct xioaddr_endpoint_desc xioaddr_rawip4_recv1 = { XIOADDR_SYS, "ip4-recv", 1, XIOBIT_RDONLY, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_RANGE, XIOSHUT_DOWN, XIOCLOSE_NONE, xioopen_rawip_recv, PF_INET, SOCK_RAW, 0 HELP(":<protocol>") };
const union xioaddr_desc *xioaddrs_rawip4_recv[] = { (union xioaddr_desc *)&xioaddr_rawip4_recv1, NULL };
#endif /* IWITH_IP4 */
#if WITH_IP6
static const struct xioaddr_endpoint_desc xioaddr_rawip6_sendto2 = { XIOADDR_SYS, "ip6-sendto", 2, XIOBIT_WRONLY|XIOBIT_RDWR, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6, XIOSHUT_DOWN, XIOCLOSE_NONE, xioopen_rawip_sendto, PF_INET6, 0, 0 HELP(":<host>:<protocol>") };
const union xioaddr_desc *xioaddrs_rawip6_sendto[] = { (union xioaddr_desc *)&xioaddr_rawip6_sendto2, NULL };
static const struct xioaddr_endpoint_desc xioaddr_rawip6_datagram2= { XIOADDR_SYS, "ip6-datagram", 2, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_RANGE, XIOSHUT_DOWN, XIOCLOSE_NONE, xioopen_rawip_datagram, PF_INET6, 0, 0 HELP(":<host>:<protocol>") };
const union xioaddr_desc *xioaddrs_rawip6_datagram[] = { (union xioaddr_desc *)&xioaddr_rawip6_datagram2, NULL };
static const struct xioaddr_endpoint_desc xioaddr_rawip6_recvfrom1= { XIOADDR_SYS, "ip6-recvfrom", 1, XIOBIT_RDONLY|XIOBIT_RDWR, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_CHILD|GROUP_RANGE, XIOSHUT_DOWN, XIOCLOSE_NONE, xioopen_rawip_recvfrom, PF_INET6, SOCK_RAW, 0 HELP(":<protocol>") };
const union xioaddr_desc *xioaddrs_rawip6_recvfrom[] = { (union xioaddr_desc *)&xioaddr_rawip6_recvfrom1, NULL };
static const struct xioaddr_endpoint_desc xioaddr_rawip6_recv1 = { XIOADDR_SYS, "ip6-recv", 1, XIOBIT_RDONLY, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_RANGE, XIOSHUT_DOWN, XIOCLOSE_NONE, xioopen_rawip_recv, PF_INET6, SOCK_RAW, 0 HELP(":<protocol>") };
const union xioaddr_desc *xioaddrs_rawip6_recv[] = { (union xioaddr_desc *)&xioaddr_rawip6_recv1, NULL };
#endif /* WITH_IP6 */
/* we expect the form: host:protocol */
/* struct sockaddr_in sa;*/
/* socklen_t salen;*/
static
int xioopen_rawip_sendto(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *xxfd, unsigned groups,
int pf, int dummy2, int dummy3) {
int result;
if (argc != 3) {
Error2("%s: wrong number of parameters (%d instead of 2)",
argv[0], argc-1);
return STAT_NORETRY;
}
if ((result = _xioopen_rawip_sendto(argv[1], argv[2], opts, xioflags, xxfd,
groups, pf)) != STAT_OK) {
return result;
}
_xio_openlate(&xxfd->stream, opts);
return STAT_OK;
}
static
int _xioopen_rawip_sendto(const char *hostname, const char *protname,
struct opt *opts, int xioflags, xiofile_t *xxfd,
unsigned groups, int pf) {
char *garbage;
xiosingle_t *xfd = &xxfd->stream;
union sockaddr_union us;
socklen_t uslen;
int feats = 1; /* option bind supports only address, not port */
int socktype = SOCK_RAW;
int ipproto;
bool needbind = false;
int result;
if ((ipproto = strtoul(protname, &garbage, 0)) >= 256) {
Error3("xioopen_rawip_sendto(\"%s:%s\",,): protocol number exceeds 255 (%u)",
hostname, protname, ipproto);
return STAT_NORETRY;
} else if (*garbage) {
Warn2("xioopen_rawip_sendto(\"%s:%s\",,): trailing garbage in protocol specification",
hostname, protname);
/*return STAT_NORETRY;*/
}
retropt_int(opts, OPT_SO_TYPE, &socktype);
/* ...res_opts[] */
if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
applyopts(-1, opts, PH_INIT);
xfd->salen = sizeof(xfd->peersa);
if ((result =
xiogetaddrinfo(hostname, NULL, pf, socktype, ipproto,
&xfd->peersa, &xfd->salen,
xfd->para.socket.ip.res_opts[0],
xfd->para.socket.ip.res_opts[1]))
!= STAT_OK) {
return result;
}
if (pf == PF_UNSPEC) {
pf = xfd->peersa.soa.sa_family;
}
uslen = socket_init(pf, &us);
xfd->fdtype = FDTYPE_SINGLE;
xfd->dtype = XIODATA_RECVFROM_SKIPIP;
if (retropt_bind(opts, pf, socktype, ipproto, &us.soa, &uslen, feats,
xfd->para.socket.ip.res_opts[0],
xfd->para.socket.ip.res_opts[1]) != STAT_NOACTION) {
needbind = true;
}
return
_xioopen_dgram_sendto(needbind?&us:NULL, uslen,
opts, xioflags, xfd, groups, pf, socktype, ipproto);
}
/* we expect the form: address:protocol */
static
int xioopen_rawip_datagram(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;
char *rangename;
int result;
if (argc != 3) {
Error2("%s: wrong number of parameters (%d instead of 2)",
argv[0], argc-1);
return STAT_NORETRY;
}
if ((result =
_xioopen_rawip_sendto(argv[1], argv[2], 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;
/* which reply packets will be accepted - determine by range option */
if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) {
if (parserange(rangename, pf, &xfd->para.socket.range) < 0) {
free(rangename);
return STAT_NORETRY;
}
xfd->para.socket.dorange = true;
xfd->dtype |= XIOREAD_RECV_CHECKRANGE;
free(rangename);
}
#if WITH_LIBWRAP
xio_retropt_tcpwrap(xfd, opts);
#endif /* WITH_LIBWRAP */
_xio_openlate(xfd, opts);
return STAT_OK;
}
static
int xioopen_rawip_recvfrom(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *xfd, unsigned groups,
int pf, int socktype, int dummy3) {
const char *protname = argv[1];
char *garbage;
union sockaddr_union us;
socklen_t uslen = sizeof(us);
int ipproto;
bool needbind = false;
int result;
if (argc != 2) {
Error2("%s: wrong number of parameters (%d instead of 1)",
argv[0], argc-1);
return STAT_NORETRY;
}
if ((ipproto = strtoul(protname, &garbage, 0)) >= 256) {
Error2("xioopen_rawip_recvfrom(\"%s\",,): protocol number exceeds 255 (%u)",
protname, ipproto);
return STAT_NORETRY;
} else if (*garbage) {
Warn1("xioopen_rawip_recvfrom(\"%s\",,): trailing garbage in protocol specification",
protname);
/*return STAT_NORETRY;*/
}
xfd->stream.howtoshut = XIOSHUT_NONE;
xfd->stream.howtoclose = XIOCLOSE_CLOSE;
retropt_int(opts, OPT_SO_TYPE, &socktype);
retropt_socket_pf(opts, &pf);
if (pf == PF_UNSPEC) {
#if WITH_IP4 && WITH_IP6
pf = xioopts.default_ip=='6'?PF_INET6:PF_INET;
#elif WITH_IP6
pf = PF_INET6;
#else
pf = PF_INET;
#endif
}
if (retropt_bind(opts, pf, socktype, ipproto, &us.soa, &uslen, 1,
xfd->stream.para.socket.ip.res_opts[0],
xfd->stream.para.socket.ip.res_opts[1]) != STAT_NOACTION) {
needbind = true;
}
xfd->stream.fdtype = FDTYPE_SINGLE;
xfd->stream.dtype = XIODATA_RECVFROM_SKIPIP_ONE;
if ((result =
_xioopen_dgram_recvfrom(&xfd->stream, xioflags, needbind?&us.soa:NULL,
uslen, opts, pf, socktype, ipproto, E_ERROR))
!= STAT_OK) {
return result;
}
_xio_openlate(&xfd->stream, opts);
return STAT_OK;
}
static
int xioopen_rawip_recv(int argc, const char *argv[], struct opt *opts,
int xioflags, xiofile_t *xfd, unsigned groups,
int pf, int socktype, int ipproto) {
const char *protname = argv[1];
char *garbage;
union sockaddr_union us;
socklen_t uslen = sizeof(us);
int result;
if (argc != 2) {
Error2("%s: wrong number of parameters (%d instead of 1)",
argv[0], argc-1);
return STAT_NORETRY;
}
if ((ipproto = strtoul(protname, &garbage, 0)) >= 256) {
Error2("xioopen_rawip_recvfrom(\"%s\",,): protocol number exceeds 255 (%u)",
protname, ipproto);
return STAT_NORETRY;
} else if (*garbage) {
Warn1("xioopen_rawip_recvfrom(\"%s\",,): trailing garbage in protocol specification",
protname);
/*return STAT_NORETRY;*/
}
retropt_int(opts, OPT_SO_TYPE, &socktype);
retropt_socket_pf(opts, &pf);
if (pf == PF_UNSPEC) {
#if WITH_IP4 && WITH_IP6
pf = xioopts.default_ip=='6'?PF_INET6:PF_INET;
#elif WITH_IP6
pf = PF_INET6;
#else
pf = PF_INET;
#endif
}
if (retropt_bind(opts, pf, socktype, ipproto, &us.soa, &uslen, 1,
xfd->stream.para.socket.ip.res_opts[0],
xfd->stream.para.socket.ip.res_opts[1]) !=
STAT_OK) {
/* pf is required during xioread checks */
xfd->stream.para.socket.la.soa.sa_family = pf;
}
xfd->stream.fdtype = FDTYPE_SINGLE;
xfd->stream.dtype = XIODATA_RECV_SKIPIP;
result = _xioopen_dgram_recv(&xfd->stream, xioflags, NULL/*&us.soa*/, uslen,
opts, pf, socktype, ipproto, E_ERROR);
_xio_openlate(&xfd->stream, opts);
return result;
}
#endif /* (WITH_IP4 || WITH_IP6) && WITH_RAWIP */