diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..ce47c6c --- /dev/null +++ b/Makefile @@ -0,0 +1,22 @@ +.DEFAULT_GOAL := protomolecule +.PHONY = fmt vet all clean deps benchmark + +all: main + +protomolecule: + go build -ldflags="-s -w -X main.GitVersion=git-$(shell git rev-list --count HEAD)-$(shell git rev-parse --short HEAD) -X main.BuildDate=$(shell date -u +%Y-%m-%dT%H:%M:%S%Z)" +install: + cp protomolecule /usr/local/bin/ +uninstall: + rm /usr/local/bin/protomolecule +benchmark: + go test -bench=. +deps: + go mod tidy -v +fmt: + find . -name "*.go" -exec gofmt -s -w {} \; +vet: + go vet ./ +clean: + rm protomolecule + diff --git a/README.md b/README.md index 9a8ab18..99bc245 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,8 @@ Cross platform BLE scanner and logger with teeth - ### GATT fuzzing +- ### Advertisment fuzzing / flooding + - ### Sweyntooth - ### Search for DFU diff --git a/cmd.go b/cmd.go new file mode 100644 index 0000000..fdcb382 --- /dev/null +++ b/cmd.go @@ -0,0 +1,324 @@ +package main + +import ( + "fmt" + "os" + "strconv" + "strings" + + cli "git.tcp.direct/Mirrors/go-prompt" + . "github.com/logrusorgru/aurora" + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" + + "protomolecule/src/eros" + + // "protomolecule/src/wrath" + projVars "protomolecule/src/config" + "protomolecule/src/deimos" +) + +var suggestions = []cli.Suggest{ + // Main Commands + // {"scan", + // "Start and stop scans"}, + + {"scan start", + "Start default scan"}, + + {"scan start attack", + "Start scan that also attempts to connect to all discovered BLE devices"}, + + {"scan start tracking", + "Start continuous RSSI tracking of all BLE devices within range"}, + + {"eros recall mac", + "Retrieve device info from database by MAC address"}, + + {"eros recall all", + "Retrieve info on all devices"}, + + {"eros backup", + "Backup all databases to the supplied directory"}, + + {"arboghast start", + "Start entropic fuzzing via advertising"}, + /* + {"wrath", + "attack by address"}, + */ + {"exit", + "Exit ProtoMolecule"}, + + {"debug", + "Toggle debug messages"}, + + {"help", + "in-app documentation"}, +} + +func completer(in cli.Document) []cli.Suggest { + c := in.CurrentLineBeforeCursor() + if c == "" { + return []cli.Suggest{} + } + + return cli.FilterHasPrefix(suggestions, c, true) +} + +// Interpret is where we will actuall define our commands +func executor(cmd string) { + cmd = strings.TrimSpace(cmd) + + var args []string + args = strings.Split(cmd, " ") + + getArgs := func(args []string) string { + var ret string + for i, a := range args { + if i == 0 { + ret = a + continue + } + ret = ret + " " + a + if i != len(args)-1 { + ret = ret + " " + } + } + return ret + } + + switch args[0] { + + case "exit": + fallthrough + + case "quit": + eros.Slumber() + os.Exit(0) + + case "debug": + switch log.Logger.GetLevel() { + case zerolog.DebugLevel: + zerolog.SetGlobalLevel(zerolog.InfoLevel) + log.Info(). + Msg("Debug mode turned " + Sprintf(BrightRed("OFF\n").Bold())) + case zerolog.InfoLevel: + zerolog.SetGlobalLevel(zerolog.DebugLevel) + log.Debug(). + Msg("Debug mode turned " + Sprintf(BrightGreen("ON\n").Bold())) + default: + return + } + + case "eros": + if len(args) < 2 { + getHelp("eros") + return + } + + switch args[1] { + case "recall": + if len(args) < 3 { + getHelp("eros recall") + return + } + switch args[2] { + case "mac": + if len(args) < 4 { + getHelp("eros recall") + return + } + fromEros, err := eros.Recall(args[3]) + if err != nil { + log.Error().Err(err).Str("target", args[3]). + Msg("Failed to recall MAC") + println() + return + } + + log.Info(). + Str("Name", fromEros.Name). + Str("Addr", fromEros.Addr). + Str("ManuF", fromEros.Manufacturer). // needs to be changed back to fromEros.Manufacturer + Int16("Current_RSSI", fromEros.RSSIlast). + Int("Service_Count", len(fromEros.Services)). + Msg("EROS_RECALL") + + case "backup": + if len(args) < 3 { + getHelp("eros backup") + return + } + if err := eros.Backup(args[3]); err != nil { + log.Error().Err(err).Msg("Failed to backup databases!") + } + } + + } + + case "help": + if len(args) < 2 { + getHelp("meta") + return + } + + getHelp(getArgs(args)) + + case "loadnames": + if len(args) < 2 { + log.Error().Msg("missing argument: path to json file with manufacturer UUIDs") + println() + } + + projVars.GlobalConfig.ManuFile = args[1] + eros.ManufLoad() + + case "adapter": + if len(args) > 1 { + switch args[1] { + case "list": + deimos.PrintBlueDevices() + case "sniff": + var ( + err error + devint int + ) + if len(args) < 2 { + log.Error().Msg("not enough parameters, missing adapter ID") + println() + return + } + if devint, err = strconv.Atoi(args[2]); err != nil { + log.Error().Msg("invalid parameter, must be integer of adapter ID") + println() + return + } + deimos.Sniff(devint) + default: + log.Error().Msg("unknown sub-command: " + args[1]) + println() + } + } else { + getHelp(getArgs(args)) + } + case "scan": + if len(args) > 1 { + switch args[1] { + + case "list": + fallthrough + + case "status": + fmt.Println(getArgs(args) + ": start new default BLE scan") + + case "start": + if len(args) > 2 { + switch args[2] { + case "tracking": + *projVars.GlobalConfig.CooleanFlags.Tracking = true + *projVars.GlobalConfig.CooleanFlags.Attack = false + case "attack": + *projVars.GlobalConfig.CooleanFlags.Tracking = false + *projVars.GlobalConfig.CooleanFlags.Attack = true + default: + // getHelp(getArgs(args)) + log.Error().Msg("unknown sub command: " + args[2]) + println() + } + } + + bleScan() + } + + } else { + getHelp(getArgs(args)) + } + + case "rpc": + if len(args) > 1 { + switch args[1] { + + case "status": + fmt.Println(getArgs(args) + ": ") + + case "server": + fmt.Println(getArgs(args) + ": ") + + case "client": + fmt.Println(getArgs(args) + ": ") + } + } else { + getHelp(getArgs(args)) + } + + /* + case "wrath": + if len(args) < 2 { + getHelp("wrath") + return + } + wrath(args[1]) + */ + + case "clear": + print("\033[H\033[2J") + // termenv.ClearScreen() + + default: + log.Error().Msg("unknown command: " + cmd) + println() + } + +} + +func getHelp(target string) { + fmt.Println("pRaNkeD! (help not available just yet.)") + fmt.Println() + return + /* + var lines []string + + lines = append(lines, "help: "+target) + + switch target { + + case "meta": + var list string + for _, cmd := range cmds { + list = list + cmd + ", " + } + + fmt.Println("Enabled commands: ") + list = strings.TrimSuffix(list, ", ") + fmt.Println(list) + fmt.Println() + + default: + log.Error().Msg("Help entry not found!") + fmt.Println() + } + */ +} + +func StartCLI() { + var hist []string + + p := cli.New( + executor, + completer, + cli.OptionPrefix("ProtoMolecule"+"> "), + // cli.OptionPrefixBackgroundColor(cli.Black), + cli.OptionPrefixTextColor(cli.Cyan), + cli.OptionHistory(hist), + cli.OptionSuggestionBGColor(cli.Black), + cli.OptionSuggestionTextColor(cli.White), + cli.OptionSelectedSuggestionBGColor(cli.Black), + cli.OptionSelectedSuggestionTextColor(cli.Cyan), + // prompt.OptionLivePrefix + cli.OptionTitle("ProtoMolecule"), + ) + + p.Run() + +} diff --git a/go.mod b/go.mod index bdb3f92..9f30215 100644 --- a/go.mod +++ b/go.mod @@ -1,16 +1,37 @@ module protomolecule -go 1.16 +go 1.19 require ( - git.tcp.direct/kayos/prototooth v0.3.1-0.20210513000132-e440008138af - github.com/go-ole/go-ole v1.2.5 // indirect - github.com/godbus/dbus/v5 v5.0.4 // indirect - github.com/muka/go-bluetooth v0.0.0-20201211051136-07f31c601d33 // indirect + git.tcp.direct/Mirrors/go-prompt v0.3.0 + git.tcp.direct/kayos/prototooth v0.5.1 + github.com/google/gopacket v1.1.19 + github.com/json-iterator/go v1.1.12 + github.com/logrusorgru/aurora v2.0.3+incompatible github.com/prologic/bitcask v0.3.10 - github.com/rs/zerolog v1.21.0 - github.com/sirupsen/logrus v1.8.1 // indirect - github.com/stretchr/testify v1.7.0 // indirect - golang.org/x/sys v0.0.0-20210414055047-fe65e336abe0 // indirect - gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect + github.com/rs/zerolog v1.27.0 + tinygo.org/x/bluetooth v0.5.0 +) + +require ( + github.com/JuulLabs-OSS/cbgo v0.0.2 // indirect + github.com/fatih/structs v1.1.0 // indirect + github.com/go-ole/go-ole v1.2.6 // indirect + github.com/godbus/dbus/v5 v5.1.0 // indirect + github.com/mattn/go-colorable v0.1.12 // indirect + github.com/mattn/go-isatty v0.0.14 // indirect + github.com/mattn/go-runewidth v0.0.13 // indirect + github.com/mattn/go-tty v0.0.4 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/muka/go-bluetooth v0.0.0-20220819143208-8b1989180f4c // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pkg/term v1.1.0 // indirect + github.com/plar/go-adaptive-radix-tree v1.0.4 // indirect + github.com/rivo/uniseg v0.2.0 // indirect + github.com/sirupsen/logrus v1.9.0 // indirect + golang.org/x/crypto v0.7.0 // indirect + golang.org/x/exp v0.0.0-20200228211341-fcea875c7e85 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/term v0.6.0 // indirect ) diff --git a/go.sum b/go.sum index 2cf6ff1..e5e64e5 100644 --- a/go.sum +++ b/go.sum @@ -11,8 +11,10 @@ cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqCl cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -git.tcp.direct/kayos/prototooth v0.3.1-0.20210513000132-e440008138af h1:+J2MfTQvW1DmX1HYIQUsrCd5l0Il9JMYTOowIs8ju1Y= -git.tcp.direct/kayos/prototooth v0.3.1-0.20210513000132-e440008138af/go.mod h1:kk4oyPgWq6Rijn30Js4ITQC5DFwmpyzWL3+8V6q9wdM= +git.tcp.direct/Mirrors/go-prompt v0.3.0 h1:4IXTCPeuMfoemcJ+riSuKQhAx1rJo5hTtuSkr/IFq+A= +git.tcp.direct/Mirrors/go-prompt v0.3.0/go.mod h1:x8Gs5SGQbFzTglOjiK16geOcdw1dVZas3HYkfx0o6ls= +git.tcp.direct/kayos/prototooth v0.5.1 h1:j/WOekGSZLGCt1gqLFAedWEooprTyxYEIyQKei4kcew= +git.tcp.direct/kayos/prototooth v0.5.1/go.mod h1:sRAZ69v83VhnR037/DylbPPBwKb5UCoqEurDFNum0fM= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/JuulLabs-OSS/cbgo v0.0.2 h1:gCDyT0+EPuI8GOFyvAksFcVD2vF4CXBAVwT6uVnD9oo= @@ -27,6 +29,7 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bgould/http v0.0.0-20190627042742-d268792bdee7/go.mod h1:BTqvVegvwifopl4KTEDth6Zezs9eR+lCWhvGKvkxJHE= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= @@ -36,6 +39,7 @@ github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -56,12 +60,13 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2 github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= -github.com/go-ole/go-ole v1.2.5 h1:t4MGB5xEDZvXI+0rMjjsfBsD7yAgp/s9ZDkL1JndXwY= -github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= +github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -77,6 +82,9 @@ github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +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/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -113,23 +121,38 @@ github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/J github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 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/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= +github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= +github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-tty v0.0.4 h1:NVikla9X8MN0SQAqCYzpGyXv0jY7MNl3HOWD2dkle7E= +github.com/mattn/go-tty v0.0.4/go.mod h1:u5GGXBtZU6RQoKV8gY5W6UhMudbR5vXnUe7j3pxse28= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= @@ -140,11 +163,15 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4 github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/muka/go-bluetooth v0.0.0-20200619025933-f6113f7141c5/go.mod h1:yV39+EVOWdnoTe75NyKdo9iuyI3Slyh4t7eQvElUbWE= -github.com/muka/go-bluetooth v0.0.0-20201211051136-07f31c601d33 h1:p3srutpE8TpQmOUQ5Qw94jYFUdoG2jBbILeYLroQNoI= -github.com/muka/go-bluetooth v0.0.0-20201211051136-07f31c601d33/go.mod h1:dMCjicU6vRBk34dqOmIZm0aod6gUwZXOXzBROqGous0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/muka/go-bluetooth v0.0.0-20210812063148-b6c83362e27d/go.mod h1:dMCjicU6vRBk34dqOmIZm0aod6gUwZXOXzBROqGous0= +github.com/muka/go-bluetooth v0.0.0-20220819143208-8b1989180f4c h1:CTU9zYG49RMMVTZwRcC78uBJ5gGmvLSgQXCDn1n4jJY= +github.com/muka/go-bluetooth v0.0.0-20220819143208-8b1989180f4c/go.mod h1:dMCjicU6vRBk34dqOmIZm0aod6gUwZXOXzBROqGous0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= @@ -156,6 +183,8 @@ github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE 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/pkg/term v1.1.0 h1:xIAAdCMh3QIAy+5FrE8Ad8XoDhEU4ufwbaSozViP9kk= +github.com/pkg/term v1.1.0/go.mod h1:E25nymQcrSllhX42Ok8MRm1+hyBdHY0dCeiKZ9jpNGw= github.com/plar/go-adaptive-radix-tree v1.0.4 h1:Ucd8R6RH2E7RW8ZtDKrsWyOD3paG2qqJO0I20WQ8oWQ= github.com/plar/go-adaptive-radix-tree v1.0.4/go.mod h1:Ot8d28EII3i7Lv4PSvBlF8ejiD/CtRYDuPsySJbSaK8= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -172,11 +201,13 @@ github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= -github.com/rs/zerolog v1.21.0 h1:Q3vdXlfLNT+OftyBHsU0Y445MD+8m8axjKgf2si0QcM= -github.com/rs/zerolog v1.21.0/go.mod h1:ZPhntP/xmq1nnND05hhpAh2QMhSsA4UN3MGZ6O2J3hM= +github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.27.0 h1:1T7qCieN22GVc8S4Q2yuexzBb1EqjbgjSH9RohbMjKs= +github.com/rs/zerolog v1.27.0/go.mod h1:7frBqO0oezxmnO7GF86FY++uy8I0Tk/If5ni1G9Qc0U= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= @@ -185,8 +216,8 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= -github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= @@ -208,7 +239,6 @@ github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -219,6 +249,7 @@ github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0 github.com/tidwall/redcon v1.4.0/go.mod h1:IGzxyoKE3Ea5AWIXo/ZHP+hzY8sWXaMKr7KlFgcWSZU= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/valyala/fastjson v1.6.3/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -235,6 +266,8 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 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.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -251,6 +284,7 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= @@ -274,7 +308,8 @@ golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -284,7 +319,6 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -292,6 +326,7 @@ golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/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-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -301,20 +336,27 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210414055047-fe65e336abe0 h1:g9s1Ppvvun/fI+BptTMj909BBIcGrzQ32k9FNlcevOE= -golang.org/x/sys v0.0.0-20210414055047-fe65e336abe0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -335,9 +377,9 @@ golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200925191224-5d1fdd8fa346/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= 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/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -376,14 +418,20 @@ gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bl gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +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-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +tinygo.org/x/bluetooth v0.5.0 h1:UftQTmx/snuTbeoS/R6+ZixmxSl5d6BvyfxlmD8eDng= +tinygo.org/x/bluetooth v0.5.0/go.mod h1:3rm7IKtmhP7aU2XRJI/Ods3J9Lqc3BAPPTNZmTtb42Q= +tinygo.org/x/drivers v0.14.0/go.mod h1:uT2svMq3EpBZpKkGO+NQHjxjGf1f42ra4OnMMwQL2aI= tinygo.org/x/drivers v0.15.1/go.mod h1:uT2svMq3EpBZpKkGO+NQHjxjGf1f42ra4OnMMwQL2aI= +tinygo.org/x/drivers v0.16.0/go.mod h1:uT2svMq3EpBZpKkGO+NQHjxjGf1f42ra4OnMMwQL2aI= +tinygo.org/x/drivers v0.20.0/go.mod h1:uJD/l1qWzxzLx+vcxaW0eY464N5RAgFi1zTVzASFdqI= +tinygo.org/x/tinyfont v0.2.1/go.mod h1:eLqnYSrFRjt5STxWaMeOWJTzrKhXqpWw7nU3bPfKOAM= +tinygo.org/x/tinyfs v0.1.0/go.mod h1:ysc8Y92iHfhTXeyEM9+c7zviUQ4fN9UCFgSOFfMWv20= +tinygo.org/x/tinyterm v0.1.0/go.mod h1:/DDhNnGwNF2/tNgHywvyZuCGnbH3ov49Z/6e8LPLRR4= diff --git a/main.go b/main.go index 515141b..7f59353 100644 --- a/main.go +++ b/main.go @@ -4,19 +4,22 @@ import ( "flag" "os" "os/signal" + "syscall" + "time" + + projVars "protomolecule/src/config" "protomolecule/src/dust" "protomolecule/src/eros" "protomolecule/src/protogen" - projVars "protomolecule/src/vars" - "syscall" - "time" "github.com/rs/zerolog" "github.com/rs/zerolog/log" ) var ( - manufLoad bool + manufLoad bool + GitVersion string + BuildDate string ) func loginit() { @@ -48,56 +51,57 @@ func loginit() { func cliFlags() { flag.Parse() - - if *projVars.AFlag { - projVars.AttackMode = true - } - - if *projVars.DFlag { + if *projVars.GlobalConfig.CooleanFlags.Debug { zerolog.SetGlobalLevel(zerolog.DebugLevel) } - - if *projVars.TFlag { - projVars.TrackingMode = true - } - - if *projVars.MFlag != "0" { - projVars.ManuFile = *projVars.MFlag - manufLoad = true - } + manufLoad = *projVars.GlobalConfig.StringFlags.MACVendorFile != "" } func sigHandler() { - c := make(chan os.Signal) + c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt, syscall.SIGTERM) - go func() { - <-c - log.Warn().Msg("Interrupt detected, shutting down gracefully...") - eros.Slumber() - os.Exit(0) - }() + for { + select { + case <-c: + log.Warn(). + Msg("Interrupt detected, stopping scan...") + for _, scan := range protogen.ScanMgr.Scans { + for _, dev := range scan.Device { + if dev.Connected { + _ = dev.Conn.Disconnect() + } + } + _ = scan.Stop() + } + } + } } func init() { // Initializing an instance of our scan manager to keep track of concurrent scans // NOTE: Devices are kept track of per Scan via a nested map of eros.Device instances // + // TODO: Get all of this management stuff into its own package (structs and maps and initialization of the former) // TODO: Name these structs and maps and instances more uniformly and idiomatically dust.PrintBanner() protogen.ScanMgr = &protogen.Meta{ - Count: 0, Scans: make(map[int]*protogen.Scan), Mailbox: make(chan protogen.Postcard), } loginit() cliFlags() - sigHandler() + go sigHandler() - log.Debug().Msg("Logging initialized") + if len(GitVersion) > 0 { + log.Info(). + Str("Version", GitVersion). + Str("Built", BuildDate). + Msg("Initializing protomolecule") + } // see ./src/eros log.Debug().Msg("Initializing database engine") @@ -126,10 +130,9 @@ func earToTheWire() { } } - for { select { - case postcard := <- protogen.ScanMgr.Mailbox: + case postcard := <-protogen.ScanMgr.Mailbox: sublog = log.With().Int("scan_id", postcard.From).Logger() interpret(postcard) } @@ -137,8 +140,7 @@ func earToTheWire() { } } -func main() { - defer eros.Slumber() +func bleScan() { var scan *protogen.Scan // Note: the tinygo bluetooth (prototooth here) library does already have a channel system for starting and stopping scans @@ -149,7 +151,11 @@ func main() { scan = protogen.ScanMgr.NewScan() - //time.Sleep(30 * time.Millisecond) + // time.Sleep(30 * time.Millisecond) go dust.Must("Scan", scan.Start()) - +} + +func main() { + defer eros.Slumber() + StartCLI() } diff --git a/profiling/bluetooth_and_dbus_calls.html b/profiling/bluetooth_and_dbus_calls.html new file mode 100644 index 0000000..6fd6f40 --- /dev/null +++ b/profiling/bluetooth_and_dbus_calls.html @@ -0,0 +1,3663 @@ + + + + + unknown calls + + + + + + +
+
+

