pull/18/head
Hugo Landau 10 years ago
parent 53ab040fdc
commit cc5afd43b7

File diff suppressed because it is too large Load Diff

@ -1,32 +1,33 @@
package main package main
import "github.com/hlandau/degoutils/config" import "github.com/hlandau/degoutils/config"
import "github.com/hlandau/degoutils/log" import "github.com/hlandau/degoutils/log"
import "github.com/hlandau/degoutils/daemon" import "github.com/hlandau/degoutils/daemon"
import "github.com/hlandau/ncdns/server" import "github.com/hlandau/ncdns/server"
func main() { func main() {
cfg := server.ServerConfig{} cfg := server.ServerConfig{}
config := config.Configurator{ config := config.Configurator{
ProgramName: "ncdns", ProgramName: "ncdns",
ConfigFilePaths: []string { "etc/ncdns.conf", "/etc/ncdns/ncdns.conf", }, ConfigFilePaths: []string{"etc/ncdns.conf", "/etc/ncdns/ncdns.conf"},
} }
config.ParseFatal(&cfg) config.ParseFatal(&cfg)
err := daemon.Init() err := daemon.Init()
log.Fatale(err) log.Fatale(err)
if cfg.Daemonize { if cfg.Daemonize {
err := daemon.Daemonize() err := daemon.Daemonize()
log.Fatale(err) log.Fatale(err)
} }
err = daemon.DropPrivileges(cfg.UID, cfg.GID) err = daemon.DropPrivileges(cfg.UID, cfg.GID)
log.Fatale(err, "can't drop privileges") log.Fatale(err, "can't drop privileges")
s, err := server.NewServer(&cfg) s, err := server.NewServer(&cfg)
log.Fatale(err) log.Fatale(err)
s.Run() s.Run()
} }
// © 2014 Hugo Landau <hlandau@devever.net> GPLv3 or later // © 2014 Hugo Landau <hlandau@devever.net> GPLv3 or later

@ -6,62 +6,62 @@ import "github.com/hlandauf/btcjson"
import "encoding/json" import "encoding/json"
type NameShowCmd struct { type NameShowCmd struct {
id interface{} id interface{}
Name string `json:"name"` Name string `json:"name"`
} }
func NewNameShowCmd(id interface{}, name string) (*NameShowCmd, error) { func NewNameShowCmd(id interface{}, name string) (*NameShowCmd, error) {
return &NameShowCmd { return &NameShowCmd{
id: id, id: id,
Name: name, Name: name,
}, nil }, nil
} }
func (c *NameShowCmd) Id() interface{} { func (c *NameShowCmd) Id() interface{} {
return c.id return c.id
} }
func (c *NameShowCmd) Method() string { func (c *NameShowCmd) Method() string {
return "name_show" return "name_show"
} }
func (c *NameShowCmd) MarshalJSON() ([]byte, error) { func (c *NameShowCmd) MarshalJSON() ([]byte, error) {
params := []interface{}{ params := []interface{}{
c.Name, c.Name,
} }
raw, err := btcjson.NewRawCmd(c.id, c.Method(), params) raw, err := btcjson.NewRawCmd(c.id, c.Method(), params)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return json.Marshal(raw) return json.Marshal(raw)
} }
func (c *NameShowCmd) UnmarshalJSON(b []byte) error { func (c *NameShowCmd) UnmarshalJSON(b []byte) error {
// We don't need to implement this as we are only ever the client. // We don't need to implement this as we are only ever the client.
panic("not implemented") panic("not implemented")
return nil return nil
} }
type NameShowReply struct { type NameShowReply struct {
Name string `json:"name"` Name string `json:"name"`
Value string `json:"value"` Value string `json:"value"`
ExpiresIn int `json:"expires_in"` ExpiresIn int `json:"expires_in"`
} }
func replyParser(m json.RawMessage) (interface{}, error) { func replyParser(m json.RawMessage) (interface{}, error) {
nsr := &NameShowReply{} nsr := &NameShowReply{}
err := json.Unmarshal(m, nsr) err := json.Unmarshal(m, nsr)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return nsr, nil return nsr, nil
} }
func init() { func init() {
btcjson.RegisterCustomCmd("name_show", nil, replyParser, "name_show <name>") btcjson.RegisterCustomCmd("name_show", nil, replyParser, "name_show <name>")
} }
// © 2014 Hugo Landau <hlandau@devever.net> GPLv3 or later // © 2014 Hugo Landau <hlandau@devever.net> GPLv3 or later

