-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #29 from duedil-ltd/feature/accept-reject-queries
Query filters
- Loading branch information
Showing
5 changed files
with
283 additions
and
29 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package main | ||
|
||
import ( | ||
"github.com/miekg/dns" | ||
"strings" | ||
) | ||
|
||
type QueryFilter struct { | ||
domain string | ||
qTypes []string | ||
} | ||
|
||
type QueryFilterer struct { | ||
acceptFilters []QueryFilter | ||
rejectFilters []QueryFilter | ||
} | ||
|
||
// Matches returns true if the given DNS query matches the filter | ||
func (f *QueryFilter) Matches(req *dns.Msg) bool { | ||
queryDomain := req.Question[0].Name | ||
queryQType := dns.TypeToString[req.Question[0].Qtype] | ||
if len(queryDomain) > 0 && !strings.HasSuffix(queryDomain, f.domain) { | ||
debugMsg("Domain match failed (" + queryDomain + ", " + f.domain + ")") | ||
return false | ||
} | ||
|
||
matches := false | ||
if len(f.qTypes) > 0 { | ||
for _, qType := range f.qTypes { | ||
if qType == queryQType { | ||
matches = true | ||
} | ||
} | ||
} else { | ||
matches = true | ||
} | ||
|
||
return matches | ||
} | ||
|
||
// ShouldAcceptQuery returns true if the given DNS query matches the given | ||
// accept/reject filters, and should be accepted. | ||
func (f *QueryFilterer) ShouldAcceptQuery(req *dns.Msg) bool { | ||
accepted := true | ||
|
||
for _, filter := range f.rejectFilters { | ||
filterDescription := "Filter " + filter.domain + ":" + strings.Join(filter.qTypes, ",") | ||
if filter.Matches(req) { | ||
debugMsg(filterDescription + " rejected") | ||
accepted = false | ||
break | ||
} | ||
debugMsg(filterDescription + " not rejected") | ||
} | ||
|
||
if accepted && len(f.acceptFilters) > 0 { | ||
accepted = false | ||
for _, filter := range f.acceptFilters { | ||
filterDescription := "Filter " + filter.domain + ":" + strings.Join(filter.qTypes, ",") | ||
if filter.Matches(req) { | ||
debugMsg(filterDescription + " accepted") | ||
accepted = true | ||
break | ||
} | ||
debugMsg(filterDescription + " not accepted") | ||
} | ||
} | ||
|
||
return accepted | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
package main | ||
|
||
import ( | ||
"github.com/miekg/dns" | ||
"testing" | ||
) | ||
|
||
func TestFilters(t *testing.T) { | ||
// Enable debug logging | ||
log_debug = true | ||
} | ||
|
||
func TestNoFilters(t *testing.T) { | ||
filterer := QueryFilterer{} | ||
msg := generateDNSMessage("discodns.net", dns.TypeA) | ||
|
||
if filterer.ShouldAcceptQuery(msg) != true { | ||
t.Error("Expected the query to be accepted") | ||
t.Fatal() | ||
} | ||
} | ||
|
||
func TestSimpleAccept(t *testing.T) { | ||
filterer := QueryFilterer{acceptFilters: parseFilters([]string{"net:A"})} | ||
|
||
msg := generateDNSMessage("discodns.net", dns.TypeA) | ||
if filterer.ShouldAcceptQuery(msg) != true { | ||
t.Error("Expected the query to be accepted") | ||
t.Fatal() | ||
} | ||
|
||
msg = generateDNSMessage("discodns.net", dns.TypeAAAA) | ||
if filterer.ShouldAcceptQuery(msg) != false { | ||
t.Error("Expected the query to be rejected") | ||
t.Fatal() | ||
} | ||
|
||
msg = generateDNSMessage("discodns.com", dns.TypeA) | ||
if filterer.ShouldAcceptQuery(msg) != false { | ||
t.Error("Expected the query to be rejected") | ||
t.Fatal() | ||
} | ||
} | ||
|
||
func TestSimpleReject(t *testing.T) { | ||
filterer := QueryFilterer{rejectFilters: parseFilters([]string{"net:A"})} | ||
|
||
msg := generateDNSMessage("discodns.com", dns.TypeA) | ||
if filterer.ShouldAcceptQuery(msg) != true { | ||
t.Error("Expected the query to be accepted") | ||
t.Fatal() | ||
} | ||
|
||
msg = generateDNSMessage("discodns.net", dns.TypeAAAA) | ||
if filterer.ShouldAcceptQuery(msg) != true { | ||
t.Error("Expected the query to be accepted") | ||
t.Fatal() | ||
} | ||
|
||
msg = generateDNSMessage("discodns.net", dns.TypeA) | ||
if filterer.ShouldAcceptQuery(msg) != false { | ||
t.Error("Expected the query to be rejected") | ||
t.Fatal() | ||
} | ||
} | ||
|
||
func TestMultipleAccept(t *testing.T) { | ||
filterer := QueryFilterer{acceptFilters: parseFilters([]string{"net:A", "com:AAAA"})} | ||
|
||
msg := generateDNSMessage("discodns.net", dns.TypeA) | ||
if filterer.ShouldAcceptQuery(msg) != true { | ||
t.Error("Expected the query to be accepted") | ||
t.Fatal() | ||
} | ||
|
||
msg = generateDNSMessage("discodns.net", dns.TypeAAAA) | ||
if filterer.ShouldAcceptQuery(msg) != false { | ||
t.Error("Expected the query to be rejected") | ||
t.Fatal() | ||
} | ||
|
||
msg = generateDNSMessage("discodns.com", dns.TypeAAAA) | ||
if filterer.ShouldAcceptQuery(msg) != true { | ||
t.Error("Expected the query to be accepted") | ||
t.Fatal() | ||
} | ||
|
||
msg = generateDNSMessage("discodns.com", dns.TypeA) | ||
if filterer.ShouldAcceptQuery(msg) != false { | ||
t.Error("Expected the query to be rejected") | ||
t.Fatal() | ||
} | ||
} | ||
|
||
|
||
// generateDNSMessage returns a simple DNS query with a single question, | ||
// comprised of the domain and rrType given. | ||
func generateDNSMessage(domain string, rrType uint16) *dns.Msg { | ||
domain = dns.Fqdn(domain) | ||
msg := dns.Msg{Question: []dns.Question{dns.Question{Name: domain, Qtype: rrType}}} | ||
return &msg | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters