-
Notifications
You must be signed in to change notification settings - Fork 1
/
netflixv4.go
145 lines (126 loc) · 3.59 KB
/
netflixv4.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
package main
//This simple DNS client/server filters out ipv6 addresses from Netflix's domains.
import (
"flag"
"github.com/miekg/dns"
"log"
"os"
"os/signal"
"strconv"
"sync"
"syscall"
)
//use one and only one dns client object
var resolver = &dns.Client{}
var wg = sync.WaitGroup{}
//command-line flags
var (
debugMode bool
listenPort uint
upstreamResolver string
)
//set up flags
func init() {
flag.BoolVar(&debugMode, "d", false, "Print debug info")
flag.UintVar(&listenPort, "p", 5353, "Listen on this TCP/UDP port")
flag.StringVar(&upstreamResolver, "r", "8.8.8.8:53", "DNS resolver to proxy")
}
func main() {
flag.Parse()
serveMux := dns.NewServeMux()
serveMux.HandleFunc(".", handleNormalRequest) //if for some reason we get a non-Netflix dns request, handle it
serveMux.HandleFunc("netflix.com.", handleNetflixRequest)
serveMux.HandleFunc("nflxvideo.com.", handleNetflixRequest)
serveMux.HandleFunc("nflxext.com.", handleNetflixRequest)
serveMux.HandleFunc("nflximg.com.", handleNetflixRequest)
servers := make(chan *dns.Server, 2)
wg.Add(1)
go func() {
defer wg.Done()
server := &dns.Server{Addr: ":" + strconv.FormatUint(uint64(listenPort), 10), Net: "udp", Handler: serveMux}
servers <- server
if err := server.ListenAndServe(); err != nil {
log.Printf("UDP listener err: %v", err)
}
}()
wg.Add(1)
go func() {
defer wg.Done()
server := &dns.Server{Addr: ":" + strconv.FormatUint(uint64(listenPort), 10), Net: "tcp", Handler: serveMux}
servers <- server
if err := server.ListenAndServe(); err != nil {
log.Printf("TCP listener err: %v", err)
}
}()
go func() {
sig := make(chan os.Signal)
signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
_ = <-sig
for i := 0; i < 2; i++ {
server := <-servers
server.Shutdown()
}
}()
wg.Wait()
}
func handleNormalRequest(writer dns.ResponseWriter, req *dns.Msg) {
if debugMode {
log.Printf("received non-Netflix query: %v", req)
}
response := fetchProxiedResult(req)
if debugMode {
log.Printf("sending response to non-Netflix query: %v", response)
}
writer.WriteMsg(response)
}
func handleNetflixRequest(writer dns.ResponseWriter, req *dns.Msg) {
if debugMode {
log.Printf("received Netflix query: %v", req)
}
response := fetchProxiedResult(req)
response.Answer = filterRRSet(response.Answer)
response.Extra = filterRRSet(response.Extra)
if debugMode {
log.Printf("sending response to Netflix query: %v", response)
}
writer.WriteMsg(response)
}
func filterRRSet(rrset []dns.RR) (ret []dns.RR) {
for _, rr := range rrset {
header := rr.Header()
if header.Rrtype != dns.TypeAAAA || header.Class != dns.ClassINET {
ret = append(ret, rr)
}
}
return
}
func fetchProxiedResult(req *dns.Msg) *dns.Msg {
nestedQuery := &dns.Msg{}
nestedQuery.Question = make([]dns.Question, 1)
nestedQuery.SetEdns0(4096, false)
nestedQuery.Question[0] = req.Question[0]
nestedQuery.Id = dns.Id()
nestedQuery.RecursionDesired = true
if debugMode {
log.Printf("sending nested query: %v", nestedQuery)
}
nestedResponse, _, err := resolver.Exchange(nestedQuery, upstreamResolver)
if err != nil {
log.Print(err)
response := &dns.Msg{}
response.SetRcode(req, dns.RcodeServerFailure)
return response
}
if debugMode {
log.Printf("received nested response: %v", nestedResponse)
}
response := &dns.Msg{
Answer: make([]dns.RR, len(nestedResponse.Answer)),
Extra: make([]dns.RR, len(nestedResponse.Extra)),
}
response.SetRcode(req, nestedResponse.Rcode)
response.RecursionAvailable = true
copy(response.Answer, nestedResponse.Answer)
copy(response.Extra, nestedResponse.Extra)
return response
}