@ -12,52 +12,52 @@ import "fmt"
var idCounter int32 = 0 var idCounter int32 = 0
func newID() int32 { func newID() int32 {
return atomic.AddInt32(&idCounter, 1) return atomic.AddInt32(&idCounter, 1)
} }
// Used to query a Namecoin JSON-RPC interface. Initialize the struct with a // Used to query a Namecoin JSON-RPC interface. Initialize the struct with a
// username, password, and address (hostname:port). // username, password, and address (hostname:port).
type NamecoinConn struct { type NamecoinConn struct {
Username string Username string
Password string Password string
Server string Server string
} }
// Query the Namecoin daemon for a Namecoin domain (e.g. d/example). // Query the Namecoin daemon for a Namecoin domain (e.g. d/example).
// If the domain exists, returns the value stored in Namecoin, which should be JSON. // If the domain exists, returns the value stored in Namecoin, which should be JSON.
// Note that this will return domain data even if the domain is expired. // Note that this will return domain data even if the domain is expired.
func (nc *NamecoinConn) Query(name string) (v string, err error) { func (nc *NamecoinConn) Query(name string) (v string, err error) {
cmd, err := extratypes.NewNameShowCmd(newID(), name) cmd, err := extratypes.NewNameShowCmd(newID(), name)
if err != nil { if err != nil {
//log.Info("NC NEWCMD ", err) //log.Info("NC NEWCMD ", err)
return "", err return "", err
} }
r, err := btcjson.RpcSend(nc.Username, nc.Password, nc.Server, cmd) r, err := btcjson.RpcSend(nc.Username, nc.Password, nc.Server, cmd)
if err != nil { if err != nil {
return "", err return "", err
} }
if r.Error != nil { if r.Error != nil {
//log.Info("RPC error: ", r.Error) //log.Info("RPC error: ", r.Error)
if r.Error.Code == -4 { if r.Error.Code == -4 {
return "", merr.ErrNoSuchDomain return "", merr.ErrNoSuchDomain
} }
return "", r.Error return "", r.Error
} }
if r.Result == nil { if r.Result == nil {
//log.Info("NC NILRESULT") //log.Info("NC NILRESULT")
return "", fmt.Errorf("got nil result") return "", fmt.Errorf("got nil result")
} }
if nsr, ok := r.Result.(*extratypes.NameShowReply); ok { if nsr, ok := r.Result.(*extratypes.NameShowReply); ok {
//log.Info("NC OK") //log.Info("NC OK")
return nsr.Value, nil return nsr.Value, nil
} else { } else {
//log.Info("NC BADREPLY") //log.Info("NC BADREPLY")
return "", fmt.Errorf("bad reply") return "", fmt.Errorf("bad reply")
} }
} }
// © 2014 Hugo Landau <hlandau@devever.net> GPLv3 or later // © 2014 Hugo Landau <hlandau@devever.net> GPLv3 or later

