mirror of
https://repo.or.cz/socat.git
synced 2024-12-22 23:42:34 +00:00
Socat option -r,-R path specifications allow use of variables
This commit is contained in:
parent
9faf068949
commit
2af6089436
9 changed files with 378 additions and 65 deletions
4
CHANGES
4
CHANGES
|
@ -37,6 +37,10 @@ Features:
|
||||||
Test: RCVTIMEO_DTLS
|
Test: RCVTIMEO_DTLS
|
||||||
Feature proposed by Vladimir Nikishkin.
|
Feature proposed by Vladimir Nikishkin.
|
||||||
|
|
||||||
|
The file names with -r and -R now may contain environment variable
|
||||||
|
references.
|
||||||
|
Test: VARS_IN_SNIFFPATH
|
||||||
|
|
||||||
Corrections:
|
Corrections:
|
||||||
When a sub process (EXEC, SYSTEM) terminated with exit code other than
|
When a sub process (EXEC, SYSTEM) terminated with exit code other than
|
||||||
0, its last sent data might have been lost depending on timing of read/
|
0, its last sent data might have been lost depending on timing of read/
|
||||||
|
|
10
doc/socat.yo
10
doc/socat.yo
|
@ -161,12 +161,16 @@ dit(bf(tt(-x)))
|
||||||
Writes the transferred data not only to their target streams, but also to
|
Writes the transferred data not only to their target streams, but also to
|
||||||
stderr. The output format is hexadecimal, prefixed with "> " or "< "
|
stderr. The output format is hexadecimal, prefixed with "> " or "< "
|
||||||
indicating flow directions. Can be combined with code(-v).
|
indicating flow directions. Can be combined with code(-v).
|
||||||
dit(bf(tt(-r <file>)))
|
label(option_r)dit(bf(tt(-r <file>)))
|
||||||
Dumps the raw (binary) data flowing from left to right address to the given
|
Dumps the raw (binary) data flowing from left to right address to the given
|
||||||
file.
|
file. The file name may contain references to environment variables and
|
||||||
|
code($$) (pid), code($PROGNAME) (see option link(option -lp)(option_lp)),
|
||||||
|
code($TIMESTAMP) (uses format %Y%m%dT%H%M%S), and code(MICROS) (microseconds
|
||||||
|
of daytime). These references have to be protected from shell expansion of
|
||||||
|
course.
|
||||||
dit(bf(tt(-R <file>)))
|
dit(bf(tt(-R <file>)))
|
||||||
Dumps the raw (binary) data flowing from right to left address to the given
|
Dumps the raw (binary) data flowing from right to left address to the given
|
||||||
file.
|
file. See link(option -r)(option_r) for customization of file name.
|
||||||
label(option_b)dit(bf(tt(-b))tt(<size>))
|
label(option_b)dit(bf(tt(-b))tt(<size>))
|
||||||
Sets the data transfer block <size> [link(size_t)(TYPE_SIZE_T)].
|
Sets the data transfer block <size> [link(size_t)(TYPE_SIZE_T)].
|
||||||
At most <size> bytes are transferred per step. Default is 8192 bytes.
|
At most <size> bytes are transferred per step. Default is 8192 bytes.
|
||||||
|
|
94
socat.c
94
socat.c
|
@ -36,8 +36,6 @@ struct {
|
||||||
char logopt; /* y..syslog; s..stderr; f..file; m..mixed */
|
char logopt; /* y..syslog; s..stderr; f..file; m..mixed */
|
||||||
bool lefttoright; /* first addr ro, second addr wo */
|
bool lefttoright; /* first addr ro, second addr wo */
|
||||||
bool righttoleft; /* first addr wo, second addr ro */
|
bool righttoleft; /* first addr wo, second addr ro */
|
||||||
int sniffleft; /* -1 or an FD for teeing data arriving on xfd1 */
|
|
||||||
int sniffright; /* -1 or an FD for teeing data arriving on xfd2 */
|
|
||||||
xiolock_t lock; /* a lock file */
|
xiolock_t lock; /* a lock file */
|
||||||
unsigned long log_sigs; /* signals to be caught just for logging */
|
unsigned long log_sigs; /* signals to be caught just for logging */
|
||||||
} socat_opts = {
|
} socat_opts = {
|
||||||
|
@ -52,8 +50,6 @@ struct {
|
||||||
's', /* logopt */
|
's', /* logopt */
|
||||||
false, /* lefttoright */
|
false, /* lefttoright */
|
||||||
false, /* righttoleft */
|
false, /* righttoleft */
|
||||||
-1, /* sniffleft */
|
|
||||||
-1, /* sniffright */
|
|
||||||
{ NULL, 0 }, /* lock */
|
{ NULL, 0 }, /* lock */
|
||||||
1<<SIGHUP | 1<<SIGINT | 1<<SIGQUIT | 1<<SIGILL | 1<<SIGABRT | 1<<SIGBUS | 1<<SIGFPE | 1<<SIGSEGV | 1<<SIGTERM, /* log_sigs */
|
1<<SIGHUP | 1<<SIGINT | 1<<SIGQUIT | 1<<SIGILL | 1<<SIGABRT | 1<<SIGBUS | 1<<SIGFPE | 1<<SIGSEGV | 1<<SIGTERM, /* log_sigs */
|
||||||
};
|
};
|
||||||
|
@ -61,7 +57,6 @@ struct {
|
||||||
void socat_usage(FILE *fd);
|
void socat_usage(FILE *fd);
|
||||||
void socat_opt_hint(FILE *fd, char a, char b);
|
void socat_opt_hint(FILE *fd, char a, char b);
|
||||||
void socat_version(FILE *fd);
|
void socat_version(FILE *fd);
|
||||||
static int xio_openauxwr(const char *path, const char *hint);
|
|
||||||
int socat(const char *address1, const char *address2);
|
int socat(const char *address1, const char *address2);
|
||||||
int _socat(void);
|
int _socat(void);
|
||||||
int cv_newline(unsigned char *buff, ssize_t *bytes, int lineterm1, int lineterm2);
|
int cv_newline(unsigned char *buff, ssize_t *bytes, int lineterm1, int lineterm2);
|
||||||
|
@ -213,9 +208,7 @@ int main(int argc, const char *argv[]) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((socat_opts.sniffleft = xio_openauxwr(a, "option -r")) < 0) {
|
xiosetopt('r', a);
|
||||||
Error2("option -r: failed to open \"%s\": %s", a, strerror(errno));
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case 'R': if (arg1[0][2]) {
|
case 'R': if (arg1[0][2]) {
|
||||||
a = *arg1+2;
|
a = *arg1+2;
|
||||||
|
@ -226,9 +219,7 @@ int main(int argc, const char *argv[]) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((socat_opts.sniffright = xio_openauxwr(a, "option -R")) < 0) {
|
xiosetopt('R', a);
|
||||||
Error2("option -R: failed to open \"%s\": %s", a, strerror(errno));
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case 'b': if (arg1[0][2]) {
|
case 'b': if (arg1[0][2]) {
|
||||||
a = *arg1+2;
|
a = *arg1+2;
|
||||||
|
@ -655,50 +646,11 @@ void socat_version(FILE *fd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Opens a path for logging or tracing.
|
|
||||||
Return the filedescriptor, or -1 when an error occurred (errn0).
|
|
||||||
Prints messages but no Error().
|
|
||||||
*/
|
|
||||||
static int xio_openauxwr(const char *path, const char *hint)
|
|
||||||
{
|
|
||||||
int fd;
|
|
||||||
int _errno;
|
|
||||||
|
|
||||||
if ((fd = Open(path, O_CREAT|O_WRONLY|O_APPEND|
|
|
||||||
#ifdef O_LARGEFILE
|
|
||||||
O_LARGEFILE|
|
|
||||||
#endif
|
|
||||||
#ifdef O_CLOEXEC
|
|
||||||
O_CLOEXEC|
|
|
||||||
#endif
|
|
||||||
O_NONBLOCK, 0664)) < 0) {
|
|
||||||
if (errno != ENXIO)
|
|
||||||
return -1;
|
|
||||||
/* Possibly a named pipe that does not yet have a reader */
|
|
||||||
_errno = errno;
|
|
||||||
Notice3("%s \"%s\": %s, retrying r/w", hint, path, strerror(errno));
|
|
||||||
if ((fd = Open(path, O_CREAT|O_RDWR|O_APPEND|
|
|
||||||
#ifdef O_LARGEFILE
|
|
||||||
O_LARGEFILE|
|
|
||||||
#endif
|
|
||||||
#ifdef O_CLOEXEC
|
|
||||||
O_CLOEXEC|
|
|
||||||
#endif
|
|
||||||
O_NONBLOCK, 0664)) < 0) {
|
|
||||||
errno = _errno;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#ifndef O_CLOEXEC
|
|
||||||
Fcntl_l(fd, F_SETFD, FD_CLOEXEC);
|
|
||||||
#endif
|
|
||||||
return fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
xiofile_t *sock1, *sock2;
|
xiofile_t *sock1, *sock2;
|
||||||
int closing = 0; /* 0..no eof yet, 1..first eof just occurred,
|
int closing = 0; /* 0..no eof yet, 1..first eof just occurred,
|
||||||
2..counting down closing timeout */
|
2..counting down closing timeout */
|
||||||
|
int sniffleft = -1; /* -1 or an FD for teeing data arriving on xfd1 */
|
||||||
|
int sniffright = -1; /* -1 or an FD for teeing data arriving on xfd2 */
|
||||||
|
|
||||||
/* call this function when the common command line options are parsed, and the
|
/* call this function when the common command line options are parsed, and the
|
||||||
addresses are extracted (but not resolved). */
|
addresses are extracted (but not resolved). */
|
||||||
|
@ -861,6 +813,28 @@ int _socat(void) {
|
||||||
int wasaction = 1; /* last poll was active, do NOT sleep before next */
|
int wasaction = 1; /* last poll was active, do NOT sleep before next */
|
||||||
struct timeval total_timeout; /* the actual total timeout timer */
|
struct timeval total_timeout; /* the actual total timeout timer */
|
||||||
|
|
||||||
|
{
|
||||||
|
/* Open sniff file(s) */
|
||||||
|
char name[PATH_MAX];
|
||||||
|
struct timeval tv = { 0 }; /* 'cache' to have same time in both */
|
||||||
|
|
||||||
|
if (xioinqopt('r', name, sizeof(name)) == 0) {
|
||||||
|
if (sniffleft >= 0) Close(sniffleft);
|
||||||
|
sniffleft = xio_opensnifffile(name, &tv);
|
||||||
|
if (sniffleft < 0) {
|
||||||
|
Error2("option -r \"%s\": %s", name, strerror(errno));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xioinqopt('R', name, sizeof(name)) == 0) {
|
||||||
|
if (sniffright >= 0) Close(sniffright);
|
||||||
|
sniffright = xio_opensnifffile(name, &tv);
|
||||||
|
if (sniffright < 0) {
|
||||||
|
Error2("option -R \"%s\": %s", name, strerror(errno));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if WITH_FILAN
|
#if WITH_FILAN
|
||||||
if (socat_opts.debug) {
|
if (socat_opts.debug) {
|
||||||
int fdi, fdo;
|
int fdi, fdo;
|
||||||
|
@ -1398,23 +1372,23 @@ int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe,
|
||||||
errno = EAGAIN; return -1;
|
errno = EAGAIN; return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!righttoleft && socat_opts.sniffleft >= 0) {
|
if (!righttoleft && sniffleft >= 0) {
|
||||||
if ((sniffed = Write(socat_opts.sniffleft, buff, bytes)) < bytes) {
|
if ((sniffed = Write(sniffleft, buff, bytes)) < bytes) {
|
||||||
if (sniffed < 0)
|
if (sniffed < 0)
|
||||||
Warn3("-r: write(%d, buff, "F_Zu"): %s",
|
Warn3("-r: write(%d, buff, "F_Zu"): %s",
|
||||||
socat_opts.sniffleft, bytes, strerror(errno));
|
sniffleft, bytes, strerror(errno));
|
||||||
else if (sniffed < bytes)
|
else if (sniffed < bytes)
|
||||||
Warn3("-r: write(%d, buff, "F_Zu") -> "F_Zd,
|
Warn3("-r: write(%d, buff, "F_Zu") -> "F_Zd,
|
||||||
socat_opts.sniffleft, bytes, sniffed);
|
sniffleft, bytes, sniffed);
|
||||||
}
|
}
|
||||||
} else if (righttoleft && socat_opts.sniffright >= 0) {
|
} else if (righttoleft && sniffright >= 0) {
|
||||||
if ((sniffed = Write(socat_opts.sniffright, buff, bytes)) < bytes) {
|
if ((sniffed = Write(sniffright, buff, bytes)) < bytes) {
|
||||||
if (sniffed < 0)
|
if (sniffed < 0)
|
||||||
Warn3("-R: write(%d, buff, "F_Zu"): %s",
|
Warn3("-R: write(%d, buff, "F_Zu"): %s",
|
||||||
socat_opts.sniffright, bytes, strerror(errno));
|
sniffright, bytes, strerror(errno));
|
||||||
else if (sniffed < bytes)
|
else if (sniffed < bytes)
|
||||||
Warn3("-R: write(%d, buff, "F_Zu") -> "F_Zd,
|
Warn3("-R: write(%d, buff, "F_Zu") -> "F_Zd,
|
||||||
socat_opts.sniffright, bytes, sniffed);
|
sniffright, bytes, sniffed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
205
sysutils.c
205
sysutils.c
|
@ -941,3 +941,208 @@ double Strtod(const char *nptr, char **endptr, const char *txt) {
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* This function gets a string with possible references to environment
|
||||||
|
variables and expands them. Variables must be prefixed with '$' and their
|
||||||
|
names consist only of A-Z, a-z, 0-9, and '_'.
|
||||||
|
The name may be enclosed with { }.
|
||||||
|
To pass a literal "$" us "\$".
|
||||||
|
There are special variables supported whose values do not comr from
|
||||||
|
environment:
|
||||||
|
$$ expands to the process's pid
|
||||||
|
$PROGNAME expands to the executables basename or the value of option -lp
|
||||||
|
$TIMESTAMP expands to the actual time in format %Y%m%dT%H%M%S
|
||||||
|
$MICROS expands to the actual microseconds (decimal)
|
||||||
|
The dst output is a copy of src but with the variables expanded.
|
||||||
|
Returns 0 on success;
|
||||||
|
returns -1 when the output buffer was too short (overflow);
|
||||||
|
returns 1 on syntax error.
|
||||||
|
*/
|
||||||
|
int expandenv(
|
||||||
|
char *dst, /* prealloc'd output buff, will be \0 termd */
|
||||||
|
const char *src, /* input string to generate expansion from */
|
||||||
|
size_t n, /* length of dst */
|
||||||
|
struct timeval *tv) /* in/out timestamp for sync */
|
||||||
|
{
|
||||||
|
char c; /* char currently being lex'd/parsed */
|
||||||
|
bool esc = false; /* just got '\' */
|
||||||
|
bool bra = false; /* within ${ } */
|
||||||
|
char *nam = NULL; /* points to temp.allocated rw copy of src */
|
||||||
|
const char *e; /* pointer to isolated var name in tmp[] */
|
||||||
|
size_t s=0, d=0; /* counters in src, dst */
|
||||||
|
size_t v; /* variable name begin */
|
||||||
|
bool ofl = false; /* dst overflow, output truncated */
|
||||||
|
char tmp[18]; /* buffer for timestamp, micros */
|
||||||
|
|
||||||
|
while (c = src[s++]) {
|
||||||
|
if (esc) {
|
||||||
|
if (c == '\0') {
|
||||||
|
if (d+2 > n) { ofl = true; break; }
|
||||||
|
dst[d++] = '\\';
|
||||||
|
dst[d++] = c;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (c != '$') {
|
||||||
|
if (d+3 > n) { ofl = true; break; }
|
||||||
|
dst[d++] = '\\';
|
||||||
|
} else {
|
||||||
|
if (d+2 > n) { ofl = true; break; }
|
||||||
|
}
|
||||||
|
dst[d++] = c;
|
||||||
|
esc = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (c == '\0') {
|
||||||
|
dst[d++] = c;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (c == '\\') {
|
||||||
|
esc = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (c != '$') {
|
||||||
|
if (d+2 > n) { ofl = true; break; }
|
||||||
|
dst[d++] = c;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* c == '$': Expecting env var to expand */
|
||||||
|
c = src[s];
|
||||||
|
if (c == '\0') {
|
||||||
|
if (d+2 > n) { ofl = true; break; }
|
||||||
|
++s;
|
||||||
|
dst[d++] = '$';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (c == '$') {
|
||||||
|
int wr;
|
||||||
|
/* Special case: pid */
|
||||||
|
++s;
|
||||||
|
wr = snprintf(&dst[d], n-d, F_pid, getpid());
|
||||||
|
if (wr >= n-d || wr < 0) { ofl = true; break; }
|
||||||
|
d += wr;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (c == '{') {
|
||||||
|
++s;
|
||||||
|
bra = true;
|
||||||
|
}
|
||||||
|
if (!isalpha(c) && c != '_') {
|
||||||
|
/* Special case no var name, just keep '$' */
|
||||||
|
if (d+3 > n) { ofl = true; break; }
|
||||||
|
++s;
|
||||||
|
dst[d++] = '$';
|
||||||
|
dst[d++] = c;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
v = 0; /* seems we found valid variable name */
|
||||||
|
if (nam == NULL) {
|
||||||
|
nam = strdup(src+s);
|
||||||
|
if (nam == NULL) {
|
||||||
|
errno = ENOMEM;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (c = src[s]) {
|
||||||
|
if (!isalnum(c) && c != '_') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
nam[v++] = c;
|
||||||
|
++s;
|
||||||
|
}
|
||||||
|
if (bra && c != '}') {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
nam[v] = '\0';
|
||||||
|
/* Var name is complete */
|
||||||
|
/* Check hardcoded var names */
|
||||||
|
if (strcmp(nam, "PROGNAME") == 0) {
|
||||||
|
e = diag_get_string('p');
|
||||||
|
} else if (strcmp(nam, "TIMESTAMP") == 0) {
|
||||||
|
if (tv->tv_sec == 0) {
|
||||||
|
gettimeofday(tv, NULL);
|
||||||
|
}
|
||||||
|
struct tm tm;
|
||||||
|
localtime_r(&tv->tv_sec, &tm);
|
||||||
|
strftime(tmp, sizeof(tmp), "%Y%m%dT%H%M%S", &tm);
|
||||||
|
e = tmp;
|
||||||
|
} else if (strcmp(nam, "MICROS") == 0) {
|
||||||
|
if (tv->tv_sec == 0) {
|
||||||
|
gettimeofday(tv, NULL);
|
||||||
|
}
|
||||||
|
sprintf(tmp, F_tv_usec, tv->tv_usec);
|
||||||
|
e = tmp;
|
||||||
|
} else {
|
||||||
|
e = getenv(nam);
|
||||||
|
}
|
||||||
|
if (e == NULL) {
|
||||||
|
/* Var not found, skip it */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Var found, copy it to output buffer */
|
||||||
|
if (d+strlen(e)+1 > n) { ofl = true; break; }
|
||||||
|
strcpy(&dst[d], e);
|
||||||
|
d += strlen(&dst[d]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nam != NULL) {
|
||||||
|
free(nam);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ofl) {
|
||||||
|
dst[d] = '\0';
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
dst[d] = '\0';
|
||||||
|
if (src[s-1] != '\0') {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int xio_opensnifffile(
|
||||||
|
const char *a,
|
||||||
|
struct timeval *tv)
|
||||||
|
{
|
||||||
|
char path[PATH_MAX];
|
||||||
|
int flags;
|
||||||
|
int rc;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
rc = expandenv(path, a, sizeof(path), tv);
|
||||||
|
if (rc < 0) {
|
||||||
|
Error2("expandenv(source=\"%s\", n="F_Zu"): Out of memory", a, sizeof(path));
|
||||||
|
errno = ENOMEM;
|
||||||
|
return -1;
|
||||||
|
} else if (rc > 0) {
|
||||||
|
Error1("expandenv(source=\"%s\"): Syntax error", a);
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
flags = O_CREAT|O_WRONLY|O_APPEND|
|
||||||
|
#ifdef O_LARGEFILE
|
||||||
|
O_LARGEFILE|
|
||||||
|
#endif
|
||||||
|
#ifdef O_CLOEXEC
|
||||||
|
O_CLOEXEC|
|
||||||
|
#endif
|
||||||
|
O_NONBLOCK;
|
||||||
|
if ((fd = Open(path, flags, 0664)) < 0) {
|
||||||
|
if (errno == ENXIO) {
|
||||||
|
/* try to open pipe rdwr */
|
||||||
|
if ((fd = Open(path, flags, 0664)) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef O_CLOEXEC
|
||||||
|
if (Fcntl_l(fd, F_SETFD, FD_CLOEXEC) < 0) {
|
||||||
|
Warn2("fcntl(%d, F_SETFD, FD_CLOEXEC): %s", fd, strerror(errno));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
|
@ -113,5 +113,6 @@ extern int xiosetenvushort(const char *varname, unsigned short value,
|
||||||
extern unsigned long int Strtoul(const char *nptr, char **endptr, int base, const char *txt);
|
extern unsigned long int Strtoul(const char *nptr, char **endptr, int base, const char *txt);
|
||||||
extern long long int Strtoll(const char *nptr, char **endptr, int base, const char *txt);
|
extern long long int Strtoll(const char *nptr, char **endptr, int base, const char *txt);
|
||||||
extern double Strtod(const char *nptr, char **endptr, const char *txt);
|
extern double Strtod(const char *nptr, char **endptr, const char *txt);
|
||||||
|
extern int xio_opensnifffile(const char *a, struct timeval *tv);
|
||||||
|
|
||||||
#endif /* !defined(__sysutils_h_included) */
|
#endif /* !defined(__sysutils_h_included) */
|
||||||
|
|
98
test.sh
98
test.sh
|
@ -15224,6 +15224,7 @@ wait
|
||||||
fi ;; # NUMCOND, feats
|
fi ;; # NUMCOND, feats
|
||||||
esac
|
esac
|
||||||
PORT=$((PORT+1))
|
PORT=$((PORT+1))
|
||||||
|
N=$((N+1))
|
||||||
|
|
||||||
|
|
||||||
# Test the so-rcvtimeo address option with DTLS
|
# Test the so-rcvtimeo address option with DTLS
|
||||||
|
@ -15297,6 +15298,103 @@ esac
|
||||||
N=$((N+1))
|
N=$((N+1))
|
||||||
|
|
||||||
|
|
||||||
|
# Test the use of interesting variables in the sniffing file names
|
||||||
|
NAME=VARS_IN_SNIFFPATH
|
||||||
|
case "$TESTS" in
|
||||||
|
*%$N%*|*%functions%*|*%socket%*|*%$NAME%*)
|
||||||
|
TEST="$NAME: sniff file names with variables"
|
||||||
|
# Start a server process with option fork that sniffs traffic and stores it in
|
||||||
|
# two files for each child process, using PID, timestamp, microseconds, and
|
||||||
|
# client IP
|
||||||
|
# Connect two times.
|
||||||
|
# For now we say that the test succeeded when 4 log files have been generated.
|
||||||
|
if ! eval $NUMCOND; then :;
|
||||||
|
elif ! A=$(testfeats IP4 TCP LISTEN PIPE STDIO); then
|
||||||
|
$PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not available${NORMAL}\n" $N
|
||||||
|
numCANT=$((numCANT+1))
|
||||||
|
listCANT="$listCANT $N"
|
||||||
|
elif ! A=$(testaddrs - TCP4 TCP4-LISTEN PIPE STDIO); then
|
||||||
|
$PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available in $SOCAT${NORMAL}\n" $N
|
||||||
|
numCANT=$((numCANT+1))
|
||||||
|
listCANT="$listCANT $N"
|
||||||
|
elif ! o=$(testoptions so-reuseaddr fork) >/dev/null; then
|
||||||
|
$PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available in $SOCAT${NORMAL}\n" $N
|
||||||
|
numCANT=$((numCANT+1))
|
||||||
|
listCANT="$listCANT $N"
|
||||||
|
elif ! runsip4 >/dev/null; then
|
||||||
|
$PRINTF "test $F_n $TEST... ${YELLOW}IPv4 not available${NORMAL}\n" $N
|
||||||
|
numCANT=$((numCANT+1))
|
||||||
|
listCANT="$listCANT $N"
|
||||||
|
else
|
||||||
|
tf="$td/test$N.stdout"
|
||||||
|
te="$td/test$N.stderr"
|
||||||
|
tdiff="$td/test$N.diff"
|
||||||
|
da="test$N $(date) $RANDOM"
|
||||||
|
newport tcp4 # or whatever proto, or drop this line
|
||||||
|
CMD0="$TRACE $SOCAT $opts -lp server0 -r \"$td/test$N.\\\$PROGNAME-\\\$TIMESTAMP.\\\$MICROS-\\\$SERVER0_PEERADDR-\\\$\\\$.in.log\" -R \"$td/test$N.\\\$PROGNAME-\\\$TIMESTAMP.\\\$MICROS-\\\$SERVER0_PEERADDR-\\\$\\\$.out.log\" TCP4-LISTEN:$PORT,so-reuseaddr,fork PIPE"
|
||||||
|
CMD1="$TRACE $SOCAT $opts - TCP4-CONNECT:$LOCALHOST:$PORT"
|
||||||
|
printf "test $F_n $TEST... " $N
|
||||||
|
eval "$CMD0" >/dev/null 2>"${te}0" &
|
||||||
|
pid0=$!
|
||||||
|
waittcp4port $PORT 1
|
||||||
|
echo "$da" |$CMD1 >"${tf}1a" 2>"${te}1a"
|
||||||
|
rc1a=$?
|
||||||
|
echo "$da" |$CMD1 >"${tf}1b" 2>"${te}1b"
|
||||||
|
rc1b=$?
|
||||||
|
kill $(childpids $pid0) $pid0 2>/dev/null; wait
|
||||||
|
if [ $rc1a != 0 -o $rc1b != 0 ]; then
|
||||||
|
$PRINTF "$FAILED (client problem)\n"
|
||||||
|
echo "$CMD0 &"
|
||||||
|
cat "${te}0" >&2
|
||||||
|
echo "$CMD1"
|
||||||
|
cat "${te}1a" >&2
|
||||||
|
echo "$CMD1"
|
||||||
|
cat "${te}1b" >&2
|
||||||
|
numFAIL=$((numFAIL+1))
|
||||||
|
listFAIL="$listFAIL $N"
|
||||||
|
namesFAIL="$namesFAIL $NAME"
|
||||||
|
elif test $(ls -l $td/test$N.*.log |wc -l) -eq 4 &&
|
||||||
|
test $(ls $td/test$N.*.log |head -n 1 |wc -c) -ge 56; then
|
||||||
|
# Are the names correct?
|
||||||
|
# Convert timestamps to epoch and compare
|
||||||
|
# Are the contents correct?
|
||||||
|
$PRINTF "$OK\n"
|
||||||
|
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}1a" >&2; fi
|
||||||
|
if [ "$VERBOSE" ]; then echo "$CMD1"; fi
|
||||||
|
if [ "$DEBUG" ]; then cat "${te}1b" >&2; fi
|
||||||
|
numOK=$((numOK+1))
|
||||||
|
elif test -f $td/test$N.\$PROGNAME-\$TIMESTAMP.\$MICROS-\$SERVER0_PEERADDR-\$\$.in.log; then
|
||||||
|
$PRINTF "$FAILED (vars not resolved)\n"
|
||||||
|
echo "$CMD0 &"
|
||||||
|
cat "${te}0" >&2
|
||||||
|
echo "$CMD1"
|
||||||
|
cat "${te}1a" >&2
|
||||||
|
echo "$CMD1"
|
||||||
|
cat "${te}1b" >&2
|
||||||
|
numFAIL=$((numFAIL+1))
|
||||||
|
listFAIL="$listFAIL $N"
|
||||||
|
namesFAIL="$namesFAIL $NAME"
|
||||||
|
else
|
||||||
|
$PRINTF "$FAILED (unknown)\n"
|
||||||
|
echo "$CMD0 &"
|
||||||
|
cat "${te}0" >&2
|
||||||
|
echo "$CMD1"
|
||||||
|
cat "${te}1a" >&2
|
||||||
|
echo "$CMD1"
|
||||||
|
cat "${te}1b" >&2
|
||||||
|
numFAIL=$((numFAIL+1))
|
||||||
|
listFAIL="$listFAIL $N"
|
||||||
|
namesFAIL="$namesFAIL $NAME"
|
||||||
|
fi
|
||||||
|
fi # NUMCOND
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
N=$((N+1))
|
||||||
|
|
||||||
|
|
||||||
# end of common tests
|
# end of common tests
|
||||||
|
|
||||||
##################################################################################
|
##################################################################################
|
||||||
|
|
1
utils.c
1
utils.c
|
@ -89,7 +89,6 @@ int setenv(const char *name, const char *value, int overwrite) {
|
||||||
#endif /* !HAVE_SETENV */
|
#endif /* !HAVE_SETENV */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* sanitizes an "untrusted" character. output buffer must provide at least 4
|
/* sanitizes an "untrusted" character. output buffer must provide at least 4
|
||||||
characters space.
|
characters space.
|
||||||
Does not append \0. returns length of output (currently: max 4) */
|
Does not append \0. returns length of output (currently: max 4) */
|
||||||
|
|
4
xio.h
4
xio.h
|
@ -112,6 +112,8 @@ typedef struct {
|
||||||
char preferred_ip; /* preferred prot.fam. for name resolution ('0' for
|
char preferred_ip; /* preferred prot.fam. for name resolution ('0' for
|
||||||
unspecified, '4', or '6') */
|
unspecified, '4', or '6') */
|
||||||
bool experimental; /* enable some features */
|
bool experimental; /* enable some features */
|
||||||
|
const char *sniffleft_name; /* file name with -r */
|
||||||
|
const char *sniffright_name; /* file name with -R */
|
||||||
} xioparms_t;
|
} xioparms_t;
|
||||||
|
|
||||||
/* pack the description of a lock file */
|
/* pack the description of a lock file */
|
||||||
|
@ -440,6 +442,8 @@ extern int xioopenhelp(FILE *of, int level);
|
||||||
|
|
||||||
/* must be outside function for use by childdied handler */
|
/* must be outside function for use by childdied handler */
|
||||||
extern xiofile_t *sock1, *sock2;
|
extern xiofile_t *sock1, *sock2;
|
||||||
|
extern int sniffleft, sniffright;
|
||||||
|
|
||||||
#define NUMUNKNOWN 4
|
#define NUMUNKNOWN 4
|
||||||
extern pid_t diedunknown[NUMUNKNOWN]; /* child died before it is registered */
|
extern pid_t diedunknown[NUMUNKNOWN]; /* child died before it is registered */
|
||||||
#define diedunknown1 (diedunknown[0])
|
#define diedunknown1 (diedunknown[0])
|
||||||
|
|
26
xioparam.c
26
xioparam.c
|
@ -21,7 +21,9 @@ xioparms_t xioparms = {
|
||||||
NULL, /* syslogfac */
|
NULL, /* syslogfac */
|
||||||
'4', /* default_ip */
|
'4', /* default_ip */
|
||||||
'4', /* preferred_ip */
|
'4', /* preferred_ip */
|
||||||
false /* experimental */
|
false, /* experimental */
|
||||||
|
NULL, /* sniffleft_name */
|
||||||
|
NULL /* sniffright_name */
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
@ -43,6 +45,8 @@ int xiosetopt(char what, const char *arg) {
|
||||||
break;
|
break;
|
||||||
case 'l': xioparms.logopt = *arg; break;
|
case 'l': xioparms.logopt = *arg; break;
|
||||||
case 'y': xioparms.syslogfac = arg; break;
|
case 'y': xioparms.syslogfac = arg; break;
|
||||||
|
case 'r': xioparms.sniffleft_name = arg; break;
|
||||||
|
case 'R': xioparms.sniffright_name = arg; break;
|
||||||
default:
|
default:
|
||||||
Error2("xiosetopt('%c', \"%s\"): unknown option",
|
Error2("xiosetopt('%c', \"%s\"): unknown option",
|
||||||
what, arg?arg:"NULL");
|
what, arg?arg:"NULL");
|
||||||
|
@ -60,6 +64,26 @@ int xioinqopt(char what, char *arg, size_t n) {
|
||||||
return 0;
|
return 0;
|
||||||
case 'o': return xioparms.ip4portsep;
|
case 'o': return xioparms.ip4portsep;
|
||||||
case 'l': return xioparms.logopt;
|
case 'l': return xioparms.logopt;
|
||||||
|
case 'r':
|
||||||
|
if (xioparms.sniffleft_name == NULL) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (n < strlen(xioparms.sniffleft_name)+1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
arg[0] = '\0';
|
||||||
|
strncat(arg, xioparms.sniffleft_name, n-1);
|
||||||
|
return 0;
|
||||||
|
case 'R':
|
||||||
|
if (xioparms.sniffright_name == NULL) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (n < strlen(xioparms.sniffright_name)+1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
arg[0] = '\0';
|
||||||
|
strncat(arg, xioparms.sniffright_name, n-1);
|
||||||
|
return 0;
|
||||||
default:
|
default:
|
||||||
Error3("xioinqopt('%c', \"%s\", "F_Zu"): unknown option",
|
Error3("xioinqopt('%c', \"%s\", "F_Zu"): unknown option",
|
||||||
what, arg, n);
|
what, arg, n);
|
||||||
|
|
Loading…
Reference in a new issue