You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ncdns/server/server.go

171 lines
4.0 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"
import "path/filepath"
const version = "1.0"
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:"100" 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"`
ConfigDir string // path to interpret filenames relative to
}
func (cfg *ServerConfig) cpath(s string) string {
return filepath.Join(cfg.ConfigDir, s)
}
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,
VersionString: "ncdns/" + version,
}
// 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) {
fn = s.cfg.cpath(fn)
privateFn = s.cfg.cpath(privateFn)
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) Start() error {
s.mux = dns.NewServeMux()
s.mux.Handle(".", s.engine)
s.udpListener = s.runListener("udp")
s.tcpListener = s.runListener("tcp")
return nil
}
func (s *Server) Run() {
s.Start()
// 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
}