This commit is contained in:
Miek Gieben 2012-09-03 12:06:26 +02:00
parent 9f7ac05652
commit 984d8a7781
11 changed files with 0 additions and 533 deletions

View File

@ -1,5 +0,0 @@
; This is a zone-signing key, keyid 21798, for miek.nl.
; Created: 20110122104659 (Sat Jan 22 11:46:59 2011)
; Publish: 20110122104659 (Sat Jan 22 11:46:59 2011)
; Activate: 20110122104659 (Sat Jan 22 11:46:59 2011)
miek.nl. IN DNSKEY 256 3 5 AwEAAQGk589980oEiFs1AUicHq2YlHbE5n0DWgfgCqTfBZ1ZYRjn2mye mQotdt4Yzq97nBPy1nzxrZhKabhX9nZriVv8jurPLXeauW/NT1Drfrjz DQRidU+A1DvLDkEKeEl8O+kOyiIHK49kUrjbfar9yQuFZUAeo+24FRfH q9oGysW70Q==

View File

@ -1,13 +0,0 @@
Private-key-format: v1.3
Algorithm: 5 (RSASHA1)
Modulus: AaTnz33zSgSIWzUBSJwerZiUdsTmfQNaB+AKpN8FnVlhGOfabJ6ZCi123hjOr3ucE/LWfPGtmEppuFf2dmuJW/yO6s8td5q5b81PUOt+uPMNBGJ1T4DUO8sOQQp4SXw76Q7KIgcrj2RSuNt9qv3JC4VlQB6j7bgVF8er2gbKxbvR
PublicExponent: AQAB
PrivateExponent: /IkdBCupeEi7uHS5tPnvHAHPtNm5nf4xhWm9fBYpT0wjnlB+JTYbViXgoa+4uAhwK54nPvXxzovZz+UPLfwvFBoG3D0vYS+M9WWOBCnEuDK0MfcBWfTE2hlV13xDll1o7Pj/fvpRQ7paBhjpP6uBwlVI1vH6GR9kNXQRfWK1NQU=
Prime1: AdG+8ixEeDzHKI2GRD7lGhrQ8EzN4Tc0mek1u6ioFZ0imohaPqtqNq7RWVo35cWuvYflhFQYzFn99HGRvfGfDv8=
Prime2: 51psvlotBXuaqzrgfb5I6u7DG9JhU5WO68PZf1RMmq2e2xLvKvDGXCP5oFur9AOsHdbmahnzgFC1s18vg7kFLw==
Exponent1: glXRJ5oxm7CQJKrCRmeOmpqF5Lhooi5SM/UZguUmx0Z7wFSg3Q9oJhvnyVuDLYLs/y63jWEzLqvm0DFc2lUMuQ==
Exponent2: Aq3qan3y3Yhj7y28YdhtUcM4IT9bfzNRN2vKPg5E4Nm36EOc33twYKrN/kxxfl74hFPz0TDBwC+vGwe0LitbYw==
Coefficient: AZX3xIGzo/3fw4ouA6nAjpiWGpTK+OdFRkZtvbmzwgqnFDQopB0SweVnd1shpKCXkPTkdvpLTdmhU/84CW5m7cQ=
Created: 20110122104659
Publish: 20110122104659
Activate: 20110122104659

View File

@ -1,10 +0,0 @@
# Copyright 2009 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
include $(GOROOT)/src/Make.inc
TARG=funkensturm
GOFILES=funkensturm.go\
config_delay.go\
DEPS=../../
include $(GOROOT)/src/Make.cmd

View File

@ -1,10 +0,0 @@
# Copyright 2009 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
include $(GOROOT)/src/Make.inc
TARG=funkensturm
GOFILES=funkensturm.go\
config_rproxy.go\
DEPS=../../
include $(GOROOT)/src/Make.cmd

View File

@ -1,10 +0,0 @@
# Copyright 2009 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
include $(GOROOT)/src/Make.inc
TARG=funkensturm
GOFILES=funkensturm.go\
config_sign.go\
DEPS=../../
include $(GOROOT)/src/Make.cmd

View File

