Testing for Remote Listener

Latest response

Anyone know a good method for testing whether a remote UDP service is reachable - preferably without the use of netcat or similar tools? TCP-based listeners are easy enough to do a cursory test: TCP gives you a basic pass/fail on a socket open attempt. Thus, a test like:

      for HOST in ${SERVERLIST}
      do
         printf "Attempting service-connect to ${HOST}...\n"
         SOCKTEST=$(timeout 5 bash -c 'cat < /dev/null > \
                                   /dev/tcp/${HOST}/53')$?

         if [[ ${SOCKTEST} -eq 0 ]]
         then
            printf "Socket-test passed.\n"
         else
            printf "Socket-test failed.\n"
         fi

      done

Is a fairly quick way to ensure that (in this case) the guys who provisioned a system pointed it to reachable DNS servers (didn't fat-finger any entries in the DHCP zone).

Using the above method-type for UDP doesn't really work - you get false successes. The specific case I'm trying to verify is NTPD accessibility. Using ntpdate <SERVER> would be fine, but I'd need to do my tests like service ntpd stop ; <TESTS> ; service ntpd start. Could also use ntpq -c peers, but would really rather test servers individually rather than all at once. And, really, would overall prefer a generalizable method for UDP testing rather than having to do per-service test-definitions.

Any ideas?

Responses

UDP is a connectionless protocol, there is no reliable way of testing whether there is anything listening unless the listener replies to you.

You will sometimes get systems which reply with an "ICMP Destination Unreachable", but you'll also get firewalls which just drop with no ICMP reply.

As a UDP sender, you have no way of telling whether your data was read by an application or dropped by a firewall. That reliability of transmission is not a feature which UDP offers.

You might want to look into nmap, it's a network tool which contains a port scanner which can do this for large network ranges with a variety of protocols. It's available in the RHEL Server channel.

Unfortunately, nmap falls into the same proscription-problem that prompted my "preferably without the use of netcat" notation. Our systems security folks look at tools like that (and even tcpdump) as grounds for shutting down systems with them installed if those systems live anywhere but lab/integration environments.

Well, you can do the same thing in bash:

$ echo "a" > /dev/udp/127.0.0.1/12345
$ echo $?
0

However what you're testing for with $? is that the message was delivered to the transmitting socket, which of course it was.

To intercept a possible "ICMP Destinaton Unreachable" you'd need to write something which listens back on the socket - essentially writing your own netcat/nmap.

If your aim is to test DNS servers, how about performing a lookup using dig @serverip example.com instead?

dig and related utilities are also not part of standard production builds. Since most modern DNS servers support TCP in addition to UDP (at least DNS servers that are configured to support full zone AXFERs), it's easy enough to avoid the UDP problem (why I had it in my original post).

NTP is a bit more problematic (and the problem I'm most specifically looking to solve), but really looking to create a sufficiently-generic solution that I don't have to write a per-service test. ntpdate is useful, if wanting to unbind ntpd for the duration of the test (sub-ideal). ntpq is useful if I want to parse the entire return-stream to extract each server and state so appropriate exit-codes can be assigned and reported ...but it sub-ideal from a "sufficiently-generic solution" standpoint.

Basically, I'm looking for a method that allows me with - what's not much more than an @Core build (basically, @Core plus support for LVM2 and cloud-init) - to write, at most, a function for TCP-based services and a function for UDP-based services.

Writing a "listen back" isn't that hard. Basically, if I can predictably provoke an arbitrary return from the remote UDP socket, then I've got my success-criteria. And if nothing at all comes back, I've got my failure-criteria. I just don't know that there's actually a method for reliably provoking a response (my "arbitrary" meaning I don't care what the response is, just that there is or is not something returned).

Any way, mostly opened this thread because Google was proving to be of little help and hoped somebody had something in their bag of tricks. =)

Writing a "listen back" isn't that hard.

Run this past your security team. Whilst I don't mean to speak poorly of your programming ability, I bet the collective authors of netcat have written a safer listener (which is more protected from buffer overflows and arbitrary code execution) than you or I could knock up for a quick service test :)

I got looking into this more, you can use bash to open an FD like so:

$ exec 3<> /dev/udp/127.0.0.1/12345

Now writing into the FD twice throws an error:

$ echo 1>&3
$ echo 1>&3
bash: echo: write error: Connection refused

Or you can read back from the socket and check for error:

$ echo 1>&3
$ while read 0<&3; do echo $REPLY; done
bash: read: read error: 0: Connection refused

Close the opened FD with:

$ exec 3>&-

Reference:

On the programming front: it's a bit harder for the security guys to get their dander up about the presence of core functionality (you're not going to have a EL system without Bash or python). The toolset, itself would be dropped into a pseudofs so that it disappears on reboot, any way (basically, just there for the amount of time it takes to determine whether the Ops team built the host correctly).

I'd tried similar solutions to the TLDP ones. They were a bit fraught. If the exec failed and you author your code to close the file-handle without checking that the exec succeeded, it causes your whole script to exit.

Small side-note: I tend to avoid FD-3 for scripts. I've run into some edge-cases (in the mists of the past) where, depending on what else is going on with the tool, some things will be doing their own fd-opens and will pull first-available (usually "3"). Use of higher FD-numbers avoids potential collisions.

I'd settled on the action-within-subshell method both because it's "self-cleaning" (no need to try to be nice and close dangling file-handle since the subshell's closure handles that for you) plus it had the benefit of allowing me to set an arbitrary timeout rather than waiting for the whole socket-open attempt to auto-timeout (meaning the script-pause drops from a couple minutes to as few seconds as you want).

I'll have to give the doubled string-send a try, though. =)

Close

Welcome! Check out the Getting Started with Red Hat page for quick tours and guides for common tasks.