Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses

Comment on

( #3333=superdoc: print w/replies, xml ) Need Help??

Okay my first reply on this subject was a fairly quick one to get Ovid some useful information in the little time I had. Here are some more details (and the results of some research).

TCP and UDP pings vs. ICMP pings

Okay, TCP and UDP "pings" used to be supported on "most" computers. For me, the story starts with a typical Unix system that had a inetd process (InterNET Daemon) that would read a configuration file that gave it a fairly long list of TCP and UDP ports to listen() on and what program to run when it received a request on which port. This was nice because, for example, you could handle FTP requests without having to have ftpd sitting around in your process table all day when you rarely used it (though that isn't an efficient configuration if you are constantly servicing a lot of FTP requests).

Well inetd would default to listening to TCP port 7 and UDP port 7. When a request came in on either of those ports it would echo any data received back to client (and the service name for port 7 is "echo").

Now Windows boxes don't come with inetd. You can get an inetd (I think it is either on a resource kit or can be downloaded or something) and configure it to respond to port 7 requests. But that requires way too much work for most people to get something that doesn't do them any good (it does other people good).

Also, the rising awareness of denial of service attacks has lead to many people turning off port 7 support in their inetd configuration files (sometimes due to identified weaknesses, sometimes just to "be safe" since there was little use for these services).

Meanwhile, many ICMP packets need to be handled by the TCP/IP stack itself [for example, so it can return "host unreachable" to a TCP connect() request if an ICMP packet comes in saying that the host is unreachable]. So the TCP/IP stack also handles ICMP echo requests (pings) itself without the need for inetd nor its configuration file.

So all (or nearly all) computers will respond to ICMP echo requests. Some firewalls get configured to block these, but other than that, an ICMP echo request is a very reliable type of "ping". Meanwhile, the proportion of computers that will process TCP or UDP echo requests is quite low and probably falling.

TCP pings could be great

A TCP ping could actually be about as useful as an ICMP ping if the Net::Ping module did them correctly.

I used Net::Ping on a Unix box to perform a TCP ping to a computer that I knew was up. It turns out that the other computer didn't support TCP echo requests. Well, Net::Ping reported that the ping failed. That was stupid.

I used the Perl debugger to step into Net::Ping and found that the connect() was failing with "Connection refused". What does this mean? It means that the other computer is up, is reachable, and isn't listening on TCP port 7 (and it did this all without triggering the time out). Well, that is a wonderful form of a successful ping in my book. When I ping a computer, I don't want to be told whether it is listening on port 7! So Net::Ping should return a true value for this case. Instead it returns a false value and manages to hide the value of $! so you can't just change the false to true if $! is "Connection refused". *sigh*

There are two (other) important practical differences between TCP and ICMP pings, however. First, either can be blocked at a firewall, rendering it useless. Why is that a difference? Well, if the firewalls you pass through block ICMP pings but not TCP echos, then that is a big difference. I suspect that TCP pings are commonly blocked at firewalls because there is no reason for them and a secure site should block anything that isn't required to be unblocked. I suspect that ICMP pings are often blocked to prevent probing of your inner network by strangers. So I suspect that TCP pings will have at least slightly more problems with firewalls.

Second, TCP pings require a time out or a nonblocking connect(). Net::Ping requires a time out for TCP pings, which means that you can't use Net::Ping to do TCP pings under Win32 [since Win32 Perl doesn't support the alarm() call]. You could patch Net::Ping to use nonblocking connect() instead, but that wouldn't do you any good because the Win32 nonblocking connect() is only nonblocking when you use the nonstandard Async* APIs. It is supposed to work using the standard nonblocking socket option. However, that option makes everything but connect() nonblocking. This is just a bug in Win32's winsock library. *sigh*

UDP pings don't get "Connection refused"

Now UDP pings don't require a time out [and don't use connect()]. But they don't get "Connection refused" so they can't detect machines that are up but not listening to UDP port 7. Actually, I think that you could detect the "Packet refused" condition [or the other errors like "host unreachable" which a TCP connect() will detect immediately and save you from waiting for a time out]. But doing that requires catching and parsing ICMP packets. Well, if you can do that then you might as well just do ICMP pings. *sigh*

Non-administrators can't use ICMP under WinNT/Win2K

Here is a quote from Microsoft documentation concerning the creation of "raw" sockets for processing TCP/IP packets other than TCP or UDP.

Note: On Windows NT/Windows 2000, raw socket support requires administrative privileges. Users running Winsock applications that make use of raw sockets must have administrative privileges on the computer, otherwise raw socket calls fail with an error code of WSAEACCESS.
So you can use ICMP pings under Win9x (which I have verified) [since there is no such thing as a Win9x administrator]. Under WinNT/Win2K, you can't open a "raw" socket to get full access to all kinds of packets unless you are an administrator.

So how does PING.EXE do it?

Ping uses ICMP.DLL

I popped up the "Depends" tool [no, it doesn't catch "Adult accidents"] from MS Developers' Studio and examined PING.EXE. I quickly discovered that it uses three functions from ICMP.DLL:

  • HANDLE IcmpCreateFile( void );
  • BOOL IcmpCloseHandle( HANDLE IcmpHandle );
  • DWORD IcmpSendEcho(
    • HANDLE IcmpHandle
    • IPAddr DestinationAddress
    • void * RequestData
    • WORD RequestSize
    • void * ReplyBuffer
    • DWORD ReplySize
    • DWORD Timeout
So you could use the Inline module [or, if you don't have a C compiler and can get someone to compile C::Dynalib, FFI, or Win32::API for you, then use one of those] to use these functions to perform ICMP pings under WinNT/Win2K without administrator rights.

Here is a paraphrase of the documentation for IcmpSendEcho():

It sends an ICMP echo request and returns one or more replies.

See Icmpapi.h. Uses ICMP.DLL.

IcmpHandle is returned by IcmpCreateFile() [duh].

DestinationAddress is the obvious. I haven't found the documentation on the structure of IPAddr just yet.

RequestData is the data to be included in the request (can be used to test for certain packet sizes, problematic data values, and/or to line up requests with responses).

RequestSize is the number of bytes in RequestData.

RequestOptions is NULL or points to the IP header options for the request. I haven't found the documentation on this struct either yet.

ReplyBuffer is the buffer for any replies. The buffer will contain one or more ICMP_ECHO_REPLY structures, followed by options and data.

ReplySize is the size (in bytes) of ReplyBuffer and must be at least 8+sizeof(ICMP_ECHO_REPLY) [8 is the size of an ICMP error message].

Timeout is the time in milliseconds.

The return value is the number of replies received and stored in the reply buffer or zero for failure. See $^E for failure reason.

I'll try to put something together to use these in the next few days.

        - tye (but my friends call me "Tye")

In reply to Net::Ping, the mini series by tye

Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":

  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.
  • Log In?

    What's my password?
    Create A New User
    [stevieb]: it's a reminder to re-inforce it :P
    [atcroft]: james28909: That particular questions was a bit of trick, actually (depending on the country you are in). More interesting is, if you are trying to subtract from an epoch time, for instance, you might have to consider when/if DST occurs for a location,
    [atcroft]: because you may have to adjust the number of seconds you change from an epoch from 86400 (not to mention leap seconds)....
    [atcroft]: james28909: Although if your program is using a database, you might be able to "pass the buck" to the database and ask it to do the date change for you....

    How do I use this? | Other CB clients
    Other Users?
    Others exploiting the Monastery: (3)
    As of 2017-04-29 04:37 GMT
    Find Nodes?
      Voting Booth?
      I'm a fool:

      Results (531 votes). Check out past polls.