pprof

+
+ + + + + + + + + + +
+ +
+ +
+ unknown calls +
+
Type: calls
Time: Jun 1, 2021 at 7:43pm (PDT)
Active filters:
focus=git\.tcp\.direct/kayos/prototooth\.\(\*Adapter\)\.Scan
ignore=protomolecule/src/eros\.Remember|github\.com/rs/zerolog/log\.Fatal|github…
Showing nodes accounting for 41542, 12.21% of 340337 total
Dropped 146 nodes (cum <= 1701)
Dropped 4 edges (freq <= 340)
Showing top 80 nodes out of 86
+See https://git.io/JfYMW for how to read the graph
+
+
+
+ +
+ +
+
Save options as
+ + + + +
+ +
+
Delete config
+
+ +
+ +
+ +
+ + +unnamed + + + +N1 + + +prototooth +(*Adapter) +Scan +1190 (0.35%) +of 50770 (14.92%) + + + + + +N3 + + +protogen +(*Scan) +resultHandler +3606 (1.06%) +of 12609 (3.70%) + + + + + +N1->N3 + + + + + + + 12609 + + + + + +N8 + + +adapter +(*Adapter1) +GetDevices +172 (0.051%) +of 16374 (4.81%) + + + + + +N1->N8 + + + + + + + 16374 + + + + + +N10 + + +dbus +SystemBus +204 (0.06%) +of 4110 (1.21%) + + + + + +N1->N10 + + + + + + + 3974 + + + + + +N28 + + +prototooth +makeScanResult +510 (0.15%) +of 1248 (0.37%) + + + + + +N1->N28 + + + + + + + 1248 + + + + + +N30 + + +adapter +(*Adapter1) +SetDiscoveryFilter +70 (0.021%) +of 2826 (0.83%) + + + + + +N1->N30 + + + + + + + 2826 + + + + + +N49 + + +dbus +(*defaultSignalHandler) +AddSignal +45 (0.013%) +of 928 (0.27%) + + + + + +N1->N49 + + + + + + + 928 + + + + + +N52 + + +adapter +(*Adapter1) +StartDiscovery +24 (0.0071%) +of 1402 (0.41%) + + + + + +N1->N52 + + + + + + + 1402 + + + + + +N53 + + +adapter +(*Adapter1) +StopDiscovery +23 (0.0068%) +of 1401 (0.41%) + + + + + +N1->N53 + + + + + + + 1401 + + + + + +N75 + + +dbus +(*Conn) +RemoveMatchSignal +70 (0.021%) +of 1290 (0.38%) + + + + + +N1->N75 + + + + + + + 1290 + + + + + +N77 + + +dbus +(*Conn) +AddMatchSignal +66 (0.019%) +of 1284 (0.38%) + + + + + +N1->N77 + + + + + + + 1284 + + + + + +N79 + + +device +(*Device1Properties) +FromDBusMap +45 (0.013%) +of 4796 (1.41%) + + + + + +N1->N79 + + + + + + + 4796 + + + + + +N80 + + +dbus +(*Conn) +RemoveSignal +53 (0.016%) +of 1249 (0.37%) + + + + + +N1->N80 + + + + + + + 1249 + + + + + +N2 + + +protomolecule +main +0 of 50770 (14.92%) + + + + + +N2->N1 + + + + + + + 50770 + + + + + +N13 + + +prototooth +(*Device) +DiscoverServices +900 (0.26%) +of 2442 (0.72%) + + + + + +N3->N13 + + + + + + + 2442 + + + + + +N16 + + +prototooth +(*DeviceService) +DiscoverCharacteristics +825 (0.24%) +of 2262 (0.66%) + + + + + +N3->N16 + + + + + + + 2262 + + + + + +N19 + + +prototooth +(UUID) +String +1356 (0.4%) + + + + + +N3->N19 + + + + + + + 864 + + + + + +N35 + + +protogen +resultHandler$2 +1008 (0.3%) + + + + + +N3->N35 + + + + + + + 1008 + + + + + +N38 + + +prototooth +(*Adapter) +Connect +309 (0.091%) +of 963 (0.28%) + + + + + +N3->N38 + + + + + + + 963 + + + + + +N66 + + +prototooth +(*DeviceCharacteristic) +Read +117 (0.034%) +of 357 (0.1%) + + + + + +N3->N66 + + + + + + + 357 + + + + + +N68 + + +device +(*Device1) +Disconnect +72 (0.021%) +of 396 (0.12%) + + + + + +N3->N68 + + + + + + + 396 + + + + + +N4 + + +fmt +(*pp) +printArg +1848 (0.54%) +of 11088 (3.26%) + + + + + +N15 + + +fmt +(*pp) +printValue +3228 (0.95%) + + + + + +N4->N15 + + + + + + + 3228 + + + + + +N17 + + +fmt +(*pp) +fmtInteger +2640 (0.78%) + + + + + +N4->N17 + + + + + + + 2640 + + + + + +N23 + + +reflect +ValueOf +812 (0.24%) + + + + + +N4->N23 + + + + + + + 240 + + + + + +N27 + + +fmt +(*pp) +handleMethods +1248 (0.37%) + + + + + +N4->N27 + + + + + + + 1248 + + + + + +N60 + + +fmt +(*pp) +fmtComplex +384 (0.11%) + + + + + +N4->N60 + + + + + + + 384 + + + + + +N70 + + +fmt +(*pp) +fmtPointer +297 (0.087%) + + + + + +N4->N70 + + + + + + + 297 + + + + + +N71 + + +fmt +(*pp) +fmtBytes +294 (0.086%) + + + + + +N4->N71 + + + + + + + 294 + + + + + +N5 + + +bluez +(*Client) +Call +1027 (0.3%) +of 5890 (1.73%) + + + + + +N21 + + +fmt +Sprint +102 (0.03%) +of 2337 (0.69%) + + + + + +N5->N21 + + + + + + + 2337 + + + + + +N50 + + +dbus +(*Object) +Call +183 (0.054%) +of 1470 (0.43%) + + + + + +N5->N50 + + + + + + + 1449 + + + + + +N57 + + +bluez +(*Client) +Connect +206 (0.061%) +of 1016 (0.3%) + + + + + +N5->N57 + + + + + + + 1016 + + + + + +N6 + + +fmt +Errorf +337 (0.099%) +of 15644 (4.60%) + + + + + +N7 + + +fmt +(*pp) +doPrintf +2859 (0.84%) +of 14197 (4.17%) + + + + + +N6->N7 + + + + + + + 14197 + + + + + +N25 + + +fmt +(*pp) +free +615 (0.18%) +of 1054 (0.31%) + + + + + +N6->N25 + + + + + + + 550 + + + + + +N39 + + +fmt +newPrinter +188 (0.055%) +of 899 (0.26%) + + + + + +N6->N39 + + + + + + + 518 + + + + + +N7->N4 + + + + + + + 10092 + + + + + +N67 + + +fmt +intFromArg +220 (0.065%) +of 512 (0.15%) + + + + + +N7->N67 + + + + + + + 512 + + + + + +N74 + + +fmt +(*pp) +argNumber +156 (0.046%) +of 324 (0.095%) + + + + + +N7->N74 + + + + + + + 324 + + + + + +N8->N6 + + + + + + + 12892 + + + + + +N18 + + +bluez +(*ObjectManager) +GetManagedObjects +308 (0.09%) +of 1319 (0.39%) + + + + + +N8->N18 + + + + + + + 573 + + + + + +N34 + + +bluez +GetObjectManager +290 (0.085%) +of 604 (0.18%) + + + + + +N8->N34 + + + + + + + 106 + + + + + +N46 + + +adapter +parseDevice +56 (0.016%) +of 2207 (0.65%) + + + + + +N8->N46 + + + + + + + 2207 + + + + + +N61 + + +adapter +(*Adapter1) +GetDeviceList +104 (0.031%) +of 424 (0.12%) + + + + + +N8->N61 + + + + + + + 424 + + + + + +N9 + + +util +mapStructField +477 (0.14%) +of 6664 (1.96%) + + + + + +N9->N6 + + + + + + + 2752 + + + + + +N9->N23 + + + + + + + 172 + + + + + +N29 + + +reflect +(Value) +Type +1188 (0.35%) + + + + + +N9->N29 + + + + + + + 1188 + + + + + +N58 + + +reflect +MapOf +456 (0.13%) + + + + + +N9->N58 + + + + + + + 456 + + + + + +N20 + + +sync +(*Mutex) +Lock +167 (0.049%) +of 1819 (0.53%) + + + + + +N10->N20 + + + + + + + 610 + + + + + +N26 + + +sync +(*Mutex) +Unlock +224 (0.066%) +of 985 (0.29%) + + + + + +N10->N26 + + + + + + + 328 + + + + + +N32 + + +dbus +Connect +53 (0.016%) +of 2187 (0.64%) + + + + + +N10->N32 + + + + + + + 2187 + + + + + +N62 + + +context +(*cancelCtx) +Err +14 (0.0041%) +of 636 (0.19%) + + + + + +N10->N62 + + + + + + + 636 + + + + + +N11 + + +dbus +(*Object) +createCall +1012 (0.3%) +of 2404 (0.71%) + + + + + +N45 + + +strings +LastIndex +688 (0.2%) + + + + + +N11->N45 + + + + + + + 688 + + + + + +N59 + + +dbus +MakeVariant +440 (0.13%) + + + + + +N11->N59 + + + + + + + 440 + + + + + +N12 + + +dbus +(*Call) +Store +531 (0.16%) +of 1613 (0.47%) + + + + + +N43 + + +dbus +Store +380 (0.11%) +of 1082 (0.32%) + + + + + +N12->N43 + + + + + + + 1082 + + + + + +N13->N18 + + + + + + + 270 + + + + + +N13->N19 + + + + + + + 246 + + + + + +N22 + + +prototooth +ParseUUID +894 (0.26%) + + + + + +N13->N22 + + + + + + + 264 + + + + + +N13->N34 + + + + + + + 204 + + + + + +N76 + + +gatt +NewGattService1 +171 (0.05%) +of 276 (0.081%) + + + + + +N13->N76 + + + + + + + 276 + + + + + +N14 + + +util +MapToStruct +64 (0.019%) +of 6728 (1.98%) + + + + + +N14->N9 + + + + + + + 6664 + + + + + +N16->N18 + + + + + + + 270 + + + + + +N16->N19 + + + + + + + 246 + + + + + +N16->N22 + + + + + + + 264 + + + + + +N16->N34 + + + + + + + 204 + + + + + +N73 + + +gatt +NewGattCharacteristic1 +186 (0.055%) +of 297 (0.087%) + + + + + +N16->N73 + + + + + + + 297 + + + + + +N18->N5 + + + + + + + 786 + + + + + +N18->N12 + + + + + + + 225 + + + + + +N24 + + +sync +(*Mutex) +lockSlow +1522 (0.45%) +of 1591 (0.47%) + + + + + +N20->N24 + + + + + + + 1591 + + + + + +N21->N25 + + + + + + + 504 + + + + + +N21->N39 + + + + + + + 381 + + + + + +N48 + + +fmt +(*pp) +doPrint +234 (0.069%) +of 1350 (0.4%) + + + + + +N21->N48 + + + + + + + 1350 + + + + + +N64 + + +sync +(*Pool) +Put +242 (0.071%) +of 439 (0.13%) + + + + + +N25->N64 + + + + + + + 439 + + + + + +N44 + + +sync +(*Mutex) +unlockSlow +676 (0.2%) +of 709 (0.21%) + + + + + +N26->N44 + + + + + + + 709 + + + + + +N28->N22 + + + + + + + 366 + + + + + +N65 + + +prototooth +ParseMAC +330 (0.097%) + + + + + +N28->N65 + + + + + + + 330 + + + + + +N30->N5 + + + + + + + 2324 + + + + + +N30->N12 + + + + + + + 432 + + + + + +N31 + + +dbus +(*Conn) +RemoveMatchSignalContext +116 (0.034%) +of 1200 (0.35%) + + + + + +N31->N12 + + + + + + + 158 + + + + + +N37 + + +dbus +(*Object) +CallWithContext +124 (0.036%) +of 1276 (0.37%) + + + + + +N31->N37 + + + + + + + 638 + + + + + +N54 + + +dbus +formatMatchOptions +148 (0.043%) +of 472 (0.14%) + + + + + +N31->N54 + + + + + + + 236 + + + + + +N40 + + +dbus +(*Conn) +Auth +258 (0.076%) +of 1564 (0.46%) + + + + + +N32->N40 + + + + + + + 1564 + + + + + +N78 + + +dbus +(*Conn) +Close +130 (0.038%) +of 302 (0.089%) + + + + + +N32->N78 + + + + + + + 302 + + + + + +N33 + + +dbus +(*Conn) +AddMatchSignalContext +114 (0.033%) +of 1198 (0.35%) + + + + + +N33->N12 + + + + + + + 158 + + + + + +N33->N37 + + + + + + + 638 + + + + + +N33->N54 + + + + + + + 236 + + + + + +N69 + + +bluez +NewObjectManager +289 (0.085%) +of 314 (0.092%) + + + + + +N34->N69 + + + + + + + 314 + + + + + +N36 + + +sync +(*RWMutex) +Lock +182 (0.053%) +of 1076 (0.32%) + + + + + +N36->N20 + + + + + + + 806 + + + + + +N37->N11 + + + + + + + 1152 + + + + + +N38->N5 + + + + + + + 114 + + + + + +N51 + + +device +NewDevice1 +221 (0.065%) +of 435 (0.13%) + + + + + +N38->N51 + + + + + + + 261 + + + + + +N56 + + +sync +(*Pool) +Get +324 (0.095%) +of 663 (0.19%) + + + + + +N39->N56 + + + + + + + 663 + + + + + +N47 + + +dbus +(*Conn) +tryAuth +600 (0.18%) + + + + + +N40->N47 + + + + + + + 600 + + + + + +N41 + + +dbus +(*defaultSignalHandler) +RemoveSignal +73 (0.021%) +of 1196 (0.35%) + + + + + +N41->N36 + + + + + + + 538 + + + + + +N42 + + +sync +(*RWMutex) +Unlock +180 (0.053%) +of 690 (0.2%) + + + + + +N41->N42 + + + + + + + 345 + + + + + +N42->N26 + + + + + + + 438 + + + + + +N63 + + +dbus +storeInterfaces +134 (0.039%) +of 626 (0.18%) + + + + + +N43->N63 + + + + + + + 626 + + + + + +N46->N14 + + + + + + + 1977 + + + + + +N46->N51 + + + + + + + 174 + + + + + +N48->N4 + + + + + + + 996 + + + + + +N49->N36 + + + + + + + 538 + + + + + +N49->N42 + + + + + + + 345 + + + + + +N50->N11 + + + + + + + 1252 + + + + + +N52->N5 + + + + + + + 1162 + + + + + +N52->N12 + + + + + + + 216 + + + + + +N53->N5 + + + + + + + 1162 + + + + + +N53->N12 + + + + + + + 216 + + + + + +N72 + + +strings +Join +204 (0.06%) +of 324 (0.095%) + + + + + +N54->N72 + + + + + + + 324 + + + + + +N55 + + +bluez +GetConnection +429 (0.13%) +of 737 (0.22%) + + + + + +N55->N10 + + + + + + + 136 + + + + + +N57->N55 + + + + + + + 737 + + + + + +N61->N18 + + + + + + + 206 + + + + + +N61->N34 + + + + + + + 90 + + + + + +N62->N20 + + + + + + + 403 + + + + + +N62->N26 + + + + + + + 219 + + + + + +N63->N23 + + + + + + + 320 + + + + + +N66->N5 + + + + + + + 114 + + + + + +N67->N23 + + + + + + + 80 + + + + + +N68->N5 + + + + + + + 228 + + + + + +N68->N12 + + + + + + + 96 + + + + + +N75->N31 + + + + + + + 1200 + + + + + +N77->N33 + + + + + + + 1198 + + + + + +N79->N14 + + + + + + + 4751 + + + + + +N80->N41 + + + + + + + 1196 + + + + + + +
+ + + + + + + \ No newline at end of file diff --git a/profiling/protomolecule.profile b/profiling/protomolecule.profile new file mode 100644 index 0000000..839527b Binary files /dev/null and b/profiling/protomolecule.profile differ diff --git a/src/arboghast/arboghast.go b/src/arboghast/arboghast.go new file mode 100644 index 0000000..32e4b92 --- /dev/null +++ b/src/arboghast/arboghast.go @@ -0,0 +1,54 @@ +// arboghast is a package focused on fuzzing BLE devices +package arboghast + +import ( + "sync" + + bluetooth "git.tcp.direct/kayos/prototooth" + + projVars "protomolecule/src/config" +) + +type Circus struct { + Trick map[int]*Fuzzy + uuid_pool []bluetooth.UUID + mu *sync.Mutex +} + +type Fuzzy struct { + config *bluetooth.AdvertisementOptions + ad *bluetooth.Advertisement + mu *sync.Mutex +} + +var circus *Circus + +func Awaken() { + circus = &Circus{ + Trick: make(map[int]*Fuzzy), + uuid_pool: []bluetooth.UUID{}, + mu: &sync.Mutex{}, + } +} + +func NewEntropicFuzzer() *Fuzzy { + options := &bluetooth.AdvertisementOptions{ + LocalName: RandomAlpha(16), + + // Interval: + } + mutex := &sync.Mutex{} + + ad := projVars.GlobalConfig.GetScanAdapter().DefaultAdvertisement() + ad.Configure(*options) + + return &Fuzzy{ + config: options, + ad: ad, + mu: mutex, + } +} + +func (f *Fuzzy) StartAd() { + f.ad.Start() +} diff --git a/src/arboghast/entropy.go b/src/arboghast/entropy.go new file mode 100644 index 0000000..f61b6c9 --- /dev/null +++ b/src/arboghast/entropy.go @@ -0,0 +1,34 @@ +package arboghast + +import ( + "math/rand" + "time" + "unsafe" +) + +var src = rand.NewSource(time.Now().UnixNano()) + +const ( + letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + letterIdxBits = 6 // 6 bits to represent a letter index + letterIdxMask = 1<= 0; { + if remain == 0 { + cache, remain = src.Int63(), letterIdxMax + } + if idx := int(cache & letterIdxMask); idx < len(letterBytes) { + b[i] = letterBytes[idx] + i-- + } + cache >>= letterIdxBits + remain-- + } + + return *(*string)(unsafe.Pointer(&b)) +} diff --git a/src/blueStuff/blueStuff.go b/src/blueStuff/blueStuff.go index a3914ec..3f52e90 100644 --- a/src/blueStuff/blueStuff.go +++ b/src/blueStuff/blueStuff.go @@ -2,19 +2,15 @@ package blueStuff import "git.tcp.direct/kayos/prototooth" -//controls connections to found devices to get service characteristics - -//TODO: disable the scan adapter, enable the attack adapter (this step pmight not be needed) +// controls connections to found devices to get service characteristics +// TODO: disable the scan adapter, enable the attack adapter (this step pmight not be needed) // use the result.LocalName passed from scanStuff to start connection // once connected, for list of service characteristics and check for read / write for each // loog all of this to eros func pathways(target bluetooth.ScanResult) { - println("Discovery") - //device, err := projVars.ScanAdapter.Connect(bluetooth.ScanResult.Address, bluetooth.ConnectionParams{}) - - //srvcs, err := projVars.ScanAdapter. - + // device, err := projVars.GlobalConfig.GetScanAdapter().Connect(bluetooth.ScanResult.Address, bluetooth.ConnectionParams{}) + // srvcs, err := projVars.GlobalConfig.GetScanAdapter(). } diff --git a/src/config/config.go b/src/config/config.go new file mode 100644 index 0000000..c10f1ad --- /dev/null +++ b/src/config/config.go @@ -0,0 +1,99 @@ +package common + +import ( + "flag" + + bluetooth "git.tcp.direct/kayos/prototooth" +) + +type Mode uint32 + +const ( + ModeNone Mode = iota + ModeScan + ModeTrack + ModeAttack +) + +func (m Mode) String() string { + return [...]string{"None", "Track", "Attack"}[m] +} + +// Tooth is a bluetooth adapter. +type Tooth struct { + ID int + Usecase Mode + *bluetooth.Adapter +} + +type Config struct { + // ManuFile is a place holder for a file with list of all known Manufacturers + // this is actually stored by eros and likely deprecated. + ManuFile string + Teeth []*Tooth + + CooleanFlags struct { + Debug *bool + Attack *bool + Tracking *bool + } + StringFlags struct { + MACVendorFile *string + MACTarget *string + } +} + +func (c *Config) GetScanAdapter() *bluetooth.Adapter { + if len(c.Teeth) == 1 { + return c.Teeth[0].Adapter + } + var choice *bluetooth.Adapter + for _, v := range c.Teeth { + if v.Usecase == ModeScan || v.Usecase == ModeTrack { + choice = v.Adapter + break + } + } + return choice +} + +var DefaultConfig = Config{ + ManuFile: DefManuFile, + Teeth: []*Tooth{ + &Tooth{ + ID: 0, + Usecase: ModeNone, + Adapter: bluetooth.DefaultAdapter, + }, + }, + CooleanFlags: struct { + Debug *bool + Attack *bool + Tracking *bool + }{ + Debug: flag.Bool("d", false, "global debug logging and pretty printing"), + Attack: flag.Bool("a", false, "attack mode"), + Tracking: flag.Bool("t", false, "device tracking mode"), + }, + + StringFlags: struct { + MACVendorFile *string + MACTarget *string + }{ + MACVendorFile: flag.String("m", DefManuFile, "json file with manufacturer identifying data to preload into eros"), + MACTarget: flag.String("w", "00:00:00:00:00:00", "MAC address of target"), + }, +} + +const DefManuFile = "./ManufUUID.json" + +// Service UUIDs for testing +var ( + SonosScanTest = bluetooth.New16BitUUID(0xfe07) + AppleScanTest = bluetooth.New16BitUUID(0x004c) + GlobalConfig *Config +) + +func init() { + GlobalConfig = &DefaultConfig +} diff --git a/src/cortazar/cortazar.go b/src/cortazar/cortazar.go new file mode 100644 index 0000000..07a3aaf --- /dev/null +++ b/src/cortazar/cortazar.go @@ -0,0 +1,34 @@ +package cortazar + +//Intended to be used as the target analysis package + +//for example + +/* + +1. attempt bonding (LTK exchange) with target, while in aggressive attack mode +2. store current LTK associated with target to device in eros +3. disconnect and forget target +4. recconect to target, pair, bond, store LTK, disconnect, forget -- repeatTK +5. compare LTKs for entropy + +** could also be used for link key which is the pin established during pairing +*/ + +//--------- + +/* + device metrics + - location and device type/manufacturer/etc... + - when and where a device is seen over time + + + + +*/ + +//----------- + +/* + + */ diff --git a/src/deimos/main.go b/src/deimos/main.go new file mode 100644 index 0000000..a070c01 --- /dev/null +++ b/src/deimos/main.go @@ -0,0 +1,77 @@ +package deimos + +import ( + "errors" + "fmt" + "github.com/google/gopacket/dumpcommand" + "github.com/google/gopacket/pcap" + "github.com/rs/zerolog/log" + "strconv" + "strings" +) + +type DevMap map[int]pcap.Interface + +var Devices DevMap +var Interface *pcap.Handle + +func init() { + Devices = make(map[int]pcap.Interface) +} + +func getInterfaces() []pcap.Interface { + devices, err := pcap.FindAllDevs() + if err != nil { + log.Error().Err(err).Msg("failed to get network interfaces") + return nil + } + return devices +} + +func getBlueDevices() []pcap.Interface { + var blues []pcap.Interface + devices := getInterfaces() + for n, device := range devices { + if strings.Contains(strings.ToLower(device.Name), "bluetooth") { + Devices[n] = device + blues = append(blues, device) + } + if strings.Contains(strings.ToLower(device.Name), "hci") { + Devices[n] = device + blues = append(blues, device) + } + } + return blues +} + +func PrintBlueDevices() { + getBlueDevices() + for n := range Devices { + devid := strconv.Itoa(n) + fmt.Println("[" + devid + "] " + Devices[n].Name) + } +} + +func Sniff(dev int) error { + var ( + err error + d pcap.Interface + preInterface *pcap.InactiveHandle + ok bool + ) + if d, ok = Devices[dev]; !ok { + return errors.New("adapter ID does not exist") + } + if preInterface, err = pcap.NewInactiveHandle(d.Name); err != nil { + return err + } + defer preInterface.CleanUp() + if err = preInterface.SetPromisc(true); err != nil { + return err + } + if Interface, err = preInterface.Activate(); err != nil { + return err + } + go dumpcommand.Run(Interface) + return nil +} diff --git a/src/dust/dust.go b/src/dust/dust.go index 1d3b8e9..4ae7ef9 100644 --- a/src/dust/dust.go +++ b/src/dust/dust.go @@ -9,7 +9,12 @@ import ( func Must(action string, err error) { if err != nil { - log.Fatal().Err(err).Str("action", action).Msg("FATAL_ERROR") + switch err.Error() { + case "AdapterExists: Launch helper exited with unknown return code 1": + log.Error().Msg("Is your bluetooth adapter enabled? Linux: is bluetoothd started?") + default: + log.Fatal().Err(err).Str("action", action).Msg("FATAL_ERROR") + } } } diff --git a/src/eros/eros.go b/src/eros/eros.go index a184cf7..60c9359 100644 --- a/src/eros/eros.go +++ b/src/eros/eros.go @@ -1,5 +1,3 @@ -package eros - // Eros controls the Bitcask db that holds the devices captured during scanning // // Addr (Key) @@ -7,19 +5,22 @@ package eros // Raw Advertisement Packet (Advertisement) // Services UUIDs (Services) -// TODO: -// Output to report +// TODO: // +// Output to report +package eros import ( "bufio" - "encoding/json" "os" "strconv" "strings" + "sync" "time" - projVars "protomolecule/src/vars" + jsoniter "github.com/json-iterator/go" + + projVars "protomolecule/src/config" bluetooth "git.tcp.direct/kayos/prototooth" "github.com/prologic/bitcask" @@ -27,23 +28,27 @@ import ( ) var ( - // deviceDb will hold details about devices discovered - deviceDb *bitcask.Bitcask - // attackDb will hold details about exploits to be used against BLE devices - attackDb *bitcask.Bitcask - // serviceDb will hold definitions of various bluetook services and will ultimately be updated via an HTTP repository - serviceDb *bitcask.Bitcask + json = jsoniter.ConfigCompatibleWithStandardLibrary + + dbs = []string{ + "devices", // details about devices discovered + "exploits", // details about exploits to be used against BLE devices + "services", // definitions of various bluetooth services and will ultimately be updated via an HTTP repository + "manufacturers", // manufacturer to UUID correlations and info + } err error Manufacturers ManufData + // Exploits Exploit // DataDir - should be defined by config or cmd flag DataDir string = "./.eros-data/" ) +var DB map[string]*bitcask.Bitcask + // Ingest UUID will add the UUID to the manufacturer if it doesn't already exist func (manuf *Manufacturer) IngestUUID(uuid bluetooth.UUID) bool { - contains := func(s []bluetooth.UUID, v bluetooth.UUID) bool { for _, a := range s { if a == v { @@ -60,10 +65,24 @@ func (manuf *Manufacturer) IngestUUID(uuid bluetooth.UUID) bool { manuf.UUIDs = append(manuf.UUIDs, uuid) return true } +func FinalizeDevice(bigidea Device) *Device { + bigidea.mu = &sync.RWMutex{} + return &bigidea +} + +func (d *Device) ConnectHandler(target bluetooth.Addresser, c bool) { + d.mu.Lock() + defer d.mu.Unlock() + if c { + d.Connected = true + } else { + d.Connected = false + } +} // ManufLoad loads data from a json file containing UUID manufacturer associations func ManufLoad() { - path := projVars.ManuFile + path := *projVars.GlobalConfig.StringFlags.MACVendorFile var uuid bluetooth.UUID log.Info(). @@ -72,8 +91,8 @@ func ManufLoad() { f, err := os.Open(path) if err != nil { - log.Debug().Msg(err.Error()) - os.Exit(1) + log.Error().Err(err). + Msg("Failed to open JSON file") } defer f.Close() @@ -88,7 +107,7 @@ func ManufLoad() { utmp, err := strconv.ParseUint(mf.UString, 0, 16) if err != nil { - log.Fatal().Str("file", projVars.ManuFile). + log.Fatal().Str("file", path). Str("string", mf.UString). Err(err).Msg("MANUFACTURER_PARSE_ERROR") } @@ -99,8 +118,8 @@ func ManufLoad() { log.Debug(). Str("Manufacturer", mf.Name). Str("UUID_String", mf.UString). - //Interface("UUID_Type", uuid). - //Str("Website", mf.Website). + // Interface("UUID_Type", uuid). + // Str("Website", mf.Website). Msg("LOADED_MANUFACTURER_DATA") mf.UString = "" @@ -123,7 +142,7 @@ func ManufLoad() { log.Debug().Str("Manufacturer", mf.Name). Int("UUID_Count", len(mf.UUIDs)). - //Interface("UUIDs", mf.UUIDs). + // Interface("UUIDs", mf.UUIDs). Msg("EXISTING_MANUFACTURER_FOUND") } @@ -132,52 +151,64 @@ func ManufLoad() { Manufacturers.Entries = append(Manufacturers.Entries, *mf) } } + + for _, manuf := range Manufacturers.Entries { + var jsonData []byte + jsonData, err = json.Marshal(manuf) + if err != nil { + log.Fatal().Err(err). + Msg("EROS_FATAL_MANUFACTURER_JSON_MARSHAL") + } + + err := DB["manufacturers"].Put([]byte(manuf.Name), jsonData) + if err != nil { + log.Fatal().Err(err). + Msg("EROS_FATAL_MANUFACTURER_JSON_STORE") + } + + log.Debug().Str("Name", manuf.Name). + Msg("EROS_MANUFACTURER_STORE") + } } // Awaken - create the data directory if it does not exist; initialize bitcask in this directory func Awaken() { - //log.Debug().Str("DataDir",DataDir).Msg("Initializing eros...") - - deviceDb, err = bitcask.Open(DataDir + "devices") - if err != nil { - panic(err.Error) + DB = make(map[string]*bitcask.Bitcask) + for _, name := range dbs { + DB[name], err = bitcask.Open(DataDir+name, bitcask.WithMaxValueSize(1024*1024*1024)) + if err != nil { + panic(err.Error()) + } } +} - attackDb, err = bitcask.Open(DataDir + "exploits") +func logErr(err error) { if err != nil { - panic(err.Error) - } - - serviceDb, err = bitcask.Open(DataDir + "services") - if err != nil { - panic(err.Error) + log.Error().Err(err). + Msg("EROS_DATABASE_ERROR") } } // Slumber - Clean up database entries, sync them to persistent storage, and safelty close the database. func Slumber() { - rest := func(db *bitcask.Bitcask) { - db.Merge() - db.Sync() - db.Close() + for _, db := range DB { + logErr(db.Merge()) + logErr(db.Sync()) + logErr(db.Close()) } - - rest(deviceDb) - rest(attackDb) - rest(serviceDb) } // Exists - check if a device is present in the Database func Exists(Addr string) bool { - if deviceDb.Has([]byte(Addr)) { + if DB["devices"].Has([]byte(Addr)) { return true } return false } -// Remember - store device details into the database -func Remember(dev Device) error { +// Remember stores device details into the database via an argument +func Remember(dev *Device) error { var err error var rhist map[time.Time]int16 @@ -200,7 +231,7 @@ func Remember(dev Device) error { return err } - err = deviceDb.Put([]byte(dev.Addr), jsonData) + err = DB["devices"].Put([]byte(dev.Addr), jsonData) return err } @@ -210,28 +241,148 @@ func Recall(Addr string) (Device, error) { var bytes []byte var member Device - bytes, err = deviceDb.Get([]byte(Addr)) + bytes, err = DB["devices"].Get([]byte(Addr)) if err != nil { member = Device{} return member, err } - json.Unmarshal(bytes, &member) + if err := json.Unmarshal(bytes, &member); err != nil { + log.Panic().Err(err).Msg("Failed to unmarshal device") + } return member, err } +func Backup(path string) error { + for _, db := range DB { + logErr(db.Merge()) + logErr(db.Sync()) + err := db.Backup(path) + if err != nil { + return err + } + } + return nil +} + +/* // Hypnosis - retrieve new exploits/attacks from a remote http repository func Hypnosis(repo string) { - // placeholder + + e:= echo.New() + // CORS + e.Use(middleware.CORSWithConfig(middleware.CORSConfig{ + AllowOrigins: []string{"*"}, + AllowMethods: []string{echo.GET, echo.HEAD, echo.PUT, echo.PATCH, echo.POST, echo.DELETE} //TODO: possibly trim the methods + })) + + // GET + e.GET("/exploits", func(c echo.Context) error { // This will definitely need to be updated + // Build request + req, err := http.NewRequest("GET", repo, nil) + if err != nil { + fmt.Println("Error in GET request: ", err) + } + + // Certificate sanity checks + caCert, err := os.Readfile("server.crt") + if err != nil { + log.Fatal(err) + } + cert, err := tls.LoadX509KeyPair("client.crt", "client.key") + if err != nil { + log.Fatal(err) + } + + // Add certificates + caCertPool := x509.NewCertPool() + caCertPool.AppendCertsFromPEM(caCert) + + // Create client + client := &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{ + RootCAs: caCertPool, + Certificates: []tls.Certificate{cert}, + }, + }, + } + + // Send request + res, err := client.Do(req) + if err != nil { + fmt.Println("Client Error: ", err) + } + + // Defer body close + defer res.Body.Close() + + // Late binding data from JSON + var exp Exploit + + // Decode JSON stream + If err := json.NewDecoder(res.Body).Decode(&exp); err != nil { + fmt.Println(err) + } + + return c.JSON(http.StatusOK, exp) + }) } // Trauma - store details of an exploit/attack against BLE devices -func Trauma(name string, targ string, cat string, vec Vector, pay Payload) { - // placeholder +func Trauma(exp *Exploit) error { + var err error + var rhist map[time.Time]int16 + + if !Known(exp.Addr) { + exp.Discovered = time.Now() + rhist = make(map[time.Time]int16) + } else { + re, _ := Flashback(exp.Addr) + exp.Discovered = re.Discovered + rhist = re.RSSIhist + } + + rhist[time.Now()] = exp.RSSIlast + exp.RSSIhist = rhist + exp.Seen = time.Now() + + var jsonData []byte + jsonData, err = json.Marshal(exp) + if err != nil { + return err + } + + err = DB["exploits"].Put([]byte(exp.Addr), jsonData) + return err +} + +func FinalizeExploit(bigidea Exploit) *Exploit { + bigidea.mu = &sync.RWMutex{} + return &bigidea +} +*/ +// Known - check if an exploit is present in the database +func Known(Addr string) bool { + return DB["exploits"].Has([]byte(Addr)) } // Flashback - retrieve details for the named exploit/attack -func Flashback(name string) { - //placeholder +func Flashback(Addr string) (Exploit, error) { + var err error + var bytes []byte + var member Exploit + + bytes, err = DB["exploits"].Get([]byte(Addr)) + + if err != nil { + member = Exploit{} + return member, err + } + + if err := json.Unmarshal(bytes, &member); err != nil { + log.Panic().Err(err).Msg("Failed to unmarshal exploit") + } + return member, err } diff --git a/src/eros/structs.go b/src/eros/structs.go index 0840157..d4bc2ca 100644 --- a/src/eros/structs.go +++ b/src/eros/structs.go @@ -1,13 +1,15 @@ package eros import ( - "git.tcp.direct/kayos/prototooth" + bluetooth "git.tcp.direct/kayos/prototooth" + "sync" "time" ) type Permissions struct { - Read string - Write string + Read string + Write string + Notify string } type Characteristic struct { @@ -25,7 +27,6 @@ type Service struct { Characteristic []Characteristic } - type ManufData struct { Entries []Manufacturer } @@ -45,7 +46,7 @@ type Manufacturer struct { // Exploit - BLE service exploit details to be marshalled into json before stored in bitcask type Exploit struct { Name string - Target string + Target string // Should prabably be a struct of some sort since exploits target service chars Category string Vector Vector Payload Payload @@ -63,11 +64,14 @@ type Payload struct { // Device will hold details about the discoverd device type Device struct { - Name string - Addr string - Manufacturer string - RSSIlast int16 - RSSIhist map[time.Time]int16 + Name string // local name of the device + Addr string // Broadcast MAC + Manufacturer string // Manufacturer Data if broadcast + RSSIlast int16 // Most Current RSSI + RSSIhist map[time.Time]int16 // Last RSSI readings + Alias string // Alias given to device + Trusted bool // Is is in the trusted devices + WakeAllowed bool // Does the device allow wake // Services - see Service struct Services []Service @@ -75,4 +79,10 @@ type Device struct { Discovered time.Time // Seen - timestamp from when the device was last seen Seen time.Time + + Connected bool + Conn *bluetooth.Device + + // The most at-risk type we have so far for concurrency, needs to be mutexed + mu *sync.RWMutex } diff --git a/src/protogen/ble_scan.go b/src/protogen/ble_scan.go index 1ba6083..b1ad767 100644 --- a/src/protogen/ble_scan.go +++ b/src/protogen/ble_scan.go @@ -1,37 +1,37 @@ package protogen import ( - projVars "protomolecule/src/vars" + "sync" + "time" + + projVars "protomolecule/src/config" - "protomolecule/src/eros" "github.com/rs/zerolog" "github.com/rs/zerolog/log" - bluetooth "git.tcp.direct/kayos/prototooth" + "protomolecule/src/eros" - "time" + bluetooth "git.tcp.direct/kayos/prototooth" ) // ScanMgr will keep track of concurrently running scans var ScanMgr *Meta +// NewScan - here we are creating an "anonymous" instance of a Scan struct +// You'll notice it doesn't contain most of the data that actually is supposed to live within that struct +// +// This works because the integer ID is being used as a key that will have a global scope +// +// See: Remember function as it is defined in eros/eros.go +// Remember usage in this file (scanStuff/scanStuff.go +// +// In these examples we are sending an instance of a struct with some data to eros; allowing it to finish filling out the rest +// This can be done with just structs, but becomes problematic when trying to refer to them later +// +// ref: https://gobyexample.com/mutexes +// ref: https://golang.org/pkg/sync/#Mutex +// ref: https://www.geeksforgeeks.org/mutex-in-golang-with-examples/ func (m *Meta) NewScan() *Scan { - // Here we are creating an "anonymous" instance of a Scan struct - // You'll notice it doesn't contain most of the data that actually is supposed to live within that struct - - // This works because the integer ID is being used as a key that will have a global scope - // - // See: Remember function as it is defined in eros/eros.go - // Remember usage in this file (scanStuff/scanStuff.go - // - // In these examples we are sending an instance of a struct with some data to eros; allowing it to finish filling out the rest - // This can be done with just structs, but becomes problematic when trying to refer to them later - // - //TODO: implement Mutex locking from sync in most of these structs to prevent concurrent read/write operations from causing a race w̶a̶r̶ condition - // ref: https://gobyexample.com/mutexes - // ref: https://golang.org/pkg/sync/#Mutex - // ref: https://www.geeksforgeeks.org/mutex-in-golang-with-examples/ - newid := len(m.Scans) m.Scans[newid] = &Scan{ @@ -40,23 +40,22 @@ func (m *Meta) NewScan() *Scan { } scan := m.Scans[newid] - scan.Devices = make(map[int]*eros.Device) - - m.Count = len(m.Scans) + scan.Device = make(map[int]*eros.Device) + scan.mu = &sync.RWMutex{} return scan } func (s *Scan) NewDevice(name string, addr string, manuf string, rssi int16) *eros.Device { - newid := len(s.Devices) - s.Devices[newid] = &eros.Device{ + s.mu.Lock() + defer s.mu.Unlock() + draft := eros.Device{ Name: name, - Addr: addr, + Addr: addr, Manufacturer: manuf, RSSIlast: rssi, } - s.Count = len(s.Devices) - return s.Devices[newid] + return eros.FinalizeDevice(draft) } /* @@ -93,27 +92,22 @@ func ManfCheck(TargetAdvertData bluetooth.AdvertisementPayload) string { func (s *Scan) resultHandler(scanAdapter *bluetooth.Adapter, result bluetooth.ScanResult) { var sublog zerolog.Logger - projVars.ScanAdapter.SetConnectHandler(func(Result bluetooth.Addresser, connected bool) { - // It seems that because this is a callback that the library calls itself that it is passing us "connected" as an argument - // therefore I think what we're supposed to do is store that boolean so we can then reference it later - projVars.ConnectedToTarget = connected - }) - payload := result.AdvertisementPayload addr := result.Address.String() + lname := result.LocalName() - //adbytes := payload.Bytes() + // adbytes := payload.Bytes() rssi := result.RSSI EnumedManuf := "" // TODO: probably make this a function or a method in eros(?) // - //---attempts to set the manufacturer value---- - //range through the uuids in the payload and compare - //known manufacturers list + // ---attempts to set the manufacturer value---- + // range through the uuids in the payload and compare + // known manufacturers list uuids := payload.ServiceUUIDOut() for range uuids { - //for every element within the manufacturers list + // for every element within the manufacturers list // check each UUID for _, man := range eros.Manufacturers.Entries { // pull the UUID the current element of the manufacturer list @@ -121,7 +115,7 @@ func (s *Scan) resultHandler(scanAdapter *bluetooth.Adapter, result bluetooth.Sc // for each manufacturer's UUID: compare the advertisment payload for a match for _, manusss := range currManufErosOut { manufBool := payload.HasServiceUUID(manusss) - //if there is a UUID match then assign the Manufacturer's name + // if there is a UUID match then assign the Manufacturer's name // to the output variable EnumedManuf if manufBool == true { EnumedManuf = man.Name @@ -132,11 +126,13 @@ func (s *Scan) resultHandler(scanAdapter *bluetooth.Adapter, result bluetooth.Sc } - //ManufOut := ManfCheck(payload) + // ManufOut := ManfCheck(payload) layToRest := func(dev *eros.Device) { sublog.Debug().Msg("Storing data with Eros") - eros.Remember(*dev) + if err := eros.Remember(dev); err != nil { + log.Warn().Err(err).Msg("EROS_REMEMBER_FAILURE") + } // simple eros test fromEros, err := eros.Recall(addr) @@ -147,13 +143,13 @@ func (s *Scan) resultHandler(scanAdapter *bluetooth.Adapter, result bluetooth.Sc log.Info(). Str("Name", fromEros.Name). Str("Addr", fromEros.Addr). - Str("ManuF", EnumedManuf). //needs to be changed back to fromEros.Manufacturer + Str("ManuF", fromEros.Manufacturer). // needs to be changed back to fromEros.Manufacturer Int16("Current_RSSI", fromEros.RSSIlast). Int("Service_Count", len(fromEros.Services)). Msg("EROS_RECALL") } - //Services level logging + // Service enumeration and storage // TODO: // Fix Logging output here -- Prob shouldnt output this much info // for each service discovered @@ -164,8 +160,8 @@ func (s *Scan) resultHandler(scanAdapter *bluetooth.Adapter, result bluetooth.Sc Int16("RSSI", rssi).Logger() // Skipping duplicate results unless tracking mode enabled (to store RSSI as devices move) - if projVars.TrackingMode == false { - for _, dev := range s.Devices { + if !*projVars.GlobalConfig.CooleanFlags.Tracking { + for _, dev := range s.Device { if addr == dev.Addr { return } @@ -176,6 +172,8 @@ func (s *Scan) resultHandler(scanAdapter *bluetooth.Adapter, result bluetooth.Sc s.Activity = time.Now() dev := s.NewDevice(lname, addr, EnumedManuf, rssi) + projVars.GlobalConfig.GetScanAdapter().SetConnectHandler(dev.ConnectHandler) + // Record all the services advertised, append them into the nested struct within Device for _, uuid := range uuids { svc := &eros.Service{ @@ -183,89 +181,60 @@ func (s *Scan) resultHandler(scanAdapter *bluetooth.Adapter, result bluetooth.Sc } dev.Services = append(dev.Services, *svc) - sublog.Debug().Str("UUID", svc.UUID).Msg("SERVICE_DISCOVERED") + sublog.Info().Str("UUID", svc.UUID).Msg("SERVICE_DISCOVERED") } - if !projVars.AttackMode { + if !*projVars.GlobalConfig.CooleanFlags.Attack { layToRest(dev) return } - //////////////////////////////////////////////////////////////////////// - //var PreTargetHandling type - //var TargetDeviceService *bluetooth.DeviceService - //var TargetDeviceServiceChar *bluetooth.DeviceCharacteristic - sublog.Info().Str("Adapter", "Attempting Connection").Msg("ADAPTER_STATUS") + var connErr error + var err error - // TODO: re-assess the timeout mechanism - // this is largely going to depend on how concurrent we can get (at least with only one ble adapter) + // TODO: make timeout values and intervals command line arguments instead of hard coding them + timeout := bluetooth.NewDuration(time.Duration(3) * time.Second) + interval := bluetooth.NewDuration(time.Duration(20) * time.Millisecond) - // creates a new timer of d (time.Duration) - // outputs time on {timer_Name}.C chan - // can then be checked against tick (time.Time) - TimerCounts := time.NewTimer(10 * time.Millisecond) + dev.Conn, connErr = projVars.GlobalConfig.GetScanAdapter(). + Connect(result.Address, bluetooth.ConnectionParams{ConnectionTimeout: timeout, MinInterval: interval}) - var ( - conTimeOut time.Duration - //tick <-chan time.Time - //not needed? - //tock <-chan time.Timer - err error - ) - - TargetDevice, connectError := projVars.ScanAdapter.Connect(result.Address, bluetooth.ConnectionParams{}) + if connErr != nil { + sublog.Error().Err(connErr).Msg("CONNECT_ERROR") + layToRest(dev) + return + } var targetServices []bluetooth.DeviceService sublog.Info(). - Str("status", "Attempting to Read Target Services"). + Str("status", "Connected, attempting to Read Target Services"). Msg("ADAPTER_STATUS") - // TODO: this will be running concurrently in a goroutine, - // so rather than set out timeout to be egregiously low we will just let it take its time - conTimeOut = 50 * time.Millisecond - - //attempted to fix but probably didnt help anything - if TimerCounts.C == nil { - endTime := time.After(conTimeOut) - select { - case <-endTime: - sublog.Error().Str("Adapter", "Connection Timeout").Msg("ADAPTER_STATUS") - TargetDevice.Disconnect() - endTime = nil - default: - if connectError != nil { - sublog.Error().Err(connectError).Msg("CONNECT_ERROR") - layToRest(dev) - return - } - sublog.Debug().Str("Status", "Connecting...").Msg("ADAPTER_STATUS") - } - } - - if !projVars.ConnectedToTarget { + if !dev.Connected { layToRest(dev) return } - ServBuf := make([]byte, 255) + // ServBuf := make([]byte, 255) Charbuf := make([]byte, 255) - targetServices, err = TargetDevice.DiscoverServices(nil) + targetServices, err = dev.Conn.DiscoverServices(nil) if err != nil { sublog.Error().Err(err).Msg("DISCOVER_SERVICE_ERROR") } - for SerReadPos, srvcs := range targetServices { + // for SerReadPos, srvcs := range targetServices { + for _, srvcs := range targetServices { charSer := eros.Service{ UUID: srvcs.String(), } sublog.Info().Str("Service UUID", charSer.UUID). - Int("Bytes", SerReadPos). - Str("Value", string(ServBuf[:SerReadPos])). + // Int("Bytes", SerReadPos). + // Str("Value", string(ServBuf[:SerReadPos])). Msg("GATT_SERVICE") sublog.Debug().Str("status", "Attempting to Retrieve Characteristic List").Msg("ADAPTER_STATUS") @@ -275,51 +244,62 @@ func (s *Scan) resultHandler(scanAdapter *bluetooth.Adapter, result bluetooth.Sc for _, char := range chars { ReadPos, _ := char.Read(Charbuf) + // flags := char.Flags + sublog.Info().Str("UUID", char.UUID().String()). - Int("Bytes", ReadPos).Str("Value", string(Charbuf[:ReadPos])). + // Int("Bytes", ReadPos). + Str("Value", string(Charbuf[:ReadPos])). + // Bool("Read", flags.Read()). + // Bool("Write", flags.Write()). Msg("SERVICE_CHARACTERISTIC") } } // finished with this device - - TargetDevice.Disconnect() + _ = dev.Conn.Disconnect() + dev.Connected = false sublog.Info().Str("Adapter", "Successfully Disconnected From Target").Msg("ADAPTER_STATUS") - projVars.ConnectedToTarget = false layToRest(dev) - //TODO: stop scan and call bluestuff func and pass it the local name value + // TODO: stop scan and call bluestuff func and pass it the local name value +} + +func (s *Scan) Stop() error { + // TODO: fix this adapterId situation + err := projVars.GlobalConfig.GetScanAdapter().StopScan() + if err != nil { + return err + } + return nil } func (s *Scan) Start() error { s.Started = time.Now() // create list of devices in the Area of Operation - //log.Debug().Msg("Creating Device Map") + // log.Debug().Msg("Creating Device Map") // Enable BLE interface log.Debug().Msg("Enabling Adapter") - err := projVars.ScanAdapter.Enable() + err := projVars.GlobalConfig.GetScanAdapter().Enable() if err != nil { return err } - adapterId := projVars.ScanAdapter.ID - + adapterId := projVars.GlobalConfig.GetScanAdapter().ID log.Info(). Str("ID", adapterId). - Bool("MODE_TRACK", projVars.TrackingMode). - Bool("MODE_ATTACK", projVars.AttackMode). + Bool("MODE_TRACK", *projVars.GlobalConfig.CooleanFlags.Tracking). + Bool("MODE_ATTACK", *projVars.GlobalConfig.CooleanFlags.Attack). Msg("Starting new ProtoMolecule BLE Scan") - err = projVars.ScanAdapter.Scan(s.resultHandler) + err = projVars.GlobalConfig.GetScanAdapter().Scan(s.resultHandler) if err != nil { return err } - return nil } diff --git a/src/protogen/structs.go b/src/protogen/structs.go index 5de1f96..1c263cc 100644 --- a/src/protogen/structs.go +++ b/src/protogen/structs.go @@ -1,57 +1,63 @@ package protogen import ( - "time" + bluetooth "git.tcp.direct/kayos/prototooth" "protomolecule/src/eros" + "sync" + "time" ) /* - Why the Meta struct? This shit is a fucking maze. -Well in theory we will have multiple types of scans in the future, -if that's the case this is going to become necessary very quickly +Why the Meta struct? + In theory we will have multiple types of scans in the future, + if that's the case this is going to become necessary very quickly -I've mocked up some commented out examples below. + I've mocked up some commented out examples in the source code below. */ type Meta struct { - Count int - Scans map[int]*Scan - + Scans map[int]*Scan Mailbox chan Postcard - // // // Future Concepts // // // // BLEScans map[int]*BLEScan // LoraScans map[int]*LoraScan // ZigScans map[int]*ZigScan // WiFiScans map[int]*WiFiScan + + // we definitely need this to be safe for concurrency + mu *sync.RWMutex } // Postcard will encapsulate interprocess communication messages that we send back to the main thread type Postcard struct { - // From - the ScanID the message originated from From int - // Stamp - the time the IPC message was created Stamp time.Time - // Device ID - relevant DeviceID (if applicable) - Remember to use Scan.Devices[id] for easy referral DeviceID int - // Command - the actual IPC command Command string - // Arguments - augmenting arguments to the command Arguments []string - } -// Instance of a BLE scan +// TODO: Form profiles on devices +// Scan represents an instance of a BLE scan type Scan struct { - Count int - - // The ID is how we will refer back to running scans during IPC to react or cancel a scan - ID int - Started time.Time + Count int + ID int + // Started the scan at this time + Started time.Time + // Activity was last seen at this time Activity time.Time - Devices map[int]*eros.Device + // Device represents a bluetooth endpoints + Device map[int]*eros.Device + // Connection is an active connection to a bluetooth endpoint + Connection map[int]*bluetooth.Connection + /* Ignore is a map of devices to disregard during a scan, + by using the hardware address as a key. (needs disclaimer?) */ + Ignore map[string]bool + + // Gonna plan on mutexing scan operations just to be safe + mu *sync.RWMutex } diff --git a/src/vars/projVars.go b/src/vars/projVars.go deleted file mode 100644 index 862fe22..0000000 --- a/src/vars/projVars.go +++ /dev/null @@ -1,61 +0,0 @@ -package projVars - -import ( - "flag" - - bluetooth "git.tcp.direct/kayos/prototooth" - "github.com/rs/zerolog" -) - -//The initial list of device in the area -var ScanList map[string]string - -var InitResults []string - -// Place holder for -// File with list of all known Manufacturers -// is probably unneeded***** -var ManuFile = "./ManufUUID.json" - -//var to hold service UUIDs -var SrvcUUID bluetooth.UUID - -var AdapterInUse = *&bluetooth.Adapter{} - -var AttackMode bool = false -var TrackingMode bool = false - -var ConnectedToTarget bool = false - -//var SrvcUUIDList map[uint32]string - -//hold the values for the initial ble scan results.. -// ... i.e. the mac and broadcast name string -var C = make(chan bluetooth.ScanResult) - -//the BLE adapter --duh -//var Adapter = bluetooth.DefaultAdapter -var ScanAdapter = bluetooth.DefaultAdapter - -var AttackAdapter = bluetooth.DefaultAdapter - -//Device to be targeted --not fully implemented -//var Target = flag.String("t", "00:00:00:00:00:00", "Target device to attack") -var DFlag = flag.Bool("d", false, "global debug logging and pretty printing") -var AFlag = flag.Bool("a", false, "attack mode") -var TFlag = flag.Bool("t", false, "device tracking mode") -var MFlag = flag.String("m", "0", "json file with manufacturer identifying data to preload into eros") - -//flag.Parse() - -//var attacker bluetooth.Addresser -//var connected bool -//var disconnected bool = true - -var log *zerolog.Logger - -//Service UUIDs for testing -var SonosScanTest = bluetooth.New16BitUUID(0xfe07) -var AppleScanTest = bluetooth.New16BitUUID(0x004c) - -//var ServiceUUID16Out diff --git a/src/wrath/wrath.go b/src/wrath/wrath.go new file mode 100644 index 0000000..ea77578 --- /dev/null +++ b/src/wrath/wrath.go @@ -0,0 +1,161 @@ +package wrath + +import ( + bluetooth "git.tcp.direct/kayos/prototooth" + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" + "tinygo.org/x/bluetooth/rawterm" + + projVars "protomolecule/src/config" +) + +// used for offensive operations +/* +func targetPicture() bluetooth.MAC { + + type targetMac bluetooth.MAC + + for c, err := range projVars.WAFlag { + append(targetMac{}) + } + + println(targetMac) + + target, err := bluetooth.ParseMAC(targetMac) + if err != nil { + log.Err(err).Msg("Error") + } + + a := bluetooth.Address{ + MACAddress: target, + } + + return target + +} +*/ + +func Start(targetUUID bluetooth.UUID) { + + var sublog zerolog.Logger + + // bluetooth.DefaultAdapter.Connect(targetPicture(), bluetooth.ConnectionParams{}) + + // TargetDevice, connectError := projVars.GlobalConfig.GetScanAdapter().Connect(result.Address, bluetooth.ConnectionParams{}) + + // Enable BLE interface. + err := projVars.GlobalConfig.GetScanAdapter().Enable() + if err != nil { + log.Error(). + Err(err). + Msg("could not enable the BLE stack") + return + } + + // The address to connect to. Set during scanning and read afterwards. + var foundDevice bluetooth.ScanResult + // Scan for NUS peripheral. + log.Info().Msg("Scanning...") + err = projVars.GlobalConfig.GetScanAdapter().Scan(func(adapter *bluetooth.Adapter, foundDevice bluetooth.ScanResult) { + if !foundDevice.AdvertisementPayload.HasServiceUUID(targetUUID) { + return + } + + // Stop the scan. + err := projVars.GlobalConfig.GetScanAdapter().StopScan() + if err != nil { + // Unlikely, but we can't recover from this. + log.Panic().Err(err). + Msg("failed to stop scan") + } + }) + if err != nil { + log.Error().Err(err). + Msg("failed to start scan") + return + } + + // Found a device: print this event. + if name := foundDevice.LocalName(); name == "" { + sublog = log.With().Str("MAC", foundDevice.Address.String()).Logger() + } else { + sublog = log.With().Str("MAC", foundDevice.Address.String()). + Str("Name", foundDevice.LocalName()).Logger() + } + + // Found a NUS peripheral. Connect to it. + device, err := projVars.GlobalConfig.GetScanAdapter().Connect(foundDevice.Address, bluetooth.ConnectionParams{}) + if err != nil { + sublog.Error().Err(err). + Msg("Failed to connect") + return + } + + // Connected. Look up the Nordic UART Service. + sublog.Info().Msg("Discovering services...") + services, err := device.DiscoverServices([]bluetooth.UUID{targetUUID}) + if err != nil { + log.Error().Err(err). + Msg("Failed to discover the Nordic UART Service") + return + } + service := services[0] + + // Discover all characteristics (we'll filter later) + chars, err := service.DiscoverCharacteristics([]bluetooth.UUID{}) + if err != nil { + log.Error().Err(err). + Msg("Failed to discover RX and TX characteristics") + return + } + rx := chars[0] + tx := chars[1] + + // Enable notifications to receive incoming data. + err = tx.EnableNotifications(func(value []byte) { + for _, c := range value { + rawterm.Putchar(c) + } + }) + if err != nil { + sublog.Error().Err(err). + Msg("Failed to enable TX notifications") + return + } + + sublog.Info().Msg("Connected. Exit console using Ctrl-X.") + rawterm.Configure() + defer rawterm.Restore() + var line []byte + for { + ch := rawterm.Getchar() + line = append(line, ch) + + // Send the current line to the central. + if ch == '\x18' { + // The user pressed Ctrl-X, exit the program. + break + } else if ch == '\n' { + sendbuf := line // copy buffer + // Reset the slice while keeping the buffer in place. + line = line[:0] + + // Send the sendbuf after breaking it up in pieces. + for len(sendbuf) != 0 { + // Chop off up to 20 bytes from the sendbuf. + partlen := 20 + if len(sendbuf) < 20 { + partlen = len(sendbuf) + } + part := sendbuf[:partlen] + sendbuf = sendbuf[partlen:] + // This performs a "write command" aka "write without response". + _, err := rx.WriteWithoutResponse(part) + if err != nil { + sublog.Error().Err(err). + Msg("could not send:") + } + } + } + } +}