Add funkenstorm

Added funkenstorm, only does stripping of additional section

Fix encoding of ipv4 addresses that are put in a  16 byte buffer (AAAA).
Just assume the last four bytes are ipv4 in that case
This commit is contained in:
Miek Gieben 2011-01-21 12:55:35 +01:00
parent 131b3f388b
commit 05c75c348b
7 changed files with 187 additions and 24 deletions

2
README
View File

@ -12,7 +12,7 @@ be build with: make examples (after the dns package has been installed)
The major omission at the moment is parsing Resource Records from
strings. (I.e. supporting the 1035 zone file format).
Everything else should be present and working. If not, drop me an mail.
Everything else should be present and working. If not, drop me an email.
Have fun!
Miek Gieben - 2010, 2011 - miek@miek.nl

1
TODO
View File

@ -1,5 +1,6 @@
Todo:
* NSEC and nsec3 closest encloser helper functions
* os.Error in Pack()/Unpack()
* wildcards
* Tsig testing
* Private key file parsing use io.Reader (or the like)

View File

@ -1,19 +1,15 @@
EXAMPLES=mx \
q \
chaos \
axfr \
notify \
reflect \
rude \
s \
funkensturm \
all:
gomake -C mx # query for MX records
gomake -C q # Dig-like tool
gomake -C chaos # show version.bind and hostname.bind
gomake -C axfr # perform an AXFR
gomake -C notify # send a notify msg
gomake -C reflect # a reflector nameserver
gomake -C rude # a rude nameserver (send formerr back)
goamke -C s # a complete nameserver
for i in $(EXAMPLES); do gomake -C $$i; done
clean:
gomake -C mx clean
gomake -C q clean
gomake -C chaos clean
gomake -C axfr clean
gomake -C notify clean
gomake -C reflect clean
gomake -C rude clean
goamke -C s
for i in $(EXAMPLES); do gomake -C $$i clean; done

View File

@ -0,0 +1,8 @@
# 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
DEPS=../../
include $(GOROOT)/src/Make.cmd

View File

@ -0,0 +1,19 @@
/*
Funkensturm rewrites DNS packets in the broadest sense of the word.
The features 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.
It includes a configuration language which makes setting up funkensturm
real easy. (It may be the case that this configuration language will be Go)
Not sure if this is doable:
- support packet of death (TSIG signed) for stopping funkensturm
- support packet of config (TSIG signed) for configuring funkensturm on the fly
*/
package documentation

View File

@ -0,0 +1,118 @@
/*
* Funkensturm
* Miek Gieben <miek@miek.nl>
*/
package main
import (
"net"
_ "fmt"
"dns"
"strconv"
"dns/resolver"
"dns/responder"
"runtime"
"os/signal"
)
type server responder.Server
func reply(a net.Addr, in []byte, tcp bool) *dns.Msg {
inmsg := new(dns.Msg)
if !inmsg.Unpack(in) {
println("Unpacking failed")
return nil
}
// it's valid mesg, return it
return inmsg
if inmsg.MsgHdr.Response == true {
return nil // Don't answer responses
}
m := new(dns.Msg)
m.MsgHdr.Id = inmsg.MsgHdr.Id
m.MsgHdr.Authoritative = true
m.MsgHdr.Response = true
m.MsgHdr.Opcode = dns.OpcodeQuery
m.MsgHdr.Rcode = dns.RcodeSuccess
m.Question = make([]dns.Question, 1)
m.Answer = make([]dns.RR, 1)
m.Extra = make([]dns.RR, 1)
r := new(dns.RR_A)
r.Hdr = dns.RR_Header{Name: "whoami.miek.nl.", Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 0}
ip, _ := net.ResolveUDPAddr(a.String()) // No general variant for both upd and tcp
r.A = ip.IP.To4() // To4 very important
t := new(dns.RR_TXT)
t.Hdr = dns.RR_Header{Name: "whoami.miek.nl.", Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 0}
if tcp {
t.Txt = "Port: " + strconv.Itoa(ip.Port) + " (tcp)"
} else {
t.Txt = "Port: " + strconv.Itoa(ip.Port) + " (udp)"
}
m.Question[0] = inmsg.Question[0]
m.Answer[0] = r
m.Extra[0] = t
return m
}
func (s *server) ResponderUDP(c *net.UDPConn, a net.Addr, i []byte) {
m := reply(a, i, false)
if m == nil {
return
}
// okay, send it using the resolver
qr <- resolver.Msg{m, nil, nil}
in := <-qr
// Okay, not strip the additional section
if len(in.Dns.Extra) > 0 {
println("Stripping additional section")
in.Dns.Extra = []dns.RR{}
}
// in may be nil
out, ok := in.Dns.Pack()
if !ok {
println("Failed to pack")
return
}
responder.SendUDP(out, c, a)
}
func (s *server) ResponderTCP(c *net.TCPConn, in []byte) {
}
var qr chan resolver.Msg
func main() {
runtime.GOMAXPROCS(5)
r := new(resolver.Resolver)
r.Servers = []string{"127.0.0.1"}
r.Port = "53"
qr = r.NewQuerier()
s := new(responder.Server)
s.Address = "127.0.0.1"
s.Port = "8053"
var srv *server
ch := make(chan bool)
go s.NewResponder(srv, ch)
forever:
for {
// Wait for a signal to stop
select {
case <-signal.Incoming:
println("Signal received, stopping")
break forever
}
}
}

35
msg.go
View File

