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:
parent
131b3f388b
commit
05c75c348b
2
README
2
README
|
@ -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
1
TODO
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
35
msg.go
|
@ -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])
|
||||
|
|
Loading…
Reference in New Issue