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 The major omission at the moment is parsing Resource Records from
strings. (I.e. supporting the 1035 zone file format). 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! Have fun!
Miek Gieben - 2010, 2011 - miek@miek.nl Miek Gieben - 2010, 2011 - miek@miek.nl

1
TODO
View File

@ -1,5 +1,6 @@
Todo: Todo:
* NSEC and nsec3 closest encloser helper functions * NSEC and nsec3 closest encloser helper functions
* os.Error in Pack()/Unpack()
* wildcards * wildcards
* Tsig testing * Tsig testing
* Private key file parsing use io.Reader (or the like) * 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: all:
gomake -C mx # query for MX records for i in $(EXAMPLES); do gomake -C $$i; done
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
clean: clean:
gomake -C mx clean for i in $(EXAMPLES); do gomake -C $$i clean; done
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

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
}
}
}

27
msg.go
View File

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