@ -1,44 +0,0 @@
package main
// This is transparant proxy
import (
"dns"
"fmt"
)
func send(m *dns.Msg) (buf []byte) {
if *verbose {
fmt.Printf("--> %s\n", m.Question[0].String())
}
var o *dns.Msg
var err error
for _, c := range qr {
o, err = c.Client.Exchange(m, c.Addr)
if *verbose {
if err == nil {
fmt.Printf("<-- %s\n", m.Question[0].String())
} else {
fmt.Printf("%s\n", err.Error())
}
}
}
if err == nil {
buf, _ = o.Pack()
}
return
}
// Return the configration
func NewFunkenSturm() *FunkenSturm {
f := new(FunkenSturm)
f.Setup = func() bool { return true } // no setup
f.Default = send
f.Funk = make([]*Funk, 1) // 1 Funk chain
f.Funk[0] = new(Funk)
f.Funk[0].Match = func(m *dns.Msg) (*dns.Msg, bool) { return m, true }
f.Funk[0].Action = send
return f
}

View File

@ -1,59 +0,0 @@
package main
// This proxy delays pkt that have the RD bit set.
import (
"dns"
"time"
)
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)
if tdiff < NSECDELAY {
// too often
return previous, false
}
return current, true
}
// the only matching we do is on the RD bit
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) (buf []byte) {
var (
ok1 bool
o *dns.Msg
)
if previous, ok1 = checkDelay(); !ok1 {
println("Dropping: too often")
time.Sleep(NSECDELAY)
return
}
println("Ok: let it through")
for _, c := range qr {
o, _ = c.Client.Exchange(m, c.Addr)
}
buf, _ = o.Pack()
return
}
// Return the configration
func NewFunkenSturm() *FunkenSturm {
f := new(FunkenSturm)
f.Setup = func() bool { previous = time.Nanoseconds(); return true }
f.Funk = make([]*Funk, 1)
f.Funk[0] = new(Funk)
f.Funk[0].Match = match
f.Funk[0].Action = delay
return f
}

View File

@ -1,117 +0,0 @@
package main
// Keep a local cache of DNS packets. Match incoming
// qname,qclass,qtype and return the saved packet.
// On a cache miss consult the nameserver
import (
"dns"
"sync"
"time"
)
// Keep everything in the cache for 60 seconds
const (
CACHETTL = 1
_CLASS = 2 << 16
INSERT = iota
DELETE
)
var cache Cache
type item struct {
epoch int64
msg []byte
}
// Number in the second map denotes the class + type.
func intval(c, t uint16) int {
return int(c)*_CLASS + int(t)
}
// Mutex entry in the cache, if non-nill take the lock
// Ala Zone in zone.go, but slightly different
type Cache struct {
data map[string]map[int]*item
rw *sync.RWMutex
}
func NewCache() Cache {
c := new(Cache)
c.data = make(map[string]map[int]*item)
c.rw = new(sync.RWMutex)
return *c
}
// Add an entry to the cache. The old entry (if any) gets overwritten
func (c Cache) add(q *dns.Msg) {
c.rw.Lock()
defer c.rw.Unlock()
qname := q.Question[0].Name
i := intval(q.Question[0].Qclass, q.Question[0].Qtype)
if c.data[qname] == nil {
im := make(map[int]*item)
c.data[qname] = im
}
buf, _ := q.Pack()
im := c.data[qname]
im[i] = &item{time.Seconds(), buf}
}
// Lookup an entry in the cache. Returns nil
// when nothing found.
func (c Cache) lookup(q *dns.Msg) []byte {
// Use the question section for looking up
c.rw.RLock()
defer c.rw.RUnlock()
i := intval(q.Question[0].Qclass, q.Question[0].Qtype)
if im, ok := c.data[q.Question[0].Name]; ok {
// we have the name
if d, ok := im[i]; ok {
// We even have the entry, check cache time
if time.Seconds()-d.epoch > CACHETTL {
// Too olds means we get a new one
return nil
}
e := make([]byte, len(d.msg))
copy(e, d.msg)
return e
}
}
return nil
}
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
// in the cache.
o = cache.lookup(m)
if o != nil {
// octet 1 and 2 contain the Id, set the one for the current pkt
dns.RawSetId(o, 0, m.MsgHdr.Id)
return
}
println("Cache miss")
var p *dns.Msg
for _, c := range qr {
p, _ = c.Client.Exchange(m, c.Addr)
}
cache.add(p)
o, _ = p.Pack()
return
}
// Return the configration
func NewFunkenSturm() *FunkenSturm {
f := new(FunkenSturm)
f.Funk = make([]*Funk, 1)
f.Setup = func() bool { cache = NewCache(); return true }
f.Funk[0] = new(Funk)
f.Funk[0].Match = func(m *dns.Msg) (*dns.Msg, bool) { return m, true }
f.Funk[0].Action = checkcache
return f
}

