PCやサーバの時間合わせにntpdateを通常用いますが、80番と443番しか外部接続を許されないネットワークだとNTPが使えない事があります。そんな時にNTPの代替としてWEBサーバの時間を元にマシンの時間を合わせるコマンドが”htpdate”です。
仕組はHTTPのレスポンスヘッダに含まれる”Date”を元にソコソコ正確な時間を取得してOSの時間を設定します。
とても単純明快で清々しいくらいです。
例えばこのサーバだと、このようなレスポンスヘッダが帰ってきます。
この中の「Date: Wed, 08 Apr 2015 11:35:10 GMT」がサーバの時間となります。
HTTP/1.1 200 OK
Date: Wed, 08 Apr 2015 11:35:10 GMT
Server: Apache/2.2.3 (CentOS)
Last-Modified: Fri, 29 Jun 2012 10:40:46 GMT
ETag: "16e07e-5-4c39a14ab6780"
Accept-Ranges: bytes
Content-Length: 5
Connection: close
Content-Type: text/html
# vi htpdate.go
package main
import (
"os"
"fmt"
"time"
"syscall"
"net/http"
)
// HTTPサーバへアクセスしてヘッダーからアクセス日時を取得する関数
func get_http_date(url string) (string, error) {
response, err := http.Get(url)
if err != nil { return "", err }
access_time := response.Header.Get("Date")
return access_time, nil
}
// 引数として受け取ったUNIXタイムをOSの時間に設定する関数
func settime(sec int64, usec int64) error {
tv := syscall.Timeval{ Sec: sec, Usec: usec }
return os.NewSyscallError("settimeofday", syscall.Settimeofday(&tv))
}
func main() {
if len(os.Args) > 1 {
// とりあえずHTTPサーバを1個だけ引数に受け取る
host_name := os.Args[1]
target_url := "http://" + host_name
// HTTPサーバからアクセス日時を取得
access_time, err := get_http_date(target_url)
if err != nil {
fmt.Fprintln(os.Stderr, "Failed to access the HTTP server.")
os.Exit(1)
}
// 取得した時間をパーズする
server_time, err := time.Parse(time.RFC1123, access_time)
if err != nil {
fmt.Fprintln(os.Stderr, "Time of format is not a RFC1123.")
os.Exit(1)
}
// 取得した時間をOSの時間として設定する
if err := settime(server_time.Unix(), 0); err != nil {
fmt.Fprintln(os.Stderr, "Failed to set the date and time.")
os.Exit(1)
}
fmt.Println(time.Now())
os.Exit(0)
} else {
fmt.Fprintln(os.Stderr, "Please set the HTTP server to argument.")
os.Exit(1)
}
}
実行してみると時間が設定される事が分かるはずです。
# go run htpdate.go orsx.net
2015-04-08 21:05:18.000046645 +0900 JST
Proxyなどは対応していませんがGo言語を勉強するうえで良い教材になりそうな気がしたので簡単に実装してみました。
[HTTP Time Protocol / htpdate] Webプロキシを経由して時刻を同期するの巻 – TrippyBoyの愉快な日々
Introduction | HTTP Time Protocol
最近のコメント