@ -1,4 +1,5 @@
package server package server
import "github.com/hlandau/madns" import "github.com/hlandau/madns"
import "github.com/hlandau/degoutils/log" import "github.com/hlandau/degoutils/log"
import "github.com/hlandau/ncdns/backend" import "github.com/hlandau/ncdns/backend"
@ -9,148 +10,148 @@ import "os/signal"
import "syscall" import "syscall"
type Server struct { type Server struct {
cfg ServerConfig cfg ServerConfig
engine madns.Engine engine madns.Engine
mux *dns.ServeMux mux *dns.ServeMux
udpListener *dns.Server udpListener *dns.Server
tcpListener *dns.Server tcpListener *dns.Server
} }
type ServerConfig struct { type ServerConfig struct {
Bind string `default:":53" usage:"Address to bind to (e.g. 0.0.0.0:53)"` Bind string `default:":53" usage:"Address to bind to (e.g. 0.0.0.0:53)"`
PublicKey string `default:"ncdns.key" usage:"Path to the DNSKEY KSK public key file"` PublicKey string `default:"ncdns.key" usage:"Path to the DNSKEY KSK public key file"`
PrivateKey string `default:"ncdns.private" usage:"Path to the KSK's corresponding private key file"` PrivateKey string `default:"ncdns.private" 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"` 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"` ZonePrivateKey string `default:"" usage:"Path to the ZSK's corresponding private key file"`
NamecoinRPCUsername string `default:"" usage:"Namecoin RPC username"` NamecoinRPCUsername string `default:"" usage:"Namecoin RPC username"`
NamecoinRPCPassword string `default:"" usage:"Namecoin RPC password"` NamecoinRPCPassword string `default:"" usage:"Namecoin RPC password"`
NamecoinRPCAddress string `default:"localhost:8336" usage:"Namecoin RPC server address"` NamecoinRPCAddress string `default:"localhost:8336" usage:"Namecoin RPC server address"`
CacheMaxEntries int `default:"1000" usage:"Maximum name cache entries"` 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)"` 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"` SelfIP string `default:"127.127.127.127" usage:"The canonical IP address for this service"`
Daemonize bool `default:"false" usage:"Daemonize (doesn't fork)"` Daemonize bool `default:"false" usage:"Daemonize (doesn't fork)"`
UID int `default:"0" usage:"UID to drop privileges to if run as root"` 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"` GID int `default:"0" usage:"GID to drop privileges to if run as root"`
} }
func NewServer(cfg *ServerConfig) (s *Server, err error) { func NewServer(cfg *ServerConfig) (s *Server, err error) {
s = &Server{} s = &Server{}
s.cfg = *cfg s.cfg = *cfg
bcfg := &backend.Config { bcfg := &backend.Config{
RPCUsername: cfg.NamecoinRPCUsername, RPCUsername: cfg.NamecoinRPCUsername,
RPCPassword: cfg.NamecoinRPCPassword, RPCPassword: cfg.NamecoinRPCPassword,
RPCAddress: cfg.NamecoinRPCAddress, RPCAddress: cfg.NamecoinRPCAddress,
CacheMaxEntries: cfg.CacheMaxEntries, CacheMaxEntries: cfg.CacheMaxEntries,
SelfName: cfg.SelfName, SelfName: cfg.SelfName,
SelfIP: cfg.SelfIP, SelfIP: cfg.SelfIP,
} }
b, err := backend.New(bcfg) b, err := backend.New(bcfg)
if err != nil { if err != nil {
return return
} }
ecfg := &madns.EngineConfig{ ecfg := &madns.EngineConfig{
Backend: b, Backend: b,
} }
// key setup // key setup
if cfg.PublicKey != "" { if cfg.PublicKey != "" {
ksk, kskPrivate, err := s.loadKey(cfg.PublicKey, cfg.PrivateKey) ksk, kskPrivate, err := s.loadKey(cfg.PublicKey, cfg.PrivateKey)
if err != nil { if err != nil {
return nil, err return nil, err
} }
ecfg.KSK = ksk ecfg.KSK = ksk
ecfg.KSKPrivate = kskPrivate ecfg.KSKPrivate = kskPrivate
} }
if cfg.ZonePublicKey != "" { if cfg.ZonePublicKey != "" {
zsk, zskPrivate, err := s.loadKey(cfg.ZonePublicKey, cfg.ZonePrivateKey) zsk, zskPrivate, err := s.loadKey(cfg.ZonePublicKey, cfg.ZonePrivateKey)
if err != nil { if err != nil {
return nil, err return nil, err
} }
ecfg.ZSK = zsk ecfg.ZSK = zsk
ecfg.ZSKPrivate = zskPrivate ecfg.ZSKPrivate = zskPrivate
} }
if ecfg.KSK != nil && ecfg.ZSK == nil { if ecfg.KSK != nil && ecfg.ZSK == nil {
return nil, fmt.Errorf("Must specify ZSK if KSK is specified") return nil, fmt.Errorf("Must specify ZSK if KSK is specified")
} }
e, err := madns.NewEngine(ecfg) e, err := madns.NewEngine(ecfg)
if err != nil { if err != nil {
return return
} }
s.engine = e s.engine = e
return return
} }
func (s *Server) loadKey(fn, privateFn string) (k *dns.DNSKEY, privatek dns.PrivateKey, err error) { func (s *Server) loadKey(fn, privateFn string) (k *dns.DNSKEY, privatek dns.PrivateKey, err error) {
f, err := os.Open(fn) f, err := os.Open(fn)
if err != nil { if err != nil {
return return
} }
rr, err := dns.ReadRR(f, fn) rr, err := dns.ReadRR(f, fn)
if err != nil { if err != nil {
return return
} }
k, ok := rr.(*dns.DNSKEY) k, ok := rr.(*dns.DNSKEY)
if !ok { if !ok {
err = fmt.Errorf("Loaded record from key file, but it wasn't a DNSKEY") err = fmt.Errorf("Loaded record from key file, but it wasn't a DNSKEY")
return return
} }
privatef, err := os.Open(privateFn) privatef, err := os.Open(privateFn)
if err != nil { if err != nil {
return return
} }
privatek, err = k.ReadPrivateKey(privatef, privateFn) privatek, err = k.ReadPrivateKey(privatef, privateFn)
log.Fatale(err) log.Fatale(err)
return return
} }
func (s *Server) Run() { func (s *Server) Run() {
s.mux = dns.NewServeMux() s.mux = dns.NewServeMux()
s.mux.Handle(".", s.engine) s.mux.Handle(".", s.engine)
s.udpListener = s.runListener("udp") s.udpListener = s.runListener("udp")
s.tcpListener = s.runListener("tcp") s.tcpListener = s.runListener("tcp")
log.Info("Ready.") log.Info("Ready.")
// wait // wait
sig := make(chan os.Signal) sig := make(chan os.Signal)
signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM) signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
for { for {
s := <-sig s := <-sig
fmt.Printf("Signal %v received, stopping.", s) fmt.Printf("Signal %v received, stopping.", s)
break break
} }
} }
func (s *Server) doRunListener(ds *dns.Server) { func (s *Server) doRunListener(ds *dns.Server) {
err := ds.ListenAndServe() err := ds.ListenAndServe()
log.Fatale(err) log.Fatale(err)
} }
func (s *Server) runListener(net string) *dns.Server { func (s *Server) runListener(net string) *dns.Server {
ds := &dns.Server { ds := &dns.Server{
Addr: s.cfg.Bind, Addr: s.cfg.Bind,
Net: net, Net: net,
Handler: s.mux, Handler: s.mux,
} }
go s.doRunListener(ds) go s.doRunListener(ds)
return ds return ds
} }

@ -1,17 +1,18 @@
package util package util
import "strings" import "strings"
// Split a domain name a.b.c.d.e into parts a (the head) and b.c.d.e (the rest). // Split a domain name a.b.c.d.e into parts a (the head) and b.c.d.e (the rest).
func SplitDomainHead(name string) (head string, rest string, err error) { func SplitDomainHead(name string) (head string, rest string, err error) {
parts := strings.Split(name, ".") parts := strings.Split(name, ".")
head = parts[len(parts)-1] head = parts[len(parts)-1]
if len(parts) >= 2 { if len(parts) >= 2 {
rest = strings.Join(parts[0:len(parts)-1], ".") rest = strings.Join(parts[0:len(parts)-1], ".")
} }
return return
} }
// © 2014 Hugo Landau <hlandau@devever.net> GPLv3 or later // © 2014 Hugo Landau <hlandau@devever.net> GPLv3 or later

Loading…
Cancel
Save