<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="../feed.xsl" type="text/xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Susam's Networking Pages</title>
  <subtitle>Feed for Susam's Networking Pages</subtitle>
  <link href="https://susam.net/"/>
  <link href="https://susam.net/tag/networking.xml" rel="self"/>
  <id>https://susam.net/tag/networking.xml</id>
  <updated>2025-04-05T00:00:00Z</updated>
  <author><name>Susam Pal</name></author>
  <entry>
    <title>Hacker News Hug of Deaf</title>
    <link href="https://susam.net/hn-bell.html"/>
    <id>urn:uuid:94fda865-ecac-4354-a570-4e6fd18db614</id>
    <updated>2025-04-05T00:00:00Z</updated>
    <content type="html">
<!-- BEGIN HTML -->
&lt;blockquote&gt;
  &lt;p&gt;
    &quot;It&apos;s essentially the Hacker News Hug of Deaf.&quot;
    &amp;ndash;
    &lt;a href=&quot;https://news.ycombinator.com/item?id=30146019#30147639&quot;&gt;@TonyTrapp&lt;/a&gt;
  &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;
  About three years ago, I set up a tiny &lt;code&gt;netcat&lt;/code&gt; loop on
  one of my Debian servers to accept arbitrary connections from the
  Hacker News (HN) community.  The loop ran for 24 hours and did
  exactly three things whenever a client connected:
&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;
    Send a simple &lt;code&gt;ok&lt;/code&gt; message to the client.
  &lt;/li&gt;
  &lt;li&gt;
    Close the connection immediately.
  &lt;/li&gt;
  &lt;li&gt;
    Make my terminal beep four times.
  &lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
  That&apos;s it!  It was a playful experiment in response to a thread
  about quirky, do-it-yourself alerting systems for friends and
  family.  See
  &lt;a href=&quot;https://news.ycombinator.com/item?id=30146019#30146451&quot;&gt;this
  HN thread&lt;/a&gt; for the original discussion.  Here is the exact
  command I ran on my server:
&lt;/p&gt;
&lt;pre class=&quot;wrap&quot;&gt;&lt;code&gt;while true; do (echo ok | nc -q 1 -vlp 8000 2&amp;gt;&amp;amp;1; echo; date -u) | tee -a beeper.log; for i in 1 2 3 4; do printf &apos;\a&apos;; sleep 1; done &amp;amp; done&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
  The &lt;code&gt;nc&lt;/code&gt; command closes the connection immediately after
  sending the &lt;code&gt;ok&lt;/code&gt; message and runs an
  inner &lt;code&gt;for&lt;/code&gt; loop in a background shell that
  asynchronously prints the bell character to the terminal four times.
  Meanwhile, the outer &lt;code&gt;while&lt;/code&gt; command loops back quickly
  to run a new &lt;code&gt;nc&lt;/code&gt; process, thus making this one-liner
  script instantly ready to accept the next incoming connection.
&lt;/p&gt;
&lt;p&gt;
  Soon after I shared this, members of the HN community began
  connecting to the demo running on &lt;code&gt;susam.net:8000&lt;/code&gt;.
  Anyone on the Internet could use any client of their choice to
  connect.  Here&apos;s how I explained it in the HN thread:
&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;
    Now anytime someone connects to port 8000 of my system
    by &lt;em&gt;any&lt;/em&gt; means, I will hear 4 beeps!  The other party can
    use &lt;em&gt;whatever client&lt;/em&gt; they have to connect to port 8000 of
    my system, e.g. a web browser, &lt;code&gt;nc HOST
    8000&lt;/code&gt;, &lt;code&gt;curl HOST:8000&lt;/code&gt; or even &lt;code&gt;ssh HOST -p
    8000&lt;/code&gt;, &lt;code&gt;irssi -c HOST -p 8000&lt;/code&gt;, etc.
  &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;
  In the next 24 hours, I received over 4761 connections, each one
  triggering four beeps.  That&apos;s a total of 19&amp;#x202f;044 terminal
  beeps echoing throughout the day!
&lt;/p&gt;
&lt;figure class=&quot;soft&quot;&gt;
  &lt;img src=&quot;files/blog/beeper1.png&quot; alt=&quot;Graph&quot;&gt;
  &lt;figcaption&gt;
    Number of connections received every hour since 31 Jan 2022 10:00 UTC
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;
  The data for the above graph is available at
  &lt;a href=&quot;https://gist.github.com/susam/159c7d92659b3185eb0b0d683998a3b7&quot;&gt;beeper.log&lt;/a&gt;.
  Now, 4761 isn&apos;t a huge number in the grand scheme of things, but it
  was still pretty cool to see people notice an obscure comment buried
  in a regular HN thread, act on it and make my terminal beep
  thousands of time.
&lt;/p&gt;
&lt;p&gt;
  At the end of the day, this was a fun experiment.  Pointless, but
  fun!  Computing isn&apos;t always about solving problems.  Sometimes,
  it&apos;s also about exploring quirky ideas.  The joy is in the
  exploration and having others join in made it even more enjoyable.
  Activities like this keep computing fun for me!
&lt;/p&gt;
&lt;hr&gt;
&lt;p id=&quot;update-2025-04-10&quot;&gt;
  &lt;strong&gt;Update on 10 Apr 2025:&lt;/strong&gt;
  I &lt;a href=&quot;https://news.ycombinator.com/item?id=43642123&quot;&gt;shared
  this article on Hacker News&lt;/a&gt; today and saw another surge in
  connections to my beeper loop.
&lt;/p&gt;
&lt;figure class=&quot;soft&quot;&gt;
  &lt;img src=&quot;files/blog/beeper2.png&quot; alt=&quot;Graph&quot;&gt;
  &lt;figcaption&gt;
    Number of connections received every hour since 10 Apr 2025 10:00 UTC
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;
  The data for the above graph is available at
  &lt;a href=&quot;https://gist.github.com/susam/3cec5db1a78a9db527327460656daeae&quot;&gt;beeper2.log&lt;/a&gt;.
  The data shows a total of 352&amp;#x202f;831 connections from 1396
  unique client addresses over 14 hours.  That amounts to a total of
  1&amp;#x202f;411&amp;#x202f;324 beeps!  Much of the traffic seems to have
  come from persistent client loops constantly connecting to my beeper
  loop.  In particular, the client identified by the anonymised
  identifier C0276 made the largest number of connections by far, with
  327&amp;#x202f;209 total connections.  The second most active client,
  C0595, made only 6771 connections.  There were 491 clients that
  connected exactly once.  If you&apos;d like to see the number of
  connections by each client, see
  &lt;a href=&quot;https://gist.github.com/susam/d6766f4b722f899250a8f3da0c98f993&quot;&gt;beeperclient2.log&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
  In conclusion, the difference in the volume of connections between
  the earlier experiment and today&apos;s is striking.  In the first round,
  three years ago, there were only 4761 connections from some readers
  of a comment thread.  But in today&apos;s round, with this post being
  featured on the HN front page, there were 352&amp;#x202f;831
  connections!  It is fascinating to see how odd experiments like this
  can find so many participants within the HN community!
&lt;/p&gt;
<!-- ### -->
&lt;p&gt;
  &lt;a href="https://susam.net/hn-bell.html"&gt;Read on website&lt;/a&gt; |
  &lt;a href=&quot;https://susam.net/tag/absurd.html&quot;&gt;#absurd&lt;/a&gt; |
  &lt;a href=&quot;https://susam.net/tag/unix.html&quot;&gt;#unix&lt;/a&gt; |
  &lt;a href=&quot;https://susam.net/tag/shell.html&quot;&gt;#shell&lt;/a&gt; |
  &lt;a href=&quot;https://susam.net/tag/networking.html&quot;&gt;#networking&lt;/a&gt; |
  &lt;a href=&quot;https://susam.net/tag/technology.html&quot;&gt;#technology&lt;/a&gt;
&lt;/p&gt;
<!-- END HTML -->
    </content>
  </entry>
  <entry>
    <title>Pretty-Printing JSON Response with HTTP Headers</title>
    <link href="https://susam.net/pretty-print-json-response-with-http-headers.html"/>
    <id>urn:uuid:894ff191-0b1a-454a-8757-7aa3a94b94f2</id>
    <updated>2024-04-14T00:00:00Z</updated>
    <content type="html">
<!-- BEGIN HTML -->
&lt;p&gt;
  Often while using &lt;code&gt;curl&lt;/code&gt; with URLs that return a JSON
  response, I need to print the HTTP response headers along with the
  JSON response.  Here is an example that shows how this can be done:
&lt;/p&gt;
&lt;pre&gt;&lt;samp&gt;$ &lt;kbd&gt;curl -sSi https://susam.net/code/lab/json/books.json&lt;/kbd&gt;
HTTP/1.1 200 OK
Server: nginx/1.18.0
Date: Sat, 05 Apr 2024 11:53:24 GMT
Content-Type: application/json
Content-Length: 172
Last-Modified: Sat, 05 Apr 2024 11:53:05 GMT
Connection: keep-alive
ETag: &quot;67f119a1-ac&quot;
Accept-Ranges: bytes

[
  {&quot;title&quot;: &quot;Gulliver&apos;s Travels&quot;, &quot;author&quot;: &quot;Jonathan Swift&quot;, &quot;published&quot;: 1726},
  {&quot;title&quot;: &quot;Treasure Island&quot;, &quot;author&quot;: &quot;Robert Louis Stevenson&quot;, &quot;published&quot;: 1883}
]&lt;/samp&gt;&lt;/pre&gt;
&lt;p&gt;
  The above output is obtained using curl 7.77.0
  (x86_64-apple-darwin21.0).  The &lt;code&gt;-i&lt;/code&gt; option is
  responsible for including the HTTP response headers.
  The &lt;code&gt;-s&lt;/code&gt; and &lt;code&gt;-S&lt;/code&gt; options are not too
  important for the current discussion but I usually happen to use
  them out of habit.  The &lt;code&gt;-s&lt;/code&gt; option suppresses the
  progress meter and error messages but the &lt;code&gt;-S&lt;/code&gt; re-enables
  the display of error messages.  This helps me avoid the progress
  meter in the output without having to lose visibility of any errors
  that may arise.
