68

Is it possible to use ntpdate behind an HTTP proxy with authentication? In case it is not possible, are there any good alternatives?

12 Answers12

62

Expanding on the answer by carveone:

sudo date -s "$(wget -S  "http://www.google.com/" 2>&1 | grep -E '^[[:space:]]*[dD]ate:' | sed 's/^[[:space:]]*[dD]ate:[[:space:]]*//' | head -1l | awk '{print $1, $3, $2,  $5 ,"GMT", $4 }' | sed 's/,//')"
fiford_g
  • 621
38

This seems like a clear case for tlsdate.

 tlsdate: secure parasitic rdate replacement

  tlsdate sets the local clock by securely connecting with TLS to remote
  servers and extracting the remote time out of the secure handshake. Unlike
  ntpdate, tlsdate uses TCP, for instance connecting to a remote HTTPS or TLS
  enabled service, and provides some protection against adversaries that try
  to feed you malicious time information.

I do not think i have ever seen so many recommendations to use unsanitized data from internet as an argument to a sudo invocation.

Github: https://github.com/ioerror/tlsdate

dfc
  • 757
  • 6
  • 11
26

One Liner

Assuming environment variable http_proxy is already set:

sudo date -s "$(curl -H'Cache-Control:no-cache' -sI google.com | grep '^Date:' | cut -d' ' -f3-6)Z"

we can verify the retrieved date/time first:

# local  date/time
date -d "$(curl -HCache-Control:no-cache -sI google.com | grep '^Date:' | cut -d' ' -f3-6)Z"

# or UTC date/time
date -ud "$(curl -HCache-Control:no-cache -sI google.com | grep '^Date:' | cut -d' ' -f3-6)"    

Notes

Just in case, certain options might be needed for curl:

  • curl -x $proxy

    to explicitly set the proxy server to use, when the http_proxy environment variable is not set, default to protocol http and port 1080 (manual).

  • curl -H 'Cache-Control: no-cache'

    to explicitly disable caching, especially when used in a cron job and/or behind a proxy server.

Alternate form tested with RHEL 6 that uses the '-u' option to date instead of appending the "Z" to the output:

sudo date -u --set="$(curl -H 'Cache-Control: no-cache' -sD - http://google.com |grep '^Date:' |cut -d' ' -f3-6)"

BTW, google.com is preferred over www.google.com, because the former results in a 301 redirect response, which is much smaller (569 vs 20k+ characters) but still good to use.

ryenus
  • 969
  • 1
  • 10
  • 15
9

NTP service is using UDP protocol to sync the time. So HTTP/TCP proxy may not work for it. Alternative to accepted answer, there is a good htpdate tool to sync time behind proxy.

A cron job example:

* 3 * * * /usr/bin/htpdate -s -P <PROXY_HOST>:<PROXY__PORT> www.linux.org www.freebsd.org
artificerpi
  • 191
  • 1
  • 4
6

If it is purely an HTTP proxy, it is using port 80, so the basic answer is no to that specifically. NTP uses UDP port 123. If it is a more generic proxy server, serving all ports, then maybe.

There are some programs out there that do NTP over HTTP. I do not use Linux, but this one might do it:

http://www.rkeene.org/oss/htp/ (still not sure if this will do authentication either).

I could not find one for Windows, but I will post back if I do.

KCotreau
  • 25,622
5

A quick and dirty solution for people behind a http proxy server:

My location is GMT+4, I can check out the current time from timeapi server with url http://www.timeapi.org/utc/in+four+hours, for more info pls checkout the website for your location.

To setup date & time I do:

time sudo date $(wget -O - "http://www.timeapi.org/utc/in+four+hours" 2>/dev/null | sed s/[-T:+]/\ /g | awk '{print $2,$3,$4,$5,".",$6}' | tr -d " " )

You can repeat the command if the initial 'time' command reports a high value...

2

Although ntp over http has been mentioned, I am surprised that nobody mentioned the nifty little utility htpdate as available on http://www.vervest.org/htp/. Unlike the alternatives, htpdate is part of Debian's and Ubuntu's default repositories and can be installed using apt-get.

It can be run both as an ordinary command or silently in daemon mode.

1

Assuming the http_proxy environment variable is set:

wget -S --spider "http://www.google.com/" 2>&1 | grep -E '^[[:space:]]*[dD]ate:' | sed 's/^[[:space:]]*[dD]ate:[[:space:]]*//'

Or use curl -I --proxy="..." "http://www.google.com/"

After all, if Google's site doesn't have its time set there's no hope.

jonsca
  • 4,084
carveone
  • 327
1

Expanding on https://superuser.com/a/509620/362156

