Fix funkensturm and make it simpler
This commit is contained in:
parent
ba30caf3b3
commit
327c9870c4
|
@ -4,46 +4,27 @@ import (
|
|||
"dns"
|
||||
)
|
||||
|
||||
func match(m *dns.Msg, d int) (*dns.Msg, bool) {
|
||||
// Matching criteria
|
||||
switch d {
|
||||
case IN:
|
||||
// nothing
|
||||
case OUT:
|
||||
// Note that when sending back only the mangling is important
|
||||
// the actual return code of these function isn't checked by
|
||||
// funkensturm
|
||||
}
|
||||
|
||||
// Packet Mangling
|
||||
switch d {
|
||||
case IN:
|
||||
// nothing
|
||||
case OUT:
|
||||
// nothing
|
||||
}
|
||||
func match(m *dns.Msg) (*dns.Msg, bool) {
|
||||
return m, true
|
||||
}
|
||||
|
||||
func send(m *dns.Msg, ok bool) (o *dns.Msg) {
|
||||
func send(m *dns.Msg) (buf []byte) {
|
||||
var o *dns.Msg
|
||||
for _, c := range qr {
|
||||
o = c.Client.Exchange(m, c.Addr)
|
||||
}
|
||||
return
|
||||
buf, _ = o.Pack()
|
||||
return
|
||||
}
|
||||
|
||||
// Return the configration
|
||||
func funkensturm() *Funkensturm {
|
||||
f := new(Funkensturm)
|
||||
func NewFunkenSturm() *FunkenSturm {
|
||||
f := new(FunkenSturm)
|
||||
f.Funk = make([]*Funk, 1) // 1 Chain
|
||||
f.Setup = func() bool { return true } // no setup
|
||||
|
||||
// 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
|
||||
f.Funk[0] = NewFunk(1) // First chains with 1 match/action
|
||||
f.Funk[0].Matches[0].Op = AND
|
||||
f.Funk[0].Matches[0].Func = func(m *dns.Msg) (*dns.Msg, bool) { return m ,true }
|
||||
f.Funk[0].Action = send
|
||||
return f
|
||||
}
|
||||
|
|
|
@ -3,9 +3,7 @@ package main
|
|||
// This proxy delays pkt that have the RD bit set.
|
||||
|
||||
import (
|
||||
"os"
|
||||
"dns"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -25,62 +23,39 @@ func checkDelay() (ti int64, limitok bool) {
|
|||
}
|
||||
|
||||
// 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
|
||||
switch d {
|
||||
case IN:
|
||||
// only delay pkts with RD bit
|
||||
ok = m.MsgHdr.RecursionDesired == true
|
||||
case OUT:
|
||||
// nothing
|
||||
}
|
||||
|
||||
// Packet Mangling
|
||||
switch d {
|
||||
case IN:
|
||||
// nothing
|
||||
case OUT:
|
||||
// nothing
|
||||
}
|
||||
return m, ok
|
||||
func match(m *dns.Msg) (*dns.Msg, bool) {
|
||||
// only delay pkts with RD bit
|
||||
return m, m.MsgHdr.RecursionDesired == true
|
||||
}
|
||||
|
||||
func delay(m *dns.Msg, ok bool) (o *dns.Msg) {
|
||||
var ok1 bool
|
||||
switch ok {
|
||||
case true:
|
||||
previous, ok1 = checkDelay()
|
||||
if !ok1 {
|
||||
fmt.Fprintf(os.Stderr, "Info: Dropping: too often\n")
|
||||
time.Sleep(NSECDELAY)
|
||||
return
|
||||
} else {
|
||||
fmt.Fprintf(os.Stderr, "Info: Ok: let it through\n")
|
||||
for _, c := range qr {
|
||||
o = c.Client.Exchange(m, c.Addr)
|
||||
}
|
||||
return
|
||||
}
|
||||
case false:
|
||||
for _, c := range qr {
|
||||
o = c.Client.Exchange(m, c.Addr)
|
||||
}
|
||||
return
|
||||
}
|
||||
return
|
||||
func delay(m *dns.Msg) (buf []byte) {
|
||||
var (
|
||||
ok1 bool
|
||||
o *dns.Msg
|
||||
)
|
||||
if previous, ok1 = checkDelay(); !ok1 {
|
||||
println("Info: Dropping: too often")
|
||||
time.Sleep(NSECDELAY)
|
||||
return
|
||||
}
|
||||
println("Info: Ok: let it through")
|
||||
for _, c := range qr {
|
||||
o = c.Client.Exchange(m, c.Addr)
|
||||
}
|
||||
buf, _ = o.Pack()
|
||||
return
|
||||
}
|
||||
|
||||
// Return the configration
|
||||
func funkensturm() *Funkensturm {
|
||||
f := new(Funkensturm)
|
||||
func NewFunkenSturm() *FunkenSturm {
|
||||
f := new(FunkenSturm)
|
||||
f.Funk = make([]*Funk, 1)
|
||||
// Not concurrent save
|
||||
f.Setup = func() bool { previous = time.Nanoseconds(); return true }
|
||||
|
||||
f.Matches = make([]Match, 1)
|
||||
f.Matches[0].Op = AND
|
||||
f.Matches[0].Func = match
|
||||
|
||||
f.Actions = make([]Action, 1)
|
||||
f.Actions[0].Func = delay
|
||||
f.Funk[0] = NewFunk(1)
|
||||
f.Funk[0].Matches[0].Op = AND
|
||||
f.Funk[0].Matches[0].Func = match
|
||||
f.Funk[0].Action = delay
|
||||
return f
|
||||
}
|
||||
|
|
|
@ -32,7 +32,6 @@ func (c Cache) evict(q dns.Msg) {
|
|||
// todo
|
||||
}
|
||||
|
||||
|
||||
// Add an entry from the cache. The old entry (if any) gets
|
||||
// overwritten
|
||||
func (c Cache) add(q *dns.Msg) {
|
||||
|
@ -63,7 +62,7 @@ func (c Cache) lookup(q *dns.Msg) []byte {
|
|||
return nil
|
||||
}
|
||||
|
||||
func checkcache(m *dns.Msg, ok bool) (o []byte) {
|
||||
func checkcache(m *dns.Msg) (o []byte) {
|
||||
// Check if we have the packet in Cache
|
||||
// if so, return it. Otherwise ask the
|
||||
// server, return that answer and put it
|
||||
|
@ -77,7 +76,6 @@ func checkcache(m *dns.Msg, ok bool) (o []byte) {
|
|||
}
|
||||
println("Cache miss")
|
||||
var p *dns.Msg
|
||||
// nothing found
|
||||
for _, c := range qr {
|
||||
p = c.Client.Exchange(m, c.Addr)
|
||||
}
|
||||
|
@ -89,10 +87,12 @@ func checkcache(m *dns.Msg, ok bool) (o []byte) {
|
|||
var cache Cache
|
||||
|
||||
// Return the configration
|
||||
func funkensturm() *Funkensturm {
|
||||
f := new(Funkensturm)
|
||||
func NewFunkenSturm() *FunkenSturm {
|
||||
f := new(FunkenSturm)
|
||||
f.Funk = make([]*Funk, 1)
|
||||
f.Setup = func() bool { cache = NewCache(); return true }
|
||||
f.ActionsRaw = make([]ActionRaw, 1)
|
||||
f.ActionsRaw[0].FuncRaw = checkcache
|
||||
f.Funk[0] = NewFunk(1)
|
||||
f.Funk[0].Matches[0].Func = func(m *dns.Msg) (*dns.Msg, bool) { return m, true }
|
||||
f.Funk[0].Action = checkcache
|
||||
return f
|
||||
}
|
||||
|
|
|
@ -18,13 +18,13 @@ func sign(m *dns.Msg) *dns.Msg {
|
|||
sg.Inception = 1293942305 // date -u '+%s' -d"2011-01-02 04:25:05"
|
||||
sg.KeyTag = pubkey.KeyTag() // Get the keyfrom the Key
|
||||
sg.SignerName = pubkey.Hdr.Name
|
||||
sg.Algorithm = dns.AlgRSASHA256
|
||||
sg.Algorithm = dns.RSASHA256
|
||||
|
||||
if len(m.Answer) > 0 {
|
||||
// sign the first record
|
||||
an := m.Answer[0]
|
||||
sg.TypeCovered = an.Header().Rrtype
|
||||
sg.Labels = dns.LabelCount(an.Header().Name)
|
||||
sg.Labels = dns.Labels(an.Header().Name)
|
||||
sg.OrigTtl = an.Header().Ttl
|
||||
switch p:=privkey.(type) {
|
||||
case *rsa.PrivateKey:
|
||||
|
@ -35,34 +35,16 @@ func sign(m *dns.Msg) *dns.Msg {
|
|||
return m
|
||||
}
|
||||
|
||||
func match(m *dns.Msg, d int) (*dns.Msg, bool) {
|
||||
// Matching criteria
|
||||
switch d {
|
||||
case IN:
|
||||
// nothing
|
||||
case OUT:
|
||||
// Note that when sending back only the mangling is important
|
||||
// the actual return code of these function isn't checked by
|
||||
// funkensturm
|
||||
}
|
||||
|
||||
// Packet Mangling
|
||||
switch d {
|
||||
case IN:
|
||||
// nothing
|
||||
case OUT:
|
||||
if m.Question[0].Name == "www.example.org." {
|
||||
// On the way out sign the packet
|
||||
m = sign(m) // keys are global
|
||||
}
|
||||
}
|
||||
return m, true
|
||||
func match(m *dns.Msg) (*dns.Msg, bool) {
|
||||
return m, m.Question[0].Name == "www.example.org."
|
||||
}
|
||||
|
||||
func send(m *dns.Msg, ok bool) (o *dns.Msg) {
|
||||
func send(m *dns.Msg) (o []byte) {
|
||||
var p *dns.Msg
|
||||
for _, c := range qr {
|
||||
o = c.Client.Exchange(m, c.Addr)
|
||||
p = c.Client.Exchange(m, c.Addr)
|
||||
}
|
||||
o, _ = sign(p).Pack()
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -92,16 +74,13 @@ Activate: 20110122104659`
|
|||
}
|
||||
|
||||
// Return the configration
|
||||
func funkensturm() *Funkensturm {
|
||||
f := new(Funkensturm)
|
||||
|
||||
func NewFunkenSturm() *FunkenSturm {
|
||||
f := new(FunkenSturm)
|
||||
f.Funk = make([]*Funk, 1) // 1 Chain
|
||||
f.Setup = setup
|
||||
|
||||
f.Matches = make([]Match, 1)
|
||||
f.Matches[0].Op = AND
|
||||
f.Matches[0].Func = match
|
||||
|
||||
f.Actions = make([]Action, 1)
|
||||
f.Actions[0].Func = send
|
||||
f.Funk[0] = NewFunk(1)
|
||||
f.Funk[0].Matches[0].Func = match
|
||||
f.Funk[0].Action = send
|
||||
return f
|
||||
}
|
||||
|
|
|
@ -17,29 +17,20 @@ import (
|
|||
"runtime/pprof"
|
||||
)
|
||||
|
||||
var qr []*Funk
|
||||
var f *Funkensturm
|
||||
var qr []*FunkClient
|
||||
var f *FunkenSturm
|
||||
var verbose *bool
|
||||
|
||||
// A small wrapper to keep the address together
|
||||
// with a client.
|
||||
type Funk struct {
|
||||
type FunkClient struct {
|
||||
Client *dns.Client
|
||||
Addr string
|
||||
}
|
||||
|
||||
// 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.
|
||||
// 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
|
||||
|
||||
OR // chain match functions with logical 'or'
|
||||
AND // chain match functions with logical 'and'
|
||||
OR = iota // chain match functions with logical 'or'
|
||||
AND // chain match functions with logical 'and'
|
||||
)
|
||||
|
||||
// A Match function is used on a DNS packet and
|
||||
|
@ -49,18 +40,21 @@ const (
|
|||
// 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)
|
||||
Func func(*dns.Msg) (*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 FunkAction combines a set of matches and an action. If
|
||||
// the matches are successfull (return true) the action is
|
||||
// performed
|
||||
type Funk struct {
|
||||
Matches []Match
|
||||
Action func(*dns.Msg) []byte
|
||||
}
|
||||
|
||||
type ActionRaw struct {
|
||||
FuncRaw func(*dns.Msg, bool) []byte
|
||||
func NewFunk(m int) *Funk {
|
||||
f := new(Funk)
|
||||
f.Matches = make([]Match, m)
|
||||
return f
|
||||
}
|
||||
|
||||
// A complete config for Funkensturm. All matches in the Matches slice are
|
||||
|
@ -69,115 +63,58 @@ type ActionRaw struct {
|
|||
//
|
||||
// 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 matching 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
|
||||
ActionsRaw []ActionRaw // Raw action, return []byte not *dns.Msg
|
||||
// The result of this matching is given to the action function. That last
|
||||
// function decides "what to do with the packet" is the match(es) return 'true'
|
||||
// There is no NewFunkenSturm() because that is what needs to be done in the
|
||||
// configuration file.
|
||||
type FunkenSturm struct {
|
||||
Setup func() bool // Inital setup (for extra resolvers, or loading keys, or ...)
|
||||
Funk []*Funk // The configuration
|
||||
}
|
||||
|
||||
func verboseprint(i *dns.Msg, indent string) {
|
||||
for _, line := range strings.Split(i.String(), "\n", -1) {
|
||||
fmt.Printf("%s%s\n", indent, line)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
func doFunkensturm(pkt *dns.Msg) ([]byte, os.Error) {
|
||||
if *verbose {
|
||||
verboseprint(pkt, "> ")
|
||||
}
|
||||
func doFunkenSturm(pkt *dns.Msg) (ret []byte) {
|
||||
// No matter what, we refuse to answer requests with the response bit set.
|
||||
if pkt.MsgHdr.Response == true {
|
||||
return nil, &dns.Error{Error: "Response bit set, not replying"}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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
|
||||
if len(f.Matches) > 0 {
|
||||
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 Funks and decide what to do with
|
||||
// the packet.
|
||||
for _, f := range f.Funk {
|
||||
ok := true
|
||||
for _, m := range f.Matches {
|
||||
var ok1 bool
|
||||
pkt, ok1 = m.Func(pkt)
|
||||
switch m.Op {
|
||||
case AND:
|
||||
ok = ok && ok1
|
||||
case OR:
|
||||
ok = ok || ok1
|
||||
}
|
||||
}
|
||||
if ok {
|
||||
ret = f.Action(pkt)
|
||||
return
|
||||
}
|
||||
}
|
||||
// If still alive, non of the action did something.
|
||||
// So we do it ourselves
|
||||
var o *dns.Msg
|
||||
for _, c := range qr {
|
||||
o = c.Client.Exchange(pkt, c.Addr)
|
||||
}
|
||||
if *verbose { //modified
|
||||
verboseprint(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 *verbose { //orignal out
|
||||
verboseprint(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
|
||||
if len(f.Matches) > 0 {
|
||||
pkt1 = resultpkt
|
||||
for _, m := range f.Matches {
|
||||
pkt1, _ = m.Func(pkt1, OUT)
|
||||
}
|
||||
if pkt1 == nil {
|
||||
// don't need to send something back
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
if len(f.ActionsRaw) > 0 {
|
||||
var buf []byte
|
||||
for _, r := range f.ActionsRaw {
|
||||
buf = r.FuncRaw(pkt, ok)
|
||||
}
|
||||
if buf != nil {
|
||||
// send the buffer back at once
|
||||
return buf, nil
|
||||
}
|
||||
}
|
||||
|
||||
if *verbose { // modified out
|
||||
verboseprint(pkt1, "<< ")
|
||||
}
|
||||
|
||||
out, ok1 := pkt1.Pack()
|
||||
if !ok1 {
|
||||
return nil, &dns.Error{Error: "Packing packet failed"}
|
||||
}
|
||||
// Some final byte changing function here?
|
||||
return out, nil
|
||||
ret, _ = o.Pack()
|
||||
return
|
||||
}
|
||||
|
||||
func serve(w dns.ResponseWriter, req *dns.Msg) {
|
||||
out, err := doFunkensturm(req)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error: %s\n", err.String())
|
||||
return
|
||||
}
|
||||
if out != nil {
|
||||
if out := doFunkenSturm(req); out != nil {
|
||||
w.Write(out)
|
||||
}
|
||||
}
|
||||
|
||||
func listenAndServe(add, net string) {
|
||||
err := dns.ListenAndServe(add, net, nil)
|
||||
if err != nil {
|
||||
if err := dns.ListenAndServe(add, net, nil); err != nil {
|
||||
fmt.Printf("Failed to setup: " + net + " " + add + "\n")
|
||||
}
|
||||
}
|
||||
|
@ -202,14 +139,14 @@ func main() {
|
|||
}
|
||||
|
||||
clients := strings.Split(*rserver, ",", -1)
|
||||
qr = make([]*Funk, len(clients))
|
||||
qr = make([]*FunkClient, len(clients))
|
||||
for i, ra := range clients {
|
||||
qr[i] = new(Funk)
|
||||
qr[i] = new(FunkClient)
|
||||
qr[i].Client = dns.NewClient()
|
||||
qr[i].Addr = ra
|
||||
}
|
||||
|
||||
f = funkensturm()
|
||||
f = NewFunkenSturm()
|
||||
ok := f.Setup()
|
||||
if !ok {
|
||||
fmt.Fprintf(os.Stderr, "Setup failed")
|
||||
|
|
|
@ -17,8 +17,8 @@ type QueryHandler interface {
|
|||
QueryDNS(w RequestWriter, q *Msg)
|
||||
}
|
||||
|
||||
// A RequestWriter interface is used by an DNS query handler to
|
||||
// construct an DNS request.
|
||||
// The RequestWriter interface is used by a DNS query handler to
|
||||
// construct a DNS request.
|
||||
type RequestWriter interface {
|
||||
WriteMessages([]*Msg)
|
||||
Write(*Msg)
|
||||
|
@ -36,6 +36,7 @@ type reply struct {
|
|||
tsigTimersOnly bool
|
||||
}
|
||||
|
||||
// A Request is a incoming message from a Client
|
||||
type Request struct {
|
||||
Request *Msg
|
||||
Addr string
|
||||
|
|
Loading…
Reference in New Issue