An external data provider makes a tcp connection to one of our servers.
I would like to use socat to 'multiplex' the incoming data so that multiple programs can receive data sent from the external data provider.
socat -u TCP4-LISTEN:42000,reuseaddr,fork OPEN:/home/me/my.log,creat,append
happily accepts incoming data and puts it into a file.
What I'd like to do is something that will allow local programs to connect to a TCP port and begin to receive data that arrives from connections to the external port. I tried
socat -u TCP4-LISTEN:42000,reuseaddr,fork TCP4-LISTEN:43000,reuseaddr
but that doesn't work. I haven't been able to find any examples in the socat doco that seem relevant to back to back TCP servers.
Can someone point me in the right direction?
With Bash process-substitution
Multiplexing from the shell can in general be achieved with coreutils tee and Bash process-substitution. So for example to have the socat-stream multiplexed to multiple pipelines do something like this:
socat -u tcp-l:42000,fork,reuseaddr system:'bash -c \"tee >(sed s/foo/bar/ > a) >(cat > b) > /dev/null\"'
Now if you send foobar to the server:
socat - tcp:localhost:42000 <<<fobar
Files a and b will contain:
a
barbar
b
foobar
With named pipes
If the pipelines are complicated and/or you want to avoid using Bash, you can use named pipes to improve readability and portability:
mkfifo x y
Create the reader processes:
sed s/foo/bar/ x > a &
cat y > b &
Start the server:
socat -u tcp-l:42000,fork,reuseaddr system:'tee x y > /dev/null'
Again, send foobar to the server:
echo foobar | socat - tcp:localhost:42000
And the result is the same as in the above.
I found ncat ( http://nmap.org/ncat/) to be flexible and easier to use. I suggest you give it a try. I cannot currently test it for you to find the exact command, but you can let it listen on 2 ports; for one port you use the -k option to accept multiple clients.
Related
I'm working on a bash script to connect to a server via SSH that is running sish (https://github.com/antoniomika/sish). This will essentially create a port forward on the internet like ngrok using only SSH. Here is what happens during normal usage.
The command:
ssh -i ./tun -o StrictHostKeyChecking=no -R 5900:localhost:5900 tun.domain.tld sleep 10
The response:
Starting SSH Forwarding service for tcp:5900. Forwarded connections can be accessed via the following methods:
TCP: tun.domain.tld:43345
Now I need to send the ssh command to the background and figure out some way of capturing the response from the server as a variable so that I can grab the port that sish has assigned and send that somewhere (probably a webhook). I've tried a few things like using -f and piping to a file or named pipe and trying to cat it, but the issue is that the piping to the file never works and although the file is created, it's always empty. Any assistance would be greatly appreciated.
If you're running a single instance of sish (and the tunnel you're attempting to define) you can actually have sish bind the specific part you want (in this case 5900).
You just set the --bind-random-ports=false flag on your server command in order to tell sish that it's okay to not use random ports.
If you don't want to do this (or you have multiple clients that will expose this same port), you can use a simple script like the following:
#!/bin/bash
ADDR=""
# Start the tunnel. Use a phony command to tell ssh to clean the output.
exec 3< <(ssh -R 5900:localhost:5900 tun.domain.tld foobar 2>&1 | grep --line-buffered TCP | awk '{print $2; system("")}')
# Get our buffered output that is now just the address sish has given to us.
for i in 1; do
read <&3 line;
ADDR="$line"
done
# Here is where you'd call the webhook
echo "Do something with $ADDR"
# If you want the ssh command to continue to run in the background
# you can omit the following. This is to wait for the ssh command to
# exit or until this script dies in order to kill the ssh command.
PIDS=($(pgrep -P $(pgrep -P $$)))
function killssh() {
kill ${PIDS[0]}
}
trap killssh EXIT
while kill -0 ${PIDS[0]} 2> /dev/null; do sleep 1; done;
sish also has an admin api which you can scrape. The information on that is available here.
References: I build and maintain sish and use it myself (as well as a similar type of script).
I'm trying to simulating a telnet client in bash using tcp socket and I'm starting from zero.
Doing this I am reading and writing on a file descriptor (stdin stdout).
(I know that it's too much simple to do $telnet hostname, but I'm doing this to understand bash).
To start I want to get the first line (welcome message).
There are some troubles with particular ip.
With some it works, but with some others it fails. It has to go good with all!
Example with some random Ip I found to test it
It works good with:
exec 3<> /dev/tcp/77.239.64.182/23; cat <&3
output:
????????
* TELRAD CMTS UBR-10K *
User Access Verification
Username:
Here the trouble
It works bad with:
exec 3<> /dev/tcp/77.239.64.158/23; cat <&3
output:
0???? ??#??'
but, if I use telnet the output it's different:
$ telnet 77.239.64.158
Trying 77.239.64.158...
Connected to 77.239.64.158.
Escape character is '^]'.
MikroTik v6.18
Login:
I thought that the trouble was that the client had to send some string before having the welcome message.
So I changed it to:
exec 3<> /dev/tcp/77.239.64.158/23; echo -e "aaaaaaaa\r\n\rAAAA...lonstring...AAAA\r\n\r\n\rAAAAlonstringAAAA\n\r\n" >&3; cat <&3
Same thing, same output.
Someone able to adjust this?!
In bash how can I issue a command to a running process I just started?
For example;
# Start Bluez gatttool then Connect to bluetooth device
gatttool -b $MAC -I
connect # send 'connect' to the gatttool process?
Currently my shell script doesn't get to the connect line because the gatttool process is running.
If you simply want to send the string "connect\n" to the process, you can use a standard pipe:
echo "connect" | gatttool -b $MAC -I
If you want to engage in a more complex "conversation" with the gatttool process, take a look at the expect (1) and chat (8) tool, which allow you to send a sequence of strings, and wait for certain responses.
If you'd prefer a slightly "lighter" way of piping you could use a heredoc such as in:
gatttool -b $MAC -I <<EOF
connect
(...)
EOF
Everything contained between the two EOF tags will be piped to the command's input. I believe this will not allow you to interact with the command whilst between the EOF tags so, as mentioned in the previous answer, you might want to consider using expect if you need to act upon the commands' output before sending something back to it.
I have the following scenario:
I use netcat to connect to a host running telnet server on port 23, I log in using provided username and password, issue some commands, after which I need to do fairly complex analysis of the provided output. Naturally, expect comes to mind, with a script like this:
spawn nc host 23
send "user\r"
send "pass\r"
send "command\r"
expect EOF
then, it is executed with expect example.scr >output.log, so the output file can be parsed. The parser is 150+ lines of bash code that executes under 2 seconds, and makes a decision what command should be executed next. Thus, it replaces "command" with "command2", and executes the expect script again, like this:
sed -i '/send "command\r"/send "command2\r"/' example.scr
expect example.scr >output.log
Obviously, it is not needed to re-establish telnet connection and perform log in process all over again, just to issue a single telnet command after 2 seconds of processing. A conclusion can be made, that telnet session should be kept alive as a background process, so one could freely talk to it at any given time. Naturally, using named pipes comes to mind:
mkfifo in
mkfifo output.log
cat in | nc host 23 >output.log &
echo -e "user\npass\ncommand\n" >in
cat output.log
After the file is written to, EOF causes the named pipe to close, thus terminating the telnet session. I was thinking what kind of eternal process could be piped to netcat so it can be used as telnet relay to host. I came up with a very silly idea, but it works:
nc -k -l 666 | nc host 23 >output.log &
echo -e "user\npass\ncommand\n" | nc localhost 666
cat output.log
The netcat server is started with k(eep alive), listening on port 666, and any data stream is redirected to the netcat telnet client connected to the host, while the entire conversation is dumped to output.log. One can now echo telnet commands to nc localhost 666, and read the result from output.log.
One should keep in mind that the expect script can be easily modified to accommodate SSH and even serial console connection, just by spawning ssh or socat instead of netcat. I never liked expect because it forces a use of another scripting language within bash, requires tcl libraries, and needs to be compiled for the embedded platforms, while netcat is a part of busybox and readily available everywhere.
So, the question is - could this be done in a simpler way? I'd put my bet on having some sort of link between console and TCP socket. Any suggestions are appreciated.
How about using like a file descriptor?
exec 3<>/dev/tcp/host/port
while true; do
echo -e "user\npass\ncommand" >&3
read_response_generate_next_command <&3 >&3
# if no more commands, break;
done
exec 3>&-
I'm trying to listen socket into bash to produce dynamic response. I tried do like this nc -l 8088 -c``echo 'Request got, let's produce it' but -c option is deprecated and unsupported now.
Then I tried to list port using /dev/tcp: exec 3<>/dev/tcp/127.0.0.1/8088;
cat <&3 But i've got an error:
connect: Connection denied*
line 1: /dev/tcp/127.0.0.1/8088: Connection denied*
line 2: 3: Wrong file descriptor*
Translated from russian word for word
That syntax, according to the Bash manpage, is for opening a connection to an existing socket. I don't know of an option to create a socket using only Bash. And your nc command uses port 8000 not 8088.
[update]
OK then, but you're also missing the -p switch to set the port. Didn't catch that before.
jcomeau#intrepid:~$ nc -l -p8088 -c 'echo bleah' &
[1] 4752
jcomeau#intrepid:~$ exec 3<>/dev/tcp/127.0.0.1/8088; cat <&3
bleah
For an example of using pipes, see the bottom of this page, in the explanation of a proxy: http://www.stearns.org/doc/nc-intro.v0.9.html, hopefully you can adapt it for your needs.
Why not use inetd? The main problem with using netcat with Bash is that there's no straightforward way that I can think of to send back a reply, because you don't know what port they used to connect with. Whereas inetd handles the tcp/ip connection for you, letting your shell script just deal with stdin and stdout.