-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathdns.go
149 lines (126 loc) · 3.41 KB
/
dns.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
package main
import (
"context"
"flag"
"fmt"
"io/ioutil"
"log"
"net"
"net/http"
"os"
"strconv"
"time"
"github.com/miekg/dns"
)
const eth10Addr = "10.0.0.1"
const eth11Addr = "10.0.0.2"
const ttl = 0
var closeConn = flag.Bool("close-idle-conns", false, "causes the http client to close idle conns")
var records = map[string]string{
"foo.service.": eth10Addr,
}
func parseQuery(m *dns.Msg) {
for _, q := range m.Question {
switch q.Qtype {
case dns.TypeA:
log.Println("[DNS] received query for " + q.Name)
ip := records[q.Name]
if ip != "" {
rr := handleARecord(q.Name)
m.Answer = append(m.Answer, rr)
}
}
}
}
func handleARecord(recordName string) dns.RR {
rr, err := dns.NewRR(fmt.Sprintf("%s A %s", recordName, records[recordName]))
if err == nil {
rr.Header().Ttl = ttl
} else {
log.Println("[DNS] failed to serve " + recordName + ": " + err.Error())
}
return rr
}
func handleDnsRequest(w dns.ResponseWriter, r *dns.Msg) {
m := new(dns.Msg)
m.SetReply(r)
m.Compress = false
if r.Opcode == dns.OpcodeQuery {
parseQuery(m)
}
_ = w.WriteMsg(m)
}
func main() {
flag.Parse()
// attach request handler func
dns.HandleFunc("service.", handleDnsRequest)
// start server
port := 8053
server := &dns.Server{Addr: ":" + strconv.Itoa(port), Net: "udp"}
log.Printf("[DNS] starting on :%d\n", port)
go func() {
if err := server.ListenAndServe(); err != nil {
log.Fatalf("Failed to start server: %s\n", err.Error())
}
}()
serveHTTP("ETH10", eth10Addr)
serveHTTP("ETH11", eth11Addr)
queryDNS()
}
func serveHTTP(iface, addr string) {
server := &http.Server{Addr: addr + ":8080"}
mux := http.NewServeMux()
mux.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
_, _ = writer.Write([]byte("hello on " + addr + ":8080!"))
})
server.Handler = mux
go func() {
log.Printf("[%s] starting on %s:8080\n", iface, addr)
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatalf("[%s] failed to start HTTP server on %s:8080: %s\n", iface, addr, err.Error())
}
}()
}
func queryDNS() {
time.Sleep(time.Second)
// set PreferGo in order to override the Dial func
net.DefaultResolver.PreferGo = true
net.DefaultResolver.Dial = func(ctx context.Context, network, addr string) (net.Conn, error) {
d := net.Dialer{}
if network == "udp" {
return d.DialContext(ctx, "udp", ":8053")
}
return d.DialContext(ctx, network, addr)
}
msg1 := doRequest("http://foo.service.:8080")
log.Printf("[HTTP] request response 1: %s", msg1)
// update foo.service. record to point to eth11
records = map[string]string{
"foo.service.": eth11Addr,
}
if *closeConn {
http.DefaultClient.CloseIdleConnections()
}
msg2 := doRequest("http://foo.service.:8080")
log.Printf("[HTTP] request response 2: %s", msg2)
// check if we got a response from eth11 or eth10
if msg2 == "hello on "+eth10Addr+":8080!" {
fmt.Printf("received message from %s but expected %s\n", eth10Addr, eth11Addr)
os.Exit(1)
} else if msg2 == "hello on "+eth11Addr+":8080!" {
os.Exit(0)
}
log.Fatalf("unknown response: " + msg2)
}
func doRequest(location string) string {
resp, err := http.Get(location)
if err != nil {
log.Fatalf("[HTTP] failed to do request to %s: %s\n", location, err.Error())
}
msg, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatalf("[HTTP] failed to read request body:%s\n", err.Error())
}
_ = resp.Body.Close()
return string(msg)
}