add NCAT_LOCAL_ADDR, NCAT_LOCAL_PORT, NCAT_REMOTE_ADDR, NCAR_REMOTE_PORT,

NCAT_REMOTE_ADDR environment variables set in all --*-exec child processes.
(this is a merge of ncat-env-conninfo as of r31516)
This commit is contained in:
d33tah 2013-07-24 13:58:15 +00:00
parent f5a142b0d4
commit 8f84863a23
12 changed files with 276 additions and 4 deletions

View file

@ -135,16 +135,16 @@ config.h:
$(SHELL) ./config.status; \
fi
test/addrset: test/addrset.o ncat_core.o sys_wrap.o util.o $(LUA_OBJS)
test/addrset: test/addrset.o ncat_core.o sys_wrap.o util.o ncat_posix.o $(LUA_OBJS)
$(CC) -o $@ $(CFLAGS) $(LDFLAGS) $^ $(LIBS) $(NSOCKLIB) $(NBASELIB) $(OPENSSL_LIBS) $(PCAP_LIBS) $(LUA_LIBS)
test/test-uri: test/test-uri.o base64.o http.o ncat_core.o sys_wrap.o util.o $(LUA_OBJS)
test/test-uri: test/test-uri.o base64.o http.o ncat_core.o sys_wrap.o util.o ncat_posix.o $(LUA_OBJS)
$(CC) -o $@ $(CFLAGS) $(LDFLAGS) $^ $(LIBS) $(NSOCKLIB) $(NBASELIB) $(OPENSSL_LIBS) $(PCAP_LIBS) $(LUA_LIBS)
test/test-cmdline-split: test/test-cmdline-split.o ncat_posix.o ncat_core.o sys_wrap.o util.o $(LUA_OBJS)
$(CC) -o $@ $(CFLAGS) $(LDFLAGS) $^ $(LIBS) $(NSOCKLIB) $(NBASELIB) $(OPENSSL_LIBS) $(PCAP_LIBS) $(LUA_LIBS)
test/test-wildcard: test/test-wildcard.o ncat_core.o ncat_ssl.o sys_wrap.o util.o $(LUA_OBJS)
test/test-wildcard: test/test-wildcard.o ncat_core.o ncat_ssl.o sys_wrap.o util.o ncat_posix.o $(LUA_OBJS)
$(CC) -o $@ $(CFLAGS) $(LDFLAGS) $^ $(LIBS) $(NSOCKLIB) $(NBASELIB) $(OPENSSL_LIBS) $(PCAP_LIBS) $(LUA_LIBS)
.PHONY: uninstall all clean distclean

View file

@ -462,6 +462,30 @@
accept a maximum, definable, number of simultaneous connections
controlled by the <option>-m</option> option. By default this is set
to 100 (60 on Windows).</para>
<para>--exec adds the following variables to the child's environment:
<itemizedlist>
<listitem>NCAT_REMOTE_ADDR - the remote address - in connect mode,
it's the one we're connecting to, in listen mode - it's the one
that connected to us,</listitem>
<listitem>NCAT_REMOTE_PORT - the remote port number, where "remote"
means the same as above,</listitem>
<listitem>NCAT_LOCAL_ADDR - our local address used for
establishing/receiving the connection,</listitem>
<listitem>NCAT_LOCAL_PORT - our local port number,</listitem>
<listitem>NCAT_PROTO - the protocol name - TCP, UDP or SCTP,</listitem>
</itemizedlist>
</para>
<para>Currently the address fields are numeric IP addresses. In IPv6
mode, the address might be not expanded.</para>
</listitem>
</varlistentry>
@ -476,7 +500,9 @@
<para>Same as <option>-e</option>, except it tries to execute
the command via <filename>/bin/sh</filename>. This means you don't
have to specify the full path for the command, and shell facilities
like environment variables are available.</para>
like environment variables are available. Ncat also sets a few
special environment variables (see <option>-e</option> for details).
</para>
</listitem>
</varlistentry>

View file

