Skip to content

Commit 05c9c4b

Browse files
authored
add QNameSubDomain (#17)
1 parent ef80f86 commit 05c9c4b

6 files changed

+230
-6
lines changed

matcher/dnsmsg_query_name.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ func NewMatchDNSMsgQueryName(arg interface{}) (DnsMsgMatcher, error) {
1717
return nil, errors.Errorf("invalid type args %v", arg)
1818
}
1919
buf := make([]byte, 255)
20-
_, err := dns.PackDomainName(dns.CanonicalName(qName), buf, 0, nil, false)
20+
offset, err := dns.PackDomainName(dns.CanonicalName(qName), buf, 0, nil, false)
2121
if err != nil {
2222
return nil, errors.Wrap(err, "invalid domain name")
2323
}
24-
return &matchDNSMsgQueryName{target: buf}, nil
24+
return &matchDNSMsgQueryName{target: buf[:offset]}, nil
2525
}
2626

2727
type matchDNSMsgQueryName struct {
@@ -33,11 +33,11 @@ func (m *matchDNSMsgQueryName) Match(d *dns.Msg) bool {
3333
return false
3434
}
3535
buf := make([]byte, 255)
36-
_, err := dns.PackDomainName(dns.CanonicalName(d.Question[0].Name), buf, 0, nil, false)
36+
offset, err := dns.PackDomainName(dns.CanonicalName(d.Question[0].Name), buf, 0, nil, false)
3737
if err != nil {
3838
return false
3939
}
40-
return bytes.Equal(m.target, buf)
40+
return bytes.Equal(m.target, buf[:offset])
4141
}
4242

