Skip to content

Commit

Permalink
improve except option
Browse files Browse the repository at this point in the history
Signed-off-by: denis-tingajkin <denis.tingajkin@xored.com>
  • Loading branch information
denis-tingaikin committed Apr 7, 2020
1 parent 47a5b58 commit 424dc48
Show file tree
Hide file tree
Showing 5 changed files with 190 additions and 27 deletions.
120 changes: 120 additions & 0 deletions domain.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// Copyright (c) 2020 Doc.ai and/or its affiliates.
//
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package fanout

import (
"strings"
)

// Domain -
type Domain interface {
Get(string) Domain
AddMany(string)
Add(string, Domain)
Contains(string) bool
IsFinal() bool
Finish()
}

type domain struct {
children map[string]Domain
end bool
}

// Finish -
func (l *domain) Finish() {
l.end = true
}

// Add -
func (l *domain) Add(n string, d Domain) {
l.children[n] = d
}

// IsFinal -
func (l *domain) IsFinal() bool {
return l.end
}

// Contains -
func (l *domain) Contains(s string) bool {
end := len(s) - 1
var curr Domain = l
for start := strings.LastIndex(s, "."); start != -1; start = strings.LastIndex(s[:start], ".") {
var k string
if start == end {
k = "."
} else {
k = s[start+1 : end]
}
end = start
curr = curr.Get(k)
if curr == nil {
return false
}
if curr.IsFinal() {
return true
}
}
curr = curr.Get(s[:end])
if curr == nil {
return false
}
return curr.IsFinal()
}

// AddMany -
func (l *domain) AddMany(s string) {
end := len(s) - 1
var curr = Domain(l)
for start := strings.LastIndex(s, "."); start != -1; start = strings.LastIndex(s[:start], ".") {
var k string
if start == end {
k = "."
} else {
k = s[start+1 : end]
}
end = start
if v := curr.Get(k); v != nil {
if v.IsFinal() {
return
} else {
curr = v
}
} else {
next := &domain{children: map[string]Domain{}}
curr.Add(k, next)
curr = next
}
}
if end != len(s)-1 {
next := &domain{children: map[string]Domain{}, end: true}
curr.Add(s[:end], next)
} else {
curr.Finish()
}
}

// Get -
func (l *domain) Get(s string) Domain {
return l.children[s]
}

// NewDomain -
func NewDomain() Domain {
return &domain{children: map[string]Domain{}}
}
53 changes: 53 additions & 0 deletions domain_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright (c) 2020 Doc.ai and/or its affiliates.
//
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package fanout

import (
"github.com/stretchr/testify/require"
"testing"
)

func TestDomainBasic(t *testing.T) {
samples := []struct {
child string
parent string
expected bool
}{
{".", ".", true},
{"example.org.", ".", true},
{"example.org.", "example.org.", true},
{"example.org.", "org.", true},
{"org.", "example.org.", false},
}

for i, s := range samples {
l := NewDomain()
l.AddMany(s.parent)
require.Equal(t, s.expected, l.Contains(s.child), i)
}
}

func TestDomainFewEntries(t *testing.T) {
d := NewDomain()
d.AddMany("google.com.")
d.AddMany("example.com.")
require.True(t, d.Contains("google.com."))
require.True(t, d.Contains("example.com."))
require.False(t, d.Contains("com."))
}

// TODO: add benchmark tests
34 changes: 11 additions & 23 deletions fanout.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,16 @@ var log = clog.NewWithPlugin("fanout")

// Fanout represents a plugin instance that can do async requests to list of DNS servers.
type Fanout struct {
clients []Client
tlsConfig *tls.Config
ignored []string
tlsServerName string
timeout time.Duration
net string
from string
attempts int
workerCount int
Next plugin.Handler
clients []Client
tlsConfig *tls.Config
excludeDomains Domain
tlsServerName string
timeout time.Duration
net string
from string
attempts int
workerCount int
Next plugin.Handler
}

// New returns reference to new Fanout plugin instance with default configs.
Expand Down Expand Up @@ -135,24 +135,12 @@ func (f *Fanout) getFanoutResult(ctx context.Context, responseCh <-chan *respons
}

func (f *Fanout) match(state *request.Request) bool {
if !plugin.Name(f.from).Matches(state.Name()) || !f.isAllowedDomain(state.Name()) {
if !plugin.Name(f.from).Matches(state.Name()) || f.excludeDomains.Contains(state.Name()) {
return false
}
return true
}

func (f *Fanout) isAllowedDomain(name string) bool {
if dns.Name(name) == dns.Name(f.from) {
return true
}
for _, ignore := range f.ignored {
if plugin.Name(ignore).Matches(name) {
return false
}
}
return true
}

func (f *Fanout) processClient(ctx context.Context, c Client, r *request.Request) *response {
start := time.Now()
for j := 0; j < f.attempts || f.attempts == 0; <-time.After(attemptDelay) {
Expand Down
4 changes: 2 additions & 2 deletions setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,9 +182,9 @@ func parseIgnored(f *Fanout, c *caddyfile.Dispenser) error {
return c.ArgErr()
}
for i := 0; i < len(ignore); i++ {
ignore[i] = plugin.Host(ignore[i]).Normalize()
f.excludeDomains.AddMany(plugin.Host(ignore[i]).Normalize())

}
f.ignored = ignore
return nil
}

Expand Down
6 changes: 4 additions & 2 deletions setup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,10 @@ func TestSetup(t *testing.T) {
t.Fatalf("Test %d: expected: %s, got: %s", i, test.expectedFrom, f.from)
}
if test.expectedIgnored != nil {
if !reflect.DeepEqual(f.ignored, test.expectedIgnored) {
t.Fatalf("Test %d: expected: %q, actual: %q", i, test.expectedIgnored, f.ignored)
for _, expected := range test.expectedIgnored {
if !f.excludeDomains.Contains(expected) {
t.Fatalf("Test %d: missed exclude domain name: %v", i, test.expectedIgnored)
}
}
}
if test.expectedTo != nil {
Expand Down

0 comments on commit 424dc48

Please sign in to comment.