View File

@ -1,93 +0,0 @@
package main
// This is a signing proxy.
// Lots of hardcoded stuff. The first record in the answer section is
// signed with the key for example.org. The RRSIG is added to the packet.
// We could also use one 1 key for multiple domains.
import (
"crypto/rsa"
"dns"
"strings"
)
func sign(m *dns.Msg) *dns.Msg {
sg := new(dns.RR_RRSIG)
sg.Hdr = dns.RR_Header{"c.miek.nl.", dns.TypeRRSIG, dns.ClassINET, 14400, 0}
sg.Expiration = 1296534305 // date -u '+%s' -d"2011-02-01 04:25:05"
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.RSASHA256
if len(m.Answer) > 0 {
// sign the first record
an := m.Answer[0]
sg.TypeCovered = an.Header().Rrtype
sg.Labels = dns.Labels(an.Header().Name)
sg.OrigTtl = an.Header().Ttl
switch p := privkey.(type) {
case *rsa.PrivateKey:
sg.Sign(p, []dns.RR{an})
}
}
m.Answer = append(m.Answer, sg)
return m
}
func sendsign(m *dns.Msg) (o []byte) {
var p *dns.Msg
for _, c := range qr {
p, _ = c.Client.Exchange(m, c.Addr)
}
o, _ = sign(p).Pack()
println("signing")
return
}
func send(m *dns.Msg) (o []byte) {
var p *dns.Msg
for _, c := range qr {
p, _ = c.Client.Exchange(m, c.Addr)
}
o, _ = p.Pack()
return
}
var pubkey *dns.RR_DNSKEY
var privkey dns.PrivateKey
func setup() bool {
privdata := `Private-key-format: v1.3
Algorithm: 5 (RSASHA1)
Modulus: AaTnz33zSgSIWzUBSJwerZiUdsTmfQNaB+AKpN8FnVlhGOfabJ6ZCi123hjOr3ucE/LWfPGtmEppuFf2dmuJW/yO6s8td5q5b81PUOt+uPMNBGJ1T4DUO8sOQQp4SXw76Q7KIgcrj2RSuNt9qv3JC4VlQB6j7bgVF8er2gbKxbvR
PublicExponent: AQAB
PrivateExponent: /IkdBCupeEi7uHS5tPnvHAHPtNm5nf4xhWm9fBYpT0wjnlB+JTYbViXgoa+4uAhwK54nPvXxzovZz+UPLfwvFBoG3D0vYS+M9WWOBCnEuDK0MfcBWfTE2hlV13xDll1o7Pj/fvpRQ7paBhjpP6uBwlVI1vH6GR9kNXQRfWK1NQU=
Prime1: AdG+8ixEeDzHKI2GRD7lGhrQ8EzN4Tc0mek1u6ioFZ0imohaPqtqNq7RWVo35cWuvYflhFQYzFn99HGRvfGfDv8=
Prime2: 51psvlotBXuaqzrgfb5I6u7DG9JhU5WO68PZf1RMmq2e2xLvKvDGXCP5oFur9AOsHdbmahnzgFC1s18vg7kFLw==
Exponent1: glXRJ5oxm7CQJKrCRmeOmpqF5Lhooi5SM/UZguUmx0Z7wFSg3Q9oJhvnyVuDLYLs/y63jWEzLqvm0DFc2lUMuQ==
Exponent2: Aq3qan3y3Yhj7y28YdhtUcM4IT9bfzNRN2vKPg5E4Nm36EOc33twYKrN/kxxfl74hFPz0TDBwC+vGwe0LitbYw==
Coefficient: AZX3xIGzo/3fw4ouA6nAjpiWGpTK+OdFRkZtvbmzwgqnFDQopB0SweVnd1shpKCXkPTkdvpLTdmhU/84CW5m7cQ=
Created: 20110122104659
Publish: 20110122104659
Activate: 20110122104659`
pubkey = new(dns.RR_DNSKEY)
privkey, _ = pubkey.ReadPrivateKey(strings.NewReader(privdata))
pubkey.Hdr = dns.RR_Header{"miek.nl.", dns.TypeDNSKEY, dns.ClassINET, 3600, 0}
pubkey.Protocol = 3
pubkey.Flags = 256
return true
}
// Return the configration
func NewFunkenSturm() *FunkenSturm {
f := new(FunkenSturm)
f.Funk = make([]*Funk, 1)
f.Setup = setup
f.Default = send
f.Funk[0] = new(Funk)
f.Funk[0].Match = func(m *dns.Msg) (*dns.Msg, bool) { return m, m.Question[0].Name == "c.miek.nl." }
f.Funk[0].Action = sendsign
return f
}