4343
func init() {
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package matcher
2+
3+
import (
4+
"bytes"
5+
6+
"github.com/miekg/dns"
7+
"github.com/pkg/errors"
8+
)
9+
10+
const (
11+
DNSMatcherQNameSubDomain MatcherName = "QNameSubDomain"
12+
)
13+
14+
func NewMatchDNSMsgQueryNameSubDomain(arg interface{}) (DnsMsgMatcher, error) {
15+
qName, ok := arg.(string)
16+
if !ok {
17+
return nil, errors.Errorf("invalid type args %v", arg)
18+
}
19+
buf := make([]byte, 255)
20+
offset, err := dns.PackDomainName(dns.CanonicalName(qName), buf, 0, nil, false)
21+
if err != nil {
22+
return nil, errors.Wrap(err, "invalid domain name")
23+
}
24+
return &matchDNSMsgQueryNameSubDomain{target: buf[:offset], offset: offset}, nil
25+
}
26+
27+
type matchDNSMsgQueryNameSubDomain struct {
28+
target []byte
29+
offset int
30+
}
31+
32+
func (m *matchDNSMsgQueryNameSubDomain) Match(d *dns.Msg) bool {
33+
if len(d.Question) == 0 {
34+
return false
35+
}
36+
buf := make([]byte, 255)
37+
offset, err := dns.PackDomainName(dns.CanonicalName(d.Question[0].Name), buf, 0, nil, false)
38+
if err != nil {
39+
return false
40+
}
41+
buf = buf[:offset]
42+
if len(buf) < len(m.target) {
43+
return false
44+
}
45+
return bytes.Equal(m.target, buf[offset-m.offset:])
46+
}
47+
48+
func init() {
49+
RegisterDnsMsgMatcher(DNSMatcherQNameSubDomain, NewMatchDNSMsgQueryNameSubDomain, UnmarshalStringArg)
50+
}
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
package matcher_test
2+
3+
import (
4+
_ "embed"
5+
"encoding/json"
6+
7+
"github.com/miekg/dns"
8+
"github.com/mimuret/dnsutils/matcher"
9+
. "github.com/onsi/ginkgo"
10+
. "github.com/onsi/gomega"
11+
)
12+
13+
//go:embed testdata/dnsmsg_query_name_subdomain_fail.json
14+
var matchDNSMsgQuerySubDomainFailData []byte
15+
16+
//go:embed testdata/dnsmsg_query_name_subdomain_success.json
17+
var matchDNSMsgQuerySubDomainValidData []byte
18+
19+
var _ = Describe("QName", func() {
20+
Context("NewMatchDNSMsgQueryNameSubDomain", func() {
21+
var (
22+
m matcher.DnsMsgMatcher
23+
err error
24+
)
25+
When("arg is string", func() {
26+
When("valid domain name", func() {
27+
BeforeEach(func() {
28+
m, err = matcher.NewMatchDNSMsgQueryNameSubDomain("exmaple.jp")
29+
})
30+
It("returns matcher", func() {
31+
Expect(err).To(Succeed())
32+
Expect(m).NotTo(BeNil())
33+
})
34+
})
35+
When("invalid domain name", func() {
36+
BeforeEach(func() {
37+
m, err = matcher.NewMatchDNSMsgQueryNameSubDomain("..")
38+
})
39+
It("returns error", func() {
40+
Expect(err).To(HaveOccurred())
41+
})
42+
})
43+
})
44+
When("arg is invalid type", func() {
45+
BeforeEach(func() {
46+
m, err = matcher.NewMatchDNSMsgQueryNameSubDomain(true)
47+
})
48+
It("returns error", func() {
49+
Expect(err).To(HaveOccurred())
50+
})
51+
})
52+
})
53+
Context("UnmarshalArg", func() {
54+
var (
55+
err error
56+
mc *matcher.MatcherConfig
57+
)
58+
BeforeEach(func() {
59+
mc = &matcher.MatcherConfig{}
60+
})
61+
When("valid arg", func() {
62+
BeforeEach(func() {
63+
err = json.Unmarshal(matchDNSMsgQuerySubDomainValidData, mc)
64+
})
65+
It("not returns error", func() {
66+
Expect(err).To(Succeed())
67+
Expect(mc).To(Equal(&matcher.MatcherConfig{
68+
Name: "QNameSubDomain",
69+
Type: matcher.MatcherTypeDnsMsg,
70+
Arg: "example.jp.",
71+
}))
72+
})
73+
})
74+
When("invalid arg", func() {
75+
BeforeEach(func() {
76+
err = json.Unmarshal(matchDNSMsgQuerySubDomainFailData, mc)
77+
})
78+
It("returns error", func() {
79+
Expect(err).To(HaveOccurred())
80+
})
81+
})
82+
})
83+
Context("BuildDnsMsgMatcher", func() {
84+
var (
85+
err error
86+
m1 matcher.DnsMsgMatcher
87+
m2 matcher.DnsMsgMatcher
88+
)
89+
BeforeEach(func() {
90+
m1, err = matcher.NewMatchDNSMsgQueryNameSubDomain("exmaple.jp")
91+
Expect(err).To(Succeed())
92+
})
93+
When("Name is QName", func() {
94+
BeforeEach(func() {
95+
m2, err = matcher.BuildDnsMsgMatcher(matcher.MatcherConfig{
96+
Type: matcher.MatcherTypeDnsMsg,
97+
Name: "QNameSubDomain",
98+
Arg: "exmaple.jp",
99+
})
100+
})
101+
It("returns matcher", func() {
102+
Expect(err).To(Succeed())
103+
Expect(m2).To(Equal(m1))
104+
})
105+
})
106+
})
107+
Context("Match", func() {
108+
var (
109+
err error
110+
m matcher.DnsMsgMatcher
111+
)
112+
BeforeEach(func() {
113+
m, err = matcher.NewMatchDNSMsgQueryNameSubDomain("exmaple.jp.")
114+
Expect(err).To(Succeed())
115+
})
116+
When("msg.Question is empty ", func() {
117+
It("returns false", func() {
118+
Expect(m.Match(&dns.Msg{})).To(BeFalse())
119+
})
120+
})
121+
When("msg.Question is not domain name ", func() {
122+
It("returns false", func() {
123+
Expect(m.Match(&dns.Msg{Question: []dns.Question{
124+
{
125+
Name: "..",
126+
Qtype: dns.TypeA,
127+
Qclass: dns.ClassCHAOS,
128+
},
129+
}})).To(BeFalse())
130+
})
131+
})
132+
When("msg.QueryName != TARGET", func() {
133+
It("returns false", func() {
134+
Expect(m.Match(&dns.Msg{Question: []dns.Question{{Name: "exmaple.net"}}})).To(BeFalse())
135+
})
136+
It("returns false", func() {
137+
Expect(m.Match(&dns.Msg{Question: []dns.Question{{Name: "jp"}}})).To(BeFalse())
138+
})
139+
It("returns false", func() {
140+
Expect(m.Match(&dns.Msg{Question: []dns.Question{{Name: "ple.jp"}}})).To(BeFalse())
141+
})
142+
})
143+
When("msg.QueryName = SUBDOMAIN", func() {
144+
It("returns true", func() {
145+
Expect(m.Match(&dns.Msg{Question: []dns.Question{{Name: "www.ExmapLe.jp"}}})).To(BeTrue())
146+
})
147+
It("returns true", func() {
148+
Expect(m.Match(&dns.Msg{Question: []dns.Question{{Name: "*.ExmapLe.jp"}}})).To(BeTrue())
149+
})
150+
})
151+
When("msg.QueryName = TARGET", func() {
152+
When("different case", func() {
153+
It("returns true", func() {
154+
Expect(m.Match(&dns.Msg{Question: []dns.Question{{Name: "ExmapLe.jp."}}})).To(BeTrue())
155+
})
156+
})
157+
When("not FQDN", func() {
158+
It("returns true", func() {
159+
Expect(m.Match(&dns.Msg{Question: []dns.Question{{Name: "ExmapLe.jp"}}})).To(BeTrue())
160+
})
161+
})
162+
})
163+
})
164+
})
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
22
"Type": "DNS",
3-
"name": "QNameRegexp",
3+
"Name": "QNameRegexp",
44
"Arg": ".*"
5-
}
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"Type": "DNS",
3+
"Name": "QNameSubDomain",
4+
"Arg": false
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"Type": "DNS",
3+
"Name": "QNameSubDomain",
4+
"Arg": "example.jp."
5+
}

0 commit comments

Comments
 (0)