Implement NTP server from DHCP
This commit is contained in:
parent
f60299f3ca
commit
69200acf90
@ -9,6 +9,7 @@ package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
@ -20,8 +21,11 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"internal/notify"
|
||||
|
||||
"github.com/gokrazy/gokrazy/internal/iface"
|
||||
"github.com/google/gopacket/layers"
|
||||
"github.com/google/renameio"
|
||||
"github.com/mdlayher/raw"
|
||||
"github.com/rtr7/dhcp4"
|
||||
"golang.org/x/sys/unix"
|
||||
@ -64,7 +68,9 @@ func (c *client) discover() (*layers.DHCPv4, error) {
|
||||
layers.DHCPOptDNS,
|
||||
layers.DHCPOptRouter,
|
||||
layers.DHCPOptSubnetMask,
|
||||
layers.DHCPOptDomainName),
|
||||
layers.DHCPOptDomainName,
|
||||
layers.DHCPOptNTPServers,
|
||||
),
|
||||
})
|
||||
if err := dhcp4.Write(c.conn, discover); err != nil {
|
||||
return nil, err
|
||||
@ -101,7 +107,9 @@ func (c *client) request(last *layers.DHCPv4) (*layers.DHCPv4, error) {
|
||||
layers.DHCPOptDNS,
|
||||
layers.DHCPOptRouter,
|
||||
layers.DHCPOptSubnetMask,
|
||||
layers.DHCPOptDomainName),
|
||||
layers.DHCPOptDomainName,
|
||||
layers.DHCPOptNTPServers,
|
||||
),
|
||||
}, dhcp4.ServerID(last.Options)...))
|
||||
if err := dhcp4.Write(c.conn, request); err != nil {
|
||||
return nil, err
|
||||
@ -127,6 +135,11 @@ func (c *client) request(last *layers.DHCPv4) (*layers.DHCPv4, error) {
|
||||
}
|
||||
}
|
||||
|
||||
var permDir = flag.String(
|
||||
"perm",
|
||||
"/perm",
|
||||
"path to replace /perm")
|
||||
|
||||
func main() {
|
||||
log.SetFlags(log.LstdFlags | log.Lshortfile)
|
||||
var (
|
||||
@ -137,6 +150,10 @@ func main() {
|
||||
)
|
||||
flag.Parse()
|
||||
|
||||
if err := os.MkdirAll(filepath.Join(*permDir, "dhcp4"), 0755); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
|
||||
// NOTE: cannot gokrazy.WaitForClock() here, since the clock can only be
|
||||
// initialized once the network is up.
|
||||
|
||||
@ -197,6 +214,7 @@ func main() {
|
||||
}
|
||||
|
||||
lease := dhcp4.LeaseFromACK(last)
|
||||
saveLease(lease)
|
||||
|
||||
// Log the received DHCPACK packet:
|
||||
details := []string{
|
||||
@ -218,6 +236,9 @@ func main() {
|
||||
if len(lease.Broadcast) > 0 {
|
||||
details = append(details, fmt.Sprintf("broadcast %v", lease.Broadcast))
|
||||
}
|
||||
if len(lease.NTP) > 0 {
|
||||
details = append(details, fmt.Sprintf("NTP %v", lease.NTP))
|
||||
}
|
||||
|
||||
log.Printf("DHCPACK: %v", strings.Join(details, ", "))
|
||||
|
||||
@ -286,3 +307,22 @@ func main() {
|
||||
time.Sleep(lease.RenewalTime)
|
||||
}
|
||||
}
|
||||
|
||||
func saveLease(lease dhcp4.Lease) {
|
||||
b, err := json.Marshal(lease)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
var out bytes.Buffer
|
||||
if err := json.Indent(&out, b, "", "\t"); err == nil {
|
||||
b = out.Bytes()
|
||||
}
|
||||
if err := renameio.WriteFile(filepath.Join(*permDir, "dhcp4/lease.json"), b, 0644); err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
if err := notify.Process(filepath.Join(filepath.Dir(os.Args[0]), "/ntp"), syscall.SIGUSR1); err != nil {
|
||||
log.Printf("notifying ntp: %v", err)
|
||||
}
|
||||
}
|
||||
|
@ -2,17 +2,28 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"math/rand"
|
||||
"net"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/beevik/ntp"
|
||||
"github.com/rtr7/dhcp4"
|
||||
)
|
||||
|
||||
var server = "0.gokrazy.pool.ntp.org"
|
||||
|
||||
var permDir = flag.String("perm", "/perm", "path to replace /perm")
|
||||
|
||||
func set(rtc *os.File) error {
|
||||
r, err := ntp.Query("0.gokrazy.pool.ntp.org")
|
||||
r, err := ntp.Query(server)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -21,7 +32,7 @@ func set(rtc *os.File) error {
|
||||
if err := syscall.Settimeofday(&tv); err != nil {
|
||||
return err
|
||||
}
|
||||
log.Printf("clock set to %v", r.Time)
|
||||
log.Printf("clock set to %v using %v", r.Time, server)
|
||||
|
||||
if rtc == nil {
|
||||
return nil
|
||||
@ -30,6 +41,7 @@ func set(rtc *os.File) error {
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
log.SetFlags(log.LstdFlags | log.Lshortfile)
|
||||
|
||||
var rtc *os.File
|
||||
@ -47,6 +59,15 @@ func main() {
|
||||
|
||||
mustDropPrivileges(rtc)
|
||||
|
||||
go func() {
|
||||
ch := make(chan os.Signal, 1)
|
||||
signal.Notify(ch, syscall.SIGUSR1)
|
||||
for range ch {
|
||||
loadNTPServer()
|
||||
}
|
||||
}()
|
||||
loadNTPServer()
|
||||
|
||||
for {
|
||||
if err := set(rtc); err != nil {
|
||||
log.Fatalf("setting time failed: %v", err)
|
||||
@ -54,3 +75,21 @@ func main() {
|
||||
time.Sleep(1*time.Hour + time.Duration(rand.Int63n(250))*time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
func loadNTPServer() {
|
||||
var lease dhcp4.Lease
|
||||
file, err := ioutil.ReadFile(filepath.Join(*permDir, "dhcp4/lease.json"))
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(file, &lease)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
if len(lease.DNS) > 0 && !lease.DNS[0].To4().Equal(net.IPv4zero) {
|
||||
server = lease.DNS[0].String()
|
||||
log.Printf("Setting ntp server to: %s", server)
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
@ -84,5 +85,14 @@ func mustDropPrivileges(rtc *os.File) {
|
||||
},
|
||||
AmbientCaps: []uintptr{CAP_SYS_TIME},
|
||||
}
|
||||
|
||||
go func() {
|
||||
ch := make(chan os.Signal, 1)
|
||||
signal.Notify(ch)
|
||||
for sig := range ch {
|
||||
cmd.Process.Signal(sig)
|
||||
}
|
||||
}()
|
||||
|
||||
log.Fatal(cmd.Run())
|
||||
}
|
||||
|
1
go.mod
1
go.mod
@ -7,6 +7,7 @@ require (
|
||||
github.com/gokrazy/internal v0.0.0-20200531194636-d96421c60091
|
||||
github.com/google/go-cmp v0.4.0 // indirect
|
||||
github.com/google/gopacket v1.1.16
|
||||
github.com/google/renameio v0.1.0
|
||||
github.com/mdlayher/raw v0.0.0-20190303161257-764d452d77af
|
||||
github.com/mdlayher/watchdog v0.0.0-20201005150459-8bdc4f41966b
|
||||
github.com/rtr7/dhcp4 v0.0.0-20181120124042-778e8c2e24a5
|
||||
|
2
go.sum
2
go.sum
@ -8,6 +8,8 @@ github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/gopacket v1.1.16 h1:u6Afvia5C5srlLcbTwpHaFW918asLYPxieziOaWwz8M=
|
||||
github.com/google/gopacket v1.1.16/go.mod h1:UCLx9mCmAwsVbn6qQl1WIEt2SO7Nd2fD0th1TBAsqBw=
|
||||
github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/mdlayher/raw v0.0.0-20190303161257-764d452d77af h1:20h/EjkLGn9mV5nX9MFnGhbbeEhIGnOKPShJfBtVkVQ=
|
||||
github.com/mdlayher/raw v0.0.0-20190303161257-764d452d77af/go.mod h1:rC/yE65s/DoHB6BzVOUBNYBGTg772JVytyAytffIZkY=
|
||||
github.com/mdlayher/watchdog v0.0.0-20201005150459-8bdc4f41966b h1:7tUBfsEEBWfFeHOB7CUfoOamak+Gx/BlirfXyPk1WjI=
|
||||
|
56
internal/notify/notify.go
Normal file
56
internal/notify/notify.go
Normal file
@ -0,0 +1,56 @@
|
||||
// Copyright 2018 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package notify implements sending signals (such as SIGUSR1) to processes.
|
||||
package notify
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var numericRe = regexp.MustCompile(`^[0-9]+$`)
|
||||
|
||||
func Process(name string, sig os.Signal) error {
|
||||
fis, err := ioutil.ReadDir("/proc")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, fi := range fis {
|
||||
if !fi.IsDir() {
|
||||
continue
|
||||
}
|
||||
if !numericRe.MatchString(fi.Name()) {
|
||||
continue
|
||||
}
|
||||
b, err := ioutil.ReadFile(filepath.Join("/proc", fi.Name(), "cmdline"))
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
continue // process vanished
|
||||
}
|
||||
return err
|
||||
}
|
||||
if !strings.Contains(string(b), name) {
|
||||
continue
|
||||
}
|
||||
pid, _ := strconv.Atoi(fi.Name()) // already verified to be numeric
|
||||
p, _ := os.FindProcess(pid)
|
||||
return p.Signal(sig)
|
||||
}
|
||||
return nil
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user