Skip to content

Commit f1b3133

Browse files
committed
fix: add unit tests for CIDR subnets parsing
1 parent b98b01c commit f1b3133

File tree

2 files changed

+165
-38
lines changed

2 files changed

+165
-38
lines changed

doh-server/google.go

Lines changed: 46 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -90,45 +90,14 @@ func (s *Server) parseRequestGoogle(ctx context.Context, w http.ResponseWriter,
9090
if ednsClientSubnet == "0/0" {
9191
ednsClientSubnet = "0.0.0.0/0"
9292
}
93-
slash := strings.IndexByte(ednsClientSubnet, '/')
94-
if slash < 0 {
95-
ednsClientAddress = net.ParseIP(ednsClientSubnet)
96-
if ednsClientAddress == nil {
97-
return &DNSRequest{
98-
errcode: 400,
99-
errtext: fmt.Sprintf("Invalid argument value: \"edns_client_subnet\" = %q", ednsClientSubnet),
100-
}
101-
}
102-
if ipv4 := ednsClientAddress.To4(); ipv4 != nil {
103-
ednsClientFamily = 1
104-
ednsClientAddress = ipv4
105-
ednsClientNetmask = 24
106-
} else {
107-
ednsClientFamily = 2
108-
ednsClientNetmask = 56
109-
}
110-
} else {
111-
ednsClientAddress = net.ParseIP(ednsClientSubnet[:slash])
112-
if ednsClientAddress == nil {
113-
return &DNSRequest{
114-
errcode: 400,
115-
errtext: fmt.Sprintf("Invalid argument value: \"edns_client_subnet\" = %q", ednsClientSubnet),
116-
}
117-
}
118-
if ipv4 := ednsClientAddress.To4(); ipv4 != nil {
119-
ednsClientFamily = 1
120-
ednsClientAddress = ipv4
121-
} else {
122-
ednsClientFamily = 2
123-
}
124-
netmask, err := strconv.ParseUint(ednsClientSubnet[slash+1:], 10, 8)
125-
if err != nil {
126-
return &DNSRequest{
127-
errcode: 400,
128-
errtext: fmt.Sprintf("Invalid argument value: \"edns_client_subnet\" = %q", ednsClientSubnet),
129-
}
93+
94+
var err error
95+
ednsClientFamily, ednsClientAddress, ednsClientNetmask, err = parseSubnet(ednsClientSubnet)
96+
if err != nil {
97+
return &DNSRequest{
98+
errcode: 400,
99+
errtext: err.Error(),
130100
}
131-
ednsClientNetmask = uint8(netmask)
132101
}
133102
} else {
134103
ednsClientAddress = s.findClientIP(r)
@@ -169,6 +138,45 @@ func (s *Server) parseRequestGoogle(ctx context.Context, w http.ResponseWriter,
169138
}
170139
}
171140

141+
func parseSubnet(ednsClientSubnet string) (ednsClientFamily uint16, ednsClientAddress net.IP, ednsClientNetmask uint8, err error) {
142+
slash := strings.IndexByte(ednsClientSubnet, '/')
143+
if slash < 0 {
144+
ednsClientAddress = net.ParseIP(ednsClientSubnet)
145+
if ednsClientAddress == nil {
146+
err = fmt.Errorf("Invalid argument value: \"edns_client_subnet\" = %q", ednsClientSubnet)
147+
return
148+
}
149+
if ipv4 := ednsClientAddress.To4(); ipv4 != nil {
150+
ednsClientFamily = 1
151+
ednsClientAddress = ipv4
152+
ednsClientNetmask = 24
153+
} else {
154+
ednsClientFamily = 2
155+
ednsClientNetmask = 56
156+
}
157+
} else {
158+
ednsClientAddress = net.ParseIP(ednsClientSubnet[:slash])
159+
if ednsClientAddress == nil {
160+
err = fmt.Errorf("Invalid argument value: \"edns_client_subnet\" = %q", ednsClientSubnet)
161+
return
162+
}
163+
if ipv4 := ednsClientAddress.To4(); ipv4 != nil {
164+
ednsClientFamily = 1
165+
ednsClientAddress = ipv4
166+
} else {
167+
ednsClientFamily = 2
168+
}
169+
netmask, err1 := strconv.ParseUint(ednsClientSubnet[slash+1:], 10, 8)
170+
if err1 != nil {
171+
err = fmt.Errorf("Invalid argument value: \"edns_client_subnet\" = %q", ednsClientSubnet)
172+
return
173+
}
174+
ednsClientNetmask = uint8(netmask)
175+
}
176+
177+
return
178+
}
179+
172180
func (s *Server) generateResponseGoogle(ctx context.Context, w http.ResponseWriter, r *http.Request, req *DNSRequest) {
173181
respJSON := jsondns.Marshal(req.response)
174182
respStr, err := json.Marshal(respJSON)

doh-server/parse_test.go

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
/*
2+
DNS-over-HTTPS
3+
Copyright (C) 2017-2018 Star Brilliant <[email protected]>
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a
6+
copy of this software and associated documentation files (the "Software"),
7+
to deal in the Software without restriction, including without limitation
8+
the rights to use, copy, modify, merge, publish, distribute, sublicense,
9+
and/or sell copies of the Software, and to permit persons to whom the
10+
Software is furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in
13+
all copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21+
DEALINGS IN THE SOFTWARE.
22+
*/
23+
24+
package main
25+
26+
import (
27+
"testing"
28+
29+
"github.com/miekg/dns"
30+
)
31+
32+
func TestParseCIDR(t *testing.T) {
33+
t.Parallel()
34+
for _, ednsClientSubnet := range []string{
35+
"2001:db8::/0",
36+
"2001:db8::/56",
37+
"2001:db8::/129",
38+
"2001:db8::",
39+
40+
"127.0.0.1/0",
41+
"127.0.0.1/24",
42+
"127.0.0.1/33",
43+
"127.0.0.1",
44+
45+
"::ffff:7f00:1/0",
46+
"::ffff:7f00:1/120",
47+
"::ffff:7f00:1",
48+
"127.0.0.1/0",
49+
"127.0.0.1/24",
50+
"127.0.0.1",
51+
} {
52+
_, ip, ipNet, err := parseSubnet(ednsClientSubnet)
53+
if err != nil {
54+
t.Errorf("ecs:%s ip:[%v] ipNet:[%v] err:[%v]", ednsClientSubnet, ip, ipNet, err)
55+
}
56+
}
57+
}
58+
59+
func TestParseInvalidCIDR(t *testing.T) {
60+
t.Parallel()
61+
62+
for _, ip := range []string{
63+
"test",
64+
"test/0",
65+
"test/24",
66+
"test/34",
67+
"test/56",
68+
"test/129",
69+
} {
70+
_, _, _, err := parseSubnet(ip)
71+
if err == nil {
72+
t.Errorf("expected error for %q", ip)
73+
}
74+
}
75+
}
76+
77+
func TestEdns0SubnetParseCIDR(t *testing.T) {
78+
t.Parallel()
79+
// init dns Msg
80+
msg := new(dns.Msg)
81+
msg.Id = dns.Id()
82+
msg.SetQuestion(dns.Fqdn("example.com"), 1)
83+
84+
// init edns0Subnet
85+
edns0Subnet := new(dns.EDNS0_SUBNET)
86+
edns0Subnet.Code = dns.EDNS0SUBNET
87+
edns0Subnet.SourceScope = 0
88+
89+
// init opt
90+
opt := new(dns.OPT)
91+
opt.Hdr.Name = "."
92+
opt.Hdr.Rrtype = dns.TypeOPT
93+
opt.SetUDPSize(dns.DefaultMsgSize)
94+
95+
opt.Option = append(opt.Option, edns0Subnet)
96+
msg.Extra = append(msg.Extra, opt)
97+
98+
for _, subnet := range []string{"::ffff:7f00:1/120", "127.0.0.1/24"} {
99+
var err error
100+
edns0Subnet.Family, edns0Subnet.Address, edns0Subnet.SourceNetmask, err = parseSubnet(subnet)
101+
if err != nil {
102+
t.Error(err)
103+
continue
104+
}
105+
t.Log(msg.Pack())
106+
}
107+
108+
// ------127.0.0.1/24-----
109+
// [143 29 1 0 0 1 0 0 0 0 0 1 7 101 120 97 109 112 108 101 3 99 111 109 0 0 1 0 1 0
110+
// opt start 0 41 16 0 0 0 0 0 0 11
111+
// subnet start 0 8 0 7 0 1 24 0
112+
// client subnet start 127 0 0]
113+
114+
// -----::ffff:7f00:1/120----
115+
// [111 113 1 0 0 1 0 0 0 0 0 1 7 101 120 97 109 112 108 101 3 99 111 109 0 0 1 0 1 0
116+
// opt start 0 41 16 0 0 0 0 0 0 23
117+
// subnet start 0 8 0 19 0 2 120 0
118+
// client subnet start 0 0 0 0 0 0 0 0 0 0 255 255 127 0 0]
119+
}

0 commit comments

Comments
 (0)