Let's assume you're in Berlin (Germany).

Then use this:

sudo TZ=Europe/Berlin date -s "$(TZ=Europe/Berlin date --date='TZ="UTC" '"$(wget -S  "http://www.google.com/" 2>&1 | grep -E '^[[:space:]]*[dD]ate:' | sed 's/^[[:space:]]*[dD]ate:[[:space:]]*//' | head -1l | awk '{print $1, $3, $2,  $5 , $6, $4 }' | sed 's/,//')")"
PeterZ
  • 11
0

For a fully-working pre-baked implementation of @ryenus' excellent answer, check out set_system_clock_from_google.sh.

0

I do this on a raspi which is on a private LAN without network access, without a true proxy, but where I have a server which has another reliable internet connection on a corporate network, that I can at least ssh into from the raspi.

There are three 'setup' steps, then a couple more to actually set the time:

  1. Have had the raspi where it can temporarily access the internet (I used a personal hotspot on my phone)

    • while online: sudo apt install proxychains
    • after this completes, you can take it back offline, and back onto the isolated network.
  2. echo 'socks5 127.0.0.1 17471' | sudo tee -a /etc/proxychains.conf

  3. Make yourself a handy script for the ssh connection:

cat << EOF > startproxy.sh
#!/bin/bash

F=~/.ssh/ssh_socket_for_proxyhains if [ -f $F ]; then killall ssh rm $F fi ssh -f -NT -M -S ~/.ssh/ssh_socket_for_proxychains -D 17471 user@server EOF chmod +x startproxy.sh

  • if you change 17471, change it in both places.
  • need to do the above only once, remaining steps can be redone
  1. start it: ./startproxy.sh.

    • Should just seem to die quietly. But ssh should now show up in ps x or so.
  2. check proxychains is working, eg: sudo proxychains apt update (yes, you can update and install stuff like this too).

Then check you can get a clean date UTC with:

sudo proxychains 2>/dev/null curl -H'Cache-Control:no-cache' -sI google.com | grep '^Date:' | cut -d' ' -f3 -6 | tail -n 1

Assuming that spits out something sensible, set your date with:

sudo date -s "$(sudo proxychains 2>/dev/null curl -H'Cache-Control:no-cache' -sI google.com | grep '^Date:' | cut -d' ' -f3-6 | tail -n 1 )Z"
  • Note the extra Z on the end: Otherwise your date will probably be set wrong, since this tells date -s that it's a UTC time, and it will otherwise assume it's a local time.

  • You should probably kill that ssh process when you're done, each time you use it also.

  • You don't need server to be running a proxy - just be able to be reached via ssh, and itself have internet access.

  • You can do all of the above having connected to the raspi via ssh from somewhere else, makes no difference. You might even have ssh'd into the server, and from there into the raspi.

RGD2
  • 264
0

Here is the python script

import requests
import subprocess
import datetime

ntp doesnt work well behind proxy

so we opt for another approach

Windows expect hardware clock to set to local time

Linux expect hardware clock to set to UTC

If you opt to have hardware clock set to local time

you need to tell linux about this

disable timesync

subprocess.run(['sudo', 'systemctl', 'stop', 'systemd-timesyncd']) subprocess.run(['sudo', 'systemctl', 'disable', 'systemd-timesyncd'])

Set the timezone to your place

timezone = 'Asia/Hong_Kong'

Get the current time from the WorldTimeAPI

response = requests.get(f'https://worldtimeapi.org/api/timezone/{timezone}') data = response.json()

Extract the current time from the API response

current_time = datetime.datetime.fromisoformat(data['datetime'])

Set the hardware clock to local time

subprocess.run(['sudo', 'hwclock', '--set', '--date', current_time.strftime('%Y-%m-%d %H:%M:%S')])

tell linux that hardware clock to set to local

subprocess.run(['sudo', 'timedatectl', 'set-local-rtc', '1', '--adjust-system-clock'])

Synchronize the system clock with the hardware clock

subprocess.run(['sudo', 'hwclock', '--hctosys'])

Verify the time synchronization

print(f'WorldTimeAPI time: {current_time.strftime("%Y-%m-%d %H:%M:%S")}') print(f'Hardware clock: {subprocess.check_output(["sudo", "hwclock", "--show"]).decode().strip()}')

Check the system time

print(f'UTC time: {subprocess.check_output(["date", "-u"]).decode().strip()}')

Check the local time

print(f'Local time: {subprocess.check_output(["date"]).decode().strip()}')

Please note that this script will be different if you want to set your hardware clock to UTC. You need to modify windows registry

Hairy Ass
  • 123