mirror of
https://repo.or.cz/socat.git
synced 2024-12-22 15:32:35 +00:00
new address option "escape" allows to break a socat instance
This commit is contained in:
parent
d70b8963aa
commit
c86345a615
12 changed files with 152 additions and 26 deletions
4
CHANGES
4
CHANGES
|
@ -1,4 +1,8 @@
|
|||
|
||||
new features:
|
||||
new address option "escape" allows to break a socat instance even when
|
||||
raw terminal mode prevents ^C etc.
|
||||
|
||||
corrections:
|
||||
some raw IP and UNIX datagram modes failed on BSD systems
|
||||
|
||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
"1.6.0.1+ip4bind+recvfromfork+x64+execstderr+execspaces+cosmetics+poll+udplistencont+ignoreeofunblock"
|
||||
"1.6.0.1+ip4bind+recvfromfork+x64+execstderr+execspaces+cosmetics+poll+udplistencont+ignoreeofunblock+escape"
|
||||
|
|
18
doc/socat.yo
18
doc/socat.yo
|
@ -10,7 +10,7 @@ def(Filan)(0)(bf(Filan))
|
|||
def(procan)(0)(bf(procan))
|
||||
def(Procan)(0)(bf(Procan))
|
||||
|
||||
manpage(socat)(1)(Feb 2008)(socat)()
|
||||
manpage(socat)(1)(Jul 2008)(socat)()
|
||||
|
||||
whenhtml(
|
||||
label(CONTENTS)
|
||||
|
@ -1516,6 +1516,10 @@ label(OPTION_LOCKFILE)dit(bf(tt(lockfile=<filename>)))
|
|||
label(OPTION_WAITLOCK)dit(bf(tt(waitlock=<filename>)))
|
||||
If lockfile exists, waits until it disappears. When lockfile does not exist,
|
||||
creates it and continues, unlinks lockfile on exit.
|
||||
label(OPTION_ESCAPE)dit(bf(tt(escape=<int>)))
|
||||
Specifies the numeric code of a character that triggers EOF on the input
|
||||
stream. It is useful with a terminal in raw mode
|
||||
(link(example)(EXAMPLE_OPTION_ESCAPE)).
|
||||
enddit()
|
||||
|
||||
startdit()enddit()nl()
|
||||
|
@ -2630,13 +2634,15 @@ at most 512 data bytes per packet (link(mss)(OPTION_MSS)).
|
|||
label(EXAMPLE_ADDRESS_GOPEN)
|
||||
label(EXAMPLE_OPTION_RAW)
|
||||
label(EXAMPLE_OPTION_ECHO)
|
||||
dit(bf(tt(socat - /dev/ttyS0,raw,echo=0,crnl)))
|
||||
label(EXAMPLE_OPTION_ESCAPE)
|
||||
dit(bf(tt(socat -,raw,echo=0,escape=0x0f /dev/ttyS0,raw,echo=0,crnl)))
|
||||
|
||||
Opens an interactive connection via the serial line, e.g. for talking with a
|
||||
modem. link(raw)(OPTION_RAW) and link(echo)(OPTION_ECHO) set ttyS0's terminal
|
||||
parameters to practicable values, link(crnl)(OPTION_CRNL)
|
||||
converts to correct newline characters. Consider using
|
||||
link(READLINE)(ADDRESS_READLINE) instead of `-'.
|
||||
modem. link(raw)(OPTION_RAW) and link(echo)(OPTION_ECHO) set the console's and
|
||||
ttyS0's terminal parameters to practicable values, link(crnl)(OPTION_CRNL)
|
||||
converts to correct newline characters. link(escape)(OPTION_ESCAPE) allows to
|
||||
terminate the socat process with character control-O.
|
||||
Consider using link(READLINE)(ADDRESS_READLINE) instead of the first address.
|
||||
|
||||
|
||||
label(EXAMPLE_ADDRESS_UNIX_LISTEN)
|
||||
|
|
72
socat.c
72
socat.c
|
@ -947,7 +947,11 @@ int _socat(void) {
|
|||
XIO_RDSTREAM(sock1)->actbytes == 0) {
|
||||
/* avoid idle when all readbytes already there */
|
||||
mayrd1 = true;
|
||||
}
|
||||
}
|
||||
/* escape char occurred? */
|
||||
if (XIO_RDSTREAM(sock1)->actescape) {
|
||||
bytes1 = 0; /* indicate EOF */
|
||||
}
|
||||
}
|
||||
/* (bytes1 == 0) handled later */
|
||||
} else {
|
||||
|
@ -976,6 +980,10 @@ int _socat(void) {
|
|||
/* avoid idle when all readbytes already there */
|
||||
mayrd2 = true;
|
||||
}
|
||||
/* escape char occurred? */
|
||||
if (XIO_RDSTREAM(sock2)->actescape) {
|
||||
bytes2 = 0; /* indicate EOF */
|
||||
}
|
||||
}
|
||||
/* (bytes2 == 0) handled later */
|
||||
} else {
|
||||
|
@ -988,7 +996,8 @@ int _socat(void) {
|
|||
bytes1, XIO_RDSTREAM(sock1)->eof, XIO_RDSTREAM(sock1)->ignoreeof,
|
||||
closing);*/
|
||||
if (bytes1 == 0 || XIO_RDSTREAM(sock1)->eof >= 2) {
|
||||
if (XIO_RDSTREAM(sock1)->ignoreeof && !closing) {
|
||||
if (XIO_RDSTREAM(sock1)->ignoreeof &&
|
||||
!XIO_RDSTREAM(sock1)->actescape && !closing) {
|
||||
Debug1("socket 1 (fd %d) is at EOF, ignoring",
|
||||
XIO_RDSTREAM(sock1)->fd); /*! */
|
||||
mayrd1 = true;
|
||||
|
@ -996,16 +1005,20 @@ int _socat(void) {
|
|||
} else {
|
||||
Notice1("socket 1 (fd %d) is at EOF", XIO_GETRDFD(sock1));
|
||||
xioshutdown(sock2, SHUT_WR);
|
||||
XIO_RDSTREAM(sock1)->eof = 2;
|
||||
XIO_RDSTREAM(sock1)->ignoreeof = false;
|
||||
if (socat_opts.lefttoright) {
|
||||
break;
|
||||
}
|
||||
closing = 1;
|
||||
}
|
||||
} else if (polling && XIO_RDSTREAM(sock1)->ignoreeof) {
|
||||
polling = 0;
|
||||
}
|
||||
|
||||
if (bytes2 == 0 || XIO_RDSTREAM(sock2)->eof >= 2) {
|
||||
if (XIO_RDSTREAM(sock2)->ignoreeof && !closing) {
|
||||
if (XIO_RDSTREAM(sock2)->ignoreeof &&
|
||||
!XIO_RDSTREAM(sock2)->actescape && !closing) {
|
||||
Debug1("socket 2 (fd %d) is at EOF, ignoring",
|
||||
XIO_RDSTREAM(sock2)->fd);
|
||||
mayrd2 = true;
|
||||
|
@ -1013,9 +1026,12 @@ int _socat(void) {
|
|||
} else {
|
||||
Notice1("socket 2 (fd %d) is at EOF", XIO_GETRDFD(sock2));
|
||||
xioshutdown(sock1, SHUT_WR);
|
||||
XIO_RDSTREAM(sock2)->eof = 2;
|
||||
XIO_RDSTREAM(sock2)->ignoreeof = false;
|
||||
if (socat_opts.righttoleft) {
|
||||
break;
|
||||
}
|
||||
closing = 1;
|
||||
}
|
||||
} else if (polling && XIO_RDSTREAM(sock2)->ignoreeof) {
|
||||
polling = 0;
|
||||
|
@ -1102,8 +1118,9 @@ static int
|
|||
|
||||
/* inpipe is suspected to have read data available; read at most bufsiz bytes
|
||||
and transfer them to outpipe. Perform required data conversions.
|
||||
buff should be at least twice as large as bufsiz, to allow all standard
|
||||
conversions. Returns the number of bytes written, or 0 on EOF or <0 if an
|
||||
buff must be a malloc()'ed storage and might be realloc()'ed in this
|
||||
function if more space is required after conversions.
|
||||
Returns the number of bytes written, or 0 on EOF or <0 if an
|
||||
error occurred or when data was read but none written due to conversions
|
||||
(with EAGAIN). EAGAIN also occurs when reading from a nonblocking FD where
|
||||
the file has a mandatory lock.
|
||||
|
@ -1113,9 +1130,9 @@ static int
|
|||
/* inpipe, outpipe must be single descriptors (not dual!) */
|
||||
int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe,
|
||||
unsigned char **buff, size_t bufsiz, bool righttoleft) {
|
||||
ssize_t bytes, writt;
|
||||
ssize_t bytes, writt = 0;
|
||||
|
||||
bytes = xioread(inpipe, *buff, socat_opts.bufsiz);
|
||||
bytes = xioread(inpipe, *buff, bufsiz);
|
||||
if (bytes < 0) {
|
||||
if (errno != EAGAIN)
|
||||
XIO_RDSTREAM(inpipe)->eof = 2;
|
||||
|
@ -1123,14 +1140,35 @@ int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe,
|
|||
return -1;
|
||||
}
|
||||
if (bytes == 0 && XIO_RDSTREAM(inpipe)->ignoreeof && !closing) {
|
||||
writt = 0;
|
||||
;
|
||||
} else if (bytes == 0) {
|
||||
XIO_RDSTREAM(inpipe)->eof = 2;
|
||||
closing = MAX(closing, 1);
|
||||
writt = 0;
|
||||
}
|
||||
|
||||
else /* if (bytes > 0)*/ {
|
||||
if (bytes > 0) {
|
||||
/* handle escape char */
|
||||
if (XIO_RDSTREAM(inpipe)->escape != -1) {
|
||||
/* check input data for escape char */
|
||||
unsigned char *ptr = *buff;
|
||||
size_t ctr = 0;
|
||||
while (ctr < bytes) {
|
||||
if (*ptr == XIO_RDSTREAM(inpipe)->escape) {
|
||||
/* found: set flag, truncate input data */
|
||||
XIO_RDSTREAM(inpipe)->actescape = true;
|
||||
bytes = ctr;
|
||||
Info("escape char found in input");
|
||||
break;
|
||||
}
|
||||
++ptr; ++ctr;
|
||||
}
|
||||
if (ctr != bytes) {
|
||||
XIO_RDSTREAM(inpipe)->eof = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bytes > 0) {
|
||||
|
||||
if (XIO_RDSTREAM(inpipe)->lineterm !=
|
||||
XIO_WRSTREAM(outpipe)->lineterm) {
|
||||
|
@ -1248,8 +1286,14 @@ int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe,
|
|||
#define LF '\n'
|
||||
|
||||
|
||||
int cv_newline(unsigned char **buff, ssize_t *bytes,
|
||||
/* converts the newline characters (or character sequences) from the one
|
||||
specified in lineterm1 to that of lineterm2. Possible values are
|
||||
LINETERM_CR, LINETERM_CRNL, LINETERM_RAW.
|
||||
buff points to the malloc()'ed data, input and output. It may be subject to
|
||||
realloc(). bytes specifies the number of bytes input and output */
|
||||
int cv_newline(unsigned char **buff, ssize_t *bufsiz,
|
||||
int lineterm1, int lineterm2) {
|
||||
ssize_t *bytes = bufsiz;
|
||||
/* must perform newline changes */
|
||||
if (lineterm1 <= LINETERM_CR && lineterm2 <= LINETERM_CR) {
|
||||
/* no change in data length */
|
||||
|
@ -1287,7 +1331,7 @@ int cv_newline(unsigned char **buff, ssize_t *bytes,
|
|||
*t++ = *s++;
|
||||
}
|
||||
}
|
||||
*bytes = t - *buff;
|
||||
*bufsiz = t - *buff;
|
||||
} else {
|
||||
/* buffer becomes longer, must alloc another space */
|
||||
unsigned char *buf2;
|
||||
|
@ -1297,7 +1341,7 @@ int cv_newline(unsigned char **buff, ssize_t *bytes,
|
|||
} else {
|
||||
from = '\r';
|
||||
}
|
||||
if ((buf2 = Malloc(2*socat_opts.bufsiz+1)) == NULL) {
|
||||
if ((buf2 = Malloc(2*socat_opts.bufsiz/*sic!*/+1)) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
s = *buff; t = buf2; z = *buff + *bytes;
|
||||
|
@ -1312,7 +1356,7 @@ int cv_newline(unsigned char **buff, ssize_t *bytes,
|
|||
}
|
||||
free(*buff);
|
||||
*buff = buf2;
|
||||
*bytes = t - buf2;;
|
||||
*bufsiz = t - buf2;;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
63
test.sh
63
test.sh
|
@ -8447,6 +8447,69 @@ esac
|
|||
N=$((N+1))
|
||||
|
||||
|
||||
# test the escape option
|
||||
NAME=ESCAPE
|
||||
case "$TESTS" in
|
||||
*%functions%*|*%escape%*|*%$NAME%*)
|
||||
TEST="$NAME: escape character triggers EOF"
|
||||
# idea: start socat just echoing input, but apply escape option. send a string
|
||||
# containing the escape character and check if the output is truncated
|
||||
tf="$td/test$N.stdout"
|
||||
te="$td/test$N.stderr"
|
||||
tdiff="$td/test$N.diff"
|
||||
da="test$N $(date) $RANDOM"
|
||||
CMD="$SOCAT $opts -,escape=27 pipe"
|
||||
printf "test $F_n $TEST... " $N
|
||||
$ECHO "$da\n\x1bXYZ" |$CMD >"$tf" 2>"$te"
|
||||
if [ $? -ne 0 ]; then
|
||||
$PRINTF "$FAILED: $SOCAT:\n"
|
||||
echo "$CMD"
|
||||
cat "$te"
|
||||
numFAIL=$((numFAIL+1))
|
||||
elif ! echo "$da" |diff - "$tf" >"$tdiff"; then
|
||||
$PRINTF "$FAILED: diff:\n"
|
||||
cat "$tdiff"
|
||||
numFAIL=$((numFAIL+1))
|
||||
else
|
||||
$PRINTF "$OK\n"
|
||||
if [ -n "$debug" ]; then cat $te; fi
|
||||
numOK=$((numOK+1))
|
||||
fi
|
||||
esac
|
||||
N=$((N+1))
|
||||
|
||||
# test the escape option combined with ignoreeof
|
||||
NAME=ESCAPE_IGNOREEOF
|
||||
case "$TESTS" in
|
||||
*%functions%*|*%ignoreeof%*|*%escape%*|*%$NAME%*)
|
||||
TEST="$NAME: escape character triggers EOF"
|
||||
# idea: start socat just echoing input, but apply escape option. send a string
|
||||
# containing the escape character and check if the output is truncated
|
||||
ti="$td/test$N.file"
|
||||
tf="$td/test$N.stdout"
|
||||
te="$td/test$N.stderr"
|
||||
tdiff="$td/test$N.diff"
|
||||
da="test$N $(date) $RANDOM"
|
||||
CMD="$SOCAT -T 5 $opts file:$ti,ignoreeof,escape=27!!- pipe"
|
||||
printf "test $F_n $TEST... " $N
|
||||
>"$ti"
|
||||
$CMD >"$tf" 2>"$te" &
|
||||
$ECHO "$da\n\x1bXYZ" >>"$ti"
|
||||
sleep 1
|
||||
if ! echo "$da" |diff - "$tf" >"$tdiff"; then
|
||||
$PRINTF "$FAILED: diff:\n"
|
||||
cat "$tdiff"
|
||||
cat "$te"
|
||||
numFAIL=$((numFAIL+1))
|
||||
else
|
||||
$PRINTF "$OK\n"
|
||||
if [ -n "$debug" ]; then cat $te; fi
|
||||
numOK=$((numOK+1))
|
||||
fi
|
||||
esac
|
||||
N=$((N+1))
|
||||
|
||||
|
||||
echo "summary: $((N-1)) tests; $numOK ok, $numFAIL failed, $numCANT could not be performed"
|
||||
|
||||
if [ "$numFAIL" -gt 0 ]; then
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* source: xio-tun.c */
|
||||
/* Copyright Gerhard Rieger 2007 */
|
||||
/* Copyright Gerhard Rieger 2007-2008 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
/* this file contains the source for opening addresses of tun/tap type */
|
||||
|
@ -17,8 +17,6 @@
|
|||
|
||||
static int xioopen_tun(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3);
|
||||
|
||||
#define XIO_OFFSETOF(x) ((size_t)&((xiosingle_t *)0)->x)
|
||||
|
||||
/****** TUN addresses ******/
|
||||
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 };
|
||||
|
|
2
xio.h
2
xio.h
|
@ -167,6 +167,8 @@ typedef struct single {
|
|||
const char *name; /* only with END_UNLINK */
|
||||
int (*sigchild)(struct single *); /* callback after sigchild */
|
||||
pid_t ppid; /* parent pid, only if we send it signals */
|
||||
int escape; /* escape character; -1 for no escape */
|
||||
bool actescape; /* escape character found in input data */
|
||||
union {
|
||||
struct {
|
||||
int fdout; /* use fd for output */
|
||||
|
|
|
@ -16,6 +16,7 @@ const struct optdesc opt_crnl = { "crnl", NULL, OPT_CRNL, GROUP_A
|
|||
const struct optdesc opt_readbytes = { "readbytes", "bytes", OPT_READBYTES, GROUP_APPL, PH_LATE, TYPE_SIZE_T, OFUNC_EXT, (int)(&((struct single *)0)->readbytes), sizeof(((struct single *)0)->readbytes) };
|
||||
const struct optdesc opt_lockfile = { "lockfile", NULL, OPT_LOCKFILE, GROUP_APPL, PH_INIT, TYPE_FILENAME, OFUNC_EXT, 0, 0 };
|
||||
const struct optdesc opt_waitlock = { "waitlock", NULL, OPT_WAITLOCK, GROUP_APPL, PH_INIT, TYPE_FILENAME, OFUNC_EXT, 0, 0 };
|
||||
const struct optdesc opt_escape = { "escape", NULL, OPT_ESCAPE, GROUP_APPL, PH_INIT, TYPE_INT, OFUNC_OFFSET, XIO_OFFSETOF(escape), sizeof(((xiosingle_t *)0)->escape) };
|
||||
/****** APPL addresses ******/
|
||||
#if WITH_RETRY
|
||||
const struct optdesc opt_forever = { "forever", NULL, OPT_FOREVER, GROUP_RETRY, PH_INIT, TYPE_BOOL, OFUNC_EXT, (int)(&((struct single *)0)->forever), sizeof(((struct single *)0)->forever) };
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* source: xiolayer.h */
|
||||
/* Copyright Gerhard Rieger 2001-2005 */
|
||||
/* Copyright Gerhard Rieger 2001-2008 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
#ifndef __xiolayer_h_included
|
||||
|
@ -11,6 +11,7 @@ extern const struct optdesc opt_crnl;
|
|||
extern const struct optdesc opt_readbytes;
|
||||
extern const struct optdesc opt_lockfile;
|
||||
extern const struct optdesc opt_waitlock;
|
||||
extern const struct optdesc opt_escape;
|
||||
extern const struct optdesc opt_forever;
|
||||
extern const struct optdesc opt_intervall;
|
||||
extern const struct optdesc opt_retry;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* source: xioopen.c */
|
||||
/* Copyright Gerhard Rieger 2001-2007 */
|
||||
/* Copyright Gerhard Rieger 2001-2008 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
/* this is the source file of the extended open function */
|
||||
|
@ -301,6 +301,7 @@ static xiofile_t *xioallocfd(void) {
|
|||
#endif /* WITH_SOCKET */
|
||||
fd->stream.howtoend = END_UNSPEC;
|
||||
/* fd->stream.name = NULL; */
|
||||
fd->stream.escape = -1;
|
||||
/* fd->stream.para.exec.pid = 0; */
|
||||
fd->stream.lineterm = LINETERM_RAW;
|
||||
|
||||
|
|
|
@ -397,6 +397,7 @@ const struct optname optionnames[] = {
|
|||
IF_TERMIOS("eol2", &opt_veol2)
|
||||
IF_TERMIOS("erase", &opt_verase)
|
||||
IF_SOCKET ("error", &opt_so_error)
|
||||
IF_ANY ("escape", &opt_escape)
|
||||
IF_OPEN ("excl", &opt_o_excl)
|
||||
#if WITH_EXT2 && defined(EXT2_APPEND_FL)
|
||||
IF_ANY ("ext2-append", &opt_ext2_append)
|
||||
|
@ -3339,6 +3340,8 @@ static int applyopt_offset(struct single *xfd, struct opt *opt) {
|
|||
switch (opt->desc->type) {
|
||||
case TYPE_BOOL:
|
||||
*(bool *)ptr = opt->value.u_bool; break;
|
||||
case TYPE_INT:
|
||||
*(int *)ptr = opt->value.u_int; break;
|
||||
case TYPE_DOUBLE:
|
||||
*(double *)ptr = opt->value.u_double; break;
|
||||
case TYPE_TIMEVAL:
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#define ODESC_DONE ((void *)-1) /* indicates that option has been applied */
|
||||
#define ODESC_ERROR ODESC_DONE /* maybe later */
|
||||
|
||||
#define XIO_OFFSETOF(x) ((size_t)&((xiosingle_t *)0)->x)
|
||||
|
||||
/* atomic structure for use in the option search table; keep compatible with
|
||||
struct wordent! */
|
||||
struct optname {
|
||||
|
@ -250,6 +252,7 @@ enum e_optcode {
|
|||
OPT_ECHOPRT, /* termios.c_lflag */
|
||||
#endif
|
||||
OPT_END_CLOSE, /* xfd.stream.howtoend = END_CLOSE */
|
||||
OPT_ESCAPE,
|
||||
OPT_EXT2_SECRM,
|
||||
OPT_EXT2_UNRM,
|
||||
OPT_EXT2_COMPR,
|
||||
|
|
Loading…
Reference in a new issue