&lt;/p&gt;
&lt;p&gt;
  So far so good!  But can we also have the JSON response
  pretty-printed with say &lt;code&gt;jq&lt;/code&gt;?  The above command prints
  both the HTTP headers and the response to the standard output, so
  piping the standard output to &lt;code&gt;jq&lt;/code&gt; does not work.
  The &lt;code&gt;jq&lt;/code&gt; command fails with an error as soon as it
  encounters the HTTP headers.
&lt;/p&gt;
&lt;p&gt;
  If, however, we manage to send the HTTP header and the response to
  different streams or files, then we could utilise &lt;code&gt;jq&lt;/code&gt; to
  pretty-print the stream or file that contains the JSON response.
  Here is an example that shows how to do this:
&lt;/p&gt;
&lt;pre&gt;&lt;samp&gt;$ &lt;kbd&gt;curl -sSD head.txt -o out.json https://susam.net/code/lab/json/books.json &amp;amp;&amp;amp; cat head.txt &amp;amp;&amp;amp; jq . out.json&lt;/kbd&gt;
HTTP/1.1 200 OK
Server: nginx/1.18.0
Date: Sat, 05 Apr 2024 11:53:51 GMT
Content-Type: application/json
Content-Length: 172
Last-Modified: Sat, 05 Apr 2024 11:53:05 GMT
Connection: keep-alive
ETag: &quot;67f119a1-ac&quot;
Accept-Ranges: bytes

[
  {
    &quot;title&quot;: &quot;Gulliver&apos;s Travels&quot;,
    &quot;author&quot;: &quot;Jonathan Swift&quot;,
    &quot;published&quot;: 1726
  },
  {
    &quot;title&quot;: &quot;Treasure Island&quot;,
    &quot;author&quot;: &quot;Robert Louis Stevenson&quot;,
    &quot;published&quot;: 1883
  }
]&lt;/samp&gt;&lt;/pre&gt;
&lt;p&gt;
  Alternatively, we can achieve this using a single command by
  printing the the HTTP headers to standard error.  This ensures that
  only the JSON response is printed to standard output, which we can
  then pretty-print using &lt;code&gt;jq&lt;/code&gt;.  Here is an example:
&lt;/p&gt;
&lt;pre&gt;&lt;samp&gt;$ &lt;kbd&gt;curl -sSD /dev/stderr https://susam.net/code/lab/json/books.json | jq .&lt;/kbd&gt;
HTTP/1.1 200 OK
Server: nginx/1.18.0
Date: Sat, 05 Apr 2024 11:54:12 GMT
Content-Type: application/json
Content-Length: 172
Last-Modified: Sat, 05 Apr 2024 11:53:05 GMT
Connection: keep-alive
ETag: &quot;67f119a1-ac&quot;
Accept-Ranges: bytes

[
  {
    &quot;title&quot;: &quot;Gulliver&apos;s Travels&quot;,
    &quot;author&quot;: &quot;Jonathan Swift&quot;,
    &quot;published&quot;: 1726
  },
  {
    &quot;title&quot;: &quot;Treasure Island&quot;,
    &quot;author&quot;: &quot;Robert Louis Stevenson&quot;,
    &quot;published&quot;: 1883
  }
]&lt;/samp&gt;&lt;/pre&gt;
<!-- ### -->
&lt;p&gt;
  &lt;a href="https://susam.net/pretty-print-json-response-with-http-headers.html"&gt;Read on website&lt;/a&gt; |
  &lt;a href=&quot;https://susam.net/tag/unix.html&quot;&gt;#unix&lt;/a&gt; |
  &lt;a href=&quot;https://susam.net/tag/shell.html&quot;&gt;#shell&lt;/a&gt; |
  &lt;a href=&quot;https://susam.net/tag/networking.html&quot;&gt;#networking&lt;/a&gt; |
  &lt;a href=&quot;https://susam.net/tag/technology.html&quot;&gt;#technology&lt;/a&gt;
&lt;/p&gt;
<!-- END HTML -->
    </content>
  </entry>
  <entry>
    <title>Toy Traceroute With Ping</title>
    <link href="https://susam.net/toy-traceroute-with-ping.html"/>
    <id>urn:uuid:0cb3604a-a142-4c9b-85ea-e948fc3450bd</id>
    <updated>2022-02-01T00:00:00Z</updated>
    <content type="html">
<!-- BEGIN HTML -->
&lt;p&gt;
  Here is an example of a toy traceroute using &lt;code&gt;ping&lt;/code&gt; on
  Linux:
&lt;/p&gt;
&lt;pre&gt;&lt;samp&gt;$ &lt;kbd&gt;for ttl in {1..30}; do ping -4 -c 1 -t $ttl example.com &amp;amp;&amp;amp; break; done | grep -i from | nl -s &apos; &apos; -w 2&lt;/kbd&gt;
 1 From router1-lon.linode.com (212.111.33.229) icmp_seq=1 Time to live exceeded
 2 From if-0-1-0-0-0.gw1.lon1.gb.linode.com (109.74.207.10) icmp_seq=1 Time to live exceeded
 3 From be5787.rcr51.lon10.atlas.cogentco.com (204.68.252.58) icmp_seq=1 Time to live exceeded
 4 From be2589.ccr41.lon13.atlas.cogentco.com (154.54.59.37) icmp_seq=1 Time to live exceeded
 5 From be2099.ccr31.bos01.atlas.cogentco.com (154.54.82.34) icmp_seq=1 Time to live exceeded
 6 From verizondms.bos01.atlas.cogentco.com (154.54.11.54) icmp_seq=1 Time to live exceeded
 7 From ae-66.core1.bsa.edgecastcdn.net (152.195.233.129) icmp_seq=1 Time to live exceeded
 8 64 bytes from 93.184.216.34 (93.184.216.34): icmp_seq=1 ttl=57 time=63.0 ms&lt;/samp&gt;&lt;/pre&gt;
&lt;p&gt;
  The output above was obtained on a Debian GNU/Linux 11.2 (bullseye)
  system.  The above loop sends multiple ICMP echo requests with
  different Time to Live (TTL) values to reach the host
  for &lt;code&gt;example.com&lt;/code&gt;.  The TTL occurs as an 8-bit field in
  the Internet Protocol (IP) header of each packet.  It is the 9th
  octet in an IPv4 header and the 8th octet in an IPv6 header.
&lt;/p&gt;
&lt;p&gt;
  When a router on the path to the destination receives a packet, it
  decrements the TTL value in the IP header by one.  If the TTL value
  becomes 0 after the decrement operation, the router responds with a
  &quot;time-to-live exceeded&quot; ICMP message.  Thus an echo request with TTL
  value set to 1 gets us an ICMP &quot;time-to-live exceeded&quot; message from
  the first router in the path, the next echo request with TTL value 2
  gets us a similar ICMP message from the second router in the path
  and so on.  The traceroute is complete when we receive a successful
  ICMP echo reply.
&lt;/p&gt;
&lt;p&gt;
  For comparison, here is the output of the
  actual &lt;code&gt;traceroute&lt;/code&gt; command:
&lt;/p&gt;
&lt;pre&gt;&lt;samp&gt;$ &lt;kbd&gt;traceroute example.com&lt;/kbd&gt;
traceroute to example.com (93.184.216.34), 30 hops max, 60 byte packets
 1  router1-lon.linode.com (212.111.33.229)  0.602 ms  1.202 ms  1.326 ms
 2  if-0-1-0-1-0.gw1.lon1.gb.linode.com (109.74.207.14)  0.502 ms if-11-1-0-0-0.gw2.lon1.gb.linode.com (109.74.207.26)  0.401 ms if-11-0-0-0-0.gw2.lon1.gb.linode.com (109.74.207.30)  0.379 ms
 3  be5787.rcr51.lon10.atlas.cogentco.com (204.68.252.58)  0.573 ms  0.563 ms  0.566 ms
 4  be2589.ccr41.lon13.atlas.cogentco.com (154.54.59.37)  1.271 ms  1.311 ms ldn-bb1-link.ip.twelve99.net (62.115.122.188)  1.400 ms
 5  be2099.ccr31.bos01.atlas.cogentco.com (154.54.82.34)  63.511 ms  63.540 ms nyk-bb1-link.ip.twelve99.net (62.115.112.244)  73.397 ms
 6  nyk-b1-link.ip.twelve99.net (62.115.135.131)  70.113 ms verizondms.bos01.atlas.cogentco.com (154.54.11.54)  63.657 ms nyk-b1-link.ip.twelve99.net (62.115.135.131)  70.190 ms
 7  ae-66.core1.bsa.edgecastcdn.net (152.195.233.129)  63.535 ms edgecast-ic317659-nyk-b6.ip.twelve99-cust.net (62.115.147.199)  77.802 ms ae-66.core1.bsa.edgecastcdn.net (152.195.233.129)  63.582 ms
 8  93.184.216.34 (93.184.216.34)  62.895 ms ae-71.core1.nyb.edgecastcdn.net (152.195.69.139)  72.312 ms ae-70.core1.nyb.edgecastcdn.net (152.195.68.141)  69.419 ms
 9  93.184.216.34 (93.184.216.34)  70.827 ms  62.896 ms  73.342 ms&lt;/samp&gt;&lt;/pre&gt;
&lt;p&gt;
  Each line in the output above corresponds to a hop.  Each line shows
  one or more addresses.  A maximum of three addresses can be seen in
  the result for each hop.  That is because there are multiple paths
  to the destination and the &lt;code&gt;traceroute&lt;/code&gt; command sends 3
  UDP probe packets by default for each hop.  In this manner, it ends
  up discovering multiple routes to the destination.  It is worth
  noting here that by default &lt;code&gt;traceroute&lt;/code&gt; sends UDP
  packets, not ICMP echo requests, with different TTL values as probe
  packets.  But the route discovery mechanism remains the same.  After
  sending each probe packet, it waits for ICMP &quot;time-to-live exceeded
  messages&quot; from the routers that fall in the path to the destination.
&lt;/p&gt;
&lt;p&gt;
  By comparing the two outputs above, we can see that the route found
  by the toy traceroute using &lt;code&gt;ping&lt;/code&gt; is one of the several
  routes found by the &lt;code&gt;traceroute&lt;/code&gt; command.
&lt;/p&gt;
&lt;p&gt;
  For those on macOS, the &lt;code&gt;ping&lt;/code&gt; command options need to be
  modified as follows:
