Tcp Connection, Bash Only

TCP connection, bash only


< and > are usually used to redirect IOs. What does it mean there? Is it usable in another context? How?

It's the same - input and output is redirected to fd 5.

Why does it work, while /dev/tcp doesn't exists?

It's a special file: If host is a valid hostname or Internet address, and port is an integer port number or service name, bash attempts to open a TCP connection to the corresponding socket.

Why 5? Can it be another number? What are the values allowed?

Yes, it can be any value, but you need to ensure you don't use an fd already in use.

Why is exec necessary? (given nothing is actually executed)

exec means the redirection happens in the current shell, not within a subshell.

Read and write to the same netcat tcp connection

The correct way to do this in UNIX is to make use of a back pipe. You can do so as follows:

First, create a pipe: mknod bkpipe p

This creates a file named bkpipe of type pipe.

Next, figure out what you need to do. Here are two useful scenarios. In these, replace the hosts/addresses and port numbers with the appropriate ports for your relay.

To forward data sent to a local port to a remote port on another machine:

 nc -l -p 9999 0<bkpipe | nc remotehost 7000 | tee bkpipe

To connect to another machine and then relay data in that connection to another:

 nc leftHost 6000 0<bkpipe | nc rightHost 6000 | tee bkpipe

If you simply need to handle basic IPC within a single host, however, you can do away with netcat completely and just use the FIFO pipe that mknod creates. If you stuff things into the FIFO with one process, they will hang out there until something else reads them out.

Bash script to close open TCP connections on a specific port

I'm not familiar with the findstr command, but there's no need to use another command to search for matching lines, as awk can do that by itself.

netstat -ano | awk '$1 == "TCP" && $2 ~ /:8080/ { print $5 }'

Connecting to an open port with bash

It depends on the shell; bash, for instance, uses I/O redirection to attach to arbitrary TCP and UDP sockets. From the man page:

Bash handles several filenames specially when they are used in redirections, as
described in the following table:

[...]

/dev/tcp/host/port
If host is a valid hostname or Internet address, and port is
an integer port number or service name, bash attempts to open a
TCP connection to the corresponding socket.
/dev/udp/host/port
If host is a valid hostname or Internet address, and port is
an integer port number or service name, bash attempts to open a
UDP connection to the corresponding socket.

For example, to get the current time:

cat < /dev/tcp/time-a.nist.gov/13

Note that it must be a redirection; cat /dev/tcp/time-a.nist.gov/13 would only work if your file system implemented some sort of sockets-on-demand.

A very basic HTTP client:

$ exec 3<>/dev/tcp/www.example.com/80
$ echo "GET /" >&3
$ cat <&3

How to decrease TCP connect() system call timeout?

It is determined by TCP. It can be decreased on a per-socket basis by application code.

NB The timeout only takes effect if there is no response at all. If there is a connection refusal, the error occurs immediately.

Persistent connection in Bash script

When a process is started in the background in a script, standard input is redirected from /dev/null. This means the first cat command will read and emit EOF as soon as it executes, which will cause netcat to exit immediately after starting, so the output later in the script will never make it to the fifo, because there isn't an active listener at that time.

In this case, when cat > fifo is evaluated, the shell forks a child process, redirects standard input from /dev/null, and attempts to open fifo for write. The child remains in a blocking open call at this time. Note that cat is not executed until after the open call completes.

Next, cat fifo | nc -v localhost 3000 is spawned. cat opens fifo for read, which allows the blocking open from the first child to complete and the first cat to execute.

The first cat inherits its parent's file descriptors, so its standard input is attached to /dev/null and it thus reads and emits an EOF immediately. The second cat reads the EOF and passes that to the standard input of nc, which causes netcat to exit.

By the time the echo statements are evaluated, the processes identified by $pid1 and $pid2 are finished. Since there is no longer a listener on fifo, the first echo will block forever.



I don't have a pure-shell fix, but you can use an external program like perl to open the placeholder writer to fifo instead of using shell redirection. Aside, please note that there is a race with nc starting after the echo statements (where the kill happens before netcat has a chance to process input/send output), so here I added a delay after the cat | nc expression. There is almost certainly a better solution out there, but here's what I came up with:

#!/bin/bash

rm -f fifo
mkfifo fifo
perl -e 'open(my $fh, ">", "fifo"); sleep 3600 while 1' &
pid1=$!
cat fifo | nc -v localhost 3000 &
pid2=$!

sleep 2

echo sending...
echo comando1 > fifo
echo comando2 > fifo
echo comando3 > fifo

kill -9 $pid1 $pid2

Hope this helps, great question!

Efficiently test if a port is open on Linux?

A surprise I found out recently is that Bash natively supports tcp connections as file descriptors. To use:

exec 6<>/dev/tcp/ip.addr.of.server/445
echo -e "GET / HTTP/1.0\n" >&6
cat <&6

I'm using 6 as the file descriptor because 0,1,2 are stdin, stdout, and stderr. 5 is sometimes used by Bash for child processes, so 3,4,6,7,8, and 9 should be safe.

As per the comment below, to test for listening on a local server in a script:

exec 6<>/dev/tcp/127.0.0.1/445 || echo "No one is listening!"
exec 6>&- # close output connection
exec 6<&- # close input connection

To determine if someone is listening, attempt to connect by loopback. If it fails, then the port is closed or we aren't allowed access. Afterwards, close the connection.

Modify this for your use case, such as sending an email, exiting the script on failure, or starting the required service.

How to listen for multiple tcp connection using nc

Simultaneous connections are not possible with netcat. You should use something like ucspi-tcp's tcpserver tool or leverage xinetd since you're on Linux.

See: https://superuser.com/questions/232747/netcat-as-a-multithread-server

Consecutive connections could be handled through a shell script that restarts netcat after it finishes.



Related Topics



Leave a reply



Submit