@ -511,3 +511,45 @@ static int ncat_hexdump(int logfd, const char *data, int len)
return 1;
}
void setup_environment(struct fdinfo *info)
{
union sockaddr_u su;
char ip[INET6_ADDRSTRLEN];
char port[16];
socklen_t alen = sizeof(su);
if (getpeername(info->fd, &su.sockaddr, &alen) != 0) {
bye("getpeername failed: %s", socket_strerror(socket_errno()));
}
if (getnameinfo((struct sockaddr *)&su, alen, ip, sizeof(ip),
port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
setenv_portable("NCAT_REMOTE_ADDR", ip);
setenv_portable("NCAT_REMOTE_PORT", port);
} else {
bye("getnameinfo failed: %s", socket_strerror(socket_errno()));
}
if (getsockname(info->fd, (struct sockaddr *)&su, &alen) < 0) {
bye("getsockname failed: %s", socket_strerror(socket_errno()));
}
if (getnameinfo((struct sockaddr *)&su, alen, ip, sizeof(ip),
port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
setenv_portable("NCAT_LOCAL_ADDR", ip);
setenv_portable("NCAT_LOCAL_PORT", port);
} else {
bye("getnameinfo failed: %s", socket_strerror(socket_errno()));
}
switch(o.proto) {
case IPPROTO_TCP:
setenv_portable("NCAT_PROTO", "TCP");
break;
case IPPROTO_SCTP:
setenv_portable("NCAT_PROTO", "SCTP");
break;
case IPPROTO_UDP:
setenv_portable("NCAT_PROTO", "UDP");
break;
}
}

View file

@ -230,3 +230,6 @@ extern int ncat_hostaccess(char *matchaddr, char *filename, char *remoteip);
/* Make it so that line endings read from a console are always \n (not \r\n).
Defined in ncat_posix.c and ncat_win.c. */
extern void set_lf_mode(void);
extern int setenv_portable(const char *name, const char *value);
extern void setup_environment(struct fdinfo *fdinfo);

View file

@ -195,6 +195,28 @@ extern void set_pseudo_sigchld_handler(void (*handler)(void))
ncat_assert(rc != 0);
}
int setenv_portable(const char *name, const char *value)
{
BOOL ret = SetEnvironmentVariable(name, value);
if (ret == 0) {
DWORD last_error = GetLastError();
switch (last_error) {
case ERROR_INVALID_PARAMETER:
errno = EINVAL;
break;
case ERROR_NOT_ENOUGH_MEMORY:
errno = ENOMEM;
break;
default:
if (o.debug)
logdebug("SetEnvironmentVariable: GetLastError returned %d\n", last_error);
errno = EINVAL;
break;
}
}
return ret != 0;
}
/* Run a command and redirect its input and output handles to a pair of
anonymous pipes. The process handle and pipe handles are returned in the
info struct. Returns the PID of the new process, or -1 on error. */
@ -207,6 +229,8 @@ static int run_command_redirected(char *cmdexec, struct subprocess_info *info)
STARTUPINFO si;
PROCESS_INFORMATION pi;
setup_environment(&info->fdn);
/* Make the pipe handles inheritable. */
sa.nLength = sizeof(sa);
sa.bInheritHandle = TRUE;

View file

@ -192,6 +192,8 @@ void netexec(struct fdinfo *info, char *cmdexec)
Dup2(child_stdin[0], STDIN_FILENO);
Dup2(child_stdout[1], STDOUT_FILENO);
setup_environment(info);
switch (o.execmode) {
char **cmdargs;
@ -389,3 +391,8 @@ int ssl_load_default_ca_certs(SSL_CTX *ctx)
return 0;
}
#endif
int setenv_portable(const char *name, const char *value)
{
return setenv(name, value, 1);
}

10
ncat/scripts/log_ips.sh Normal file
View file

@ -0,0 +1,10 @@
#!/bin/sh
LOGFILE="log_ips.log"
MSG="[`date`] Incoming connection from $NCAT_REMOTE_ADDR:$NCAT_REMOTE_PORT"
echo $MSG >&2
echo $MSG >> $LOGFILE
echo "Yeah, hi."

97
ncat/scripts/p0fme.py Executable file
View file

@ -0,0 +1,97 @@
#!/usr/bin/python
from __future__ import print_function # logging, python2-only.
"""
A script that reads data generated by p0f -f p0f.log, looking for all entries
about an IP read from NCAT_REMOTE_ADDR environment variable. Then it prints out
all the information it has found. To try it out, run "p0f -i any -o p0f.log"
and ncat -l -k --sh-exec "python p0fme.py".
Script tested under Python versions 2.7 and 3.3.
"""
P0F_LOG_FILE = "p0f.log"
import datetime # logging
import sys # logging
import os # environ
import time # sleeping to wait for data
import sys # to flush STDOUT
def expand_ipv6(ip):
"""
Expands short IPv6 address like ::1 into an expanded form without trailing
zeros. Copied from:
http://svn.python.org/projects/python/tags/r31b1/Lib/ipaddr.py
(Py3 standard library; added some modifications to match p0f's output data)
"""
new_ip = []
hextet = ip.split('::')
sep = len(hextet[0].split(':')) + len(hextet[1].split(':'))
new_ip = hextet[0].split(':')
for _ in range(8 - sep):
new_ip.append('0')
new_ip += hextet[1].split(':')
# Now need to make sure every hextet is 4 lower case characters.
# If a hextet is < 4 characters, we've got missing leading 0's.
ret_ip = []
for hextet in new_ip:
if hextet == '':
hextet = '0'
ret_ip.append(hextet.lower())
return ':'.join(ret_ip)
def split_by_equals(str_):
ret = str_.split('=')
return ret[0], ''.join(ret[1:])
if __name__ == "__main__":
try:
ip = os.environ['NCAT_REMOTE_ADDR']
if os.environ['NCAT_PROTO'] != 'TCP':
sys.exit("ERROR: This script works for TCP servers only!")
except KeyError:
sys.exit("ERROR: This script has to be run from inside of Ncat.")
print("[%s] Got a request from %s" % (
datetime.datetime.now().isoformat(' '), ip), file=sys.stderr)
print("Hold on, I'm collecting data on you...")
sys.stdout.flush()
time.sleep(3.0)
if ':' in ip: # We need to expand IPv6 addresses in a specific way.
ip = expand_ipv6(ip)
result = {}
# Reading the log backward will give us more recent results.
for line in reversed(open(P0F_LOG_FILE).readlines()):
without_date = line.split('] ')
if without_date == ['\n']:
continue
without_date = ''.join(without_date[1:])
# Create a key-value dictionary out of the '|'-separated substrings.
properties = dict(map(split_by_equals, without_date.split('|')))
if not properties['cli'].startswith(ip):
continue # Not the IP we're looking for, check next one.
for key in properties:
if not key in result or result[key] == '???':
result[key] = properties[key]
if not result:
print("Got nothing on you. Try again and I will, though.")
# Now that we've finished, print out the results.
for key in sorted(result):
print("%s: %s" % (key, result[key].rstrip()))

View file

@ -0,0 +1,4 @@
--A "what is my IP" service code. Since most web browsers put up with servers
--not sending proper HTTP headers, you can simply query the service with it.
print(os.getenv("NCAT_REMOTE_ADDR"))

View file

@ -381,6 +381,16 @@ sub max_conns_test_tcp_ssl {
max_conns_test_multi(["tcp", "tcp ssl"], @_);
}
sub match_ncat_environment {
$_ = shift;
return /NCAT_REMOTE_ADDR=.+\n
NCAT_REMOTE_PORT=.+\n
NCAT_LOCAL_ADDR=.+\n
NCAT_LOCAL_PORT=.+\n
NCAT_PROTO=.+
/x;
}
# Ignore broken pipe signals that result when trying to read from a terminated
# client.
$SIG{PIPE} = "IGNORE";
@ -1084,6 +1094,35 @@ server_client_test_all "--lua-exec",
$resp eq "ABC\n" or die "Client received " . d($resp) . ", not " . d("ABC\n");
};
# Test environment variables being set for --exec, --sh-exec and --lua-exec.
server_client_test_all "--exec, environment variables",
["--exec", "/bin/sh test-environment.sh"], [], sub {
syswrite($c_in, "abc\n");
my $resp = timeout_read($c_out) or die "Read timeout";
match_ncat_environment($resp) or die "Client received " . d($resp) . ".";
};
server_client_test_all "--sh-exec, environment variables",
["--sh-exec", "sh test-environment.sh"], [], sub {
syswrite($c_in, "abc\n");
my $resp = timeout_read($c_out) or die "Read timeout";
match_ncat_environment($resp) or die "Client received " . d($resp) . ".";
};
proxy_test "--exec through proxy, environment variables",
[], [], ["--exec", "/bin/sh test-environment.sh"], sub {
my $resp = timeout_read($s_out) or die "Read timeout";
match_ncat_environment($resp) or die "Client received " . d($resp) . ".";
};
server_client_test_all "--lua-exec, environment variables",
["--lua-exec", "test-environment.lua"], [], sub {
syswrite($c_in, "abc\n");
my $resp = timeout_read($c_out) or die "Read timeout";
match_ncat_environment($resp) or die "Client received " . d($resp) . ".";
};
# Do a syswrite and then a delay to force separate reads in the subprocess.
sub delaywrite {
my ($handle, $data) = @_;

View file

@ -0,0 +1,9 @@
#!/usr/bin/lua
--Print the following NCAT_* variables and their values:
envs = {'REMOTE_ADDR', 'REMOTE_PORT', 'LOCAL_ADDR', 'LOCAL_PORT', 'PROTO'}
for _,v in pairs(envs) do
v = 'NCAT_' .. v
print(("%s=%s"):format(v, os.getenv(v)))
end

11
ncat/test/test-environment.sh Executable file
View file

@ -0,0 +1,11 @@
#!/bin/sh
# Print the contents of all environment variables set by Ncat.
echo "NCAT_REMOTE_ADDR=$NCAT_REMOTE_ADDR"
echo "NCAT_REMOTE_PORT=$NCAT_REMOTE_PORT"
echo "NCAT_LOCAL_ADDR=$NCAT_LOCAL_ADDR"
echo "NCAT_LOCAL_PORT=$NCAT_LOCAL_PORT"
echo "NCAT_PROTO=$NCAT_PROTO"