mirror of
https://github.com/namecoin/ncdns
synced 2024-11-18 03:26:00 +00:00
158 lines
3.9 KiB
Go
158 lines
3.9 KiB
Go
package server
|
|
|
|
import "github.com/hlandau/madns"
|
|
import "github.com/hlandau/degoutils/log"
|
|
import "github.com/hlandau/ncdns/backend"
|
|
import "github.com/miekg/dns"
|
|
import "os"
|
|
import "fmt"
|
|
import "os/signal"
|
|
import "syscall"
|
|
|
|
type Server struct {
|
|
cfg ServerConfig
|
|
|
|
engine madns.Engine
|
|
|
|
mux *dns.ServeMux
|
|
udpListener *dns.Server
|
|
tcpListener *dns.Server
|
|
}
|
|
|
|
type ServerConfig struct {
|
|
Bind string `default:":53" usage:"Address to bind to (e.g. 0.0.0.0:53)"`
|
|
PublicKey string `default:"" usage:"Path to the DNSKEY KSK public key file"`
|
|
PrivateKey string `default:"" usage:"Path to the KSK's corresponding private key file"`
|
|
ZonePublicKey string `default:"" usage:"Path to the DNSKEY ZSK public key file; if one is not specified, a temporary one is generated on startup and used only for the duration of that process"`
|
|
ZonePrivateKey string `default:"" usage:"Path to the ZSK's corresponding private key file"`
|
|
|
|
NamecoinRPCUsername string `default:"" usage:"Namecoin RPC username"`
|
|
NamecoinRPCPassword string `default:"" usage:"Namecoin RPC password"`
|
|
NamecoinRPCAddress string `default:"localhost:8336" usage:"Namecoin RPC server address"`
|
|
CacheMaxEntries int `default:"1000" usage:"Maximum name cache entries"`
|
|
SelfName string `default:"" usage:"Canonical name for this nameserver (default: autogenerated psuedo-hostname resolving to SelfIP; SelfIP is not used if this is set)"`
|
|
SelfIP string `default:"127.127.127.127" usage:"The canonical IP address for this service"`
|
|
|
|
Daemonize bool `default:"false" usage:"Daemonize (doesn't fork)"`
|
|
UID int `default:"0" usage:"UID to drop privileges to if run as root"`
|
|
GID int `default:"0" usage:"GID to drop privileges to if run as root"`
|
|
}
|
|
|
|
func NewServer(cfg *ServerConfig) (s *Server, err error) {
|
|
s = &Server{}
|
|
s.cfg = *cfg
|
|
|
|
bcfg := &backend.Config{
|
|
RPCUsername: cfg.NamecoinRPCUsername,
|
|
RPCPassword: cfg.NamecoinRPCPassword,
|
|
RPCAddress: cfg.NamecoinRPCAddress,
|
|
CacheMaxEntries: cfg.CacheMaxEntries,
|
|
SelfName: cfg.SelfName,
|
|
SelfIP: cfg.SelfIP,
|
|
}
|
|
|
|
b, err := backend.New(bcfg)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
ecfg := &madns.EngineConfig{
|
|
Backend: b,
|
|
}
|
|
|
|
// key setup
|
|
if cfg.PublicKey != "" {
|
|
ksk, kskPrivate, err := s.loadKey(cfg.PublicKey, cfg.PrivateKey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
ecfg.KSK = ksk
|
|
ecfg.KSKPrivate = kskPrivate
|
|
}
|
|
|
|
if cfg.ZonePublicKey != "" {
|
|
zsk, zskPrivate, err := s.loadKey(cfg.ZonePublicKey, cfg.ZonePrivateKey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
ecfg.ZSK = zsk
|
|
ecfg.ZSKPrivate = zskPrivate
|
|
}
|
|
|
|
if ecfg.KSK != nil && ecfg.ZSK == nil {
|
|
return nil, fmt.Errorf("Must specify ZSK if KSK is specified")
|
|
}
|
|
|
|
e, err := madns.NewEngine(ecfg)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
s.engine = e
|
|
return
|
|
}
|
|
|
|
func (s *Server) loadKey(fn, privateFn string) (k *dns.DNSKEY, privatek dns.PrivateKey, err error) {
|
|
f, err := os.Open(fn)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
rr, err := dns.ReadRR(f, fn)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
k, ok := rr.(*dns.DNSKEY)
|
|
if !ok {
|
|
err = fmt.Errorf("Loaded record from key file, but it wasn't a DNSKEY")
|
|
return
|
|
}
|
|
|
|
privatef, err := os.Open(privateFn)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
privatek, err = k.ReadPrivateKey(privatef, privateFn)
|
|
log.Fatale(err)
|
|
|
|
return
|
|
}
|
|
|
|
func (s *Server) Run() {
|
|
s.mux = dns.NewServeMux()
|
|
s.mux.Handle(".", s.engine)
|
|
|
|
s.udpListener = s.runListener("udp")
|
|
s.tcpListener = s.runListener("tcp")
|
|
|
|
log.Info("Ready.")
|
|
|
|
// wait
|
|
sig := make(chan os.Signal)
|
|
signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
|
|
for {
|
|
s := <-sig
|
|
fmt.Printf("Signal %v received, stopping.", s)
|
|
break
|
|
}
|
|
}
|
|
|
|
func (s *Server) doRunListener(ds *dns.Server) {
|
|
err := ds.ListenAndServe()
|
|
log.Fatale(err)
|
|
}
|
|
|
|
func (s *Server) runListener(net string) *dns.Server {
|
|
ds := &dns.Server{
|
|
Addr: s.cfg.Bind,
|
|
Net: net,
|
|
Handler: s.mux,
|
|
}
|
|
go s.doRunListener(ds)
|
|
return ds
|
|
}
|