Script for sending a header to netcat - bash

I work with a protocol that's easy to use simply with netcat. The protocol starts with a login message, so I thought I could bang out a little script which pipes the login message before stdin to netcat for me.
I was able to get close, but there's one problem I can't figure out. The following script works, in that it sends the login message and allows me to interact with netcat. But if netcat exits (because the server side closed the connection), the script just hangs there (presumably because cat is still reading stdin even though no one is reading stdout any more).
( echo "${LOGIN}"; cat ) | nc ${HOST} ${PORT}

It's a tricky problem, and you're right about the cause. Processes don't get a NOPIPE error and SIGPIPE until they actually try to write to the pipe.
If nothing else, you can use the interaction scripting tool expect:
expect <(echo '
spawn nc google.com 80
send "GET / HTTP/1.0\n"
send "Host: www.google.com\n"
interact
')
This will run nc, send some HTTP headers, and then gives control to you. When nc exits, so does the command.

Related

Bash: Remote SSH ncat command requires sigint to exit

I have a bit of an interesting situation that I can't figure out.
I need the ability to issue a command remotely over SSH, which then pipes the results into an ncat tunnel back to the original server.
My commands are a little more complex than this (involving innobackupex, a MySQL backup utility), but this minimal example shows the same issue:
ncat -l 9970 &
ssh db-202 "echo 'testing' | ncat $BACKUPSERVER 9970"
... other commands
The issue is that after the echo command completes (or whatever is run), the script just hangs and the later commands don't run. I need to send a ctrl-c (SIGINT) to continue. Obviously this isn't ideal in the context of a bash script, where lots of things may need to happen after this command completes automatically.
Not sure if it's relevant, but sending a sigint doesn't always properly terminate the ncat tunnel on both sides. Sometimes I need to kill -9 it, probably due to the sigint messing something up.
Can anybody explain this behavior and how I can get around it? Or a better way to do what I want?
Thanks!
Finally figured it out.
I added the --recv-only and --send-only arguments to each side of the tunnel.
According to the manpage:
--send-only Only send data, ignoring received; quit on EOF
This may explain it, but I though that any EOF would terminate the tunnel. Maybe without these arguments, both sides need to send an EOF?
Anyway, here are the commands that work.
ncat --recv-only -l 9970 &
ssh db-202 "echo 'testing' | ncat --send-only $BACKUPSERVER 9970"
Hopefully this helps someone in the future.

Redirect modified output of a program back to its input

For fun, I want to type something in Bash that will connect to an IRC server and automatically respond to PING messages
For example, I have the following output from telnet
Connected to irc.example.com.
Escape character is '^]'.
PING :12341234
If I pipe this to grep and then sed, I can easily turn this output into PONG :12341234, but how do I send it back to the standard input stream of telnet?
Additionally, I'd like to still being to manually send input using the keyboard
What you're trying to do is known as an "echo server". It is fairly easy to do with netcat and it's variants (nc or netcat, ncat, etc.).
For example:
ncat -l 2000 --keep-open --exec "/bin/cat"
In another shell
telnet localhost 2000
Whatever you send will be replied by ncat.

ncat on windows: -e option forwards input but does not forward output

I start ncat (on Windows 10) with
ncat -vvlp 1234 -e code.exe
and then connect with a second instance of ncat to the first instance
(ncat 127.0.0.1 1234).
code.exe is a C program written by me that can be controlled over stdin.
Everything I send via the second ncat gets forwarded to the stdin of code.exe. I know this because I can see code.exe create a folder after sending the command to do so. But the output is not send back until code.exe closes itself.
Why is that — and how can I fix it?
Ok I found a solution to my problem. I disabled buffering of stdout by using
setbuf(stdout, NULL);
at the start of my C program.

SSH command within a script terminates prematurely

From myhost.mydomain.com, I start a nc listener. Then login to another host to start a netcat push to my host:
nc -l 9999 > data.gz &
ssh repo.mydomain.com "cat /path/to/file.gz | nc myhost.mydomain.com 9999"
These two commands are part of a script. Only 32K bytes are sent to the host and the ssh command terminates, the nc listener gets an EOF and it terminates as well.
When I run the ssh command on the command line (i.e. not as part of the script) on myhost.mydomain.com the complete file is downloaded. What's going on?
I think there is something else that happens in your script which causes this effect. For example, if you run the second command in the background as well and terminate the script, your OS might kill the background commands during script cleanup.
Also look for set -o pipebreak which terminates all the commands in a pipeline when one of them returns with != 0.
On a second note, the approach looks overly complex to me. Try to reduce it to
ssh repo.mydomain.com "cat /path/to/file.gz" > data.gz
(ssh connects stdout of the remote with the local). It's more clear when you write it like this:
ssh > data.gz repo.mydomain.com "cat /path/to/file.gz"
That way, you can get rid of nc. As far as I know, nc is synchronous, so the second invocation (which sends the data) should only return after all the data has been sent and flushed.

How to connect stdin of a list of commands (with pipes) to one of those commands

I need to give the user ability to send/receive messages over the network (using netcat) while the connection is stablished (the user, in this case, is using nc as client). The problem is that I need to send a line before user starts interacting. My first attempt was:
echo 'my first line' | nc server port
The problem with this approach is that nc closes the connection when echo finishes its execution, so the user can't send commands via stdin because the shell is given back to him (and also the answer from server is not received because it delays some seconds to start answering and, as nc closes the connection, the answer is never received by the user).
I also tried grouping commands:
{ echo 'my first line'; cat -; } | nc server port
It works almost the way I need, but if server closes the connection, it will wait until I press <ENTER> to give me the shell again. I need to get the shell back when the server closes the connection (in this case, the client - my nc command - will never closes the connection, except if I press Ctrl+C).
I also tried named pipes, without success.
Do you have any tip on how to do it?
Note: I'm using openbsd-netcat.
You probably want to look into expect(1).
It is cat that wait for the 'enter'.
You may write a script execute after nc to kill the cat and it will return to shell automatically.
You can try this to see if it works for you.
perl -e "\$|=1;print \"my first line\\n\" ; while (<STDIN>) {print;}" | nc server port
This one should produce the behaviour you want:
echo "Here is your MOTD." | nc server port ; nc server port
I would suggest you use cat << EOF, but I think it will not work as you expect.
I don't know how you can send EOF when the connection is closed.

Resources