@ -274,17 +274,27 @@ func packStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int, o
off += len(data)
}
case "A":
// It must be a slice of 4
if fv.Len() > net.IPv4len || off+fv.Len() > len(msg) {
// It must be a slice of 4, even if it is 16, we encode
// only the first 4
if off+net.IPv4len > len(msg) {
fmt.Fprintf(os.Stderr, "dns: overflow packing A")
return len(msg), false
}
msg[off] = byte(fv.Elem(0).(*reflect.UintValue).Get())
msg[off+1] = byte(fv.Elem(1).(*reflect.UintValue).Get())
msg[off+2] = byte(fv.Elem(2).(*reflect.UintValue).Get())
msg[off+3] = byte(fv.Elem(3).(*reflect.UintValue).Get())
if fv.Len() == net.IPv6len {
msg[off] = byte(fv.Elem(12).(*reflect.UintValue).Get())
msg[off+1] = byte(fv.Elem(13).(*reflect.UintValue).Get())
msg[off+2] = byte(fv.Elem(14).(*reflect.UintValue).Get())
msg[off+3] = byte(fv.Elem(15).(*reflect.UintValue).Get())
} else {
msg[off] = byte(fv.Elem(0).(*reflect.UintValue).Get())
msg[off+1] = byte(fv.Elem(1).(*reflect.UintValue).Get())
msg[off+2] = byte(fv.Elem(2).(*reflect.UintValue).Get())
msg[off+3] = byte(fv.Elem(3).(*reflect.UintValue).Get())
}
off += net.IPv4len
case "AAAA":
if fv.Len() > net.IPv6len || off+fv.Len() > len(msg) {
fmt.Fprintf(os.Stderr, "dns: overflow packing AAAA")
return len(msg), false
}
for j := 0; j < net.IPv6len; j++ {
@ -400,7 +410,7 @@ func unpackStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int,
switch fv := val.Field(i).(type) {
default:
BadType:
fmt.Fprintf(os.Stderr, "dns: unknown packing type %v", f.Type)
fmt.Fprintf(os.Stderr, "dns: unknown unpacking type %v", f.Type)
return len(msg), false
case *reflect.SliceValue:
switch f.Tag {
@ -409,6 +419,7 @@ func unpackStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int,
return len(msg), false
case "A":
if off+net.IPv4len > len(msg) {
fmt.Fprintf(os.Stderr, "dns: overflow unpacking A")
return len(msg), false
}
b := net.IPv4(msg[off], msg[off+1], msg[off+2], msg[off+3])
@ -416,6 +427,7 @@ func unpackStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int,
off += net.IPv4len
case "AAAA":
if off+net.IPv6len > len(msg) {
fmt.Fprintf(os.Stderr, "dns: overflow unpacking AAAA")
return len(msg), false
}
p := make(net.IP, net.IPv6len)
@ -425,6 +437,7 @@ func unpackStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int,
off += net.IPv6len
case "OPT": // EDNS
if off+2 > len(msg) {
fmt.Fprintf(os.Stderr, "dns: overflow unpacking OPT")
// No room for anything else
break
}
@ -432,6 +445,7 @@ func unpackStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int,
opt[0].Code, off = unpackUint16(msg, off)
optlen, off1 := unpackUint16(msg, off)
if off1+int(optlen) > len(msg) {
fmt.Fprintf(os.Stderr, "dns: overflow unpacking OPT")
return len(msg), false
}
opt[0].Data = hex.EncodeToString(msg[off1 : off1+int(optlen)])
@ -448,6 +462,7 @@ func unpackStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int,
window := int(msg[off])
blocks := int(msg[off+1])
if off+blocks > len(msg) {
fmt.Fprintf(os.Stderr, "dns: overflow unpacking NSEC")
return len(msg), false
}
off += 2
@ -499,6 +514,7 @@ func unpackStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int,
goto BadType
case reflect.Uint8:
if off+1 > len(msg) {
fmt.Fprintf(os.Stderr, "dns: overflow unpacking uint8")
return len(msg), false
}
i := uint8(msg[off])
@ -507,12 +523,14 @@ func unpackStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int,
case reflect.Uint16:
var i uint16
if off+2 > len(msg) {
fmt.Fprintf(os.Stderr, "dns: overflow unpacking uint16")
return len(msg), false
}
i, off = unpackUint16(msg, off)
fv.Set(uint64(i))
case reflect.Uint32:
if off+4 > len(msg) {
fmt.Fprintf(os.Stderr, "dns: overflow unpacking uint32")
return len(msg), false
}
i := uint32(msg[off])<<24 | uint32(msg[off+1])<<16 | uint32(msg[off+2])<<8 | uint32(msg[off+3])
@ -522,6 +540,7 @@ func unpackStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int,
// This is *only* used in TSIG where the last 48 bits are occupied
// So for now, assume a uint48 (6 bytes)
if off+6 > len(msg) {
fmt.Fprintf(os.Stderr, "dns: overflow unpacking uint64")
return len(msg), false
}
i := uint64(msg[off])<<40 | uint64(msg[off+1])<<32 | uint64(msg[off+2])<<24 | uint64(msg[off+3])<<16 |
@ -573,10 +592,12 @@ func unpackStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int,
case "domain-name":
s, off, ok = unpackDomainName(msg, off)
if !ok {
fmt.Fprintf(os.Stderr, "dns: failure unpacking domain-name")
return len(msg), false
}
case "":
if off >= len(msg) || off+1+int(msg[off]) > len(msg) {
fmt.Fprintf(os.Stderr, "dns: failure unpacking string")
return len(msg), false
}
n := int(msg[off])