View File

@ -1,50 +0,0 @@
// Copyright 2011 Miek Gieben. All rights reserved.
// Lisenced under the GPLv2
/*
Funkensturm rewrites DNS packets in the broadest sense of the word.
The rewriting can include delayed (re)sending of packets, (re)sending
packets to multiple servers, rewriting the packet contents, for instance
by signing a packet, or the other way around, stripping the signatures.
In its essence this is no different that a recursive nameserver, which also
receives and sends queries. The difference is the huge amount of tweaking
Funkensturm offers.
The configuration of Funkensturm is done by writing it in Go - a
separate configuration language was deemed to be unpractical and
would limit the possibilities.
Usage:
funkensturm [flags]
The flags are:
-sserver
Listener address and port for the server. This has to be
specified as: address:port, for instance 127.0.0.1:8053.
This is also the default.
-rserver
Remote server address in address:port format. This can be
repeated, for each rserver a resolver channel is created.
The first begin `qr[0]`, the second `qr[1]`, etc.
The default is: 127.0.0.1:53
Debugging flags:
-verbose
Print packets as they flow through Funkensturm.
Predefined configurations are shown in `config_delay.go` and `config_sign.go`. The
default `config.go` implements a transparant proxy.
Also see: http://www.miek.nl/blog/archives/2011/01/23/funkensturm/index.html for
a architectural overview.
In FunkenSturm you define chains named Funk's (maybe just 'chain' is a better name). Each Funk
consists out of match and action function. If the match function matches (return true) the
action function is called.
Multiple Funk's may be used. The first 'true' value win and that action function is performed.
*/
package documentation

View File

@ -1,122 +0,0 @@
/*
* Funkensturm, a versatile DNS proxy
* Miek Gieben <miek@miek.nl> (c) 2011
* GPLv2
*/
package main
import (
"dns"
"flag"
"os/signal"
"strings"
)
var qr []*FunkClient
var f *FunkenSturm
var verbose *bool
// A small wrapper to keep the address together
// with a client.
type FunkClient struct {
Client *dns.Client
Addr string
}
// A FunkAction combines a set of matches and an action. If
// the matches are successfull (return true) the action is
// performed
type Funk struct {
Match func(*dns.Msg) (*dns.Msg, bool)
Action func(*dns.Msg) []byte
}
// Hold the information.
type FunkenSturm struct {
Setup func() bool // Inital setup (for extra resolvers, or loading keys, or ...)
Default func(*dns.Msg) []byte // Default action is all fails
Funk []*Funk // The configuration
}
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
}
// Loop through the Funks and decide what to do with the packet.
for _, f := range f.Funk {
if m, ok := f.Match(pkt); ok {
ret = f.Action(m)
return
}
}
if f.Default == nil {
println("No f.Default set!")
return
}
ret = f.Default(pkt)
return
}
func serve(w dns.ResponseWriter, req *dns.Msg) {
if out := doFunkenSturm(req); out != nil {
w.Write(out)
}
}
func listenAndServe(add, net string) {
if err := dns.ListenAndServe(add, net, nil); err != nil {
println("Failed to setup:", net, add)
}
}
func main() {
listen := flag.String("listen", "127.0.0.1:8053", "set the listener address")
server := flag.String("server", "127.0.0.1:53", "remote server address(es), seperate with commas")
verbose = flag.Bool("verbose", false, "Print packet as it flows through")
// cpuprofile := flag.String("cpuprofile", "", "write cpu profile to file")
flag.Usage = func() {
flag.PrintDefaults()
}
flag.Parse()
/*
if *cpuprofile != "" {
f, err := os.Create(*cpuprofile)
if err != nil {
log.Fatal(err)
}
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()
}
*/
clients := strings.Split(*server, ",")
qr = make([]*FunkClient, len(clients))
for i, ra := range clients {
qr[i] = new(FunkClient)
qr[i].Client = dns.NewClient()
qr[i].Addr = ra
}
f = NewFunkenSturm()
ok := f.Setup()
if !ok {
println("Setup failed")
return
}
dns.HandleFunc(".", serve)
go listenAndServe(*listen, "tcp")
go listenAndServe(*listen, "udp")
forever:
for {
select {
case <-signal.Incoming:
println("Signal received, stopping")
break forever
}
}
}