|
1 | 1 | package handlers
|
2 | 2 |
|
3 | 3 | import (
|
4 |
| - "context" |
5 |
| - "encoding/json" |
6 |
| - "net" |
7 | 4 | "net/http"
|
8 |
| - "slices" |
9 |
| - "sort" |
10 |
| - "sync" |
11 |
| - "time" |
12 |
| -) |
13 |
| - |
14 |
| -type dnsServer struct { |
15 |
| - Name string |
16 |
| - IP string |
17 |
| -} |
18 |
| - |
19 |
| -var DNS_SERVERS = []dnsServer{ |
20 |
| - {Name: "AdGuard", IP: "176.103.130.130"}, |
21 |
| - {Name: "AdGuard Family", IP: "176.103.130.132"}, |
22 |
| - {Name: "CleanBrowsing Adult", IP: "185.228.168.10"}, |
23 |
| - {Name: "CleanBrowsing Family", IP: "185.228.168.168"}, |
24 |
| - {Name: "CleanBrowsing Security", IP: "185.228.168.9"}, |
25 |
| - {Name: "CloudFlare", IP: "1.1.1.1"}, |
26 |
| - {Name: "CloudFlare Family", IP: "1.1.1.3"}, |
27 |
| - {Name: "Comodo Secure", IP: "8.26.56.26"}, |
28 |
| - {Name: "Google DNS", IP: "8.8.8.8"}, |
29 |
| - {Name: "Neustar Family", IP: "156.154.70.3"}, |
30 |
| - {Name: "Neustar Protection", IP: "156.154.70.2"}, |
31 |
| - {Name: "Norton Family", IP: "199.85.126.20"}, |
32 |
| - {Name: "OpenDNS", IP: "208.67.222.222"}, |
33 |
| - {Name: "OpenDNS Family", IP: "208.67.222.123"}, |
34 |
| - {Name: "Quad9", IP: "9.9.9.9"}, |
35 |
| - {Name: "Yandex Family", IP: "77.88.8.7"}, |
36 |
| - {Name: "Yandex Safe", IP: "77.88.8.88"}, |
37 |
| -} |
38 |
| - |
39 |
| -var knownBlockIPs = []string{ |
40 |
| - "146.112.61.106", |
41 |
| - "185.228.168.10", |
42 |
| - "8.26.56.26", |
43 |
| - "9.9.9.9", |
44 |
| - "208.69.38.170", |
45 |
| - "208.69.39.170", |
46 |
| - "208.67.222.222", |
47 |
| - "208.67.222.123", |
48 |
| - "199.85.126.10", |
49 |
| - "199.85.126.20", |
50 |
| - "156.154.70.22", |
51 |
| - "77.88.8.7", |
52 |
| - "77.88.8.8", |
53 |
| - "::1", |
54 |
| - "2a02:6b8::feed:0ff", |
55 |
| - "2a02:6b8::feed:bad", |
56 |
| - "2a02:6b8::feed:a11", |
57 |
| - "2620:119:35::35", |
58 |
| - "2620:119:53::53", |
59 |
| - "2606:4700:4700::1111", |
60 |
| - "2606:4700:4700::1001", |
61 |
| - "2001:4860:4860::8888", |
62 |
| - "2a0d:2a00:1::", |
63 |
| - "2a0d:2a00:2::", |
64 |
| -} |
65 |
| - |
66 |
| -type Blocklist struct { |
67 |
| - Server string `json:"server"` |
68 |
| - ServerIP string `json:"serverIp"` |
69 |
| - IsBlocked bool `json:"isBlocked"` |
70 |
| -} |
71 |
| - |
72 |
| -func isDomainBlocked(domain, serverIP string) bool { |
73 |
| - resolver := &net.Resolver{ |
74 |
| - PreferGo: true, |
75 |
| - Dial: func(ctx context.Context, network, address string) (net.Conn, error) { |
76 |
| - d := net.Dialer{ |
77 |
| - Timeout: time.Second * 3, |
78 |
| - } |
79 |
| - return d.DialContext(ctx, network, serverIP+":53") |
80 |
| - }, |
81 |
| - } |
82 |
| - |
83 |
| - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) |
84 |
| - defer cancel() |
85 | 5 |
|
86 |
| - ips, err := resolver.LookupIP(ctx, "ip4", domain) |
87 |
| - if err != nil { |
88 |
| - // if there's an error, consider it not blocked |
89 |
| - return false |
90 |
| - } |
91 |
| - |
92 |
| - return slices.ContainsFunc(ips, func(ip net.IP) bool { |
93 |
| - return slices.Contains(knownBlockIPs, ip.String()) |
94 |
| - }) |
95 |
| -} |
96 |
| - |
97 |
| -func checkDomainAgainstDNSServers(domain string) []Blocklist { |
98 |
| - var lock sync.Mutex |
99 |
| - var wg sync.WaitGroup |
100 |
| - limit := make(chan struct{}, 5) |
101 |
| - |
102 |
| - var results []Blocklist |
103 |
| - |
104 |
| - for _, server := range DNS_SERVERS { |
105 |
| - wg.Add(1) |
106 |
| - go func(server dnsServer) { |
107 |
| - limit <- struct{}{} |
108 |
| - defer func() { |
109 |
| - <-limit |
110 |
| - wg.Done() |
111 |
| - }() |
112 |
| - |
113 |
| - isBlocked := isDomainBlocked(domain, server.IP) |
114 |
| - lock.Lock() |
115 |
| - defer lock.Unlock() |
116 |
| - results = append(results, Blocklist{ |
117 |
| - Server: server.Name, |
118 |
| - ServerIP: server.IP, |
119 |
| - IsBlocked: isBlocked, |
120 |
| - }) |
121 |
| - }(server) |
122 |
| - } |
123 |
| - wg.Wait() |
124 |
| - |
125 |
| - sort.Slice(results, func(i, j int) bool { |
126 |
| - return results[i].Server > results[j].Server |
127 |
| - }) |
128 |
| - return results |
129 |
| -} |
| 6 | + "github.com/xray-web/web-check-api/checks" |
| 7 | +) |
130 | 8 |
|
131 |
| -func HandleBlockLists() http.Handler { |
132 |
| - type Response struct { |
133 |
| - BlockLists []Blocklist `json:"blocklists"` |
134 |
| - } |
| 9 | +func HandleBlockLists(b *checks.BlockList) http.Handler { |
135 | 10 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
136 | 11 | rawURL, err := extractURL(r)
|
137 | 12 | if err != nil {
|
138 | 13 | JSONError(w, ErrMissingURLParameter, http.StatusBadRequest)
|
139 | 14 | return
|
140 | 15 | }
|
141 |
| - json.NewEncoder(w).Encode(Response{BlockLists: checkDomainAgainstDNSServers(rawURL.Hostname())}) |
| 16 | + list := b.BlockedServers(r.Context(), rawURL.Hostname()) |
| 17 | + JSON(w, list, http.StatusOK) |
142 | 18 | })
|
143 | 19 | }
|
0 commit comments