mirror of
https://repo.or.cz/socat.git
synced 2024-12-22 23:42:34 +00:00
add generic setsockopt address options
This commit is contained in:
parent
52be3b085e
commit
140443794b
9 changed files with 192 additions and 7 deletions
7
CHANGES
7
CHANGES
|
@ -1,7 +1,10 @@
|
||||||
|
|
||||||
new features:
|
new features:
|
||||||
added address options IOCTL-VOID, IOCTL-INT, IOCTL-INTP, IOCTL-STRING,
|
added address options ioctl-void, ioctl-int, ioctl-intp, ioctl-string,
|
||||||
IOCTL-BIN for generic ioctl() calls.
|
ioctl-bin for generic ioctl() calls.
|
||||||
|
|
||||||
|
added address options setsockopt-int, setsockopt-bin, and
|
||||||
|
setsockopt-string
|
||||||
|
|
||||||
corrections:
|
corrections:
|
||||||
some raw IP and UNIX datagram modes failed on BSD systems
|
some raw IP and UNIX datagram modes failed on BSD systems
|
||||||
|
|
20
EXAMPLES
20
EXAMPLES
|
@ -286,11 +286,27 @@ $ socat -d -d -d -d - udp-datagram:224.0.0.2:6666,bind=:6666,ip-add-membership=2
|
||||||
// socket bound to specific address
|
// socket bound to specific address
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
// IOCTL
|
// GENERIC FUNCTION CALLS
|
||||||
|
|
||||||
// open CD drive (given value valid on Linux)
|
// ioctl(): open CD drive (given value valid on Linux)
|
||||||
|
// on my Linux system I find in /usr/include/linux/cdrom.h the define:
|
||||||
|
// #define CDROMEJECT 0x5309 /* Ejects the cdrom media */
|
||||||
|
// the following command makes something like ioctl(fd, CDROMEJECT, NULL)
|
||||||
$ socat /dev/cdrom,o-nonblock,ioctl-void=0x5309 -
|
$ socat /dev/cdrom,o-nonblock,ioctl-void=0x5309 -
|
||||||
|
|
||||||
|
// setsockopt(): SO_REUSEADDR
|
||||||
|
// the following command performs - beyond lots of overhead - something like:
|
||||||
|
// myint=1; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &myint, sizeof(myint))
|
||||||
|
$ socat -u udp-recv:7777,setsockopt-int=1:2:1 -
|
||||||
|
// setsockopt(): SO_BINDTODEVICE
|
||||||
|
|
||||||
|
// ways to apply SO_BINDTODEVICE without using the special socat address option
|
||||||
|
// so-bindtodevice:
|
||||||
|
// with string argument:
|
||||||
|
$ sudo ./socat tcp-l:7777,setsockopt-string=1:25:eth0 pipe
|
||||||
|
// with binary argument:
|
||||||
|
$ sudo ./socat tcp-l:7777,setsockopt-bin=1:25:x6574683000 pipe
|
||||||
|
|
||||||
===============================================================================
|
===============================================================================
|
||||||
|
|
||||||
// not tested, just ideas, or have problems
|
// not tested, just ideas, or have problems
|
||||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
||||||
"1.6.0.1+ip4bind+recvfromfork+x64+execstderr+execspaces+cosmetics+poll+udplistencont+ignoreeofunblock+ioctl"
|
"1.6.0.1+ip4bind+recvfromfork+x64+execstderr+execspaces+cosmetics+poll+udplistencont+ignoreeofunblock+ioctl+ioctl+setsockopt"
|
||||||
|
|
16
doc/socat.yo
16
doc/socat.yo
|
@ -1653,6 +1653,22 @@ COMMENT(label(OPTION_USEIFBUFS)dit(bf(tt(useifbufs)))
|
||||||
label(OPTION_PROTOCOL_FAMILY)dit(bf(tt(pf=<string>)))
|
label(OPTION_PROTOCOL_FAMILY)dit(bf(tt(pf=<string>)))
|
||||||
Forces the use of the specified IP version. <string> can be
|
Forces the use of the specified IP version. <string> can be
|
||||||
something like "ip4" or "ip6".
|
something like "ip4" or "ip6".
|
||||||
|
label(OPTION_SETSOCKOPT_INT)dit(bf(tt(setsockopt-int=<level>:<optname>:<optval>)))
|
||||||
|
Invokes tt(setsockopt()) for the socket with the given parameters. tt(level)
|
||||||
|
[link(int)(TYPE_INT)] specifies the second argument to tt(setsockopt())
|
||||||
|
which specifies the layer, e.g. SOL_TCP (=6 on Linux) for TCP, or SOL_SOCKET
|
||||||
|
(=1 on Linux) for the socket layer. tt(optname) [link(int)(TYPE_INT)]
|
||||||
|
selects the third argument to tt(setsockopt()) option. For the actual
|
||||||
|
integer values you might have to look up the appropriate include file of
|
||||||
|
your system. The 4th tt(setsockopt()) parameter, tt(value)
|
||||||
|
[link(int)(TYPE_INT)], is passed to the function per pointer, and the length
|
||||||
|
parameter to the tt(setsockopt()) call is derived from this type.
|
||||||
|
label(OPTION_SETSOCKOPT_BIN)dit(bf(tt(setsockopt-bin=<level>:<optname>:<optval>)))
|
||||||
|
Like tt(setsockopt-int), but <optval> is expected in link(dalan)(TYPE_DATA)
|
||||||
|
format and specifies an arbitrary sequence of bytes.
|
||||||
|
label(OPTION_SETSOCKOPT_STRING)dit(bf(tt(setsockopt-string=<level>:<optname>:<optval>)))
|
||||||
|
Like tt(setsockopt-int), but <optval> must be a link(string)(TYPE_STRING).
|
||||||
|
This string is passed to the function with trailing null character.
|
||||||
enddit()
|
enddit()
|
||||||
|
|
||||||
startdit()enddit()nl()
|
startdit()enddit()nl()
|
||||||
|
|
|
@ -128,6 +128,12 @@ const struct optdesc opt_bind = { "bind", NULL, OPT_BIND, GRO
|
||||||
const struct optdesc opt_connect_timeout = { "connect-timeout", NULL, OPT_CONNECT_TIMEOUT, GROUP_SOCKET, PH_PASTSOCKET, TYPE_TIMEVAL, OFUNC_OFFSET, (int)&((xiofile_t *)0)->stream.para.socket.connect_timeout };
|
const struct optdesc opt_connect_timeout = { "connect-timeout", NULL, OPT_CONNECT_TIMEOUT, GROUP_SOCKET, PH_PASTSOCKET, TYPE_TIMEVAL, OFUNC_OFFSET, (int)&((xiofile_t *)0)->stream.para.socket.connect_timeout };
|
||||||
const struct optdesc opt_protocol_family = { "protocol-family", "pf", OPT_PROTOCOL_FAMILY, GROUP_SOCKET, PH_PRESOCKET, TYPE_STRING, OFUNC_SPEC };
|
const struct optdesc opt_protocol_family = { "protocol-family", "pf", OPT_PROTOCOL_FAMILY, GROUP_SOCKET, PH_PRESOCKET, TYPE_STRING, OFUNC_SPEC };
|
||||||
|
|
||||||
|
/* generic setsockopt() options */
|
||||||
|
const struct optdesc opt_setsockopt_int = { "setsockopt-int", "sockopt-int", OPT_SETSOCKOPT_INT, GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT_INT_INT, OFUNC_SPEC, 0, 0 };
|
||||||
|
const struct optdesc opt_setsockopt_bin = { "setsockopt-bin", "sockopt-bin", OPT_SETSOCKOPT_BIN, GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT_INT_BIN, OFUNC_SPEC, 0, 0 };
|
||||||
|
const struct optdesc opt_setsockopt_string = { "setsockopt-string", "sockopt-string", OPT_SETSOCKOPT_STRING, GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT_INT_STRING, OFUNC_SPEC, 0, 0 };
|
||||||
|
|
||||||
|
|
||||||
/* a subroutine that is common to all socket addresses that want to connect
|
/* a subroutine that is common to all socket addresses that want to connect
|
||||||
to a peer address.
|
to a peer address.
|
||||||
might fork.
|
might fork.
|
||||||
|
|
|
@ -50,6 +50,9 @@ extern const struct optdesc opt_fiosetown;
|
||||||
extern const struct optdesc opt_siocspgrp;
|
extern const struct optdesc opt_siocspgrp;
|
||||||
extern const struct optdesc opt_bind;
|
extern const struct optdesc opt_bind;
|
||||||
extern const struct optdesc opt_protocol_family;
|
extern const struct optdesc opt_protocol_family;
|
||||||
|
extern const struct optdesc opt_setsockopt_int;
|
||||||
|
extern const struct optdesc opt_setsockopt_bin;
|
||||||
|
extern const struct optdesc opt_setsockopt_string;
|
||||||
|
|
||||||
extern int retropt_socket_pf(struct opt *opts, int *pf);
|
extern int retropt_socket_pf(struct opt *opts, int *pf);
|
||||||
|
|
||||||
|
|
1
xio.h
1
xio.h
|
@ -356,6 +356,7 @@ struct opt {
|
||||||
const struct optdesc *desc;
|
const struct optdesc *desc;
|
||||||
union integral value;
|
union integral value;
|
||||||
union integral value2;
|
union integral value2;
|
||||||
|
union integral value3;
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
extern const char *PIPESEP;
|
extern const char *PIPESEP;
|
||||||
|
|
138
xioopts.c
138
xioopts.c
|
@ -1196,6 +1196,9 @@ const struct optname optionnames[] = {
|
||||||
#if WITH_EXEC || WITH_SYSTEM
|
#if WITH_EXEC || WITH_SYSTEM
|
||||||
IF_EXEC ("setsid", &opt_setsid)
|
IF_EXEC ("setsid", &opt_setsid)
|
||||||
#endif
|
#endif
|
||||||
|
IF_SOCKET ("setsockopt-bin", &opt_setsockopt_bin)
|
||||||
|
IF_SOCKET ("setsockopt-int", &opt_setsockopt_int)
|
||||||
|
IF_SOCKET ("setsockopt-string", &opt_setsockopt_string)
|
||||||
IF_ANY ("setuid", &opt_setuid)
|
IF_ANY ("setuid", &opt_setuid)
|
||||||
IF_ANY ("setuid-early", &opt_setuid_early)
|
IF_ANY ("setuid-early", &opt_setuid_early)
|
||||||
#if WITH_EXEC || WITH_SYSTEM
|
#if WITH_EXEC || WITH_SYSTEM
|
||||||
|
@ -2031,13 +2034,97 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
|
||||||
ent->desc->defname);
|
ent->desc->defname);
|
||||||
}
|
}
|
||||||
++rest;
|
++rest;
|
||||||
if (((*opts)[i].value2.u_string = strdup(token)) == NULL) {
|
if (((*opts)[i].value2.u_string = strdup(rest)) == NULL) {
|
||||||
Error("out of memory"); return -1;
|
Error("out of memory"); return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Info3("setting option \"%s\" to %d:\"$s\"", ent->desc->defname,
|
Info3("setting option \"%s\" to %d:\"%s\"", ent->desc->defname,
|
||||||
(*opts)[i].value.u_int, (*opts)[i].value2.u_string);
|
(*opts)[i].value.u_int, (*opts)[i].value2.u_string);
|
||||||
break;
|
break;
|
||||||
|
case TYPE_INT_INT_INT:
|
||||||
|
if (!assign) {
|
||||||
|
Error1("option \"%s\": values required", a0);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
char *rest;
|
||||||
|
(*opts)[i].value.u_int = strtoul(token, &rest, 0);
|
||||||
|
if (*rest != ':') {
|
||||||
|
Error1("option \"%s\": 3 arguments required",
|
||||||
|
ent->desc->defname);
|
||||||
|
}
|
||||||
|
++rest;
|
||||||
|
(*opts)[i].value2.u_int = strtoul(rest, &rest, 0);
|
||||||
|
if (*rest != ':') {
|
||||||
|
Error1("option \"%s\": 3 arguments required",
|
||||||
|
ent->desc->defname);
|
||||||
|
}
|
||||||
|
++rest;
|
||||||
|
(*opts)[i].value3.u_int = strtoul(rest, &rest, 0);
|
||||||
|
}
|
||||||
|
Info4("setting option \"%s\" to %d:%d:%d", ent->desc->defname,
|
||||||
|
(*opts)[i].value.u_int, (*opts)[i].value2.u_int, (*opts)[i].value3.u_int);
|
||||||
|
break;
|
||||||
|
case TYPE_INT_INT_BIN:
|
||||||
|
if (!assign) {
|
||||||
|
Error1("option \"%s\": values required", a0);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
char *rest;
|
||||||
|
(*opts)[i].value.u_int = strtoul(token, &rest, 0);
|
||||||
|
if (*rest != ':') {
|
||||||
|
Error1("option \"%s\": 3 arguments required",
|
||||||
|
ent->desc->defname);
|
||||||
|
}
|
||||||
|
++rest;
|
||||||
|
(*opts)[i].value2.u_int = strtoul(rest, &rest, 0);
|
||||||
|
if (*rest != ':') {
|
||||||
|
Error1("option \"%s\": 3 arguments required",
|
||||||
|
ent->desc->defname);
|
||||||
|
}
|
||||||
|
++rest;
|
||||||
|
optlen = 0;
|
||||||
|
if ((result = dalan(rest, optbuf, &optlen, sizeof(optbuf))) != 0) {
|
||||||
|
Error1("parseopts(): problem with \"%s\" data", rest);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (((*opts)[i].value3.u_bin.b_data = memdup(optbuf, optlen)) == NULL) {
|
||||||
|
Error1("memdup(, "F_Zu"): out of memory", optlen);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
(*opts)[i].value3.u_bin.b_len = optlen;
|
||||||
|
}
|
||||||
|
Info3("setting option \"%s\" to %d:%d:..."/*!!!*/, ent->desc->defname,
|
||||||
|
(*opts)[i].value.u_int, (*opts)[i].value2.u_int);
|
||||||
|
break;
|
||||||
|
case TYPE_INT_INT_STRING:
|
||||||
|
if (!assign) {
|
||||||
|
Error1("option \"%s\": values required", a0);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
char *rest;
|
||||||
|
(*opts)[i].value.u_int = strtoul(token, &rest, 0);
|
||||||
|
if (*rest != ':') {
|
||||||
|
Error1("option \"%s\": 3 arguments required",
|
||||||
|
ent->desc->defname);
|
||||||
|
}
|
||||||
|
++rest;
|
||||||
|
(*opts)[i].value2.u_int = strtoul(rest, &rest, 0);
|
||||||
|
if (*rest != ':') {
|
||||||
|
Error1("option \"%s\": 3 arguments required",
|
||||||
|
ent->desc->defname);
|
||||||
|
}
|
||||||
|
++rest;
|
||||||
|
if (((*opts)[i].value3.u_string = strdup(rest)) == NULL) {
|
||||||
|
Error("out of memory"); return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Info4("setting option \"%s\" to %d:%d:\"%s\"", ent->desc->defname,
|
||||||
|
(*opts)[i].value.u_int, (*opts)[i].value2.u_int,
|
||||||
|
(*opts)[i].value3.u_int);
|
||||||
|
break;
|
||||||
#if defined(HAVE_STRUCT_IP_MREQ) || defined (HAVE_STRUCT_IP_MREQN)
|
#if defined(HAVE_STRUCT_IP_MREQ) || defined (HAVE_STRUCT_IP_MREQN)
|
||||||
case TYPE_IP_MREQN:
|
case TYPE_IP_MREQN:
|
||||||
{
|
{
|
||||||
|
@ -3134,6 +3221,53 @@ int applyopts(int fd, struct opt *opts, unsigned int phase) {
|
||||||
Error1("ioctl() data type %d not implemented", opt->desc->type);
|
Error1("ioctl() data type %d not implemented", opt->desc->type);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case OPT_SETSOCKOPT_INT:
|
||||||
|
switch (opt->desc->type) {
|
||||||
|
case TYPE_INT_INT_INT:
|
||||||
|
if (Setsockopt(fd, opt->value.u_int, opt->value2.u_int,
|
||||||
|
&opt->value3.u_int, sizeof(int)) < 0) {
|
||||||
|
Error6("setsockopt(%d, %d, %d, {%d}, "F_Zu"): %s",
|
||||||
|
fd, opt->value.u_int, opt->value2.u_int,
|
||||||
|
opt->value3.u_int, sizeof(int), strerror(errno));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Error1("setsockopt() data type %d not implemented",
|
||||||
|
opt->desc->type);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OPT_SETSOCKOPT_BIN:
|
||||||
|
switch (opt->desc->type) {
|
||||||
|
case TYPE_INT_INT_BIN:
|
||||||
|
if (Setsockopt(fd, opt->value.u_int, opt->value2.u_int,
|
||||||
|
opt->value3.u_bin.b_data, opt->value3.u_bin.b_len) < 0) {
|
||||||
|
Error5("setsockopt(%d, %d, %d, {...}, "F_Zu"): %s",
|
||||||
|
fd, opt->value.u_int, opt->value2.u_int,
|
||||||
|
opt->value3.u_bin.b_len, strerror(errno));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Error1("setsockopt() data type %d not implemented",
|
||||||
|
opt->desc->type);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OPT_SETSOCKOPT_STRING:
|
||||||
|
switch (opt->desc->type) {
|
||||||
|
case TYPE_INT_INT_STRING:
|
||||||
|
if (Setsockopt(fd, opt->value.u_int, opt->value2.u_int,
|
||||||
|
opt->value3.u_string,
|
||||||
|
strlen(opt->value3.u_string)+1) < 0) {
|
||||||
|
Error6("setsockopt(%d, %d, %d, \"%s\", "F_Zu"): %s",
|
||||||
|
fd, opt->value.u_int, opt->value2.u_int,
|
||||||
|
opt->value3.u_string, strlen(opt->value3.u_string)+1,
|
||||||
|
strerror(errno));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Error1("setsockopt() data type %d not implemented",
|
||||||
|
opt->desc->type);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default: Error1("applyopts(): option \"%s\" not implemented",
|
default: Error1("applyopts(): option \"%s\" not implemented",
|
||||||
opt->desc->defname);
|
opt->desc->defname);
|
||||||
|
|
|
@ -56,6 +56,9 @@ enum e_types {
|
||||||
TYPE_INT_INT, /* 2 parameters: first is int, second is int */
|
TYPE_INT_INT, /* 2 parameters: first is int, second is int */
|
||||||
TYPE_INT_BIN, /* 2 parameters: first is int, second is binary */
|
TYPE_INT_BIN, /* 2 parameters: first is int, second is binary */
|
||||||
TYPE_INT_STRING, /* 2 parameters: first is int, second is req string */
|
TYPE_INT_STRING, /* 2 parameters: first is int, second is req string */
|
||||||
|
TYPE_INT_INT_INT, /* 3 params: first and second are int, 3rd is int */
|
||||||
|
TYPE_INT_INT_BIN, /* 3 params: first and second are int, 3rd is binary */
|
||||||
|
TYPE_INT_INT_STRING, /* 3 params: first and second are int, 3rd is string */
|
||||||
|
|
||||||
TYPE_2BYTE = TYPE_USHORT
|
TYPE_2BYTE = TYPE_USHORT
|
||||||
} ;
|
} ;
|
||||||
|
@ -542,6 +545,9 @@ enum e_optcode {
|
||||||
OPT_SETGID_EARLY,
|
OPT_SETGID_EARLY,
|
||||||
OPT_SETPGID,
|
OPT_SETPGID,
|
||||||
OPT_SETSID,
|
OPT_SETSID,
|
||||||
|
OPT_SETSOCKOPT_BIN,
|
||||||
|
OPT_SETSOCKOPT_INT,
|
||||||
|
OPT_SETSOCKOPT_STRING,
|
||||||
OPT_SETUID,
|
OPT_SETUID,
|
||||||
OPT_SETUID_EARLY,
|
OPT_SETUID_EARLY,
|
||||||
OPT_SIGHUP,
|
OPT_SIGHUP,
|
||||||
|
|
Loading…
Reference in a new issue