dns/ex/reflect/reflect.go

203 lines
4.9 KiB
Go
Raw Normal View History

2013-05-13 00:11:13 +10:00
// Copyright 2011 Miek Gieben. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
2012-10-12 18:01:40 +11:00
// Reflect is a small name server which sends back the IP address of its client, the
2012-10-12 18:06:17 +11:00
// recursive resolver.
// When queried for type A (resp. AAAA), it sends back the IPv4 (resp. v6) address.
// In the additional section the port number and transport are shown.
2012-10-12 18:01:40 +11:00
//
2012-10-12 18:06:17 +11:00
// Basic use pattern:
//
// dig @localhost -p 8053 whoami.miek.nl A
//
2012-10-12 18:13:09 +11:00
// ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 2157
2012-10-12 18:06:17 +11:00
// ;; flags: qr rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
// ;; QUESTION SECTION:
// ;whoami.miek.nl. IN A
//
// ;; ANSWER SECTION:
// whoami.miek.nl. 0 IN A 127.0.0.1
//
// ;; ADDITIONAL SECTION:
// whoami.miek.nl. 0 IN TXT "Port: 56195 (udp)"
//
2012-10-12 18:01:40 +11:00
// Similar services: whoami.ultradns.net, whoami.akamai.net. Also (but it
// is not their normal goal): rs.dns-oarc.net, porttest.dns-oarc.net,
// amiopen.openresolvers.org.
//
// Original version is from: Stephane Bortzmeyer <stephane+grong@bortzmeyer.org>.
//
// Adapted to Go (i.e. completely rewritten) by Miek Gieben <miek@miek.nl>.
2011-01-18 02:11:11 +11:00
package main
import (
2012-01-13 08:19:42 +11:00
"flag"
2011-02-12 07:29:40 +11:00
"fmt"
2012-08-24 20:42:41 +10:00
"github.com/miekg/dns"
2011-12-17 05:17:04 +11:00
"log"
"net"
2012-01-13 08:19:42 +11:00
"os"
2012-02-26 08:47:26 +11:00
"os/signal"
2012-01-13 08:19:42 +11:00
"runtime/pprof"
2011-07-06 03:17:29 +10:00
"strconv"
"strings"
"syscall"
"time"
2011-01-18 02:11:11 +11:00
)
var (
2012-03-06 08:03:18 +11:00
printf *bool
compress *bool
2012-03-06 08:03:18 +11:00
tsig *string
)
2012-02-26 19:54:50 +11:00
2012-01-13 22:36:05 +11:00
const dom = "whoami.miek.nl."
2011-07-06 04:01:17 +10:00
func handleReflect(w dns.ResponseWriter, r *dns.Msg) {
var (
v4 bool
rr dns.RR
str string
a net.IP
)
2012-02-27 06:09:03 +11:00
// TC must be done here
2012-01-13 22:29:25 +11:00
m := new(dns.Msg)
m.SetReply(r)
m.Compress = *compress
if ip, ok := w.RemoteAddr().(*net.UDPAddr); ok {
str = "Port: " + strconv.Itoa(ip.Port) + " (udp)"
a = ip.IP
v4 = a.To4() != nil
}
if ip, ok := w.RemoteAddr().(*net.TCPAddr); ok {
str = "Port: " + strconv.Itoa(ip.Port) + " (tcp)"
a = ip.IP
v4 = a.To4() != nil
}
2011-07-06 03:17:29 +10:00
2013-01-28 03:18:25 +11:00
/*
2013-01-22 23:27:48 +11:00
if o := r.IsEdns0(); o != nil {
2013-01-23 02:42:06 +11:00
for _, s := range o.Option {
switch e := s.(type) {
2013-01-22 23:27:48 +11:00
case *dns.EDNS0_SUBNET:
2013-01-23 02:42:06 +11:00
log.Printf("Edns0 subnet %s", e.Address)
2013-01-22 23:27:48 +11:00
}
}
}
2013-01-28 03:18:25 +11:00
*/
2013-01-22 23:27:48 +11:00
2011-07-06 03:17:29 +10:00
if v4 {
2012-12-10 05:26:32 +11:00
rr = new(dns.A)
rr.(*dns.A).Hdr = dns.RR_Header{Name: dom, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 0}
rr.(*dns.A).A = a.To4()
2011-07-06 03:17:29 +10:00
} else {
2012-12-10 05:26:32 +11:00
rr = new(dns.AAAA)
rr.(*dns.AAAA).Hdr = dns.RR_Header{Name: dom, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: 0}
rr.(*dns.AAAA).AAAA = a
2011-07-06 03:17:29 +10:00
}
2011-01-18 02:11:11 +11:00
2012-12-10 05:26:32 +11:00
t := new(dns.TXT)
2011-07-06 04:01:17 +10:00
t.Hdr = dns.RR_Header{Name: dom, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 0}
t.Txt = []string{str}
2011-12-18 06:14:39 +11:00
2012-02-26 19:54:50 +11:00
switch r.Question[0].Qtype {
2012-08-28 21:12:55 +10:00
case dns.TypeAXFR:
2012-12-02 19:34:40 +11:00
c := make(chan *dns.Envelope)
2012-08-28 21:12:55 +10:00
var e *error
2012-12-02 19:34:40 +11:00
if err := dns.TransferOut(w, r, c, e); err != nil {
2012-08-28 21:12:55 +10:00
close(c)
return
}
2012-08-29 04:21:44 +10:00
soa, _ := dns.NewRR(`whoami.miek.nl. IN SOA elektron.atoom.net. miekg.atoom.net. (
2012-08-28 21:12:55 +10:00
2009032802
21600
7200
604800
3600)`)
2012-12-02 19:34:40 +11:00
c <- &dns.Envelope{RR: []dns.RR{soa, t, rr, soa}}
2012-08-28 21:12:55 +10:00
close(c)
2012-08-29 03:53:21 +10:00
w.Hijack()
// w.Close() // Client closes
2012-08-28 21:12:55 +10:00
return
2012-02-26 19:54:50 +11:00
case dns.TypeTXT:
2012-01-13 22:36:05 +11:00
m.Answer = append(m.Answer, t)
m.Extra = append(m.Extra, rr)
2012-02-26 19:54:50 +11:00
default:
fallthrough
case dns.TypeAAAA, dns.TypeA:
2012-01-13 22:36:05 +11:00
m.Answer = append(m.Answer, rr)
m.Extra = append(m.Extra, t)
2012-02-26 19:54:50 +11:00
}
2012-01-15 23:53:32 +11:00
2012-08-28 19:19:03 +10:00
if r.IsTsig() != nil {
if w.TsigStatus() == nil {
2012-12-10 05:26:32 +11:00
m.SetTsig(r.Extra[len(r.Extra)-1].(*dns.TSIG).Hdr.Name, dns.HmacMD5, 300, time.Now().Unix())
2012-03-06 08:03:18 +11:00
} else {
println("Status", w.TsigStatus().Error())
}
}
2012-02-26 19:54:50 +11:00
if *printf {
fmt.Printf("%v\n", m.String())
}
2012-11-18 23:56:54 +11:00
w.WriteMsg(m)
2011-01-18 02:11:11 +11:00
}
func serve(net, name, secret string) {
switch name {
case "":
err := dns.ListenAndServe(":8053", net, nil)
if err != nil {
fmt.Printf("Failed to setup the "+net+" server: %s\n", err.Error())
}
default:
server := &dns.Server{Addr: ":8053", Net: net, TsigSecret: map[string]string{name: secret}}
2012-08-08 17:50:21 +10:00
err := server.ListenAndServe()
if err != nil {
fmt.Printf("Failed to setup the "+net+" server: %s\n", err.Error())
}
}
2011-07-06 03:44:46 +10:00
}
2011-02-12 06:54:54 +11:00
func main() {
2012-01-13 08:19:42 +11:00
cpuprofile := flag.String("cpuprofile", "", "write cpu profile to file")
2012-01-16 01:50:19 +11:00
printf = flag.Bool("print", false, "print replies")
compress = flag.Bool("compress", false, "compress replies")
tsig = flag.String("tsig", "", "use MD5 hmac tsig: keyname:base64")
var name, secret string
2012-01-13 08:19:42 +11:00
flag.Usage = func() {
flag.PrintDefaults()
}
flag.Parse()
if *tsig != "" {
a := strings.SplitN(*tsig, ":", 2)
2012-11-13 18:29:28 +11:00
name, secret = dns.Fqdn(a[0]), a[1] // fqdn the name, which everybody forgets...
}
2012-01-13 08:19:42 +11:00
if *cpuprofile != "" {
f, err := os.Create(*cpuprofile)
if err != nil {
log.Fatal(err)
}
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()
}
2012-09-18 16:23:17 +10:00
dns.HandleFunc("miek.nl.", handleReflect)
2012-09-03 20:54:18 +10:00
dns.HandleFunc("authors.bind.", dns.HandleAuthors)
dns.HandleFunc("authors.server.", dns.HandleAuthors)
2012-09-03 21:56:43 +10:00
dns.HandleFunc("version.bind.", dns.HandleVersion)
dns.HandleFunc("version.server.", dns.HandleVersion)
go serve("tcp", name, secret)
go serve("udp", name, secret)
2012-02-26 08:47:26 +11:00
sig := make(chan os.Signal)
signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
2011-07-06 03:17:29 +10:00
forever:
for {
select {
2012-11-13 18:29:28 +11:00
case s := <-sig:
fmt.Printf("Signal (%d) received, stopping\n", s)
break forever
}
}
2011-01-18 02:11:11 +11:00
}