bunch of cleanups
This commit is contained in:
parent
e05cc84207
commit
656a0c5663
3
TODO
3
TODO
|
@ -9,6 +9,7 @@ Todo:
|
|||
extend Responder interface with ipv6?
|
||||
* Test impl of nameserver, with a small zone, 1 KSK and online signing
|
||||
* NSEC3 - need base32 for Nsec3
|
||||
* pkt log
|
||||
|
||||
Longer term:
|
||||
* Parsing from strings, going with goyacc and own lexer
|
||||
|
@ -36,3 +37,5 @@ Funkensturm:
|
|||
- sign(RRSET, privKEY), how do you specify WHAT gets signed
|
||||
if rr.Header().Name == "miek.nl." -> sign header -> add sig
|
||||
* use exp/eval - to inteprete the config file??
|
||||
* TCP how to handle stuff like AXFR
|
||||
* use package log
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
package main
|
||||
|
||||
// This is a transparant proxy config. All recevied pkt are just forwarded to the
|
||||
// nameserver, hardcoded to 127.0.0.1 and then return to the original querier
|
||||
import (
|
||||
"dns"
|
||||
"dns/resolver"
|
||||
|
@ -38,21 +36,19 @@ func send(m *dns.Msg, ok bool) *dns.Msg {
|
|||
return nil
|
||||
}
|
||||
|
||||
// qr is global and started by Funkensturm. If you
|
||||
// need 2 or more resolvers, you'll need to start
|
||||
// them yourself. This needs to be a global variable
|
||||
//var qr1 chan resolver.Msg
|
||||
|
||||
// Return the configration
|
||||
func funkensturm() *Funkensturm {
|
||||
f := new(Funkensturm)
|
||||
|
||||
// Nothing to set up
|
||||
f.Setup = func() bool { return true }
|
||||
|
||||
// 1 match function, use AND as op (doesn't matter in this case)
|
||||
f.Matches = make([]Match, 1)
|
||||
f.Matches[0].Op = AND
|
||||
f.Matches[0].Func = match
|
||||
|
||||
// 1 action
|
||||
f.Actions = make([]Action, 1)
|
||||
f.Actions[0].Func = send
|
||||
return f
|
||||
|
|
|
@ -1,16 +1,20 @@
|
|||
package main
|
||||
|
||||
// This proxy delays pkt that have the RD bit set.
|
||||
// NSECDELAY is now 1 * 1e9, which means 1 pkt/sec
|
||||
|
||||
import (
|
||||
"os"
|
||||
"dns"
|
||||
"fmt"
|
||||
"time"
|
||||
"dns/resolver"
|
||||
)
|
||||
|
||||
const NSECDELAY = 1 * 1e9 // 1 second, meaning 1 qps
|
||||
var previous int64 // previous tick
|
||||
const NSECDELAY = 1 * 1e9 // 1 second, meaning 1 qps (smaller means higher qps)
|
||||
|
||||
var previous int64 // previous tick
|
||||
|
||||
// returns false if we hit the limit set by NSECDELAY
|
||||
func checkDelay() (ti int64, limitok bool) {
|
||||
current := time.Nanoseconds()
|
||||
tdiff := (current - previous)
|
||||
|
@ -21,6 +25,7 @@ func checkDelay() (ti int64, limitok bool) {
|
|||
return current, true
|
||||
}
|
||||
|
||||
// the only matching we do is on the RD bit
|
||||
func match(m *dns.Msg, d int) (*dns.Msg, bool) {
|
||||
// Matching criteria
|
||||
var ok bool
|
||||
|
@ -48,11 +53,11 @@ func delay(m *dns.Msg, ok bool) *dns.Msg {
|
|||
case true:
|
||||
previous, ok1 = checkDelay()
|
||||
if !ok1 {
|
||||
println("Dropping: too often")
|
||||
fmt.Fprintf(os.Stderr, "Info: Dropping: too often")
|
||||
time.Sleep(NSECDELAY)
|
||||
return nil
|
||||
} else {
|
||||
println("Ok: continue")
|
||||
fmt.Fprintf(os.Stderr, "Info: Dropping: too often")
|
||||
qr <- resolver.Msg{m, nil, nil}
|
||||
in := <-qr
|
||||
return in.Dns
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package main
|
||||
|
||||
// This is a signing proxy.
|
||||
// Lots of hardcoded stuff, but stuff in the
|
||||
// answer section is signed with a key
|
||||
// the RRSIG is added to the pkt
|
||||
|
||||
// Lots of hardcoded stuff. The first record in the answer section is
|
||||
// signed with the key. The RRSIG is added to the packet.
|
||||
import (
|
||||
"dns"
|
||||
"dns/resolver"
|
||||
|
|
|
@ -1,128 +1,22 @@
|
|||
/*
|
||||
* Funkensturm
|
||||
* Miek Gieben <miek@miek.nl>
|
||||
* Miek Gieben <miek@miek.nl> (c) 2011
|
||||
* GPLv2
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"flag"
|
||||
"net"
|
||||
"fmt"
|
||||
"log"
|
||||
"dns"
|
||||
"dns/resolver"
|
||||
"dns/resolver"
|
||||
"dns/responder"
|
||||
"os/signal"
|
||||
)
|
||||
|
||||
// Where does the packet come from?
|
||||
// IN: initial packet received by the Responder
|
||||
// any modifications here will reflect what kind of
|
||||
// pkt is sent through. Normally there is no modification here.
|
||||
// OUT: pkt as received back. Modifications here will reflect
|
||||
// how the packet is send back to the original requester.
|
||||
const (
|
||||
IN = iota // set when receiving a packet
|
||||
OUT // set when sending a packet
|
||||
|
||||
OR
|
||||
AND
|
||||
)
|
||||
|
||||
// A Match function is let loose on a DNS packet and
|
||||
// returns (a possibly modified) DNS packet. It should
|
||||
// return true when the packets matches the criteria in
|
||||
// the function.
|
||||
// Op is used in chaining Match-structures together
|
||||
type Match struct {
|
||||
Op int // boolean op: OR, AND
|
||||
Func func(*dns.Msg, int) (*dns.Msg, bool)
|
||||
}
|
||||
|
||||
// An action is something that is done with a packet. Funkensturm
|
||||
// does not impose any restriction on what this can be.
|
||||
type Action struct {
|
||||
Func func(*dns.Msg, bool) *dns.Msg
|
||||
}
|
||||
|
||||
// A complete config for Funkensturm. All matches in the Matches slice are
|
||||
// chained together: Match[0] -> dns.Msg -> Match[1] -> dns.Msg -> ...
|
||||
// The dns.Msg output of Match[n] is the input for Match[n+1].
|
||||
// The final outcome (does a packet match or not?) is calculated as follows:
|
||||
// true Match[0].Op Match[0].Func() Match[1].Op Match[1].Func()
|
||||
// If the final result is true the action(s) are called. Note that
|
||||
// at least one of these action functions should send the actual message!
|
||||
type Funkensturm struct {
|
||||
Setup func() bool // Inital setup (for extra resolver or ...)
|
||||
Matches []Match // Match- and mangle functions
|
||||
Actions []Action // What to do wit the packets
|
||||
}
|
||||
|
||||
func (s *server) ResponderUDP(c *net.UDPConn, a net.Addr, i []byte) {
|
||||
pkt := reply(a, i)
|
||||
if pkt == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Loop through the Match* functions and decide what to do
|
||||
// Note the packet can be changed by these function, this
|
||||
// change is cumulative.
|
||||
ok, ok1 := true, true
|
||||
pkt1 := pkt
|
||||
for _, m := range f.Matches {
|
||||
pkt1, ok1 = m.Func(pkt1, IN)
|
||||
switch m.Op {
|
||||
case AND:
|
||||
ok = ok && ok1
|
||||
case OR:
|
||||
ok = ok || ok1
|
||||
}
|
||||
}
|
||||
|
||||
// Loop through the Actions.Func* and do something with the
|
||||
// packet. Note there can only be one returned packet.
|
||||
// We use 'ok' to signal what the above match did, true or false
|
||||
var resultpkt *dns.Msg
|
||||
for _, a := range f.Actions {
|
||||
resultpkt = a.Func(pkt1, ok)
|
||||
}
|
||||
|
||||
// loop again for matching, but now with OUT, this is done
|
||||
// for some last minute packet changing. Note the boolean return
|
||||
// code isn't used any more, i.e No more actions are allowed
|
||||
// anymore
|
||||
pkt1 = resultpkt
|
||||
for _, m := range f.Matches {
|
||||
pkt1, _ = m.Func(pkt1, OUT)
|
||||
}
|
||||
|
||||
if pkt1 == nil {
|
||||
return
|
||||
}
|
||||
out, ok1 := pkt1.Pack()
|
||||
if !ok1 {
|
||||
println("Failed to pack")
|
||||
return
|
||||
}
|
||||
responder.SendUDP(out, c, a)
|
||||
}
|
||||
|
||||
func (s *server) ResponderTCP(c *net.TCPConn, in []byte) {
|
||||
/* todo */
|
||||
}
|
||||
|
||||
// Small helper function
|
||||
func reply(a net.Addr, in []byte) *dns.Msg {
|
||||
inmsg := new(dns.Msg)
|
||||
if !inmsg.Unpack(in) {
|
||||
println("Unpacking failed")
|
||||
return nil
|
||||
}
|
||||
if inmsg.MsgHdr.Response == true {
|
||||
return nil // Don't answer responses
|
||||
}
|
||||
return inmsg
|
||||
}
|
||||
|
||||
// Setup a responder takes takes care of the incoming queries.
|
||||
type server responder.Server
|
||||
|
||||
|
@ -132,23 +26,181 @@ var qr chan resolver.Msg
|
|||
// The configuration of Funkensturm
|
||||
var f *Funkensturm
|
||||
|
||||
func main() {
|
||||
f = funkensturm()
|
||||
ok := f.Setup()
|
||||
if !ok {
|
||||
fmt.Printf("Setup failed")
|
||||
return
|
||||
}
|
||||
// The resolver
|
||||
r := new(resolver.Resolver)
|
||||
r.Servers = []string{"127.0.0.1"}
|
||||
r.Port = "53"
|
||||
qr = r.NewQuerier() // connect to global qr
|
||||
// Where does the packet come from?
|
||||
// IN: initial packet received by the Responder
|
||||
// any modifications here will reflect what kind of
|
||||
// pkt is sent through. Normally there is no modification here.
|
||||
// OUT: pkt as received back from a server. Modifications here will reflect
|
||||
// how the packet is send back to the original requester.
|
||||
const (
|
||||
IN = iota // set when receiving a packet
|
||||
OUT // set when sending a packet
|
||||
|
||||
// The responder
|
||||
OR // chain match functions with logical or
|
||||
AND // chain match functions with logical and
|
||||
)
|
||||
|
||||
// A Match function is used on a DNS packet and
|
||||
// returns (a possibly modified) DNS packet. It should
|
||||
// return true when the packets matches the criteria set in
|
||||
// the function.
|
||||
// Op is used in chaining Match-functions together
|
||||
type Match struct {
|
||||
Op int // boolean op: OR, AND
|
||||
Func func(*dns.Msg, int) (*dns.Msg, bool)
|
||||
}
|
||||
|
||||
// An action is something that is done with a packet. Funkensturm
|
||||
// does not impose any restriction on what this can be, except that
|
||||
// is must remain a valid DNS packet.
|
||||
type Action struct {
|
||||
Func func(*dns.Msg, bool) *dns.Msg
|
||||
}
|
||||
|
||||
// A complete config for Funkensturm. All matches in the Matches slice are
|
||||
// chained together: incoming dns.Msg -> Match[0] -> dns.Msg -> Match[1] -> dns.Msg -> ...
|
||||
// The dns.Msg output of Match[n] is the input for Match[n+1].
|
||||
//
|
||||
// The final outcome (does a packet match or not?) is calculated as follows:
|
||||
// true Match[0].Op Match[0].Func() Match[1].Op Match[1].Func() ...
|
||||
// The result of this macthing is given to the action function(s). They can then
|
||||
// decide what to do with a packet in the 'true' and in the 'false' case.
|
||||
type Funkensturm struct {
|
||||
Setup func() bool // Inital setup (for extra resolvers, or loading keys, or ...)
|
||||
Matches []Match // Match- and modify functions
|
||||
Actions []Action // What to do with the packets
|
||||
}
|
||||
|
||||
// No matter what, we refuse to answer request with the response bit set.
|
||||
func doFunkensturm(i []byte) ([]byte, os.Error) {
|
||||
pkt := new(dns.Msg)
|
||||
if !pkt.Unpack(i) {
|
||||
return nil, &dns.Error{Error: "Unpacking packet failed"}
|
||||
}
|
||||
if *verbose {
|
||||
fmt.Printf(">>>>>> ORIGINAL INCOMING\n")
|
||||
fmt.Printf("%v\n", pkt)
|
||||
}
|
||||
if pkt.MsgHdr.Response == true {
|
||||
return nil, &dns.Error{Error: "Response bit set, not replying"}
|
||||
}
|
||||
|
||||
// Loop through the Match* functions and decide what to do
|
||||
// Note the packet can be changed by these function, this
|
||||
// change is cumulative.
|
||||
ok, ok1 := true, true
|
||||
pkt1 := pkt
|
||||
for _, m := range f.Matches {
|
||||
pkt1, ok1 = m.Func(pkt1, IN)
|
||||
switch m.Op {
|
||||
case AND:
|
||||
ok = ok && ok1
|
||||
case OR:
|
||||
ok = ok || ok1
|
||||
}
|
||||
}
|
||||
if *verbose {
|
||||
fmt.Printf(">>>>>> MODIFIED INCOMING\n")
|
||||
fmt.Printf("%v\n", pkt1)
|
||||
}
|
||||
|
||||
// Loop through the Actions.Func* and do something with the
|
||||
// packet. Note there can only be one returned packet.
|
||||
// We use 'ok' to signal what the above match did: true or false
|
||||
var resultpkt *dns.Msg
|
||||
for _, a := range f.Actions {
|
||||
resultpkt = a.Func(pkt1, ok)
|
||||
}
|
||||
|
||||
if resultpkt == nil {
|
||||
return nil, &dns.Error{Error: "Action function returned nil packet"}
|
||||
}
|
||||
|
||||
if *verbose {
|
||||
fmt.Printf(">>>>>> ORIGINAL OUTGOING\n")
|
||||
fmt.Printf("%v\n", resultpkt)
|
||||
}
|
||||
|
||||
// loop again for matching, but now with OUT, this is done
|
||||
// for some last minute packet changing. Note the boolean return
|
||||
// code isn't used any more, i.e No more actions are allowed
|
||||
// anymore
|
||||
pkt1 = resultpkt
|
||||
for _, m := range f.Matches {
|
||||
pkt1, _ = m.Func(pkt1, OUT)
|
||||
}
|
||||
|
||||
if *verbose {
|
||||
fmt.Printf(">>>>>> MODIFIED OUTGOING\n")
|
||||
fmt.Printf("%v\n", pkt1)
|
||||
}
|
||||
|
||||
out, ok1 := pkt1.Pack()
|
||||
if !ok1 {
|
||||
return nil, &dns.Error{Error: "Packing packet failed"}
|
||||
}
|
||||
// Some final byte changing function here?
|
||||
return out, nil
|
||||
|
||||
}
|
||||
|
||||
func (s *server) ResponderUDP(c *net.UDPConn, a net.Addr, i []byte) {
|
||||
out, err := doFunkensturm(i)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error: %s\n", err.String())
|
||||
return
|
||||
}
|
||||
|
||||
if out != nil {
|
||||
responder.SendUDP(out, c, a)
|
||||
}
|
||||
// nothing is send back
|
||||
}
|
||||
|
||||
func (s *server) ResponderTCP(c *net.TCPConn, i []byte) {
|
||||
out, err := doFunkensturm(i)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error: %s\n", err.String())
|
||||
return
|
||||
}
|
||||
|
||||
if out != nil {
|
||||
responder.SendTCP(out, c)
|
||||
}
|
||||
// nothing is send back
|
||||
}
|
||||
|
||||
var verbose *bool
|
||||
|
||||
func main() {
|
||||
var sserver *string = flag.String("sserver", "127.0.0.1", "Set the listener address")
|
||||
var sport *string = flag.String("sport", "8053", "Set the listener port")
|
||||
var rserver *string = flag.String("rserver", "127.0.0.1", "Remote server address")
|
||||
// multiple rservers??
|
||||
var rport *string = flag.String("rpost", "53", "Remote server port to forward queries to")
|
||||
verbose = flag.Bool("verbose", false, "Print packet as the flow through") // needs to be global
|
||||
flag.Usage = func() {
|
||||
fmt.Fprintf(os.Stderr, "Usage: %s\n", os.Args[0])
|
||||
flag.PrintDefaults()
|
||||
}
|
||||
flag.Parse()
|
||||
|
||||
f = funkensturm()
|
||||
ok := f.Setup()
|
||||
if !ok {
|
||||
fmt.Fprintf(os.Stderr, "Setup failed")
|
||||
return
|
||||
}
|
||||
// The resolver
|
||||
r := new(resolver.Resolver)
|
||||
r.Servers = []string{*rserver}
|
||||
r.Port = *rport
|
||||
qr = r.NewQuerier() // connect to global qr
|
||||
|
||||
// The responder
|
||||
s := new(responder.Server)
|
||||
s.Address = "127.0.0.1"
|
||||
s.Port = "8053"
|
||||
s.Address = *sserver
|
||||
s.Port = *sport
|
||||
var srv *server
|
||||
rs := make(chan bool)
|
||||
go s.NewResponder(srv, rs)
|
||||
|
@ -162,8 +214,8 @@ forever:
|
|||
break forever
|
||||
}
|
||||
}
|
||||
rs <- true // shut down responder
|
||||
qr <- resolver.Msg{} // shut down resolver
|
||||
<-rs
|
||||
<-qr
|
||||
rs <- true // shutdown responder and resolver
|
||||
qr <- resolver.Msg{}
|
||||
<-rs // wait for confirmation
|
||||
<-qr
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue