Skip to content

httpdate - set local date and time from a web server

Linux

While ntp may be a great protocol, I find it quite bloated and slow for the simple purpose of just setting a local date and time to a reference clock. I do not need 20ms accuracy on a notebook's clock :-). Thus I use(d) rdate for a decade now but the public rdate servers are slowly dying out. So I'm replacing it more and more with htpdate which works quite nicely. It's written in C and a perl alternative is available on the author's site. There is also a forked windows version of it available.

Developing a bit larger bash script (which syncs a few servers), I wondered whether I could realize the time sync part in bash as well.

It's quite possible:

  1. # open a tcp connection to www.google.com
  2. exec 3<>/dev/tcp/www.google.com/80
  3. # say hello HTTP-style
  4. echo -e "GET / HTTP/1.0\n\n">&3
  5. # parse for a Date: line and with a bit of magic throw the date-string at the date command
  6. LC_ALL=C LANG=en date --rfc-2822 --utc -s "$(head <&3 | grep -i "Date: " | sed -e s/Date\:\ //I)"
  7. # close the tcp connection
  8. exec 3<&-

Simple, eh?

A stand-alone version is available as httpdate and looks like this in v0.1:

  1. #!/bin/bash
  2. #
  3. # Purpose: display or set date from a host via http
  4. #
  5. # Requires: bash, ping, head, date, grep & sed
  6. # Autor:  Daniel Lange, http://daniel-lange.com/software/
  7. # License: GPL v3 or later, http://www.gnu.org/licenses/
  8. #
  9. # Version: v0.1, 08-10-22, initial release
  10. #
  11.  
  12. if [ "$1" = "-h" -o "$1" = "--help" ] ; then
  13.  echo "$0 v0.1 (c) Daniel Lange, 2008. Released under the GNU GPL v3 or later."
  14.  echo "Usage: $0 <-d|-s> <HOST>"
  15.  echo "       -d = display date (default)"
  16.  echo "       -s = set date (may require root privileges)"
  17.  echo "      HOST = FQDN of the server to retrieve the Date: header from"
  18.  echo "            (default: www.google.com)"
  19.  exit 0
  20. fi
  21.  
  22. if [ "$1" != "-d" -a "$1" != "-s" ] ; then
  23.  echo "Error: either -d or -s expected as first argument".
  24.  exit 1
  25. fi
  26.  
  27. if [ "$#" -gt 2 ] ; then
  28.  echo "Error: too many arguments, use -h for help"
  29.  exit 2
  30. fi
  31.  
  32. DATE_OPTION="$1"
  33. DATE_HOST="${2:-www.google.com}"
  34.  
  35. ping -q -c 1 -w 10 -W 10 $DATE_HOST > /dev/null 2>&1
  36.  
  37. if [ $? -ne 0 ] ; then
  38.  echo "Error: Host $DATE_HOST not found (or ping missing)."
  39.  exit 3
  40. fi
  41.  
  42. exec 3<>/dev/tcp/$DATE_HOST/80
  43. echo -e "GET / HTTP/1.0\n\n">&3
  44. LC_ALL=C LANG=en_EN date --rfc-2822 --utc $DATE_OPTION "$(head <&3 | grep -i "Date: " | sed -e s/Date\:\ //I)"
  45. exec 3<&-

Update:

27.09.09: Just FYI: The Debian/Ubuntu (before 09.10, launchpad bug entry) bash does not have the capability to use /dev/tcp. It's been compiled with –disable-net-redirections.

Trackbacks

No Trackbacks

Comments

Display comments as Linear | Threaded

Jorge Ventura on :

Hi Daniel, I am trying to use your script httpdate but I don't have /dev/tcp in my Debian...

To tell you the truth I never heard about /dev/tcp. Do you have any pointer to me???

Thank you, Ventura

P.S: Your script is very useful. I have a situation where the ntp port is not open in the firewall.

Daniel Lange on :

Dear Ventura,

Debian has deliberately compiled bash to disable the /dev/tcp functionality (--disable-net-redirections). See http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=146464 for the corresponding bug. So you'd need to re-compile bash manually. Or use Ubuntu. Or most other distros. Easier is probably using the C or perl version of htpdate linked at the beginning of the blog entry.

Philipp Gühring on :

I could need a httpdate that works with Proxies (using the http_proxy or https_proxy environment variable ...)

Daniel Lange on :

If the http proxy doesn't require authentication a simple amendment like

exec 3/dev/tcp/$PROXY_IP/$PROXY_PORT
echo -e "GET http://www.google.com HTTP/1.0\n\n">&3

will do.

If the proxy requires authentication you need to construct an "Authorization:" Header and send that after the GET line.
For details see e.g. http://en.wikipedia.org/wiki/Basic_access_authentication#Client_side .

Misel on :

I almost coded this myself but figured someone must have done this before.

My reasoning wasn't the dislike for NTP, though. I operate a RaspberryPi behind a rather strict firewall that only allows HTTP(S) to the outside. So this is an easy way to set the time, when NTP is not available.

Thank you very much. :-)

Add Comment

Markdown format allowed
Standard emoticons like :-) and ;-) are converted to images.
E-Mail addresses will not be displayed and will only be used for E-Mail notifications.

To prevent automated Bots from commentspamming, please enter the string you see in the image below in the appropriate input box. Your comment will only be submitted if the strings match. Please ensure that your browser supports and accepts cookies, or your comment cannot be verified correctly.
CAPTCHA

Form options

Submitted comments will be subject to moderation before being displayed.