Compare commits
2 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
a5420430ab | ||
|
8ba14148d7 |
9
Makefile
9
Makefile
@ -6,6 +6,15 @@ PKGS := github.com/rtr7/router7/cmd/... \
|
|||||||
github.com/stapelberg/zkj-nas-tools/wolgw \
|
github.com/stapelberg/zkj-nas-tools/wolgw \
|
||||||
github.com/gokrazy/gdns
|
github.com/gokrazy/gdns
|
||||||
|
|
||||||
|
build:
|
||||||
|
mkdir -p result
|
||||||
|
GOOS=linux go build -o ./result github.com/rtr7/router7/cmd/...
|
||||||
|
GOOS=linux go build -o ./result/rtr7-init -ldflags "-X main.buildTimestamp=$(shell date '+%Y-%m-%dT%H:%M:%S%z') -X github.com/gokrazy/gokrazy.httpPassword=temp" init/init.go
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf result
|
||||||
|
go clean -cache
|
||||||
|
|
||||||
image:
|
image:
|
||||||
ifndef DIR
|
ifndef DIR
|
||||||
@echo variable DIR unset
|
@echo variable DIR unset
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"flag"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
@ -29,9 +30,12 @@ import (
|
|||||||
"github.com/rtr7/router7/internal/teelogger"
|
"github.com/rtr7/router7/internal/teelogger"
|
||||||
)
|
)
|
||||||
|
|
||||||
var log = teelogger.NewConsole()
|
var (
|
||||||
|
log = teelogger.NewConsole()
|
||||||
|
httpListeners = multilisten.NewPool()
|
||||||
|
|
||||||
var httpListeners = multilisten.NewPool()
|
perm = flag.String("perm", "/perm", "path to replace /perm")
|
||||||
|
)
|
||||||
|
|
||||||
func updateListeners() error {
|
func updateListeners() error {
|
||||||
hosts, err := gokrazy.PrivateInterfaceAddrs()
|
hosts, err := gokrazy.PrivateInterfaceAddrs()
|
||||||
@ -47,7 +51,7 @@ func updateListeners() error {
|
|||||||
|
|
||||||
func logic() error {
|
func logic() error {
|
||||||
http.HandleFunc("/backup.tar.gz", func(w http.ResponseWriter, r *http.Request) {
|
http.HandleFunc("/backup.tar.gz", func(w http.ResponseWriter, r *http.Request) {
|
||||||
if err := backup.Archive(w, "/perm"); err != nil {
|
if err := backup.Archive(w, *perm); err != nil {
|
||||||
log.Printf("backup.tar.gz: %v", err)
|
log.Printf("backup.tar.gz: %v", err)
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
@ -38,6 +39,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
perm = flag.String("perm", "/perm", "path to replace /perm")
|
||||||
hostKeyPath = flag.String("host_key",
|
hostKeyPath = flag.String("host_key",
|
||||||
"/perm/breakglass.host_key",
|
"/perm/breakglass.host_key",
|
||||||
"path to a PEM-encoded RSA, DSA or ECDSA private key (create using e.g. ssh-keygen -f /perm/breakglass.host_key -N '' -t rsa)")
|
"path to a PEM-encoded RSA, DSA or ECDSA private key (create using e.g. ssh-keygen -f /perm/breakglass.host_key -N '' -t rsa)")
|
||||||
@ -149,6 +151,9 @@ func logic() error {
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
if *hostKeyPath == "/perm/breakglass.host_key" && *perm != "/perm" {
|
||||||
|
*hostKeyPath = strings.Replace(*hostKeyPath, "/perm", *perm, 1)
|
||||||
|
}
|
||||||
if err := logic(); err != nil {
|
if err := logic(); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,9 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -43,6 +45,7 @@ var log = teelogger.NewConsole()
|
|||||||
var (
|
var (
|
||||||
netInterface = flag.String("interface", "uplink0", "network interface to operate on")
|
netInterface = flag.String("interface", "uplink0", "network interface to operate on")
|
||||||
stateDir = flag.String("state_dir", "/perm/dhcp4", "directory in which to store lease data (wire/lease.json) and last ACK (wire/ack)")
|
stateDir = flag.String("state_dir", "/perm/dhcp4", "directory in which to store lease data (wire/lease.json) and last ACK (wire/ack)")
|
||||||
|
perm = flag.String("perm", "/perm", "path to replace /perm")
|
||||||
)
|
)
|
||||||
|
|
||||||
func logic() error {
|
func logic() error {
|
||||||
@ -59,7 +62,7 @@ func logic() error {
|
|||||||
// still use the old hardware address. We overwrite it with the address that
|
// still use the old hardware address. We overwrite it with the address that
|
||||||
// netconfigd is going to use to fix this issue without additional
|
// netconfigd is going to use to fix this issue without additional
|
||||||
// synchronization.
|
// synchronization.
|
||||||
details, err := netconfig.Interface("/perm", *netInterface)
|
details, err := netconfig.Interface(*perm, *netInterface)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if spoof := details.SpoofHardwareAddr; spoof != "" {
|
if spoof := details.SpoofHardwareAddr; spoof != "" {
|
||||||
if addr, err := net.ParseMAC(spoof); err == nil {
|
if addr, err := net.ParseMAC(spoof); err == nil {
|
||||||
@ -118,7 +121,7 @@ func logic() error {
|
|||||||
if err := renameio.WriteFile(ackFn, buf.Bytes(), 0644); err != nil {
|
if err := renameio.WriteFile(ackFn, buf.Bytes(), 0644); err != nil {
|
||||||
return fmt.Errorf("persisting DHCPACK to %s: %v", ackFn, err)
|
return fmt.Errorf("persisting DHCPACK to %s: %v", ackFn, err)
|
||||||
}
|
}
|
||||||
if err := notify.Process("/user/netconfigd", syscall.SIGUSR1); err != nil {
|
if err := notify.Process(path.Join(path.Dir(os.Args[0]), "/netconfigd"), syscall.SIGUSR1); err != nil {
|
||||||
log.Printf("notifying netconfig: %v", err)
|
log.Printf("notifying netconfig: %v", err)
|
||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
@ -138,6 +141,9 @@ func logic() error {
|
|||||||
func main() {
|
func main() {
|
||||||
// TODO: drop privileges, run as separate uid?
|
// TODO: drop privileges, run as separate uid?
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
if *stateDir == "/perm/dhcp4" && *perm != "/perm" {
|
||||||
|
*stateDir = strings.Replace(*stateDir, "/perm", *perm, 1)
|
||||||
|
}
|
||||||
if err := logic(); err != nil {
|
if err := logic(); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
@ -50,15 +51,17 @@ import (
|
|||||||
"github.com/rtr7/router7/internal/teelogger"
|
"github.com/rtr7/router7/internal/teelogger"
|
||||||
)
|
)
|
||||||
|
|
||||||
var iface = flag.String("interface", "lan0", "ethernet interface to listen for DHCPv4 requests on")
|
var (
|
||||||
|
log = teelogger.NewConsole()
|
||||||
var log = teelogger.NewConsole()
|
nonExpiredLeases = promauto.NewGauge(prometheus.GaugeOpts{
|
||||||
|
|
||||||
var nonExpiredLeases = promauto.NewGauge(prometheus.GaugeOpts{
|
|
||||||
Name: "non_expired_leases",
|
Name: "non_expired_leases",
|
||||||
Help: "Number of non-expired DHCP leases",
|
Help: "Number of non-expired DHCP leases",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
iface = flag.String("interface", "lan0", "ethernet interface to listen for DHCPv4 requests on")
|
||||||
|
perm = flag.String("perm", "/perm", "path to replace /perm")
|
||||||
|
)
|
||||||
|
|
||||||
func updateNonExpired(leases []*dhcp4d.Lease) {
|
func updateNonExpired(leases []*dhcp4d.Lease) {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
nonExpired := 0
|
nonExpired := 0
|
||||||
@ -71,7 +74,7 @@ func updateNonExpired(leases []*dhcp4d.Lease) {
|
|||||||
nonExpiredLeases.Set(float64(nonExpired))
|
nonExpiredLeases.Set(float64(nonExpired))
|
||||||
}
|
}
|
||||||
|
|
||||||
var ouiDB = oui.NewDB("/perm/dhcp4d/oui")
|
var ouiDB = oui.NewDB(path.Join(*perm, "/dhcp4d/oui"))
|
||||||
|
|
||||||
var (
|
var (
|
||||||
leasesMu sync.Mutex
|
leasesMu sync.Mutex
|
||||||
@ -218,7 +221,7 @@ func updateListeners() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if net1, err := multilisten.IPv6Net1("/perm"); err == nil {
|
if net1, err := multilisten.IPv6Net1(*perm); err == nil {
|
||||||
hosts = append(hosts, net1)
|
hosts = append(hosts, net1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -393,7 +396,7 @@ func newSrv(permDir string) (*srv, error) {
|
|||||||
errs <- err
|
errs <- err
|
||||||
}
|
}
|
||||||
updateNonExpired(leases)
|
updateNonExpired(leases)
|
||||||
if err := notify.Process("/user/dnsd", syscall.SIGUSR1); err != nil {
|
if err := notify.Process(path.Join(path.Dir(os.Args[0]), "/dnsd"), syscall.SIGUSR1); err != nil {
|
||||||
log.Printf("notifying dnsd: %v", err)
|
log.Printf("notifying dnsd: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -422,7 +425,7 @@ func (s *srv) run(ctx context.Context) error {
|
|||||||
func main() {
|
func main() {
|
||||||
// TODO: drop privileges, run as separate uid?
|
// TODO: drop privileges, run as separate uid?
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
srv, err := newSrv("/perm")
|
srv, err := newSrv(*perm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
@ -34,15 +35,17 @@ import (
|
|||||||
|
|
||||||
var log = teelogger.NewConsole()
|
var log = teelogger.NewConsole()
|
||||||
|
|
||||||
|
var perm = flag.String("perm", "/perm", "path to replace /perm")
|
||||||
|
|
||||||
func logic() error {
|
func logic() error {
|
||||||
const leasePath = "/perm/dhcp6/wire/lease.json"
|
leasePath := path.Join(*perm, "/dhcp6/wire/lease.json")
|
||||||
if err := os.MkdirAll(filepath.Dir(leasePath), 0755); err != nil {
|
if err := os.MkdirAll(filepath.Dir(leasePath), 0755); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
duid, err := ioutil.ReadFile("/perm/dhcp6/duid")
|
duid, err := ioutil.ReadFile(path.Join(*perm, "/dhcp6/duid"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("could not read /perm/dhcp6/duid (%v), proceeding with DUID-LLT", err)
|
log.Printf("could not read %s (%v), proceeding with DUID-LLT", path.Join(*perm, "/dhcp6/duid"), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
c, err := dhcp6.NewClient(dhcp6.ClientConfig{
|
c, err := dhcp6.NewClient(dhcp6.ClientConfig{
|
||||||
@ -68,10 +71,10 @@ func logic() error {
|
|||||||
if err := renameio.WriteFile(leasePath, b, 0644); err != nil {
|
if err := renameio.WriteFile(leasePath, b, 0644); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := notify.Process("/user/netconfigd", syscall.SIGUSR1); err != nil {
|
if err := notify.Process(path.Join(path.Dir(os.Args[0]), "/netconfigd"), syscall.SIGUSR1); err != nil {
|
||||||
log.Printf("notifying netconfig: %v", err)
|
log.Printf("notifying netconfig: %v", err)
|
||||||
}
|
}
|
||||||
if err := notify.Process("/user/radvd", syscall.SIGUSR1); err != nil {
|
if err := notify.Process(path.Join(path.Dir(os.Args[0]), "/radvd"), syscall.SIGUSR1); err != nil {
|
||||||
log.Printf("notifying radvd: %v", err)
|
log.Printf("notifying radvd: %v", err)
|
||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
|
@ -38,6 +38,8 @@ import (
|
|||||||
|
|
||||||
var httpListeners = multilisten.NewPool()
|
var httpListeners = multilisten.NewPool()
|
||||||
|
|
||||||
|
var perm = flag.String("perm", "/perm", "path to replace /perm")
|
||||||
|
|
||||||
func updateListeners() error {
|
func updateListeners() error {
|
||||||
hosts, err := gokrazy.PrivateInterfaceAddrs()
|
hosts, err := gokrazy.PrivateInterfaceAddrs()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -134,6 +136,7 @@ func logic() error {
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
diag.Perm = *perm
|
||||||
|
|
||||||
if err := logic(); err != nil {
|
if err := logic(); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
|
@ -24,6 +24,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
"path"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/gokrazy/gokrazy"
|
"github.com/gokrazy/gokrazy"
|
||||||
@ -40,6 +41,9 @@ import (
|
|||||||
var (
|
var (
|
||||||
httpListeners = multilisten.NewPool()
|
httpListeners = multilisten.NewPool()
|
||||||
dnsListeners = multilisten.NewPool()
|
dnsListeners = multilisten.NewPool()
|
||||||
|
|
||||||
|
perm = flag.String("perm", "/perm", "path to replace /perm")
|
||||||
|
domain = flag.String("domain", "lan", "domain name for your network")
|
||||||
)
|
)
|
||||||
|
|
||||||
func updateListeners(mux *miekgdns.ServeMux) error {
|
func updateListeners(mux *miekgdns.ServeMux) error {
|
||||||
@ -56,7 +60,7 @@ func updateListeners(mux *miekgdns.ServeMux) error {
|
|||||||
}}
|
}}
|
||||||
})
|
})
|
||||||
|
|
||||||
if net1, err := multilisten.IPv6Net1("/perm"); err == nil {
|
if net1, err := multilisten.IPv6Net1(*perm); err == nil {
|
||||||
hosts = append(hosts, net1)
|
hosts = append(hosts, net1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,13 +79,13 @@ func (a *listenerAdapter) Close() error { return a.Shutdown() }
|
|||||||
|
|
||||||
func logic() error {
|
func logic() error {
|
||||||
// TODO: set correct upstream DNS resolver(s)
|
// TODO: set correct upstream DNS resolver(s)
|
||||||
ip, err := netconfig.LinkAddress("/perm", "lan0")
|
ip, err := netconfig.LinkAddress(*perm, "lan0")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
srv := dns.NewServer(ip.String()+":53", "lan")
|
srv := dns.NewServer(ip.String()+":53", *domain)
|
||||||
readLeases := func() error {
|
readLeases := func() error {
|
||||||
b, err := ioutil.ReadFile("/perm/dhcp4d/leases.json")
|
b, err := ioutil.ReadFile(path.Join(*perm, "/dhcp4d/leases.json"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gokrazy/gokrazy"
|
"github.com/gokrazy/gokrazy"
|
||||||
@ -35,6 +36,8 @@ import (
|
|||||||
|
|
||||||
var update = dyndns.Update
|
var update = dyndns.Update
|
||||||
|
|
||||||
|
var perm = flag.String("perm", "/perm", "path to replace /perm")
|
||||||
|
|
||||||
type DynDNSRecord struct {
|
type DynDNSRecord struct {
|
||||||
// TODO: multiple providers support
|
// TODO: multiple providers support
|
||||||
Cloudflare struct {
|
Cloudflare struct {
|
||||||
@ -105,7 +108,7 @@ func main() {
|
|||||||
var (
|
var (
|
||||||
configFile = flag.String(
|
configFile = flag.String(
|
||||||
"config_file",
|
"config_file",
|
||||||
"/perm/dyndns.json",
|
path.Join(*perm, "/dyndns.json"),
|
||||||
"Path to the JSON configuration",
|
"Path to the JSON configuration",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
"path"
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
@ -40,6 +41,8 @@ var log = teelogger.NewConsole()
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
linger = flag.Bool("linger", true, "linger around after applying the configuration (until killed)")
|
linger = flag.Bool("linger", true, "linger around after applying the configuration (until killed)")
|
||||||
|
perm = flag.String("perm", "/perm", "path to replace /perm")
|
||||||
|
noFirewall = flag.Bool("nofirewall", false, "disable the rtr7 firewall")
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -114,7 +117,7 @@ func updateListeners() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if net1, err := multilisten.IPv6Net1("/perm"); err == nil {
|
if net1, err := multilisten.IPv6Net1(*perm); err == nil {
|
||||||
hosts = append(hosts, net1)
|
hosts = append(hosts, net1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,19 +137,18 @@ func logic() error {
|
|||||||
ch := make(chan os.Signal, 1)
|
ch := make(chan os.Signal, 1)
|
||||||
signal.Notify(ch, syscall.SIGUSR1)
|
signal.Notify(ch, syscall.SIGUSR1)
|
||||||
for {
|
for {
|
||||||
err := netconfig.Apply("/perm/", "/")
|
err := netconfig.Apply(*perm, "/", !*noFirewall)
|
||||||
|
|
||||||
// Notify dhcp4d so that it can update its listeners for prometheus
|
// Notify dhcp4d so that it can update its listeners for prometheus
|
||||||
// metrics on the external interface.
|
// metrics on the external interface.
|
||||||
if err := notify.Process("/user/dhcp4d", syscall.SIGUSR1); err != nil {
|
if err := notify.Process(path.Join(path.Dir(os.Args[0]), "dhcp4d"), syscall.SIGUSR1); err != nil {
|
||||||
log.Printf("notifying dhcp4d: %v", err)
|
log.Printf("notifying dhcp4d: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notify gokrazy about new addresses (netconfig.Apply might have
|
// Notify gokrazy about new addresses (netconfig.Apply might have
|
||||||
// modified state before returning an error) so that listeners can be
|
// modified state before returning an error) so that listeners can be
|
||||||
// updated.
|
// updated.
|
||||||
p, _ := os.FindProcess(1)
|
if err := notify.Process(path.Join(path.Dir(os.Args[0]), "rtr7-init"), syscall.SIGHUP); err != nil {
|
||||||
if err := p.Signal(syscall.SIGHUP); err != nil {
|
|
||||||
log.Printf("kill -HUP 1: %v", err)
|
log.Printf("kill -HUP 1: %v", err)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -165,6 +167,7 @@ func logic() error {
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
netconfig.CmdRoot = path.Dir(os.Args[0])
|
||||||
if err := logic(); err != nil {
|
if err := logic(); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
// Binary radvd sends IPv6 router advertisments.
|
// Binary radvd sends IPv6 router advertisements.
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -23,19 +23,22 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
"path"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/rtr7/router7/internal/dhcp6"
|
"github.com/rtr7/router7/internal/dhcp6"
|
||||||
"github.com/rtr7/router7/internal/radvd"
|
"github.com/rtr7/router7/internal/radvd"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var perm = flag.String("perm", "/perm", "path to replace /perm")
|
||||||
|
|
||||||
func logic() error {
|
func logic() error {
|
||||||
srv, err := radvd.NewServer()
|
srv, err := radvd.NewServer()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
readConfig := func() error {
|
readConfig := func() error {
|
||||||
b, err := ioutil.ReadFile("/perm/dhcp6/wire/lease.json")
|
b, err := ioutil.ReadFile(path.Join(*perm, "/dhcp6/wire/lease.json"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -45,7 +48,7 @@ func logic() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var additional []net.IPNet
|
var additional []net.IPNet
|
||||||
if b, err := ioutil.ReadFile("/perm/radvd/prefixes.json"); err == nil {
|
if b, err := ioutil.ReadFile(path.Join(*perm, "/radvd/prefixes.json")); err == nil {
|
||||||
if err := json.Unmarshal(b, &additional); err != nil {
|
if err := json.Unmarshal(b, &additional); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
51
init/init.go
Normal file
51
init/init.go
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os/exec"
|
||||||
|
"path"
|
||||||
|
|
||||||
|
"github.com/gokrazy/gokrazy"
|
||||||
|
)
|
||||||
|
|
||||||
|
// buildTimestamp can be overridden by specifying e.g.
|
||||||
|
// -ldflags "-X main.buildTimestamp=foo" when building.
|
||||||
|
var (
|
||||||
|
buildTimestamp = "2020-06-08T19:45:52-07:00"
|
||||||
|
|
||||||
|
domain string
|
||||||
|
cmdRoot string
|
||||||
|
perm string
|
||||||
|
noFirewall bool
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
flag.StringVar(&cmdRoot, "cmdroot", "/usr/bin", "path to rtr7 binaries")
|
||||||
|
flag.StringVar(&domain, "domain", "lan", "domain name for your network")
|
||||||
|
flag.StringVar(&perm, "perm", "/var/lib/rtr7/", "path to replace /perm")
|
||||||
|
flag.BoolVar(&noFirewall, "nofirewall", false, "disable the rtr7 firewall")
|
||||||
|
flag.Parse()
|
||||||
|
log.SetFlags(log.LstdFlags | log.Lshortfile)
|
||||||
|
|
||||||
|
fmt.Printf("gokrazy build timestamp %s\n", buildTimestamp)
|
||||||
|
|
||||||
|
cmds := []*exec.Cmd{
|
||||||
|
// exec.Command(path.Join(cmdRoot, "/ntp")),
|
||||||
|
exec.Command(path.Join(cmdRoot, "backupd"), "-perm="+perm),
|
||||||
|
exec.Command(path.Join(cmdRoot, "captured"), "-perm="+perm),
|
||||||
|
exec.Command(path.Join(cmdRoot, "dhcp4"), "-perm="+perm),
|
||||||
|
exec.Command(path.Join(cmdRoot, "dhcp4d"), "-perm="+perm),
|
||||||
|
exec.Command(path.Join(cmdRoot, "dhcp6"), "-perm="+perm),
|
||||||
|
exec.Command(path.Join(cmdRoot, "diagd"), "-perm="+perm),
|
||||||
|
exec.Command(path.Join(cmdRoot, "dnsd"), fmt.Sprintf("-domain=%s", domain), "-perm="+perm),
|
||||||
|
exec.Command(path.Join(cmdRoot, "dyndns"), "-perm="+perm),
|
||||||
|
exec.Command(path.Join(cmdRoot, "netconfigd"), fmt.Sprintf("-nofirewall=%t", noFirewall), "-perm="+perm),
|
||||||
|
exec.Command(path.Join(cmdRoot, "radvd"), "-perm="+perm),
|
||||||
|
}
|
||||||
|
if err := gokrazy.Supervise(cmds); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
select {}
|
||||||
|
}
|
@ -18,9 +18,12 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"path"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var Perm = "/perm"
|
||||||
|
|
||||||
func leaseValid(fn string) (status string, _ error) {
|
func leaseValid(fn string) (status string, _ error) {
|
||||||
var lease struct {
|
var lease struct {
|
||||||
ValidUntil time.Time `json:"valid_until"`
|
ValidUntil time.Time `json:"valid_until"`
|
||||||
@ -56,7 +59,7 @@ func (d *dhcpv4) Children() []Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *dhcpv4) Evaluate() (string, error) {
|
func (d *dhcpv4) Evaluate() (string, error) {
|
||||||
return leaseValid("/perm/dhcp4/wire/lease.json")
|
return leaseValid(path.Join(Perm, "/dhcp4/wire/lease.json"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// DHCPv4 returns a Node which succeeds if /perm/dhcp4/wire/lease.json contains
|
// DHCPv4 returns a Node which succeeds if /perm/dhcp4/wire/lease.json contains
|
||||||
@ -83,7 +86,7 @@ func (d *dhcpv6) Children() []Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *dhcpv6) Evaluate() (string, error) {
|
func (d *dhcpv6) Evaluate() (string, error) {
|
||||||
return leaseValid("/perm/dhcp6/wire/lease.json")
|
return leaseValid(path.Join(Perm, "/dhcp6/wire/lease.json"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// DHCPv6 returns a Node which succeeds if /perm/dhcp6/wire/lease.json contains
|
// DHCPv6 returns a Node which succeeds if /perm/dhcp6/wire/lease.json contains
|
||||||
|
@ -42,6 +42,11 @@ var log = teelogger.NewConsole()
|
|||||||
// DHCP-based local name resolution can be made case-insensitive.
|
// DHCP-based local name resolution can be made case-insensitive.
|
||||||
type lcHostname string
|
type lcHostname string
|
||||||
|
|
||||||
|
type DNSIP struct {
|
||||||
|
IPv6 net.IP
|
||||||
|
IPv4 net.IP
|
||||||
|
}
|
||||||
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
Mux *dns.ServeMux
|
Mux *dns.ServeMux
|
||||||
|
|
||||||
@ -59,7 +64,7 @@ type Server struct {
|
|||||||
hostname, ip string
|
hostname, ip string
|
||||||
hostsByName map[lcHostname]string
|
hostsByName map[lcHostname]string
|
||||||
hostsByIP map[string]string
|
hostsByIP map[string]string
|
||||||
subnames map[lcHostname]map[string]net.IP // hostname → subname → ip
|
subnames map[lcHostname]map[string]DNSIP // hostname → subname → ip
|
||||||
|
|
||||||
upstreamMu sync.RWMutex
|
upstreamMu sync.RWMutex
|
||||||
upstream []string
|
upstream []string
|
||||||
@ -74,6 +79,10 @@ func NewServer(addr, domain string) *Server {
|
|||||||
domain: domain,
|
domain: domain,
|
||||||
upstream: []string{
|
upstream: []string{
|
||||||
// https://developers.google.com/speed/public-dns/docs/using#google_public_dns_ip_addresses
|
// https://developers.google.com/speed/public-dns/docs/using#google_public_dns_ip_addresses
|
||||||
|
"1.1.1.1:53",
|
||||||
|
"1.0.0.1:53",
|
||||||
|
"2606:4700:4700::1111:53",
|
||||||
|
"2606:4700:4700::1001:53",
|
||||||
"8.8.8.8:53",
|
"8.8.8.8:53",
|
||||||
"8.8.4.4:53",
|
"8.8.4.4:53",
|
||||||
"[2001:4860:4860::8888]:53",
|
"[2001:4860:4860::8888]:53",
|
||||||
@ -82,7 +91,7 @@ func NewServer(addr, domain string) *Server {
|
|||||||
sometimes: rate.NewLimiter(rate.Every(1*time.Second), 1), // at most once per second
|
sometimes: rate.NewLimiter(rate.Every(1*time.Second), 1), // at most once per second
|
||||||
hostname: hostname,
|
hostname: hostname,
|
||||||
ip: ip,
|
ip: ip,
|
||||||
subnames: make(map[lcHostname]map[string]net.IP),
|
subnames: make(map[lcHostname]map[string]DNSIP),
|
||||||
}
|
}
|
||||||
server.prom.registry = prometheus.NewRegistry()
|
server.prom.registry = prometheus.NewRegistry()
|
||||||
|
|
||||||
@ -111,7 +120,8 @@ func NewServer(addr, domain string) *Server {
|
|||||||
server.prom.registry.MustRegister(prometheus.NewGoCollector())
|
server.prom.registry.MustRegister(prometheus.NewGoCollector())
|
||||||
server.initHostsLocked()
|
server.initHostsLocked()
|
||||||
server.Mux.HandleFunc(".", server.handleRequest)
|
server.Mux.HandleFunc(".", server.handleRequest)
|
||||||
server.Mux.HandleFunc("lan.", server.handleInternal)
|
server.Mux.HandleFunc(domain+".", server.subnameHandler(domain))
|
||||||
|
server.Mux.HandleFunc("lan.", server.subnameHandler(domain))
|
||||||
server.Mux.HandleFunc("localhost.", server.handleInternal)
|
server.Mux.HandleFunc("localhost.", server.handleInternal)
|
||||||
go func() {
|
go func() {
|
||||||
for range time.Tick(10 * time.Second) {
|
for range time.Tick(10 * time.Second) {
|
||||||
@ -124,14 +134,20 @@ func NewServer(addr, domain string) *Server {
|
|||||||
func (s *Server) initHostsLocked() {
|
func (s *Server) initHostsLocked() {
|
||||||
s.hostsByName = make(map[lcHostname]string)
|
s.hostsByName = make(map[lcHostname]string)
|
||||||
s.hostsByIP = make(map[string]string)
|
s.hostsByIP = make(map[string]string)
|
||||||
|
s.subnames[lcHostname(s.domain)] = make(map[string]DNSIP)
|
||||||
if s.hostname != "" && s.ip != "" {
|
if s.hostname != "" && s.ip != "" {
|
||||||
lower := strings.ToLower(s.hostname)
|
lower := strings.ToLower(s.hostname)
|
||||||
s.hostsByName[lcHostname(lower)] = s.ip
|
s.hostsByName[lcHostname(lower)] = s.ip
|
||||||
if rev, err := dns.ReverseAddr(s.ip); err == nil {
|
if rev, err := dns.ReverseAddr(s.ip); err == nil {
|
||||||
s.hostsByIP[rev] = s.hostname
|
s.hostsByIP[rev] = s.hostname
|
||||||
}
|
}
|
||||||
s.Mux.HandleFunc(lower+".", s.subnameHandler(s.hostname))
|
subnames := s.subnames[lcHostname(s.domain)]
|
||||||
s.Mux.HandleFunc(lower+"."+s.domain+".", s.subnameHandler(s.hostname))
|
ip := net.ParseIP(s.ip)
|
||||||
|
if ip.To4() != nil {
|
||||||
|
subnames[lower] = DNSIP{IPv4: ip}
|
||||||
|
} else {
|
||||||
|
subnames[lower] = DNSIP{IPv6: ip}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,10 +211,12 @@ func (s *Server) hostByIP(n string) (string, bool) {
|
|||||||
return r, ok
|
return r, ok
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) subname(hostname, host string) (net.IP, bool) {
|
func (s *Server) subname(hostname, host string) (DNSIP, bool) {
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
defer s.mu.Unlock()
|
defer s.mu.Unlock()
|
||||||
r, ok := s.subnames[lcHostname(strings.ToLower(hostname))][host]
|
// // log.Println(s.subnames)
|
||||||
|
r, ok := s.subnames[lcHostname(strings.ToLower(hostname))][strings.ToLower(host)]
|
||||||
|
// log.Println("returning", r, ok)
|
||||||
return r, ok
|
return r, ok
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -235,10 +253,20 @@ func (s *Server) DyndnsHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
lower := strings.ToLower(hostname)
|
lower := strings.ToLower(hostname)
|
||||||
subnames, ok := s.subnames[lcHostname(lower)]
|
subnames, ok := s.subnames[lcHostname(lower)]
|
||||||
if !ok {
|
if !ok {
|
||||||
subnames = make(map[string]net.IP)
|
subnames = make(map[string]DNSIP)
|
||||||
s.subnames[lcHostname(lower)] = subnames
|
s.subnames[lcHostname(lower)] = subnames
|
||||||
}
|
}
|
||||||
subnames[host] = ip
|
if ip.To4() != nil {
|
||||||
|
subnames[host] = DNSIP{
|
||||||
|
IPv4: ip,
|
||||||
|
IPv6: subnames[host].IPv6,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
subnames[host] = DNSIP{
|
||||||
|
IPv4: subnames[host].IPv4,
|
||||||
|
IPv6: ip,
|
||||||
|
}
|
||||||
|
}
|
||||||
w.Write([]byte("ok\n"))
|
w.Write([]byte("ok\n"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -270,11 +298,27 @@ func (s *Server) SetLeases(leases []dhcp4d.Lease) {
|
|||||||
continue // don’t overwrite e.g. the hostname entry
|
continue // don’t overwrite e.g. the hostname entry
|
||||||
}
|
}
|
||||||
s.hostsByName[lcHostname(lower)] = l.Addr.String()
|
s.hostsByName[lcHostname(lower)] = l.Addr.String()
|
||||||
|
|
||||||
|
subnames, ok := s.subnames[lcHostname(s.domain)]
|
||||||
|
if !ok {
|
||||||
|
subnames = make(map[string]DNSIP)
|
||||||
|
s.subnames[lcHostname(s.domain)] = subnames
|
||||||
|
}
|
||||||
|
if l.Addr.To4() != nil {
|
||||||
|
subnames[lower] = DNSIP{
|
||||||
|
IPv4: l.Addr,
|
||||||
|
IPv6: subnames[lower].IPv6,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
subnames[lower] = DNSIP{
|
||||||
|
IPv4: subnames[lower].IPv4,
|
||||||
|
IPv6: l.Addr,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if rev, err := dns.ReverseAddr(l.Addr.String()); err == nil {
|
if rev, err := dns.ReverseAddr(l.Addr.String()); err == nil {
|
||||||
s.hostsByIP[rev] = l.Hostname
|
s.hostsByIP[rev] = l.Hostname
|
||||||
}
|
}
|
||||||
s.Mux.HandleFunc(lower+".", s.subnameHandler(lower))
|
|
||||||
s.Mux.HandleFunc(lower+"."+s.domain+".", s.subnameHandler(lower))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -329,10 +373,7 @@ func isLocalInAddrArpa(q string) bool {
|
|||||||
|
|
||||||
var errEmpty = errors.New("no answers")
|
var errEmpty = errors.New("no answers")
|
||||||
|
|
||||||
func (s *Server) resolve(q dns.Question) (rr dns.RR, err error) {
|
func (s *Server) resolveLocal(q dns.Question) (rr dns.RR, err error) {
|
||||||
if q.Qclass != dns.ClassINET {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
if strings.ToLower(q.Name) == "localhost." {
|
if strings.ToLower(q.Name) == "localhost." {
|
||||||
if q.Qtype == dns.TypeAAAA {
|
if q.Qtype == dns.TypeAAAA {
|
||||||
return dns.NewRR(q.Name + " 3600 IN AAAA ::1")
|
return dns.NewRR(q.Name + " 3600 IN AAAA ::1")
|
||||||
@ -341,18 +382,6 @@ func (s *Server) resolve(q dns.Question) (rr dns.RR, err error) {
|
|||||||
return dns.NewRR(q.Name + " 3600 IN A 127.0.0.1")
|
return dns.NewRR(q.Name + " 3600 IN A 127.0.0.1")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if q.Qtype == dns.TypeA ||
|
|
||||||
q.Qtype == dns.TypeAAAA ||
|
|
||||||
q.Qtype == dns.TypeMX {
|
|
||||||
name := strings.TrimSuffix(q.Name, ".")
|
|
||||||
name = strings.TrimSuffix(name, "."+s.domain)
|
|
||||||
if host, ok := s.hostByName(name); ok {
|
|
||||||
if q.Qtype == dns.TypeA {
|
|
||||||
return dns.NewRR(q.Name + " 3600 IN A " + host)
|
|
||||||
}
|
|
||||||
return nil, errEmpty
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if q.Qtype == dns.TypePTR {
|
if q.Qtype == dns.TypePTR {
|
||||||
if host, ok := s.hostByIP(q.Name); ok {
|
if host, ok := s.hostByIP(q.Name); ok {
|
||||||
return dns.NewRR(q.Name + " 3600 IN PTR " + host + "." + s.domain)
|
return dns.NewRR(q.Name + " 3600 IN PTR " + host + "." + s.domain)
|
||||||
@ -365,13 +394,11 @@ func (s *Server) resolve(q dns.Question) (rr dns.RR, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) handleInternal(w dns.ResponseWriter, r *dns.Msg) {
|
func (s *Server) handleInternal(w dns.ResponseWriter, r *dns.Msg) {
|
||||||
s.prom.queries.Inc()
|
s.promInc("local", r)
|
||||||
s.prom.questions.Observe(float64(len(r.Question)))
|
|
||||||
s.prom.upstream.WithLabelValues("local").Inc()
|
|
||||||
if len(r.Question) != 1 { // TODO: answer all questions we can answer
|
if len(r.Question) != 1 { // TODO: answer all questions we can answer
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
rr, err := s.resolve(r.Question[0])
|
rr, err := s.resolveLocal(r.Question[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == errEmpty {
|
if err == errEmpty {
|
||||||
m := new(dns.Msg)
|
m := new(dns.Msg)
|
||||||
@ -379,7 +406,7 @@ func (s *Server) handleInternal(w dns.ResponseWriter, r *dns.Msg) {
|
|||||||
w.WriteMsg(m)
|
w.WriteMsg(m)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Fatal(err)
|
log.Fatalf("question %#v: %v", r.Question[0], err)
|
||||||
}
|
}
|
||||||
if rr != nil {
|
if rr != nil {
|
||||||
m := new(dns.Msg)
|
m := new(dns.Msg)
|
||||||
@ -388,7 +415,7 @@ func (s *Server) handleInternal(w dns.ResponseWriter, r *dns.Msg) {
|
|||||||
w.WriteMsg(m)
|
w.WriteMsg(m)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Send an authoritative NXDOMAIN for local names:
|
// Send an authoritative NXDOMAIN for local:
|
||||||
m := new(dns.Msg)
|
m := new(dns.Msg)
|
||||||
m.SetReply(r)
|
m.SetReply(r)
|
||||||
m.SetRcode(r, dns.RcodeNameError)
|
m.SetRcode(r, dns.RcodeNameError)
|
||||||
@ -412,9 +439,7 @@ func (s *Server) handleRequest(w dns.ResponseWriter, r *dns.Msg) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s.prom.queries.Inc()
|
s.promInc("DNS", r)
|
||||||
s.prom.questions.Observe(float64(len(r.Question)))
|
|
||||||
s.prom.upstream.WithLabelValues("DNS").Inc()
|
|
||||||
|
|
||||||
for idx, u := range s.upstreams() {
|
for idx, u := range s.upstreams() {
|
||||||
in, _, err := s.client.Exchange(r, u)
|
in, _, err := s.client.Exchange(r, u)
|
||||||
@ -436,36 +461,23 @@ func (s *Server) handleRequest(w dns.ResponseWriter, r *dns.Msg) {
|
|||||||
// DNS has no reply for resolving errors
|
// DNS has no reply for resolving errors
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) resolveSubname(hostname string, q dns.Question) (dns.RR, error) {
|
func (s *Server) resolveSubname(domain string, q dns.Question) (dns.RR, error) {
|
||||||
|
// log.Println("relolving subname of", domain, q.Name)
|
||||||
if q.Qclass != dns.ClassINET {
|
if q.Qclass != dns.ClassINET {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
if q.Qtype == dns.TypeA ||
|
if q.Qtype == dns.TypeA || q.Qtype == dns.TypeAAAA /*|| q.Qtype == dns.TypeMX*/ {
|
||||||
q.Qtype == dns.TypeAAAA ||
|
name := strings.TrimSuffix(q.Name, ".")
|
||||||
q.Qtype == dns.TypeMX {
|
name = strings.TrimSuffix(name, "."+domain)
|
||||||
name := strings.TrimSuffix(q.Name, "."+hostname+".")
|
// log.Println("name to search", name)
|
||||||
name = strings.TrimSuffix(name, "."+hostname+"."+s.domain+".")
|
|
||||||
|
|
||||||
if lower := strings.ToLower(q.Name); lower == hostname+"." ||
|
if ip, ok := s.subname(domain, name); ok {
|
||||||
lower == hostname+"."+s.domain+"." {
|
|
||||||
host, ok := s.hostByName(hostname)
|
|
||||||
if !ok {
|
|
||||||
// The corresponding DHCP lease might have expired, but this
|
|
||||||
// handler is still installed on the mux.
|
|
||||||
return nil, nil // NXDOMAIN
|
|
||||||
}
|
|
||||||
if q.Qtype == dns.TypeA {
|
|
||||||
return dns.NewRR(q.Name + " 3600 IN A " + host)
|
|
||||||
}
|
|
||||||
return nil, errEmpty
|
|
||||||
}
|
|
||||||
|
|
||||||
if ip, ok := s.subname(hostname, name); ok {
|
if q.Qtype == dns.TypeA && ip.IPv4.To4() != nil {
|
||||||
if q.Qtype == dns.TypeA && ip.To4() != nil {
|
return dns.NewRR(q.Name + " 3600 IN A " + ip.IPv4.String())
|
||||||
return dns.NewRR(q.Name + " 3600 IN A " + ip.String())
|
|
||||||
}
|
}
|
||||||
if q.Qtype == dns.TypeAAAA && ip.To4() == nil {
|
if q.Qtype == dns.TypeAAAA && ip.IPv6.To4() == nil && ip.IPv6 != nil {
|
||||||
return dns.NewRR(q.Name + " 3600 IN AAAA " + ip.String())
|
return dns.NewRR(q.Name + " 3600 IN AAAA " + ip.IPv6.String())
|
||||||
}
|
}
|
||||||
return nil, errEmpty
|
return nil, errEmpty
|
||||||
}
|
}
|
||||||
@ -473,14 +485,24 @@ func (s *Server) resolveSubname(hostname string, q dns.Question) (dns.RR, error)
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Server) promInc(label string, r *dns.Msg) {
|
||||||
|
s.prom.queries.Inc()
|
||||||
|
s.prom.questions.Observe(float64(len(r.Question)))
|
||||||
|
s.prom.upstream.WithLabelValues(label).Inc()
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Server) subnameHandler(hostname string) func(w dns.ResponseWriter, r *dns.Msg) {
|
func (s *Server) subnameHandler(hostname string) func(w dns.ResponseWriter, r *dns.Msg) {
|
||||||
return func(w dns.ResponseWriter, r *dns.Msg) {
|
return func(w dns.ResponseWriter, r *dns.Msg) {
|
||||||
|
|
||||||
if len(r.Question) != 1 { // TODO: answer all questions we can answer
|
if len(r.Question) != 1 { // TODO: answer all questions we can answer
|
||||||
|
s.promInc("local", r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
rr, err := s.resolveSubname(hostname, r.Question[0])
|
rr, err := s.resolveSubname(hostname, r.Question[0])
|
||||||
|
|
||||||
|
// log.Println("handle subname", hostname, r.Question[0].Name, rr, err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
s.promInc("local", r)
|
||||||
if err == errEmpty {
|
if err == errEmpty {
|
||||||
m := new(dns.Msg)
|
m := new(dns.Msg)
|
||||||
m.SetReply(r)
|
m.SetReply(r)
|
||||||
@ -490,16 +512,24 @@ func (s *Server) subnameHandler(hostname string) func(w dns.ResponseWriter, r *d
|
|||||||
log.Fatalf("question %#v: %v", r.Question[0], err)
|
log.Fatalf("question %#v: %v", r.Question[0], err)
|
||||||
}
|
}
|
||||||
if rr != nil {
|
if rr != nil {
|
||||||
|
s.promInc("local", r)
|
||||||
m := new(dns.Msg)
|
m := new(dns.Msg)
|
||||||
m.SetReply(r)
|
m.SetReply(r)
|
||||||
m.Answer = append(m.Answer, rr)
|
m.Answer = append(m.Answer, rr)
|
||||||
w.WriteMsg(m)
|
w.WriteMsg(m)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send an authoritative NXDOMAIN for local names:
|
// Send an authoritative NXDOMAIN for local names:
|
||||||
|
if r.Question[0].Qtype == dns.TypePTR || !strings.Contains(strings.TrimSuffix(r.Question[0].Name, "."), ".") || strings.HasSuffix(r.Question[0].Name, ".lan.") {
|
||||||
|
s.promInc("local", r)
|
||||||
m := new(dns.Msg)
|
m := new(dns.Msg)
|
||||||
m.SetReply(r)
|
m.SetReply(r)
|
||||||
m.SetRcode(r, dns.RcodeNameError)
|
m.SetRcode(r, dns.RcodeNameError)
|
||||||
w.WriteMsg(m)
|
w.WriteMsg(m)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s.handleRequest(w, r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -42,6 +43,8 @@ import (
|
|||||||
|
|
||||||
var log = teelogger.NewConsole()
|
var log = teelogger.NewConsole()
|
||||||
|
|
||||||
|
var CmdRoot = "/user"
|
||||||
|
|
||||||
func subnetMaskSize(mask string) (int, error) {
|
func subnetMaskSize(mask string) (int, error) {
|
||||||
parts := strings.Split(mask, ".")
|
parts := strings.Split(mask, ".")
|
||||||
if got, want := len(parts), 4; got != want {
|
if got, want := len(parts), 4; got != want {
|
||||||
@ -729,7 +732,7 @@ func applySysctl(ifname string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func Apply(dir, root string) error {
|
func Apply(dir, root string, firewall bool) error {
|
||||||
|
|
||||||
// TODO: split into two parts: delay the up until later
|
// TODO: split into two parts: delay the up until later
|
||||||
if err := applyInterfaces(dir, root); err != nil {
|
if err := applyInterfaces(dir, root); err != nil {
|
||||||
@ -757,7 +760,7 @@ func Apply(dir, root string) error {
|
|||||||
"backupd", // listens on private IPv4/IPv6
|
"backupd", // listens on private IPv4/IPv6
|
||||||
"captured", // listens on private IPv4/IPv6
|
"captured", // listens on private IPv4/IPv6
|
||||||
} {
|
} {
|
||||||
if err := notify.Process("/user/"+process, syscall.SIGUSR1); err != nil {
|
if err := notify.Process(path.Join(CmdRoot, process), syscall.SIGUSR1); err != nil {
|
||||||
log.Printf("notifying %s: %v", process, err)
|
log.Printf("notifying %s: %v", process, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -771,9 +774,11 @@ func Apply(dir, root string) error {
|
|||||||
appendError(fmt.Errorf("sysctl: %v", err))
|
appendError(fmt.Errorf("sysctl: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if firewall {
|
||||||
if err := applyFirewall(dir, ifname); err != nil {
|
if err := applyFirewall(dir, ifname); err != nil {
|
||||||
appendError(fmt.Errorf("firewall: %v", err))
|
appendError(fmt.Errorf("firewall: %v", err))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err := applyWireGuard(dir); err != nil {
|
if err := applyWireGuard(dir); err != nil {
|
||||||
appendError(fmt.Errorf("wireguard: %v", err))
|
appendError(fmt.Errorf("wireguard: %v", err))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user