&lt;/p&gt;
&lt;pre&gt;&lt;samp&gt;&lt;kbd&gt;for ttl in {1..30}; do ping -c 1 -t 1 -m $ttl example.com &amp;amp;&amp;amp; break; done | grep -i from | nl -s &apos; &apos; -w 2&lt;/kbd&gt;&lt;/samp&gt;&lt;/pre&gt;
&lt;p&gt;
  On macOS, the &lt;code&gt;-t&lt;/code&gt; option of the &lt;code&gt;ping&lt;/code&gt;
  command specifies a timeout (not IP TTL) that prevents it from
  waiting for too long for a successful echo reply which we don&apos;t
  expect to receive.  Further, on macOS, the &lt;code&gt;-m&lt;/code&gt; option of
  the &lt;code&gt;ping&lt;/code&gt; command specifies the IP TTL.
&lt;/p&gt;
<!-- ### -->
&lt;p&gt;
  &lt;a href="https://susam.net/toy-traceroute-with-ping.html"&gt;Read on website&lt;/a&gt; |
  &lt;a href=&quot;https://susam.net/tag/networking.html&quot;&gt;#networking&lt;/a&gt; |
  &lt;a href=&quot;https://susam.net/tag/protocol.html&quot;&gt;#protocol&lt;/a&gt; |
  &lt;a href=&quot;https://susam.net/tag/shell.html&quot;&gt;#shell&lt;/a&gt; |
  &lt;a href=&quot;https://susam.net/tag/technology.html&quot;&gt;#technology&lt;/a&gt;
&lt;/p&gt;
<!-- END HTML -->
    </content>
  </entry>
  <entry>
    <title>Simplicity of IRC</title>
    <link href="https://susam.net/simplicity-of-irc.html"/>
    <id>urn:uuid:0a61290e-283f-46f6-8602-6f2ac0b4904d</id>
    <updated>2022-01-09T00:00:00Z</updated>
    <content type="html">
<!-- BEGIN HTML -->
&lt;p&gt;
  During discussions with my friends and colleagues, whenever the
  topic of chat protocols comes up, I often remark how simple the
  Internet Relay Chat (IRC) protocol is and how this simplicity has
  fostered creativity in the lives of many young computer hobbyists
  growing up in the late 1990s and early 2000s.  For many of us who
  were introduced to the Internet during that time, writing an IRC bot
  turned out to be one of our first few non-trivial hobby programming
  projects that involved network sockets, did something meaningful and
  served actual users.
&lt;/p&gt;
&lt;h2 id=&quot;simplicity&quot;&gt;Simplicity&lt;/h2&gt;
&lt;p&gt;
  The underlying payloads that IRC servers and clients exchange during
  an IRC session are quite simple to read manually and understand.
  While implementing IRC servers still involves significant work to
  keep track of users and channels as well as exchanging network state
  and messages between servers, implementing IRC clients can often be
  quite simple.  With a convenient programming language, one can
  develop all kinds of fun tools and bots pretty quickly.  Only
  creativity is the limit!
&lt;/p&gt;
&lt;p&gt;
  In the early days of IRC, it was quite common for someone with basic
  programming skills to write a simple IRC bot within a matter of
  hours.  Such IRC bots typically responded to requests from users,
  answered frequently asked questions, hosted trivia quiz, etc.  The
  simplicity of the protocol made it very enticing to write programs
  that could talk to IRC servers directly.  In fact, many people chose
  to write the code to parse and create IRC payloads from scratch.
  Observing the TCP/IP packets with a packet analyser such as
  Wireshark or Tcpdump was all one needed to learn about the various
  payload formats.  Additionally, back then
  &lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc1459&quot;&gt;RFC 1459&lt;/a&gt; served
  as a good reference to learn the IRC specification.
&lt;/p&gt;
&lt;p&gt;
  As a result of the simplicity of the IRC protocol, sometimes when I
  wanted to join an IRC channel, say to seek some technical help, from
  a system without an IRC client installed, I would often just start
  a &lt;code&gt;telnet&lt;/code&gt;, &lt;code&gt;nc&lt;/code&gt; or &lt;code&gt;openssl&lt;/code&gt;
  connection directly to my favourite IRC network and type out IRC
  protocol commands by hand to join channels and talk to users.
&lt;/p&gt;
&lt;h2 id=&quot;session&quot;&gt;Session&lt;/h2&gt;
&lt;p&gt;
  To illustrate how simple the IRC protocol is, here is an example of
  a minimal IRC session that involves joining a channel and posting a
  message:
&lt;/p&gt;
&lt;pre&gt;&lt;samp&gt;$ &lt;kbd&gt;nc irc.libera.chat 6667&lt;/kbd&gt;
:strontium.libera.chat NOTICE * :*** Checking Ident
:strontium.libera.chat NOTICE * :*** Looking up your hostname...
:strontium.libera.chat NOTICE * :*** Couldn&apos;t look up your hostname
:strontium.libera.chat NOTICE * :*** No Ident response
&lt;kbd&gt;NICK humpty&lt;/kbd&gt;
&lt;kbd&gt;USER humpty humpty irc.libera.chat :Humpty Dumpty&lt;/kbd&gt;
:strontium.libera.chat 001 humpty :Welcome to the Libera.Chat Internet Relay Chat Network humpty
:strontium.libera.chat 002 humpty :Your host is strontium.libera.chat[204.225.96.123/6667], running version solanum-1.0-dev
:strontium.libera.chat 003 humpty :This server was created Sat Oct 30 2021 at 17:56:22 UTC
:strontium.libera.chat 004 humpty strontium.libera.chat solanum-1.0-dev DGQRSZaghilopsuwz CFILMPQSTbcefgijklmnopqrstuvz bkloveqjfI
:strontium.libera.chat 005 humpty MONITOR=100 CALLERID=g WHOX FNC ETRACE KNOCK SAFELIST ELIST=CMNTU CHANTYPES=# EXCEPTS INVEX CHANMODES=eIbq,k,flj,CFLMPQSTcgimnprstuz :are supported by this server
:strontium.libera.chat 005 humpty CHANLIMIT=#:250 PREFIX=(ov)@+ MAXLIST=bqeI:100 MODES=4 NETWORK=Libera.Chat STATUSMSG=@+ CASEMAPPING=rfc1459 NICKLEN=16 MAXNICKLEN=16 CHANNELLEN=50 TOPICLEN=390 DEAF=D :are supported by this server
:strontium.libera.chat 005 humpty TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,PRIVMSG:4,NOTICE:4,ACCEPT:,MONITOR: EXTBAN=$,ajrxz :are supported by this server
:strontium.libera.chat 251 humpty :There are 66 users and 48644 invisible on 25 servers
:strontium.libera.chat 252 humpty 35 :IRC Operators online
:strontium.libera.chat 253 humpty 11 :unknown connection(s)
:strontium.libera.chat 254 humpty 21561 :channels formed
:strontium.libera.chat 255 humpty :I have 3117 clients and 1 servers
:strontium.libera.chat 265 humpty 3117 4559 :Current local users 3117, max 4559
:strontium.libera.chat 266 humpty 48710 50463 :Current global users 48710, max 50463
:strontium.libera.chat 250 humpty :Highest connection count: 4560 (4559 clients) (301752 connections received)
:strontium.libera.chat 375 humpty :- strontium.libera.chat Message of the Day -
:strontium.libera.chat 372 humpty :- Welcome to Libera Chat, the IRC network for
:strontium.libera.chat 372 humpty :- free &amp;amp; open-source software and peer directed projects.
:strontium.libera.chat 372 humpty :-
:strontium.libera.chat 372 humpty :- Use of Libera Chat is governed by our network policies.
:strontium.libera.chat 372 humpty :-
:strontium.libera.chat 372 humpty :- To reduce network abuses we perform open proxy checks
:strontium.libera.chat 372 humpty :- on hosts at connection time.
:strontium.libera.chat 372 humpty :-
:strontium.libera.chat 372 humpty :- Please visit us in #libera for questions and support.
:strontium.libera.chat 372 humpty :-
:strontium.libera.chat 372 humpty :- Website and documentation:  https://libera.chat
:strontium.libera.chat 372 humpty :- Webchat:                    https://web.libera.chat
:strontium.libera.chat 372 humpty :- Network policies:           https://libera.chat/policies
:strontium.libera.chat 372 humpty :- Email:                      support@libera.chat
:strontium.libera.chat 376 humpty :End of /MOTD command.
:humpty MODE humpty :+iw
&lt;kbd&gt;JOIN #test&lt;/kbd&gt;
:humpty!~humpty@178.79.176.169 JOIN #test
:strontium.libera.chat 353 humpty = #test :humpty susam coolnickname ptl-tab edcragg
:strontium.libera.chat 366 humpty #test :End of /NAMES list.
&lt;kbd&gt;PRIVMSG #test :Hello, World!&lt;/kbd&gt;
:susam!~susam@user/susam PRIVMSG #test :Hello, Humpty!
&lt;kbd&gt;PART #test&lt;/kbd&gt;
:humpty!~humpty@178.79.176.169 PART #test
&lt;kbd&gt;QUIT&lt;/kbd&gt;
:humpty!~humpty@178.79.176.169 QUIT :Client Quit
ERROR :Closing Link: 178.79.176.169 (Client Quit)&lt;/samp&gt;&lt;/pre&gt;
&lt;p&gt;
  In the above session, the user connects to the Libera Chat network
  with the nickname &lt;code&gt;humpty&lt;/code&gt;, joins a channel
  named &lt;code&gt;#test&lt;/code&gt; and posts a message.
&lt;/p&gt;
&lt;p&gt;
  Note that the above session is not encrypted.  By convention, IRC
  port 6667 is used for cleartext connections.  A separate port, such
  as port 6697, is available for encrypted connections.  Here is an
  example of an encrypted IRC session established with the OpenSSL
  command line tool:
&lt;/p&gt;
&lt;pre&gt;&lt;samp&gt;$ &lt;kbd&gt;openssl s_client -quiet -connect irc.libera.chat:6697 2&amp;gt; /dev/null&lt;/kbd&gt;
:strontium.libera.chat NOTICE * :*** Checking Ident
:strontium.libera.chat NOTICE * :*** Looking up your hostname...
:strontium.libera.chat NOTICE * :*** Couldn&apos;t look up your hostname
:strontium.libera.chat NOTICE * :*** No Ident response
NICK humpty
USER humpty humpty irc.libera.chat :Humpty Dumpty
:strontium.libera.chat 001 humpty :Welcome to the Libera.Chat Internet Relay Chat Network humpty
...&lt;/samp&gt;&lt;/pre&gt;
&lt;p&gt;
  The ellipsis denotes lines omitted for the sake of brevity.  The
  remainder of the session is quite similar to the first example in
  this post.
&lt;/p&gt;
&lt;p&gt;
  It is worth noting here that although the payload format of IRC
  protocol is quite simple, as one starts writing IRC clients, one
  would stumble upon several tiny details about the protocol that
  needs to be taken care of, e.g. authenticating to the network,
  responding to &lt;code&gt;PING&lt;/code&gt; messages from the server to avoid
  ping timeouts, splitting messages into shorter messages so that the
  overall payload does not exceed the message length limit of 512
  characters, etc.  For a serious IRC client, relying on a suitable
  library that already solves these problems and implements the IRC
  specification accurately is of course going to be useful.  But for a
  hobbyist who wants to understand the protocol and write some tools
  for fun, the textual nature of the IRC protocol and its simplicity
  offers a fertile ground for experimentation and creativity.
&lt;/p&gt;
&lt;h2 id=&quot;join&quot;&gt;Join&lt;/h2&gt;
&lt;p&gt;
  In case you have never used IRC but this post has piqued your
  interest and you want to try it out, you probably don&apos;t want to be
  typing out IRC payloads by hand.  You would want a good IRC client
  instead.  Let me share some convenient ways to connect to the Libera
  Chat network.  Say, you want to join the &lt;code&gt;#python&lt;/code&gt;
  channel on Libera Chat network.  Here are some ways to do it:
