mirror of
https://github.com/bettercap/bettercap
synced 2025-07-31 04:00:09 -07:00
new: supporting wildcard expressions in dns.spoof module (closes #215)
This commit is contained in:
parent
e80e73879f
commit
b5596d54d2
66 changed files with 6281 additions and 10 deletions
273
vendor/github.com/gobwas/glob/syntax/lexer/lexer.go
generated
vendored
Normal file
273
vendor/github.com/gobwas/glob/syntax/lexer/lexer.go
generated
vendored
Normal file
|
@ -0,0 +1,273 @@
|
|||
package lexer
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/gobwas/glob/util/runes"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
const (
|
||||
char_any = '*'
|
||||
char_comma = ','
|
||||
char_single = '?'
|
||||
char_escape = '\\'
|
||||
char_range_open = '['
|
||||
char_range_close = ']'
|
||||
char_terms_open = '{'
|
||||
char_terms_close = '}'
|
||||
char_range_not = '!'
|
||||
char_range_between = '-'
|
||||
)
|
||||
|
||||
var specials = []byte{
|
||||
char_any,
|
||||
char_single,
|
||||
char_escape,
|
||||
char_range_open,
|
||||
char_range_close,
|
||||
char_terms_open,
|
||||
char_terms_close,
|
||||
}
|
||||
|
||||
func Special(c byte) bool {
|
||||
return bytes.IndexByte(specials, c) != -1
|
||||
}
|
||||
|
||||
type tokens []Token
|
||||
|
||||
func (i *tokens) shift() (ret Token) {
|
||||
ret = (*i)[0]
|
||||
copy(*i, (*i)[1:])
|
||||
*i = (*i)[:len(*i)-1]
|
||||
return
|
||||
}
|
||||
|
||||
func (i *tokens) push(v Token) {
|
||||
*i = append(*i, v)
|
||||
}
|
||||
|
||||
func (i *tokens) empty() bool {
|
||||
return len(*i) == 0
|
||||
}
|
||||
|
||||
var eof rune = 0
|
||||
|
||||
type lexer struct {
|
||||
data string
|
||||
pos int
|
||||
err error
|
||||
|
||||
tokens tokens
|
||||
termsLevel int
|
||||
|
||||
lastRune rune
|
||||
lastRuneSize int
|
||||
hasRune bool
|
||||
}
|
||||
|
||||
func NewLexer(source string) *lexer {
|
||||
l := &lexer{
|
||||
data: source,
|
||||
tokens: tokens(make([]Token, 0, 4)),
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
func (l *lexer) Next() Token {
|
||||
if l.err != nil {
|
||||
return Token{Error, l.err.Error()}
|
||||
}
|
||||
if !l.tokens.empty() {
|
||||
return l.tokens.shift()
|
||||
}
|
||||
|
||||
l.fetchItem()
|
||||
return l.Next()
|
||||
}
|
||||
|
||||
func (l *lexer) peek() (r rune, w int) {
|
||||
if l.pos == len(l.data) {
|
||||
return eof, 0
|
||||
}
|
||||
|
||||
r, w = utf8.DecodeRuneInString(l.data[l.pos:])
|
||||
if r == utf8.RuneError {
|
||||
l.errorf("could not read rune")
|
||||
r = eof
|
||||
w = 0
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (l *lexer) read() rune {
|
||||
if l.hasRune {
|
||||
l.hasRune = false
|
||||
l.seek(l.lastRuneSize)
|
||||
return l.lastRune
|
||||
}
|
||||
|
||||
r, s := l.peek()
|
||||
l.seek(s)
|
||||
|
||||
l.lastRune = r
|
||||
l.lastRuneSize = s
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func (l *lexer) seek(w int) {
|
||||
l.pos += w
|
||||
}
|
||||
|
||||
func (l *lexer) unread() {
|
||||
if l.hasRune {
|
||||
l.errorf("could not unread rune")
|
||||
return
|
||||
}
|
||||
l.seek(-l.lastRuneSize)
|
||||
l.hasRune = true
|
||||
}
|
||||
|
||||
func (l *lexer) errorf(f string, v ...interface{}) {
|
||||
l.err = fmt.Errorf(f, v...)
|
||||
}
|
||||
|
||||
func (l *lexer) inTerms() bool {
|
||||
return l.termsLevel > 0
|
||||
}
|
||||
|
||||
func (l *lexer) termsEnter() {
|
||||
l.termsLevel++
|
||||
}
|
||||
|
||||
func (l *lexer) termsLeave() {
|
||||
l.termsLevel--
|
||||
}
|
||||
|
||||
var inTextBreakers = []rune{char_single, char_any, char_range_open, char_terms_open}
|
||||
var inTermsBreakers = append(inTextBreakers, char_terms_close, char_comma)
|
||||
|
||||
func (l *lexer) fetchItem() {
|
||||
r := l.read()
|
||||
switch {
|
||||
case r == eof:
|
||||
l.tokens.push(Token{EOF, ""})
|
||||
|
||||
case r == char_terms_open:
|
||||
l.termsEnter()
|
||||
l.tokens.push(Token{TermsOpen, string(r)})
|
||||
|
||||
case r == char_comma && l.inTerms():
|
||||
l.tokens.push(Token{Separator, string(r)})
|
||||
|
||||
case r == char_terms_close && l.inTerms():
|
||||
l.tokens.push(Token{TermsClose, string(r)})
|
||||
l.termsLeave()
|
||||
|
||||
case r == char_range_open:
|
||||
l.tokens.push(Token{RangeOpen, string(r)})
|
||||
l.fetchRange()
|
||||
|
||||
case r == char_single:
|
||||
l.tokens.push(Token{Single, string(r)})
|
||||
|
||||
case r == char_any:
|
||||
if l.read() == char_any {
|
||||
l.tokens.push(Token{Super, string(r) + string(r)})
|
||||
} else {
|
||||
l.unread()
|
||||
l.tokens.push(Token{Any, string(r)})
|
||||
}
|
||||
|
||||
default:
|
||||
l.unread()
|
||||
|
||||
var breakers []rune
|
||||
if l.inTerms() {
|
||||
breakers = inTermsBreakers
|
||||
} else {
|
||||
breakers = inTextBreakers
|
||||
}
|
||||
l.fetchText(breakers)
|
||||
}
|
||||
}
|
||||
|
||||
func (l *lexer) fetchRange() {
|
||||
var wantHi bool
|
||||
var wantClose bool
|
||||
var seenNot bool
|
||||
for {
|
||||
r := l.read()
|
||||
if r == eof {
|
||||
l.errorf("unexpected end of input")
|
||||
return
|
||||
}
|
||||
|
||||
if wantClose {
|
||||
if r != char_range_close {
|
||||
l.errorf("expected close range character")
|
||||
} else {
|
||||
l.tokens.push(Token{RangeClose, string(r)})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if wantHi {
|
||||
l.tokens.push(Token{RangeHi, string(r)})
|
||||
wantClose = true
|
||||
continue
|
||||
}
|
||||
|
||||
if !seenNot && r == char_range_not {
|
||||
l.tokens.push(Token{Not, string(r)})
|
||||
seenNot = true
|
||||
continue
|
||||
}
|
||||
|
||||
if n, w := l.peek(); n == char_range_between {
|
||||
l.seek(w)
|
||||
l.tokens.push(Token{RangeLo, string(r)})
|
||||
l.tokens.push(Token{RangeBetween, string(n)})
|
||||
wantHi = true
|
||||
continue
|
||||
}
|
||||
|
||||
l.unread() // unread first peek and fetch as text
|
||||
l.fetchText([]rune{char_range_close})
|
||||
wantClose = true
|
||||
}
|
||||
}
|
||||
|
||||
func (l *lexer) fetchText(breakers []rune) {
|
||||
var data []rune
|
||||
var escaped bool
|
||||
|
||||
reading:
|
||||
for {
|
||||
r := l.read()
|
||||
if r == eof {
|
||||
break
|
||||
}
|
||||
|
||||
if !escaped {
|
||||
if r == char_escape {
|
||||
escaped = true
|
||||
continue
|
||||
}
|
||||
|
||||
if runes.IndexRune(breakers, r) != -1 {
|
||||
l.unread()
|
||||
break reading
|
||||
}
|
||||
}
|
||||
|
||||
escaped = false
|
||||
data = append(data, r)
|
||||
}
|
||||
|
||||
if len(data) > 0 {
|
||||
l.tokens.push(Token{Text, string(data)})
|
||||
}
|
||||
}
|
192
vendor/github.com/gobwas/glob/syntax/lexer/lexer_test.go
generated
vendored
Normal file
192
vendor/github.com/gobwas/glob/syntax/lexer/lexer_test.go
generated
vendored
Normal file
|
@ -0,0 +1,192 @@
|
|||
package lexer
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestLexGood(t *testing.T) {
|
||||
for id, test := range []struct {
|
||||
pattern string
|
||||
items []Token
|
||||
}{
|
||||
{
|
||||
pattern: "",
|
||||
items: []Token{
|
||||
{EOF, ""},
|
||||
},
|
||||
},
|
||||
{
|
||||
pattern: "hello",
|
||||
items: []Token{
|
||||
{Text, "hello"},
|
||||
{EOF, ""},
|
||||
},
|
||||
},
|
||||
{
|
||||
pattern: "/{rate,[0-9]]}*",
|
||||
items: []Token{
|
||||
{Text, "/"},
|
||||
{TermsOpen, "{"},
|
||||
{Text, "rate"},
|
||||
{Separator, ","},
|
||||
{RangeOpen, "["},
|
||||
{RangeLo, "0"},
|
||||
{RangeBetween, "-"},
|
||||
{RangeHi, "9"},
|
||||
{RangeClose, "]"},
|
||||
{Text, "]"},
|
||||
{TermsClose, "}"},
|
||||
{Any, "*"},
|
||||
{EOF, ""},
|
||||
},
|
||||
},
|
||||
{
|
||||
pattern: "hello,world",
|
||||
items: []Token{
|
||||
{Text, "hello,world"},
|
||||
{EOF, ""},
|
||||
},
|
||||
},
|
||||
{
|
||||
pattern: "hello\\,world",
|
||||
items: []Token{
|
||||
{Text, "hello,world"},
|
||||
{EOF, ""},
|
||||
},
|
||||
},
|
||||
{
|
||||
pattern: "hello\\{world",
|
||||
items: []Token{
|
||||
{Text, "hello{world"},
|
||||
{EOF, ""},
|
||||
},
|
||||
},
|
||||
{
|
||||
pattern: "hello?",
|
||||
items: []Token{
|
||||
{Text, "hello"},
|
||||
{Single, "?"},
|
||||
{EOF, ""},
|
||||
},
|
||||
},
|
||||
{
|
||||
pattern: "hellof*",
|
||||
items: []Token{
|
||||
{Text, "hellof"},
|
||||
{Any, "*"},
|
||||
{EOF, ""},
|
||||
},
|
||||
},
|
||||
{
|
||||
pattern: "hello**",
|
||||
items: []Token{
|
||||
{Text, "hello"},
|
||||
{Super, "**"},
|
||||
{EOF, ""},
|
||||
},
|
||||
},
|
||||
{
|
||||
pattern: "[日-語]",
|
||||
items: []Token{
|
||||
{RangeOpen, "["},
|
||||
{RangeLo, "日"},
|
||||
{RangeBetween, "-"},
|
||||
{RangeHi, "語"},
|
||||
{RangeClose, "]"},
|
||||
{EOF, ""},
|
||||
},
|
||||
},
|
||||
{
|
||||
pattern: "[!日-語]",
|
||||
items: []Token{
|
||||
{RangeOpen, "["},
|
||||
{Not, "!"},
|
||||
{RangeLo, "日"},
|
||||
{RangeBetween, "-"},
|
||||
{RangeHi, "語"},
|
||||
{RangeClose, "]"},
|
||||
{EOF, ""},
|
||||
},
|
||||
},
|
||||
{
|
||||
pattern: "[日本語]",
|
||||
items: []Token{
|
||||
{RangeOpen, "["},
|
||||
{Text, "日本語"},
|
||||
{RangeClose, "]"},
|
||||
{EOF, ""},
|
||||
},
|
||||
},
|
||||
{
|
||||
pattern: "[!日本語]",
|
||||
items: []Token{
|
||||
{RangeOpen, "["},
|
||||
{Not, "!"},
|
||||
{Text, "日本語"},
|
||||
{RangeClose, "]"},
|
||||
{EOF, ""},
|
||||
},
|
||||
},
|
||||
{
|
||||
pattern: "{a,b}",
|
||||
items: []Token{
|
||||
{TermsOpen, "{"},
|
||||
{Text, "a"},
|
||||
{Separator, ","},
|
||||
{Text, "b"},
|
||||
{TermsClose, "}"},
|
||||
{EOF, ""},
|
||||
},
|
||||
},
|
||||
{
|
||||
pattern: "/{z,ab}*",
|
||||
items: []Token{
|
||||
{Text, "/"},
|
||||
{TermsOpen, "{"},
|
||||
{Text, "z"},
|
||||
{Separator, ","},
|
||||
{Text, "ab"},
|
||||
{TermsClose, "}"},
|
||||
{Any, "*"},
|
||||
{EOF, ""},
|
||||
},
|
||||
},
|
||||
{
|
||||
pattern: "{[!日-語],*,?,{a,b,\\c}}",
|
||||
items: []Token{
|
||||
{TermsOpen, "{"},
|
||||
{RangeOpen, "["},
|
||||
{Not, "!"},
|
||||
{RangeLo, "日"},
|
||||
{RangeBetween, "-"},
|
||||
{RangeHi, "語"},
|
||||
{RangeClose, "]"},
|
||||
{Separator, ","},
|
||||
{Any, "*"},
|
||||
{Separator, ","},
|
||||
{Single, "?"},
|
||||
{Separator, ","},
|
||||
{TermsOpen, "{"},
|
||||
{Text, "a"},
|
||||
{Separator, ","},
|
||||
{Text, "b"},
|
||||
{Separator, ","},
|
||||
{Text, "c"},
|
||||
{TermsClose, "}"},
|
||||
{TermsClose, "}"},
|
||||
{EOF, ""},
|
||||
},
|
||||
},
|
||||
} {
|
||||
lexer := NewLexer(test.pattern)
|
||||
for i, exp := range test.items {
|
||||
act := lexer.Next()
|
||||
if act.Type != exp.Type {
|
||||
t.Errorf("#%d %q: wrong %d-th item type: exp: %q; act: %q\n\t(%s vs %s)", id, test.pattern, i, exp.Type, act.Type, exp, act)
|
||||
}
|
||||
if act.Raw != exp.Raw {
|
||||
t.Errorf("#%d %q: wrong %d-th item contents: exp: %q; act: %q\n\t(%s vs %s)", id, test.pattern, i, exp.Raw, act.Raw, exp, act)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
88
vendor/github.com/gobwas/glob/syntax/lexer/token.go
generated
vendored
Normal file
88
vendor/github.com/gobwas/glob/syntax/lexer/token.go
generated
vendored
Normal file
|
@ -0,0 +1,88 @@
|
|||
package lexer
|
||||
|
||||
import "fmt"
|
||||
|
||||
type TokenType int
|
||||
|
||||
const (
|
||||
EOF TokenType = iota
|
||||
Error
|
||||
Text
|
||||
Char
|
||||
Any
|
||||
Super
|
||||
Single
|
||||
Not
|
||||
Separator
|
||||
RangeOpen
|
||||
RangeClose
|
||||
RangeLo
|
||||
RangeHi
|
||||
RangeBetween
|
||||
TermsOpen
|
||||
TermsClose
|
||||
)
|
||||
|
||||
func (tt TokenType) String() string {
|
||||
switch tt {
|
||||
case EOF:
|
||||
return "eof"
|
||||
|
||||
case Error:
|
||||
return "error"
|
||||
|
||||
case Text:
|
||||
return "text"
|
||||
|
||||
case Char:
|
||||
return "char"
|
||||
|
||||
case Any:
|
||||
return "any"
|
||||
|
||||
case Super:
|
||||
return "super"
|
||||
|
||||
case Single:
|
||||
return "single"
|
||||
|
||||
case Not:
|
||||
return "not"
|
||||
|
||||
case Separator:
|
||||
return "separator"
|
||||
|
||||
case RangeOpen:
|
||||
return "range_open"
|
||||
|
||||
case RangeClose:
|
||||
return "range_close"
|
||||
|
||||
case RangeLo:
|
||||
return "range_lo"
|
||||
|
||||
case RangeHi:
|
||||
return "range_hi"
|
||||
|
||||
case RangeBetween:
|
||||
return "range_between"
|
||||
|
||||
case TermsOpen:
|
||||
return "terms_open"
|
||||
|
||||
case TermsClose:
|
||||
return "terms_close"
|
||||
|
||||
default:
|
||||
return "undef"
|
||||
}
|
||||
}
|
||||
|
||||
type Token struct {
|
||||
Type TokenType
|
||||
Raw string
|
||||
}
|
||||
|
||||
func (t Token) String() string {
|
||||
return fmt.Sprintf("%v<%q>", t.Type, t.Raw)
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue