7

In command below I enable file /dev/tcp/10.10.10.1/80 both for reading and writing and associate it with file descriptor 3:

$ time exec 3<>/dev/tcp/10.10.10.1/80
bash: connect: Operation timed out
bash: /dev/tcp/10.10.10.1/80: Operation timed out

real    1m15.151s
user    0m0.000s
sys     0m0.000s

This automatically tries to perform TCP three-way handshake. If 10.10.10.1 is not reachable as in example above, then connect system call tries to connect for 75 seconds. Is this 75 second timeout determined by bash? Or is this system default? Last but not least, is there a way to decrease this timeout value?

kenorb
  • 155,785
  • 88
  • 678
  • 743
Martin
  • 957
  • 7
  • 25
  • 38
  • Stack Overflow is a site for programming and development questions. This question appears to be off-topic because it is not about programming or development. See [What topics can I ask about here](http://stackoverflow.com/help/on-topic) in the Help Center. Perhaps [Super User](http://superuser.com/) or [Unix & Linux Stack Exchange](http://unix.stackexchange.com/) would be a better place to ask. – jww Mar 12 '18 at 12:54

3 Answers3

11

It's not possible in Bash without modifying the source as already mentioned, although here is the workaround by using timeout command, e.g.:

$ timeout 1 bash -c "</dev/tcp/stackoverflow.com/80" && echo Port open. || echo Port closed.
Port open.
$ timeout 1 bash -c "</dev/tcp/stackoverflow.com/81" && echo Port open. || echo Port closed.
Port closed.

Using this syntax, the timeout command will kill the process after the given time.

See: timeout --help for more options.

kenorb
  • 155,785
  • 88
  • 678
  • 743
  • 2
    This should be the accepted answer, instead changing the values (not recommended) system widely on `/proc/sys/net/ipv4/tcp_keepalive_time` is god to know that sending the signal to the parent of the process that open the socket will close it. I was wondering why this works and `$ timeout 1 – Alan Garrido Feb 06 '19 at 18:42
1

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.

user207421
  • 305,947
  • 44
  • 307
  • 483
1

No: there is no way of changing timeout by using /dev/tcp/

Yes, you could change default timeout for TCP connection in any programming language.

But, is not a programming language!

You could have a look into source code (see: Bash Homepage), you may find lib/sh/netopen.c file where you could read in _netopen4 function:

s = socket(AF_INET, (typ == 't') ? SOCK_STREAM : SOCK_DGRAM, 0);

You could read this file carefully, there are no consideration of connection timeout.

Without patching bash sources, there is no way of changing connection timeout by a bash script.

Simple HTTP client using netcat (near pure bash)

There is a little sample HTTP client written in pure bash, but using netcat:

#!/bin/bash

tmpfile=$(mktemp -p $HOME .netbash-XXXXXX)
exec 7> >(nc -w 3 -q 0 stackoverflow.com 80 >$tmpfile)
exec 6<$tmpfile
rm $tmpfile

printf >&7 "GET %s HTTP/1.0\r\nHost: stackoverflow.com\r\n\r\n" \
    /questions/24317341/how-to-decrease-tcp-connect-system-call-timeout

timeout=100;
while ! read -t .001 -u 6 status ; do read -t .001 foo;done
echo STATUS: $status

[ "$status" ] && [ -z "${status//HTTP*200 OK*}" ] || exit 1

echo HEADER:
while read -u 6 -a head && [ "${head//$'\r'}" ]; do
    printf "%-20s : %s\n" ${head%:} "${head[*]:1}"
    done

echo TITLE:
sed '/<title>/s/<[^>]*>//gp;d' <&6

exec 7>&-
exec 6<&-

This could render:

STATUS: HTTP/1.1 200 OK
HEADER:
Cache-Control        : private
Content-Type         : text/html; charset=utf-8
X-Frame-Options      : SAMEORIGIN
X-Request-Guid       : 46d55dc9-f7fe-425f-a560-fc49d885a5e5
Content-Length       : 91642
Accept-Ranges        : bytes
Date                 : Wed, 19 Oct 2016 13:24:35 GMT
Via                  : 1.1 varnish
Age                  : 0
Connection           : close
X-Served-By          : cache-fra1243-FRA
X-Cache              : MISS
X-Cache-Hits         : 0
X-Timer              : S1476883475.343528,VS0,VE100
X-DNS-Prefetch-Control : off
Set-Cookie           : prov=ff1129e3-7de5-9375-58ee-5f739eb73449; domain=.stackoverflow.com; expires=Fri, 01-Jan-2055 00:00:00 GMT; path=/; HttpOnly
TITLE:
bash - How to decrease TCP connect() system call timeout? - Stack Overflow
Some explanations:

We create first a temporary file (under private directory for security reason), bind and delete before using them.

$ tmpfile=$(mktemp -p $HOME .netbash-XXXXXX)
$ exec 7> >(nc -w 3 -q 0 stackoverflow.com 80 >$tmpfile)
$ exec 6<$tmpfile
$ rm $tmpfile

$ ls $tmpfile
ls: cannot access /home/user/.netbash-rKvpZW: No such file or directory

$ ls -l /proc/self/fd
lrwx------ 1 user user 64 Oct 19 15:20 0 -> /dev/pts/1
lrwx------ 1 user user 64 Oct 19 15:20 1 -> /dev/pts/1
lrwx------ 1 user user 64 Oct 19 15:20 2 -> /dev/pts/1
lr-x------ 1 user user 64 Oct 19 15:20 3 -> /proc/30237/fd
lr-x------ 1 user user 64 Oct 19 15:20 6 -> /home/user/.netbash-rKvpZW (deleted)
l-wx------ 1 user user 64 Oct 19 15:20 7 -> pipe:[2097453]

$ echo GET / HTTP/1.0$'\r\n\r' >&7
$ read -u 6 foo
$ echo $foo
HTTP/1.1 500 Domain Not Found

$ exec 7>&-
$ exec 6>&-
F. Hauri - Give Up GitHub
  • 64,122
  • 17
  • 116
  • 137
  • 3
    Bash is most certainly a programming language. It's not terribly well-equipped when it comes to networking but that's beside the point. – tripleee Oct 19 '16 at 11:53
  • @tripleee No, bash is a [tag:shell]. Not basically intended to be a *programming language*... a *command language* or *scripting language*, but not a real *programming language*. see [my *ascii analog clock*](http://codegolf.stackexchange.com/a/13007/9424), specialy why *Don't use this anyway!* And [*how to read binary by using pure bash*](http://stackoverflow.com/a/13890319/1765658)... Try this pure bash script and compare performances with C written base64 encoder... – F. Hauri - Give Up GitHub Oct 19 '16 at 12:27
  • 2
    Meh, po-tah-to po-tay-to. If your criterion is that some things are inconvenient, Pascal and Fortran aren't programming languages, either. C is certainly more general-purpose, but that also means many things are less convenient than in specialized languages. – tripleee Oct 19 '16 at 14:45
  • @tripleee Did you try to run [ascii-clock.sh](http://fhauri.cartou.ch/ascii-clock/ascii-clock.sh) several hours and check memory usage? (The capitalized `S` at top left mean *sleep*, you could compare with other version on [For geeks: Ascii-Art analog clock](http://fhauri.cartou.ch/ascii-clock/)) – F. Hauri - Give Up GitHub Oct 19 '16 at 21:32
  • A memory bug like that sucks, but it's jut an implementation detail. Would you change your opinion if they fixed that problem? – tripleee Oct 20 '16 at 03:31
  • @tripleee I could workaround by running subtask each seconds, in this case, but bash lack of variable typing, memory garbage and lot or things who exist by default in any progamming language. I insist: programming language and command language are both required, but not same. (I've seen some installation script written under php! It's horrible too!)... Yes: you can use a knife to grab and fork to cut ... but it's not simplier way! – F. Hauri - Give Up GitHub Oct 20 '16 at 05:53
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/126189/discussion-between-f-hauri-and-tripleee). – F. Hauri - Give Up GitHub Oct 20 '16 at 07:41