&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;
      Join via web interface:
      &lt;a href=&quot;https://web.libera.chat/#python&quot;&gt;web.libera.chat/#python&lt;/a&gt;.
    &lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;
      Join using Irssi: On macOS, run &lt;code&gt;brew install irssi&lt;/code&gt;
      to install it.  On Debian, Ubuntu or a Debian-based Linux
      system, run &lt;code&gt;sudo apt-get install irssi&lt;/code&gt;.  Then
      enter &lt;code&gt;irssi -c irc.libera.chat&lt;/code&gt; to connect to Libera
      Chat.  Then within Irssi, type &lt;code&gt;/join #python&lt;/code&gt;.
    &lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
  There are numerous other ways to join IRC networks.  There are GUI
  desktop clients, web browser plugins, Emacs plugins, web-based
  services, bouncers, etc. that let users connect to IRC networks in
  various ways.  On Libera Chat, there are various channels for open
  source projects (&lt;code&gt;#emacs&lt;/code&gt;, &lt;code&gt;#linux&lt;/code&gt;, etc.),
  communities around specific subjects (&lt;code&gt;##math&lt;/code&gt;,
  &lt;code&gt;#physics&lt;/code&gt;, etc.), programming languages
  (&lt;code&gt;#c&lt;/code&gt;, &lt;code&gt;#c++&lt;/code&gt;, &lt;code&gt;#commonlisp&lt;/code&gt;,
  etc.).  Type the &lt;code&gt;/join&lt;/code&gt; command followed by a space and
  the channel name to join a channel and start posting and reading
  messages there.  It is also possible to search for channels by
  channel names.  For example, on Libera Chat, to search for all
  channels with &apos;python&apos; in its name, enter the IRC
  command: &lt;code&gt;/msg alis list python&lt;/code&gt;.
&lt;/p&gt;
&lt;p&gt;
  Although I have used Libera Chat in the examples above, there are
  plenty of other IRC networks too such as EFNet, DALNet, OFTC, etc.
  Libera Chat happens to be one of the very popular and active
  networks for open source projects and topic based communities.  I
  use it everyday, so I chose it for the examples here.  There are
  many tight-knit communities on Libera Chat.  Some of my favourite
  ones are &lt;code&gt;#commonlisp&lt;/code&gt;, &lt;code&gt;#emacs&lt;/code&gt;,
  &lt;code&gt;#python&lt;/code&gt;, etc.  All of these have very nice and active
  communities with great attitudes towards beginners.
&lt;/p&gt;
<!-- ### -->
&lt;p&gt;
  &lt;a href="https://susam.net/simplicity-of-irc.html"&gt;Read on website&lt;/a&gt; |
  &lt;a href=&quot;https://susam.net/tag/irc.html&quot;&gt;#irc&lt;/a&gt; |
  &lt;a href=&quot;https://susam.net/tag/networking.html&quot;&gt;#networking&lt;/a&gt; |
  &lt;a href=&quot;https://susam.net/tag/protocol.html&quot;&gt;#protocol&lt;/a&gt; |
  &lt;a href=&quot;https://susam.net/tag/technology.html&quot;&gt;#technology&lt;/a&gt; |
  &lt;a href=&quot;https://susam.net/tag/retrospective.html&quot;&gt;#retrospective&lt;/a&gt;
&lt;/p&gt;
<!-- END HTML -->
    </content>
  </entry>
  <entry>
    <title>Sinkholed</title>
    <link href="https://susam.net/sinkholed.html"/>
    <id>urn:uuid:e18668e4-2b24-42d8-a1d4-f5d757dffad1</id>
    <updated>2019-12-03T00:00:00Z</updated>
    <content type="html">
<!-- BEGIN HTML -->
&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;
  On 26 Nov 2019 at 14:55 UTC, I logged into my server that hosts my
  website to perform a simple maintenance activity.  Merely three
  minutes later, at 14:58 UTC, the domain
  name &lt;a href=&quot;https://susam.in/&quot;&gt;susam.in&lt;/a&gt; used to host this
  website was transferred to another registrant without any
  authorisation by me or without any notification sent to me.  Since
  the DNS results for this domain name was cached on my system, I was
  unaware of this issue at that time.  It would take me three days to
  realise that I had lost control of the domain name I had been using
  for my website for the last 12 years.  This blog post documents when
  this happened, how this happened and what it took to regain control
  of this domain name.
&lt;/p&gt;
&lt;h2 id=&quot;contents&quot;&gt;Contents&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;#introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#domain-name-transfer&quot;&gt;Domain Name Transfer&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#avalanche-botnet&quot;&gt;Avalanche Botnet&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#support-ticket&quot;&gt;Support Ticket&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#tweets-and-retweets&quot;&gt;Tweets and Retweets&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#domain-name-return&quot;&gt;Domain Name Return&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;domain-name-transfer&quot;&gt;Domain Name Transfer&lt;/h2&gt;
&lt;p&gt;
  On 29 Nov 2019 at 19:00 UTC, when I visited my website hosted at
  &lt;a href=&quot;https://susam.in&quot;&gt;https://susam.in/&lt;/a&gt;, I found that a
  zero-byte file was being served at this URL.  My website was
  missing.  In fact, the domain name resolved to an IPv4 address I was
  unfamiliar with.  It did not resolve to the address of my Linode
  server anymore.
&lt;/p&gt;
&lt;p&gt;
  I checked the WHOIS records for this domain name.  To my
  astonishment, I found that I was no longer the registrant of this
  domain.  An entity named The Verden Public Prosecutor&apos;s Office was
  the new registrant of this domain.  The WHOIS records showed that
  the domain name was transferred to this organisation on 26 Nov 2019
  at 14:58 UTC, merely three minutes after I had performed my
  maintenance activity on the same day.  Here is a snippet of the
  WHOIS records that I found:
&lt;/p&gt;
&lt;pre id=&quot;whois&quot;&gt;
&lt;samp&gt;Domain Name: susam.in
Registry Domain ID: D2514002-IN
Registrar WHOIS Server:
Registrar URL:
Updated Date: 2019-11-26T14:58:00Z
Creation Date: 2007-05-15T07:19:26Z
Registry Expiry Date: 2020-05-15T07:19:26Z
Registrar: NIXI Special Projects
Registrar IANA ID: 700066
Registrar Abuse Contact Email:
Registrar Abuse Contact Phone:
Domain Status: clientTransferProhibited http://www.icann.org/epp#clientTransferProhibited
Domain Status: serverRenewProhibited http://www.icann.org/epp#serverRenewProhibited
Domain Status: serverDeleteProhibited http://www.icann.org/epp#serverDeleteProhibited
Domain Status: serverUpdateProhibited http://www.icann.org/epp#serverUpdateProhibited
Domain Status: serverTransferProhibited http://www.icann.org/epp#serverTransferProhibited
Registry Registrant ID:
Registrant Name:
Registrant Organization: The Verden Public Prosecutor&apos;s Office
Registrant Street:
Registrant Street:
Registrant Street:
Registrant City:
Registrant State/Province: Niedersachsen
...
Name Server: sc-c.sinkhole.shadowserver.org
Name Server: sc-d.sinkhole.shadowserver.org
Name Server: sc-a.sinkhole.shadowserver.org
Name Server: sc-b.sinkhole.shadowserver.org
...&lt;/samp&gt;&lt;/pre&gt;
&lt;p&gt;
  The ellipsis denotes some records I have omitted for the sake of
  brevity.  There were three things that stood out in these records:
&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;
    The registrar was changed from eNom, Inc. to NIXI Special Projects.
  &lt;/li&gt;
  &lt;li&gt;
    The registrant was changed from Susam Pal to The Verden Public
    Prosecutor&apos;s Office.
  &lt;/li&gt;
  &lt;li&gt;
    The name servers were changed from Linode&apos;s servers to
    Shadowserver&apos;s sinkholes.
  &lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;avalanche-botnet&quot;&gt;Avalanche Botnet&lt;/h2&gt;
&lt;p&gt;
  On searching more about the new registrant on the web, I realised
  that it was a German criminal justice body that was involved in the
  takedown of the &lt;a href=&quot;https://en.wikipedia.org/wiki/Avalanche_(phishing_group)&quot;&gt;Avalanche&lt;/a&gt;
  malware-hosting network.  It took a four-year concerted effort by
  INTERPOL, Europol, the Shadowserver Foundation, Eurojust, the
  Luneberg Police and several other international organisations to
  finally destroy the Avalanche botnet on 30 Nov 2016.  In this list
  of organisations, one name caught my attention immediately: The
  Shadowserver Foundation.  The WHOIS name server records pointed to
  Shadowserver&apos;s sinkholes.
&lt;/p&gt;
&lt;p&gt;
  The fact that the domain name was transferred to another
  organisation merely three minutes after I had performed a simple
  maintenance activity got me worried.  Was the domain name hijacked?
  Did my maintenance activity on the server have anything to do with
  it?  What kind of attack one might have pulled off to hijack the
  domain name?  I checked all the logs and there was no evidence that
  anyone other than me had logged into the server or executed any
  command or code on it.  Further, a domain name transfer usually
  involves email notification and authorisation.  None of that had
  happened.  It increasingly looked like that the three minute
  interval between the maintenance activity and the domain name
  transfer was merely a coincidence.
&lt;/p&gt;
&lt;p&gt;
  More questions sprang up as I thought about it.  The Avalanche
  botnet was destroyed in 2016.  What has that got to do with the
  domain name being transferred in 2019?  Did my server somehow become
  part of the Avalanche botnet?  My server ran a minimal installation
  of the latest Debian GNU/Linux system.  It was always kept
  up-to-date to minimise the risk of malware infection or security
  breach.  It hosted a static website composed of static HTML files
  served with Nginx.  I found no evidence of unauthorised access of my
  server while inspecting the logs.  I could not find any malware on
  the system.
&lt;/p&gt;
&lt;p&gt;
  The presence of Shadowserver sinkhole name servers in the WHOIS
  records was a good clue.  Sinkholing of a domain name can be done
  both malicously as well as constructively.  In this case, it looked
  like the Shadowserver Foundation intended to sinkhole the domain
  name constructively, so that any malware client trying to connect to
  my server nefariously would end up connecting to a sinkhole address
  instead.  My domain name was sinkholed!  The question now was: Why
  was it sinkholed?
&lt;/p&gt;
&lt;h2 id=&quot;support-ticket&quot;&gt;Support Ticket&lt;/h2&gt;
&lt;p&gt;
  On 29 Nov 2019 at 19:29 UTC, I submitted a support ticket to
  Namecheap to report this issue.  At 21:05 UTC, I received a response
  from Namecheap support that they have contacted Enom, their upstream
  registrar, to discuss the issue.  There was no estimate for when a
  resolution might be available.
&lt;/p&gt;
&lt;p&gt;
  At 21:21 UTC, I submitted a domain name
  &lt;a href=&quot;https://forms.icann.org/en/resources/compliance/complaints/transfer/form&quot;&gt;transfer complaint&lt;/a&gt;
  to the Internet Corporation for Assigned Names and Numbers (ICANN).  I
  was not expecting any response from ICANN because they do not have any
  contractual authority on a country code top-level domain (ccTLD).
&lt;/p&gt;
&lt;p&gt;
  At 21:23 UTC, I emailed National Internet Exchange of India (NIXI).
  NIXI is the ccTLD manager for .IN domain and they have authority on
  it.  I found their contact details from
  the &lt;a href=&quot;https://www.iana.org/domains/root/db/in.html&quot;&gt;IANA
  Delegation Record for .IN&lt;/a&gt;.  Again, I was not expecting a
  response from NIXI because they do not have any contractual
  relationship directly with me.  They have a contractual relationship
  with Namecheap, so any communication from them would be received by
  Namecheap and Namecheap would have to pass that on to me.
&lt;/p&gt;
&lt;p&gt;
  At 21:30 UTC, ICANN responded and said that I should contact the
  ccTLD manager directly.  Like I explained in the previous paragraph,
  I had already done that, so there was nothing more for me to do
  except wait for Namecheap to provide an update after their
  investigation.  By the way, NIXI never replied to my email.
&lt;/p&gt;
&lt;h2 id=&quot;tweets-and-retweets&quot;&gt;Tweets and Retweets&lt;/h2&gt;
&lt;p&gt;
  On 30 Nov 2019 at 07:30 UTC, I
  &lt;a href=&quot;https://twitter.com/susam/status/1200678538254393345&quot;&gt;shared
  this issue on Twitter&lt;/a&gt;.  I was hoping that someone who had been
  through a similar experience could offer some advice.  In fact, soon
  after I posted the tweet, a kind person named Max from Germany
  generously
  &lt;a href=&quot;https://twitter.com/LTE_Max/status/1200699507631112193&quot;&gt;offered
  to help&lt;/a&gt; by writing a letter in German addressed to the new
  registrant which was a German organisation.  The reason for
  sinkholing my domain name was still unclear.  I hoped that with
  enough number of retweets someone closer to the source of truth
  could shed some light on why and how this happened.
&lt;/p&gt;
&lt;p&gt;
  At 09:54 UTC, Richard Kirkendall, founder and CEO of Namecheap,
  &lt;a href=&quot;https://twitter.com/NamecheapCEO/status/1200714718610153472&quot;&gt;responded&lt;/a&gt;
  to my tweet and informed that they were contacting NIXI regarding
  the issue.  This seemed like a good step towards resolution.  After
  all, the domain name was no longer under their upstream registrar
  named Enom.  The domain name was now with NIXI as evident from
  the &lt;a href=&quot;#whois&quot;&gt;WHOIS records&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
  Several other users tweeted about my issue, added more information
  about what might have happened and retweeted my tweet.
&lt;/p&gt;
&lt;p&gt;
  On 1 Dec 2019 at 11:48 UTC, Benedict Addis from the Shadowserver
  Foundation contacted me by email.  He said that they had begun
  looking into this issue as soon as one of the tweets about this
  issue had referred to their organisation.  He explained in his email
  that my domain name was sinkholed accidentally as part of their
  Avalanche operation.  Although it is now three years since the
  initial takedown of the botnet, they still see over 3.5 million
  unique IP addresses connecting to their sinkholes everyday.
  Unfortunately, their operation inadvertently flagged my domain name
  as one of the domain names to be sinkholed because it matched the
  pattern of command and control (C2) domain names generated by a
  malware family named Nymaim, one of the malware families hosted on
  Avalanche.  Although, they had validity checks to avoid sinkholing
  false-positives, my domain name unfortunately slipped through those
  checks.  Benedict mentioned that he had just raised this issue with
  NIXI and requested them to return the domain name to me as soon as
  possible.
&lt;/p&gt;
&lt;h2 id=&quot;domain-name-return&quot;&gt;Domain Name Return&lt;/h2&gt;
&lt;p&gt;
  On 2 Dec 2019 at 04:00 UTC, when I looked up the WHOIS records for
  the domain name, I found that it had been returned to me already.
  At 08:37 UTC, Namecheap support responded to my support ticket to
  say that they had been informed that NIXI had returned the domain
  name to its original state.  At 09:55 UTC, Juliya Zinovjeva, Domains
  Product Manager of Namecheap,
  &lt;a href=&quot;https://twitter.com/JuliyaZinovjeva/status/1201439676118290432&quot;&gt;commented
  on Twitter&lt;/a&gt; and confirmed the same thing.
&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;
  Despite the successful resolution, it was still quite unsettling
  that a domain name could be transferred to another registrant and
  sinkholed for some perceived violation.  I thought there would be
  more checks in place to confirm that a perceived violation was real
  before a domain name could be transferred.  Losing a domain name I
  have been using actively for 12 years was an unpleasant experience.
  Losing a domain name accidentally should have been a lot harder than
  this.  Benedict from the Shadowserver Foundation assured me that my
  domain name would be excluded from future sinkholing for this
  particular case.  However, the possibility that this could happen
  again due to another unrelated operation by another organisation in
  future is disconcerting.
&lt;/p&gt;
&lt;p&gt;
  I also wondered if a domain name under a country code top-level
  domain (ccTLD) like .in is more susceptible to this kind of
  sinkholing than a domain name under a generic top-level domain
  (gTLD) like .com.  I asked Benedict if it is worth migrating my
  website from .in to .com.  He replied that in his personal opinion,
  NIXI runs an excellent, clean registry and are very responsive in
  resolving issues when they arise.  He also added that domain
  generation algorithms (DGAs) of malware are equally or possibly even
  more problematic for .com domains.  He advised against migrating my
  website.
&lt;/p&gt;
&lt;p&gt;
  Thanks to everyone who retweeted my
  &lt;a href=&quot;https://twitter.com/susam/status/1200678538254393345&quot;&gt;tweet&lt;/a&gt;
  on this issue.  Also, thanks to Richard Kirkendall (CEO of
  Namecheap), Namecheap support team and Benedict Addis from the
  Shadowserver Foundation for contacting NIXI to resolve this issue.
&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;
  &lt;em&gt;
    &lt;strong&gt;Update on 06 Jan 2022:&lt;/strong&gt; Nearly two years after
    this incident, I eventually moved this website to
    &lt;a href=&quot;https://susam.net/&quot;&gt;susam.net&lt;/a&gt;.  The decision to do
    so was not influenced by this incident.  I wanted this domain name
    since 2006 but it was unavailable back then.  This domain name
    became available only very recently and I moved my website to this
    domain as soon as it became available.
  &lt;/em&gt;
&lt;/p&gt;
<!-- ### -->
&lt;p&gt;
  &lt;a href="https://susam.net/sinkholed.html"&gt;Read on website&lt;/a&gt; |
  &lt;a href=&quot;https://susam.net/tag/networking.html&quot;&gt;#networking&lt;/a&gt; |
  &lt;a href=&quot;https://susam.net/tag/protocol.html&quot;&gt;#protocol&lt;/a&gt; |
  &lt;a href=&quot;https://susam.net/tag/technology.html&quot;&gt;#technology&lt;/a&gt;
&lt;/p&gt;
<!-- END HTML -->
    </content>
  </entry>
  <entry>
    <title>File Transfer with SSH, Tee and Base64</title>
    <link href="https://susam.net/file-transfer-with-ssh-tee-and-base64.html"/>
    <id>urn:uuid:408a9050-d803-4630-a70e-9444052cb6bb</id>
    <updated>2019-11-19T00:00:00Z</updated>
    <content type="html">
<!-- BEGIN HTML -->
&lt;p&gt;
  Computer servers deployed in a secure environment may allow SSH
  sessions but forbid SCP, SFTP and execution of remote commands
  without a login shell.  Such restricted access is typically enforced
  with SSH gateways and firewalls.  An SSH gateway provides controlled
  access to the remote system.  A firewall can ensure that only an SSH
  gateway can connect to the remote system.  Thus, users can be forced
  to connect to the remote system only via the SSH gateway which can
  now control what is allowed and what isn&apos;t.
&lt;/p&gt;
&lt;p&gt;
  Even if SCP, SFTP, port forwarding and remote command execution
  without a login shell are forbidden, as long as we get a login shell
  on our terminal and we can print data on the terminal, we are
  already able to transfer data from the remote system to our local
  system.  The data is in the terminal.  It is now only a matter of
  figuring out how to copy that data to a file.
&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;
  &lt;p&gt;
    &lt;strong&gt;Note:&lt;/strong&gt; Various readers of this post notice that
    SCP or SFTP is not allowed and immediately begin suggesting me a
    solution similar to one of the following ones:
  &lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;code&gt;ssh HOST cat file &amp;gt; file&lt;/code&gt;&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;ssh HOST tar cf - file | tar xf -&lt;/code&gt;&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p&gt;
    Note that these solutions and other similar solutions are not
    going to work because the SSH gateway described in the previous
    two paragraphs forbids remote command execution without a login
    shell.  It also blocks port forwarding, so any solution involving
    port forwarding is not going to work either.
  &lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;
  Assuming that both the remote and local systems are Unix-like, the
  following steps show one way to accomplish copying a file from the
  remote system to our local system:
&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;
      Connect to the remote system with &lt;code&gt;ssh&lt;/code&gt; and pipe the
      output to &lt;code&gt;tee&lt;/code&gt; to write the entire session to a text
      file on the local system.
    &lt;/p&gt;
    &lt;pre&gt;&lt;code&gt;ssh HOST | tee ssh.txt&lt;/code&gt;&lt;/pre&gt;
    &lt;p&gt;
      This type of pipeline works as intended even while connecting to
      a remote system via a jumphost or an SSH gateway.
    &lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;
      In the remote system, create a 10 MB file to serve as an example
      payload to be transferred.
    &lt;/p&gt;
    &lt;pre&gt;&lt;code&gt;head -c 10485760 /dev/urandom &amp;gt; /tmp/payload&lt;/code&gt;&lt;/pre&gt;
    &lt;p&gt;
      You probably already have a meaningful payload that you want to
      copy, so in that case, you would skip this step.
    &lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;
      Compute checksum on the file.  This will be used later to verify
      that the entire file is transferred correctly.
    &lt;/p&gt;
    &lt;pre&gt;&lt;code&gt;sha1sum /tmp/payload&lt;/code&gt;&lt;/pre&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;
      Print Base64 representation of the file.
    &lt;/p&gt;
    &lt;pre&gt;&lt;code&gt;base64 /tmp/payload&lt;/code&gt;&lt;/pre&gt;
    &lt;p&gt;
      Depending on the Internet bandwidth, this can take a few seconds
      to a few minutes to complete.
    &lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;
      End the SSH session.
    &lt;/p&gt;
    &lt;pre&gt;&lt;code&gt;exit&lt;/code&gt;&lt;/pre&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;
      On the local system, extract the Base64 encoded payload and
      decode it.  Assuming the shell prompt on the remote system ends
      with the dollar sign (i.e. &lt;code&gt;$&lt;/code&gt;), the following
      command does this.
    &lt;/p&gt;
    &lt;pre&gt;&lt;code&gt;sed &apos;1,/$ base64/d;/$ exit/,$d&apos; ssh.txt | base64 --decode &amp;gt; payload&lt;/code&gt;&lt;/pre&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;
      Extract the checksum computed on the original file.
    &lt;/p&gt;
    &lt;pre&gt;&lt;code&gt;grep -A 1 sha1sum ssh.txt&lt;/code&gt;&lt;/pre&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;
      Compute checksum on the decoded payload.
    &lt;/p&gt;
    &lt;pre&gt;&lt;code&gt;sha1sum payload&lt;/code&gt;&lt;/pre&gt;
    &lt;p&gt;
      Ensure that the checksum in this step matches the checksum in
      the previous step.
    &lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
  The steps above assume the use of the &lt;code&gt;sha1sum&lt;/code&gt; command
  to compute checksum.  If this command is unavailable, use
  &lt;code&gt;sha1&lt;/code&gt;, &lt;code&gt;shasum&lt;/code&gt; or something else that serves
  this purpose well.  If you are worried about collision attacks, you
  might want &lt;code&gt;sha256sum&lt;/code&gt;, &lt;code&gt;sha256&lt;/code&gt;, &lt;code&gt;shasum
  -a 256&lt;/code&gt;, etc. instead.
&lt;/p&gt;
<!-- ### -->
&lt;p&gt;
  &lt;a href="https://susam.net/file-transfer-with-ssh-tee-and-base64.html"&gt;Read on website&lt;/a&gt; |
  &lt;a href=&quot;https://susam.net/tag/networking.html&quot;&gt;#networking&lt;/a&gt; |
  &lt;a href=&quot;https://susam.net/tag/protocol.html&quot;&gt;#protocol&lt;/a&gt; |
  &lt;a href=&quot;https://susam.net/tag/technology.html&quot;&gt;#technology&lt;/a&gt;
&lt;/p&gt;
<!-- END HTML -->
    </content>
  </entry>
  <entry>
    <title>Zero Point Leet Seconds</title>
    <link href="https://susam.net/zero-point-leet-seconds.html"/>
    <id>urn:uuid:db757c68-f2bc-4add-a240-2fae8f844e3e</id>
    <updated>2018-09-18T00:00:00Z</updated>
    <content type="html">
<!-- BEGIN HTML -->
&lt;p&gt;
  While calculating certain round-trip times, here is a number I came
  across that is surprisingly memorable: It takes light 0.1337 seconds
  to travel the length of the Earth&apos;s equator via vacuum or air.  Let
  me repeat that.  It takes light &quot;zero point leet&quot; seconds to travel
  once around the equator.
&lt;/p&gt;
&lt;p&gt;
  We are going to ignore practical considerations regarding how light
  would actually follow a curved path around the Earth&apos;s equator via
  vacuum or air.  This allows us to find the minimum time that any
  signal must take in order to complete a round trip around the Earth.
  Despite the lack of practicality, this is an interesting result
  because it provides us a theoretical limit for the shortest time
  interval between sending a signal and receiving it after it has made
  a complete trip around the world.
&lt;/p&gt;
&lt;p&gt;
  The equatorial radius of the Earth is about 6378.137 km.  The
  equatorial circumference of the Earth then is about 40075 km.  The
  speed of light in vacuum is 299792.458 km/s by definition.  The
  speed of light in air is about 299705 km/s.  Therefore, it takes
  light about 40075/299792.458 seconds in vacuum and about
  40075/299705 seconds in air to travel once around the equator.  Both
  values can be written as 0.1337 seconds accurate up to 4 decimal
  places.
&lt;/p&gt;
<!-- ### -->
&lt;p&gt;
  &lt;a href="https://susam.net/zero-point-leet-seconds.html"&gt;Read on website&lt;/a&gt; |
  &lt;a href=&quot;https://susam.net/tag/networking.html&quot;&gt;#networking&lt;/a&gt; |
  &lt;a href=&quot;https://susam.net/tag/technology.html&quot;&gt;#technology&lt;/a&gt;
&lt;/p&gt;
<!-- END HTML -->
    </content>
  </entry>
  <entry>
    <title>AUTH CRAM-MD5</title>
    <link href="https://susam.net/auth-cram-md5.html"/>
    <id>urn:uuid:cca4534a-ea20-4dd4-9e04-1236ec3bec92</id>
    <updated>2011-11-07T00:00:00Z</updated>
    <content type="html">
<!-- BEGIN HTML -->
&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;
  Last night, while I was setting up my SMTP server, I decided to dig
  deeper into CRAM-MD5 authentication mechanism.  It is a
  challenge-response authentication mechanism and involves HMAC-MD5.
  We don&apos;t use SSL/TLS in the SMTP session examples below in order to
  show the underlying protocol in clear.  In practice, any email
  program should be configured to use SSL/TLS while having a session
  with an SMTP server.  We will first see a few examples of other
  authentication mechanisms before discussing the CRAM-MD5 mechanism.
&lt;/p&gt;
&lt;h2 id=&quot;auth-plain&quot;&gt;AUTH PLAIN&lt;/h2&gt;
&lt;p&gt;
  Here is an example of a session that uses the PLAIN authentication
  mechanism:
&lt;/p&gt;
&lt;pre&gt;&lt;samp&gt;$ &lt;kbd&gt;telnet susam.in 25&lt;/kbd&gt;
Trying 106.187.41.241...
Connected to susam.in.
Escape character is &apos;^]&apos;.
220 tesseract.susam.in ESMTP Exim 4.72 Mon, 07 Nov 2011 20:27:56 +0530
&lt;kbd&gt;EHLO nifty.localdomain&lt;/kbd&gt;
250-tesseract.susam.in Hello nifty.localdomain [122.167.80.194]
250-SIZE 52428800
250-PIPELINING
250-AUTH PLAIN LOGIN CRAM-MD5
250-STARTTLS
250 HELP
&lt;kbd&gt;AUTH PLAIN AGFsaWNlAHdvbmRlcmxhbmQ=&lt;/kbd&gt;
235 Authentication succeeded
&lt;kbd&gt;MAIL FROM:&amp;lt;alice@susam.in&amp;gt;&lt;/kbd&gt;
250 OK
&lt;kbd&gt;RCPT TO:&amp;lt;example.recipient@gmail.com&amp;gt;&lt;/kbd&gt;
250 Accepted
&lt;kbd&gt;DATA&lt;/kbd&gt;
354 Enter message, ending with &quot;.&quot; on a line by itself
&lt;kbd&gt;Date: Mon, 07 Nov 2011 20:28:00 +0530
From: Alice &amp;lt;alice@susam.in&amp;gt;
To: Example Recipient &amp;lt;example.recipient@gmail.com&amp;gt;
Subject: Test email

This is a test email.
.&lt;/kbd&gt;
250 OK id=1RNQef-0004e7-7s
&lt;kbd&gt;QUIT&lt;/kbd&gt;
221 tesseract.susam.in closing connection
Connection closed by foreign host.&lt;/samp&gt;&lt;/pre&gt;
&lt;p&gt;
  The string &lt;code&gt;&quot;AGFsaWNlAHdvbmRlcmxhbmQ=&quot;&lt;/code&gt; in the &lt;code&gt;AUTH
  PLAIN&lt;/code&gt; command is the the base64 encoding of the string
  &lt;code&gt;&quot;\0alice\0wonderland&quot;&lt;/code&gt; where &lt;code&gt;&quot;\0&quot;&lt;/code&gt; indicates
  a null character, &lt;code&gt;&quot;alice&quot;&lt;/code&gt; is the sender&apos;s user name and
  &lt;code&gt;&quot;wonderland&quot;&lt;/code&gt; is the sender&apos;s password.  If an
  eavesdropper intercepts this traffic, he or she can easily find the
  user&apos;s password by simply decoding the base64 response sent by the
  client.  Here is an example of decoding the base64 response with
  Python 2.7:
&lt;/p&gt;
&lt;pre&gt;&lt;samp&gt;&amp;gt;&amp;gt;&amp;gt; &lt;kbd&gt;&apos;AGFsaWNlAHdvbmRlcmxhbmQ=&apos;.decode(&apos;base64&apos;)&lt;/kbd&gt;
&apos;\x00alice\x00wonderland&apos;&lt;/samp&gt;&lt;/pre&gt;
&lt;p&gt;
  This is also susceptible to replay attacks as the eavesdropper can
  use the &lt;code&gt;AUTH PLAIN&lt;/code&gt; line containing the base64 encoded
  credentials to log into the server in future.  This is why it is
  very important to secure the connection with SSL/TLS while having a
  session with the SMTP server.
&lt;/p&gt;
&lt;h2 id=&quot;auth-login&quot;&gt;AUTH LOGIN&lt;/h2&gt;
&lt;p&gt;
  Here is another example snippet that shows the LOGIN mechanism:
&lt;/p&gt;
&lt;pre&gt;&lt;samp&gt;&lt;kbd&gt;AUTH LOGIN&lt;/kbd&gt;
334 VXNlcm5hbWU6
&lt;kbd&gt;YWxpY2U=&lt;/kbd&gt;
334 UGFzc3dvcmQ6
&lt;kbd&gt;d29uZGVybGFuZA==&lt;/kbd&gt;
235 Authentication succeeded&lt;/samp&gt;&lt;/pre&gt;
&lt;p&gt;
  Here are the base64 responses decoded with Python 2.7:
&lt;/p&gt;
&lt;pre&gt;&lt;samp&gt;&amp;gt;&amp;gt;&amp;gt; &lt;kbd&gt;&apos;VXNlcm5hbWU6&apos;.decode(&apos;base64&apos;)&lt;/kbd&gt;
&apos;Username:&apos;
&amp;gt;&amp;gt;&amp;gt; &lt;kbd&gt;&apos;YWxpY2U=&apos;.decode(&apos;base64&apos;)&lt;/kbd&gt;
&apos;alice&apos;
&amp;gt;&amp;gt;&amp;gt; &lt;kbd&gt;&apos;UGFzc3dvcmQ6&apos;.decode(&apos;base64&apos;)&lt;/kbd&gt;
&apos;Password:&apos;
&amp;gt;&amp;gt;&amp;gt; &lt;kbd&gt;&apos;d29uZGVybGFuZA==&apos;.decode(&apos;base64&apos;)&lt;/kbd&gt;
&apos;wonderland&apos;&lt;/samp&gt;&lt;/pre&gt;
&lt;p&gt;
  If the session isn&apos;t encrypted, LOGIN authentication mechanism is
  susceptible to the same problems that PLAIN authentication mechanism
  is susceptible to.
&lt;/p&gt;
&lt;h2 id=&quot;auth-cram-md5&quot;&gt;AUTH CRAM-MD5&lt;/h2&gt;
&lt;p&gt;
  Let us take a look at the CRAM-MD5 authentication mechanism now.
  When the client selects the CRAM-MD5 authentication mechanism, the
  server sends a base64 encoded challenge like this:
&lt;/p&gt;
&lt;pre&gt;&lt;samp&gt;&lt;kbd&gt;AUTH CRAM-MD5&lt;/kbd&gt;
334 PDE3ODkzLjEzMjA2NzkxMjNAdGVzc2VyYWN0LnN1c2FtLmluPg==&lt;/samp&gt;&lt;/pre&gt;
&lt;p&gt;
  An HMAC is calculated for this challenge with the password as the
  key and MD5 as the hash function.  A string is formed by
  concatenating the user name, a space and the hexadecimal
  representation of the HMAC.  The base64 encoding of this string is
  sent as the response by the client.  The following statements in
  Python 2.7 show how a response can be formed for the above
  challenge:
&lt;/p&gt;
&lt;pre&gt;&lt;samp&gt;&amp;gt;&amp;gt;&amp;gt; &lt;kbd&gt;&apos;PDE3ODkzLjEzMjA2NzkxMjNAdGVzc2VyYWN0LnN1c2FtLmluPg==&apos;.decode(&apos;base64&apos;)&lt;/kbd&gt;
&apos;&amp;lt;17893.1320679123@tesseract.susam.in&amp;gt;&apos;
&amp;gt;&amp;gt;&amp;gt; &lt;kbd&gt;import hmac, hashlib&lt;/kbd&gt;
&amp;gt;&amp;gt;&amp;gt; &lt;kbd&gt;hmac.new(&apos;wonderland&apos;, &apos;&amp;lt;17893.1320679123@tesseract.susam.in&amp;gt;&apos;, hashlib.md5).hexdigest()&lt;/kbd&gt;
&apos;64b2a43c1f6ed6806a980914e23e75f0&apos;
&amp;gt;&amp;gt;&amp;gt; &lt;kbd&gt;&apos;alice 64b2a43c1f6ed6806a980914e23e75f0&apos;.encode(&apos;base64&apos;)&lt;/kbd&gt;
&apos;YWxpY2UgNjRiMmE0M2MxZjZlZDY4MDZhOTgwOTE0ZTIzZTc1ZjA=\n&apos;&lt;/samp&gt;&lt;/pre&gt;
&lt;p&gt;
  Of course, this can be written as a small function:
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import hmac, hashlib
def cram_md5_response(username, password, base64challenge):
    return (username + &apos; &apos; +
            hmac.new(password,
                     base64challenge.decode(&apos;base64&apos;),
                     hashlib.md5).hexdigest()).encode(&apos;base64&apos;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
  The following snippet shows the SMTP server accepting the
  client-response:
&lt;/p&gt;
&lt;pre&gt;&lt;samp&gt;&lt;kbd&gt;AUTH CRAM-MD5&lt;/kbd&gt;
334 PDE3ODkzLjEzMjA2NzkxMjNAdGVzc2VyYWN0LnN1c2FtLmluPg==
&lt;kbd&gt;YWxpY2UgNjRiMmE0M2MxZjZlZDY4MDZhOTgwOTE0ZTIzZTc1ZjA=&lt;/kbd&gt;
235 Authentication succeeded&lt;/samp&gt;&lt;/pre&gt;
&lt;p&gt;
  When the connection is not secured, CRAM-MD5 authentication
  mechanism is relatively more secure than the other two mechanisms
  because the password cannot be retrieved by decoding the base64
  encoded response from the client.  The password is used as the key
  to calculate the HMAC but the password itself is not present in the
  response.  It prevents replay attacks too because the server sends
  an unpredictable challenge for every authentication.  The response
  sent by the client for a certain challenge is invalid for another
  instance of authentication because the other instance would involve
  a different unpredictable challenge.
&lt;/p&gt;
&lt;h2 id=&quot;further-reading&quot;&gt;Further Reading&lt;/h2&gt;
&lt;p&gt;
  Here is a list of hyperlinks for further reading:
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc4954&quot;&gt;RFC 4954&lt;/a&gt;:
    SMTP Service Extension for Authentication
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc4616&quot;&gt;RFC 4616&lt;/a&gt;:
    The PLAIN Simple Authentication and Security Layer (SASL) Mechanism
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc2195&quot;&gt;RFC 2195&lt;/a&gt;:
    IMAP/POP AUTHorize Extension for Simple Challenge/Response
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc2104&quot;&gt;RFC 2104&lt;/a&gt;:
    HMAC: Keyed-Hashing for Message Authentication&lt;/li&gt;
&lt;/ol&gt;
<!-- ### -->
&lt;p&gt;
  &lt;a href="https://susam.net/auth-cram-md5.html"&gt;Read on website&lt;/a&gt; |
  &lt;a href=&quot;https://susam.net/tag/networking.html&quot;&gt;#networking&lt;/a&gt; |
  &lt;a href=&quot;https://susam.net/tag/protocol.html&quot;&gt;#protocol&lt;/a&gt; |
  &lt;a href=&quot;https://susam.net/tag/technology.html&quot;&gt;#technology&lt;/a&gt;
&lt;/p&gt;
<!-- END HTML -->
    </content>
  </entry>
  <entry>
    <title>Timing With Curl</title>
    <link href="https://susam.net/timing-with-curl.html"/>
    <id>urn:uuid:f1e7f4ee-9d05-4860-8bf0-9509a21451b7</id>
    <updated>2010-07-10T00:00:00Z</updated>
    <content type="html">
<!-- BEGIN HTML -->
&lt;p&gt;
  Here is a command I use often while measuring why an HTTP request is
  taking too long:
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl -L -w &quot;time_namelookup: %{time_namelookup}
time_connect: %{time_connect}
time_appconnect: %{time_appconnect}
time_pretransfer: %{time_pretransfer}
time_redirect: %{time_redirect}
time_starttransfer: %{time_starttransfer}
time_total: %{time_total}
&quot; https://example.com/&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
  Here is the same command written as a one-liner, so that I can copy
  it easily from this page with a triple-click whenever I need it in
  future:
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl -L -w &quot;time_namelookup: %{time_namelookup}\ntime_connect: %{time_connect}\ntime_appconnect: %{time_appconnect}\ntime_pretransfer: %{time_pretransfer}\ntime_redirect: %{time_redirect}\ntime_starttransfer: %{time_starttransfer}\ntime_total: %{time_total}\n&quot; https://example.com/&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
  Here is how the output of the above command typically looks:
&lt;/p&gt;
&lt;pre&gt;&lt;samp&gt;$ &lt;kbd&gt;curl -L -w &quot;namelookup: %{time_namelookup}\nconnect: %{time_connect}\nappconnect: %{time_appconnect}\npretransfer: %{time_pretransfer}\nstarttransfer: %{time_starttransfer}\ntotal: %{time_total}\n&quot; https://example.com/&lt;/kbd&gt;
&amp;lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.01 Transitional//EN&quot;&amp;gt;
&amp;lt;html&amp;gt;
...
&amp;lt;/html&amp;gt;
time_namelookup: 0.001403
time_connect: 0.245464
time_appconnect: 0.757656
time_pretransfer: 0.757823
time_redirect: 0.000000
time_starttransfer: 0.982111
time_total: 0.982326&lt;/samp&gt;&lt;/pre&gt;
&lt;p&gt;
  In the output above, I have omitted most of the HTML output and
  replaced the omitted part with ellipsis for the sake of brevity.
&lt;/p&gt;
&lt;p&gt;
  The list below provides a description of each number in the output
  above.  This information is picked straight from the manual page of
  curl 7.20.0.  Here are the details:
&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;
      &lt;em&gt;time_namelookup:&lt;/em&gt; The time, in seconds, it took from the
      start until the name resolving was completed.
    &lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;
      &lt;em&gt;time_connect:&lt;/em&gt; The time, in seconds, it took from the
      start until the TCP connect to the remote host (or proxy) was
      completed.
    &lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;
      &lt;em&gt;time_appconnect:&lt;/em&gt; The time, in seconds, it took from the
      start until the SSL/SSH/etc connect/handshake to the remote host
      was completed.  (Added in 7.19.0)
    &lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;
      &lt;em&gt;time_pretransfer:&lt;/em&gt; The time, in seconds, it took from
      the start until the file transfer was just about to begin.  This
      includes all pre-transfer commands and negotiations that are
      specific to the particular protocol(s) involved.
    &lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;
      &lt;em&gt;time_redirect:&lt;/em&gt; The time, in seconds, it took for all
      redirection steps include name lookup, connect, pretransfer and
      transfer before the final transaction was started.
      time_redirect shows the complete execution time for multiple
      redirections.  (Added in 7.12.3)
    &lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;
      &lt;em&gt;time_starttransfer:&lt;/em&gt; The time, in seconds, it took from
      the start until the first byte was just about to be transferred.
      This includes time_pretransfer and also the time the server
      needed to calculate the result.
    &lt;/p&gt;
  &lt;li&gt;
    &lt;p&gt;
      &lt;em&gt;time_total:&lt;/em&gt; The total time, in seconds, that the full
      operation lasted.  The time will be displayed with millisecond
      resolution.
    &lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
  An important thing worth noting here is that the difference in the
  numbers for &lt;code&gt;time_appconnect&lt;/code&gt;
  and &lt;code&gt;time_connect&lt;/code&gt; time tells us how much time is spent
  in SSL/TLS handshake.  For a cleartext connection without SSL/TLS,
  &lt;code&gt;time_appconnect&lt;/code&gt; is reported as zero.  Here is an example
  output that demonstrates this:
&lt;/p&gt;
&lt;pre&gt;&lt;samp&gt;$ &lt;kbd&gt;curl -L -w &quot;time_namelookup: %{time_namelookup}\ntime_connect: %{time_connect}\ntime_appconnect: %{time_appconnect}\ntime_pretransfer: %{time_pretransfer}\ntime_redirect: %{time_redirect}\ntime_starttransfer: %{time_starttransfer}\ntime_total: %{time_total}\n&quot; http://example.com/&lt;/kbd&gt;
&amp;lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.01 Transitional//EN&quot;&amp;gt;
&amp;lt;html&amp;gt;
...
&amp;lt;/html&amp;gt;
time_namelookup: 0.001507
time_connect: 0.247032
time_appconnect: 0.000000
time_pretransfer: 0.247122
time_redirect: 0.000000
time_starttransfer: 0.512645
time_total: 0.512853&lt;/samp&gt;&lt;/pre&gt;
&lt;p&gt;
  Also note that &lt;code&gt;time_redirect&lt;/code&gt; is zero in both outputs
  above.  That is because no redirection occurs while visiting
  &lt;a href=&quot;https://example.com&quot;&gt;example.com&lt;/a&gt;.  Here is another
  example that shows how the output looks when a redirection occurs:
&lt;/p&gt;
&lt;pre&gt;&lt;samp&gt;$ &lt;kbd&gt;curl -L -w &quot;time_namelookup: %{time_namelookup}\ntime_connect: %{time_connect}\ntime_appconnect: %{time_appconnect}\ntime_pretransfer: %{time_pretransfer}\ntime_redirect: %{time_redirect}\ntime_starttransfer: %{time_starttransfer}\ntime_total: %{time_total}\n&quot; https://susam.net/blog&lt;/kbd&gt;
&amp;lt;!DOCTYPE HTML&amp;gt;
&amp;lt;html&amp;gt;
...
&amp;lt;/html&amp;gt;
time_namelookup: 0.001886
time_connect: 0.152445
time_appconnect: 0.465326
time_pretransfer: 0.465413
time_redirect: 0.614289
time_starttransfer: 0.763997
time_total: 0.765413&lt;/samp&gt;&lt;/pre&gt;
&lt;p&gt;
  When faced with a potential latency issue in web services, this is
  often one of the first commands I run several times from multiple
  clients because the results from this command help to get a quick
  sense of the layer that might be responsible for the latency issue.
&lt;/p&gt;
<!-- ### -->
&lt;p&gt;
  &lt;a href="https://susam.net/timing-with-curl.html"&gt;Read on website&lt;/a&gt; |
  &lt;a href=&quot;https://susam.net/tag/networking.html&quot;&gt;#networking&lt;/a&gt; |
  &lt;a href=&quot;https://susam.net/tag/technology.html&quot;&gt;#technology&lt;/a&gt; |
  &lt;a href=&quot;https://susam.net/tag/how-to.html&quot;&gt;#how-to&lt;/a&gt;
&lt;/p&gt;
<!-- END HTML -->
    </content>
  </entry>
  <entry>
    <title>WinPopup</title>
    <link href="https://susam.net/winpopup.html"/>
    <id>urn:uuid:b996b9b4-ae3c-4110-b513-817f5e255715</id>
    <updated>2001-12-10T00:00:00Z</updated>
    <content type="html">
<!-- BEGIN HTML -->
&lt;p&gt;
  While browsing the &lt;code&gt;C:\Windows&lt;/code&gt; directory of the Windows
  98 system in our dorm room, I came across an interesting program
  named &lt;code&gt;Winpopup.exe&lt;/code&gt;.  It is a tiny little program that
  can be used to send messages from one Windows system to another on
  the same local area network (LAN).
&lt;/p&gt;
&lt;figure class=&quot;stretch&quot;&gt;
  &lt;img src=&quot;files/blog/winpopup-1.png&quot; alt=&quot;A screenshot of Windows directory&quot;&gt;
  &lt;figcaption&gt;
    Winpopup.exe in C:\Windows of Windows 98
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;
  Windows networking supports the notion of workgroups where one or
  more computers may logically belong to a common group.  Computers
  belonging to the same workgroup can share resources such as files,
  printers, etc. with each other.  To see the workgroup your computer
  belongs to, go to Start &amp;gt; Settings &amp;gt; Control Panel &amp;gt;
  Network &amp;gt; Identification and see the value of the field named
  &quot;Workgroup&quot;.  By default, this value is &quot;WORKGROUP&quot; but it can be
  changed to create smaller working groups of computers.
&lt;/p&gt;
&lt;p&gt;
  Apart from sending messages to a specific computer, WinPopup
  supports sending messages to an entire workgroup of computers too.
  An example of this is shown later in this post.
&lt;/p&gt;
&lt;figure class=&quot;stretch&quot;&gt;
  &lt;img src=&quot;files/blog/winpopup-2.png&quot; alt=&quot;A screenshot of Windows workgroup configuration&quot;&gt;
  &lt;figcaption&gt;
    Workgroup configuration in Windows 98
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;
  To start WinPopup, go to My Computer &amp;gt; C: &amp;gt; Windows, then
  click on the link that says &quot;Show Files&quot;, then scroll down to the
  bottom to find WinPopup.exe and finally double click on it to start
  it.  Alternatively, you can also type &lt;kbd&gt;win&lt;/kbd&gt;+&lt;kbd&gt;r&lt;/kbd&gt;,
  type &lt;code&gt;winpopup&lt;/code&gt; and type &lt;kbd&gt;enter&lt;/kbd&gt;.
&lt;/p&gt;
&lt;figure class=&quot;stretch&quot;&gt;
  &lt;img src=&quot;files/blog/winpopup-3.png&quot; alt=&quot;A screenshot of WinPopup&quot;&gt;
  &lt;figcaption&gt;
    WinPopup running on Windows 98
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;
  To send a message, simply click on the envelope icon, select one of
  the radio buttons depending on whether you want to send a message to
  a specific computer or an entire workgroup, then type the name of
  the computer or workgroup you want to send your message to and then
  type the message to be sent.
&lt;/p&gt;
&lt;figure class=&quot;stretch&quot;&gt;
  &lt;img src=&quot;files/blog/winpopup-4.png&quot; alt=&quot;A screenshot of message being composed in WinPopup&quot;&gt;
  &lt;figcaption&gt;
    Composing a message running on WinPopup running on Windows 98
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;
  When you are ready to send the message, just click on the OK button.
  If everything goes fine, a message box confirming that the message
  was successfully sent should appear.
&lt;/p&gt;
&lt;figure class=&quot;stretch&quot;&gt;
  &lt;img src=&quot;files/blog/winpopup-5.png&quot; alt=&quot;A screenshot of a message successfully sent with WinPopup&quot;&gt;
  &lt;figcaption&gt;
    Message sent successfully with WinPopup running on Windows 98
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;
  It is worth noting here that the recipient also needs to have
  WinPopup running in order to read messages successfully.  I found
  this tool only a few days ago and I already find this tool to be
  very useful for communicating with other users of Windows systems.
&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;
  &lt;em&gt;
    &lt;strong&gt;Update on 30 Oct 2022:&lt;/strong&gt; This article was imported
    into this website from an old intranet portal I used to run during
    my university days back in 2001-2005.  While importing this
    article here, I took the liberty of adding a few screenshots taken
    from a Windows 98 system running in an emulator.
  &lt;/em&gt;
&lt;/p&gt;
<!-- ### -->
&lt;p&gt;
  &lt;a href="https://susam.net/winpopup.html"&gt;Read on website&lt;/a&gt; |
  &lt;a href=&quot;https://susam.net/tag/windows.html&quot;&gt;#windows&lt;/a&gt; |
  &lt;a href=&quot;https://susam.net/tag/networking.html&quot;&gt;#networking&lt;/a&gt; |
  &lt;a href=&quot;https://susam.net/tag/technology.html&quot;&gt;#technology&lt;/a&gt;
&lt;/p&gt;
<!-- END HTML -->
    </content>
  </entry>
</feed>
