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

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

@ -12,52 +12,52 @@ import "fmt"
var idCounter int32 = 0
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
// username, password, and address (hostname:port).
type NamecoinConn struct {
Username string
Password string
Server string
Username string
Password string
Server string
}
// 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.
// Note that this will return domain data even if the domain is expired.
func (nc *NamecoinConn) Query(name string) (v string, err error) {
cmd, err := extratypes.NewNameShowCmd(newID(), name)
if err != nil {
//log.Info("NC NEWCMD ", err)
return "", err
}
r, err := btcjson.RpcSend(nc.Username, nc.Password, nc.Server, cmd)
if err != nil {
return "", err
}
if r.Error != nil {
//log.Info("RPC error: ", r.Error)
if r.Error.Code == -4 {
return "", merr.ErrNoSuchDomain
}
return "", r.Error
}
if r.Result == nil {
//log.Info("NC NILRESULT")
return "", fmt.Errorf("got nil result")
}
if nsr, ok := r.Result.(*extratypes.NameShowReply); ok {
//log.Info("NC OK")
return nsr.Value, nil
} else {
//log.Info("NC BADREPLY")
return "", fmt.Errorf("bad reply")
}
cmd, err := extratypes.NewNameShowCmd(newID(), name)
if err != nil {
//log.Info("NC NEWCMD ", err)
return "", err
}
r, err := btcjson.RpcSend(nc.Username, nc.Password, nc.Server, cmd)
if err != nil {
return "", err
}
if r.Error != nil {
//log.Info("RPC error: ", r.Error)
if r.Error.Code == -4 {
return "", merr.ErrNoSuchDomain
}
return "", r.Error
}
if r.Result == nil {
//log.Info("NC NILRESULT")
return "", fmt.Errorf("got nil result")
}
if nsr, ok := r.Result.(*extratypes.NameShowReply); ok {
//log.Info("NC OK")
return nsr.Value, nil
} else {
//log.Info("NC BADREPLY")
return "", fmt.Errorf("bad reply")
}
}
// © 2014 Hugo Landau <hlandau@devever.net> GPLv3 or later

@ -1,4 +1,5 @@
package server
import "github.com/hlandau/madns"
import "github.com/hlandau/degoutils/log"
import "github.com/hlandau/ncdns/backend"
@ -9,148 +10,148 @@ import "os/signal"
import "syscall"
type Server struct {
cfg ServerConfig
cfg ServerConfig
engine madns.Engine
engine madns.Engine
mux *dns.ServeMux
udpListener *dns.Server
tcpListener *dns.Server
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:"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"`
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"`
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"`
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"`
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
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
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
}
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)
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
ds := &dns.Server{
Addr: s.cfg.Bind,
Net: net,
Handler: s.mux,
}
go s.doRunListener(ds)
return ds
}

@ -1,17 +1,18 @@
package util
import "strings"
// 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) {
parts := strings.Split(name, ".")
parts := strings.Split(name, ".")
head = parts[len(parts)-1]
head = parts[len(parts)-1]
if len(parts) >= 2 {
rest = strings.Join(parts[0:len(parts)-1], ".")
}
if len(parts) >= 2 {
rest = strings.Join(parts[0:len(parts)-1], ".")
}
return
return
}
// © 2014 Hugo Landau <hlandau@devever.net> GPLv3 or later

Loading…
Cancel
Save