Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1cc3eaa0fa | |||
| bf65c3cf45 | |||
| 456a1508c0 | |||
| 3991f1625f | |||
| 4c1493506d | |||
| 80e75061da | |||
| 5b48737cc7 | |||
| da2dac70ac | |||
| 8c8ea1209b | |||
| df3718a06c | |||
| 6486d04e61 | |||
| 96928ac43c | |||
| 8e7de3f59e | |||
| fbc0b7a66d | |||
| 78eda6672e | |||
| 9f05634531 | |||
| defc308a9d | |||
| 9a6c030a74 | |||
| afe2caddd6 | |||
| 8349bc7c3a | |||
| 04ab1cfc8d | |||
| d233fd850e | |||
| 948aca316b | |||
| 3f05737bf2 | |||
| 4aabf47a5d | |||
| cb47aef7e4 | |||
| bb05fcff6f | |||
| 8634ba84ca | |||
| 3bd6b9171e | |||
| 18a933ba45 | |||
| 0187d9a553 |
@@ -0,0 +1,12 @@
|
|||||||
|
# These are supported funding model platforms
|
||||||
|
|
||||||
|
github: [ullaakut] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||||
|
patreon: # Replace with a single Patreon username
|
||||||
|
open_collective: # Replace with a single Open Collective username
|
||||||
|
ko_fi: # Replace with a single Ko-fi username
|
||||||
|
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||||
|
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||||
|
liberapay: # Replace with a single Liberapay username
|
||||||
|
issuehunt: # Replace with a single IssueHunt username
|
||||||
|
otechie: # Replace with a single Otechie username
|
||||||
|
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
# https://github.com/golangci/golangci/wiki/Configuration
|
# https://github.com/golangci/golangci/wiki/Configuration
|
||||||
|
|
||||||
service:
|
service:
|
||||||
project-path: github.com/ullaakut/cameradar
|
project-path: github.com/Ullaakut/cameradar
|
||||||
prepare:
|
prepare:
|
||||||
- apt-get update && apt-get install -y libcurl4-gnutls-dev
|
- apt-get update && apt-get install -y libcurl4-gnutls-dev
|
||||||
- dep ensure
|
- dep ensure
|
||||||
|
|||||||
-17
@@ -33,8 +33,6 @@ before_install:
|
|||||||
- docker version
|
- docker version
|
||||||
|
|
||||||
install:
|
install:
|
||||||
# needed for the snap pipe:
|
|
||||||
- sudo snap install snapcraft --classic
|
|
||||||
- docker build -t cameradar .
|
- docker build -t cameradar .
|
||||||
|
|
||||||
script:
|
script:
|
||||||
@@ -59,21 +57,6 @@ script:
|
|||||||
- grep "Successful attack" logs.txt || exit 1
|
- grep "Successful attack" logs.txt || exit 1
|
||||||
- git clean -fd
|
- git clean -fd
|
||||||
|
|
||||||
after_success:
|
|
||||||
# You'll need to run `snapcraft export-login snap.login` and
|
|
||||||
# `travis encrypt-file snap.login --add` to add the key to the travis
|
|
||||||
# environment.
|
|
||||||
- test -n "$TRAVIS_TAG" && snapcraft login --with snap.login
|
|
||||||
|
|
||||||
# calls goreleaser
|
|
||||||
deploy:
|
|
||||||
- provider: script
|
|
||||||
skip_cleanup: true
|
|
||||||
script: curl -sL https://git.io/goreleaser | bash
|
|
||||||
on:
|
|
||||||
tags: true
|
|
||||||
condition: $TRAVIS_OS_NAME = linux
|
|
||||||
|
|
||||||
notifications:
|
notifications:
|
||||||
email:
|
email:
|
||||||
recipients:
|
recipients:
|
||||||
|
|||||||
+9
-5
@@ -1,8 +1,8 @@
|
|||||||
# Build stage
|
# Build stage
|
||||||
FROM golang:alpine AS build-env
|
FROM golang:alpine AS build-env
|
||||||
|
|
||||||
COPY . /go/src/github.com/ullaakut/cameradar
|
COPY . /go/src/github.com/Ullaakut/cameradar
|
||||||
WORKDIR /go/src/github.com/ullaakut/cameradar/cmd/cameradar
|
WORKDIR /go/src/github.com/Ullaakut/cameradar/cmd/cameradar
|
||||||
|
|
||||||
RUN apk update && \
|
RUN apk update && \
|
||||||
apk upgrade && \
|
apk upgrade && \
|
||||||
@@ -19,14 +19,18 @@ RUN go build -o cameradar
|
|||||||
# Final stage
|
# Final stage
|
||||||
FROM alpine
|
FROM alpine
|
||||||
|
|
||||||
|
# Necessary to install curl v7.64.0-r3.
|
||||||
|
# Fix for https://github.com/Ullaakut/cameradar/issues/247
|
||||||
|
RUN echo 'http://dl-cdn.alpinelinux.org/alpine/v3.9/main' >> /etc/apk/repositories
|
||||||
|
|
||||||
RUN apk --update add --no-cache nmap \
|
RUN apk --update add --no-cache nmap \
|
||||||
nmap-nselibs \
|
nmap-nselibs \
|
||||||
nmap-scripts \
|
nmap-scripts \
|
||||||
curl-dev
|
curl-dev==7.64.0-r5
|
||||||
|
|
||||||
WORKDIR /app/cameradar
|
WORKDIR /app/cameradar
|
||||||
COPY --from=build-env /go/src/github.com/ullaakut/cameradar/dictionaries/ /app/dictionaries/
|
COPY --from=build-env /go/src/github.com/Ullaakut/cameradar/dictionaries/ /app/dictionaries/
|
||||||
COPY --from=build-env /go/src/github.com/ullaakut/cameradar/cmd/cameradar/ /app/cameradar/
|
COPY --from=build-env /go/src/github.com/Ullaakut/cameradar/cmd/cameradar/ /app/cameradar/
|
||||||
|
|
||||||
ENV CAMERADAR_CUSTOM_ROUTES="/app/dictionaries/routes"
|
ENV CAMERADAR_CUSTOM_ROUTES="/app/dictionaries/routes"
|
||||||
ENV CAMERADAR_CUSTOM_CREDENTIALS="/app/dictionaries/credentials.json"
|
ENV CAMERADAR_CUSTOM_CREDENTIALS="/app/dictionaries/credentials.json"
|
||||||
|
|||||||
@@ -76,19 +76,19 @@ e.g.: `docker run -t ullaakut/cameradar -t 192.168.100.0/24` will scan the ports
|
|||||||
|
|
||||||
Only use this solution if for some reason using docker is not an option for you or if you want to locally build Cameradar on your machine.
|
Only use this solution if for some reason using docker is not an option for you or if you want to locally build Cameradar on your machine.
|
||||||
|
|
||||||
|
**WARNING**: Manually building the binary will **NOT WORK** for any camera that uses **DIGEST AUTHENTICATION** [if your version of `curl` is over `7.64.0`](https://github.com/Ullaakut/cameradar/pull/252), which is most likely the case. For more information, see [this response on the subject from the author of curl](https://stackoverflow.com/a/59778142/4145098).
|
||||||
|
|
||||||
### Dependencies
|
### Dependencies
|
||||||
|
|
||||||
* `go` (> `1.10`)
|
* `go` (> `1.10`)
|
||||||
|
* `libcurl` development library (**[version has to be <7.66.0](https://github.com/Ullaakut/cameradar/issues/247)**)
|
||||||
|
* For apt users: `apt install libcurl4-openssl-dev`
|
||||||
|
|
||||||
### Steps to install
|
### Steps to install
|
||||||
|
|
||||||
Make sure you installed the [dependencies](#dependencies), **and that you have Go modules enabled (`GO111MODULE=on`)**.
|
1. `go get github.com/Ullaakut/cameradar/v5`
|
||||||
|
2. `cd $GOPATH/src/github.com/Ullaakut/cameradar/cmd/cameradar`
|
||||||
1. `export GO111MODULE=on` (unless it's already on)
|
3. `go install`
|
||||||
2. `go get github.com/ullaakut/cameradar`
|
|
||||||
3. `cd $GOPATH/src/github.com/ullaakut/cameradar`
|
|
||||||
4. `cd cmd/cameradar`
|
|
||||||
5. `go install`
|
|
||||||
|
|
||||||
The `cameradar` binary is now in your `$GOPATH/bin` ready to be used. See command line options [here](#command-line-options).
|
The `cameradar` binary is now in your `$GOPATH/bin` ready to be used. See command line options [here](#command-line-options).
|
||||||
|
|
||||||
@@ -118,8 +118,9 @@ If you have [VLC Media Player](http://www.videolan.org/vlc/), you should be able
|
|||||||
|
|
||||||
* **"-t, --targets"**: Set target. Required. Target can be a file (see [instructions on how to format the file](#format-input-file)), an IP, an IP range, a subnetwork, or a combination of those. Example: `--targets="192.168.1.72,192.168.1.74"`
|
* **"-t, --targets"**: Set target. Required. Target can be a file (see [instructions on how to format the file](#format-input-file)), an IP, an IP range, a subnetwork, or a combination of those. Example: `--targets="192.168.1.72,192.168.1.74"`
|
||||||
* **"-p, --ports"**: (Default: `554,5554,8554`) Set custom ports.
|
* **"-p, --ports"**: (Default: `554,5554,8554`) Set custom ports.
|
||||||
* **"-s, --speed"**: (Default: `4`) Set custom nmap discovery presets to improve speed or accuracy. It's recommended to lower it if you are attempting to scan an unstable and slow network, or to increase it if on a very performant and reliable network. You might also want to keep it low to keep your discovery stealthy. See [this for more info on the nmap timing templates](https://nmap.org/book/man-performance.html).
|
* **"-s, --scan-speed"**: (Default: `4`) Set custom nmap discovery presets to improve speed or accuracy. It's recommended to lower it if you are attempting to scan an unstable and slow network, or to increase it if on a very performant and reliable network. You might also want to keep it low to keep your discovery stealthy. See [this for more info on the nmap timing templates](https://nmap.org/book/man-performance.html).
|
||||||
* **"-T, --timeout"**: (Default: `2000`) Set custom timeout value in miliseconds after which an attack attempt without an answer should give up. It's recommended to increase it when attempting to scan unstable and slow networks or to decrease it on very performant and reliable networks.
|
* **"-I, --attack-interval"**: (Default: `0ms`) Set custom interval after which an attack attempt without an answer should give up. It's recommended to increase it when attempting to scan unstable and slow networks or to decrease it on fast and reliable networks.
|
||||||
|
* **"-T, --timeout"**: (Default: `2000ms`) Set custom timeout value after which an attack attempt without an answer should give up. It's recommended to increase it when attempting to scan unstable and slow networks or to decrease it on fast and reliable networks.
|
||||||
* **"-r, --custom-routes"**: (Default: `<CAMERADAR_GOPATH>/dictionaries/routes`) Set custom dictionary path for routes
|
* **"-r, --custom-routes"**: (Default: `<CAMERADAR_GOPATH>/dictionaries/routes`) Set custom dictionary path for routes
|
||||||
* **"-c, --custom-credentials"**: (Default: `<CAMERADAR_GOPATH>/dictionaries/credentials.json`) Set custom dictionary path for credentials
|
* **"-c, --custom-credentials"**: (Default: `<CAMERADAR_GOPATH>/dictionaries/credentials.json`) Set custom dictionary path for credentials
|
||||||
* **"-o, --nmap-output"**: (Default: `/tmp/cameradar_scan.xml`) Set custom nmap output path
|
* **"-o, --nmap-output"**: (Default: `/tmp/cameradar_scan.xml`) Set custom nmap output path
|
||||||
@@ -131,7 +132,7 @@ If you have [VLC Media Player](http://www.videolan.org/vlc/), you should be able
|
|||||||
|
|
||||||
The file can contain IPs, hostnames, IP ranges and subnetwork, separated by newlines. Example:
|
The file can contain IPs, hostnames, IP ranges and subnetwork, separated by newlines. Example:
|
||||||
|
|
||||||
```go
|
```text
|
||||||
0.0.0.0
|
0.0.0.0
|
||||||
localhost
|
localhost
|
||||||
192.17.0.0/16
|
192.17.0.0/16
|
||||||
@@ -175,17 +176,23 @@ These variables are optional, allowing to replace the default dictionaries with
|
|||||||
|
|
||||||
Default values: `<CAMERADAR_GOPATH>/dictionaries/routes` and `<CAMERADAR_GOPATH>/dictionaries/credentials.json`
|
Default values: `<CAMERADAR_GOPATH>/dictionaries/routes` and `<CAMERADAR_GOPATH>/dictionaries/credentials.json`
|
||||||
|
|
||||||
### `CAMERADAR_SPEED`
|
### `CAMERADAR_SCAN_SPEED`
|
||||||
|
|
||||||
This optional variable allows you to set custom nmap discovery presets to improve speed or accuracy. It's recommended to lower it if you are attempting to scan an unstable and slow network, or to increase it if on a very performant and reliable network. See [this for more info on the nmap timing templates](https://nmap.org/book/man-performance.html).
|
This optional variable allows you to set custom nmap discovery presets to improve speed or accuracy. It's recommended to lower it if you are attempting to scan an unstable and slow network, or to increase it if on a fast and reliable network. See [this for more info on the nmap timing templates](https://nmap.org/book/man-performance.html).
|
||||||
|
|
||||||
Default value: `4`
|
Default value: `4`
|
||||||
|
|
||||||
|
### `CAMERADAR_ATTACK_INTERVAL`
|
||||||
|
|
||||||
|
This optional variable allows you to set `custom interval` to wait between each attack in order to stay stealthy. It's recommended to increase it when attempting to scan a network that might be protected against bruteforce attacks. By default, there is no interval, in order to make attacks as fast as possible
|
||||||
|
|
||||||
|
Default value: `0ms`
|
||||||
|
|
||||||
### `CAMERADAR_TIMEOUT`
|
### `CAMERADAR_TIMEOUT`
|
||||||
|
|
||||||
This optional variable allows you to set custom timeout value in miliseconds after which an attack attempt without an answer should give up. It's recommended to increase it when attempting to scan unstable and slow networks or to decrease it on very performant and reliable networks.
|
This optional variable allows you to set custom timeout value after which an attack attempt without an answer should give up. It's recommended to increase it when attempting to scan unstable and slow networks or to decrease it on fast and reliable networks.
|
||||||
|
|
||||||
Default value: `2000`
|
Default value: `2000ms`
|
||||||
|
|
||||||
### `CAMERADAR_LOGGING`
|
### `CAMERADAR_LOGGING`
|
||||||
|
|
||||||
@@ -201,24 +208,19 @@ Default: `false`
|
|||||||
|
|
||||||
#### Docker build
|
#### Docker build
|
||||||
|
|
||||||
To build the docker image, simply run `docker build -t . cameradar` in the root of the project.
|
To build the docker image, simply run `docker build . -t cameradar` in the root of the project.
|
||||||
|
|
||||||
Your image will be called `cameradar` and NOT `ullaakut/cameradar`.
|
Your image will be called `cameradar` and NOT `ullaakut/cameradar`.
|
||||||
|
|
||||||
#### Go build
|
#### Go build
|
||||||
|
|
||||||
Make sure you installed the [dependencies](#dependencies), **and that you have Go modules enabled (`GO111MODULE=on`)**.
|
1. `go get github.com/Ullaakut/cameradar`
|
||||||
|
2. `cd $GOPATH/src/github.com/Ullaakut/cameradar`
|
||||||
1. `export GO111MODULE=on` (unless it's already on)
|
3. `cd cmd/cameradar`
|
||||||
2. `go get github.com/ullaakut/cameradar`
|
4. `go install`
|
||||||
3. `cd $GOPATH/src/github.com/ullaakut/cameradar`
|
|
||||||
4. `cd cmd/cameradar`
|
|
||||||
5. `go install`
|
|
||||||
|
|
||||||
The cameradar binary is now in `$GOPATH/bin/cameradar`.
|
The cameradar binary is now in `$GOPATH/bin/cameradar`.
|
||||||
|
|
||||||
See [the contribution document](/CONTRIBUTING.md) to get started.
|
|
||||||
|
|
||||||
## Frequently Asked Questions
|
## Frequently Asked Questions
|
||||||
|
|
||||||
> Cameradar does not detect any camera!
|
> Cameradar does not detect any camera!
|
||||||
@@ -227,27 +229,27 @@ That means that either your cameras are not streaming in RTSP or that they are n
|
|||||||
|
|
||||||
> Cameradar detects my cameras, but does not manage to access them at all!
|
> Cameradar detects my cameras, but does not manage to access them at all!
|
||||||
|
|
||||||
Maybe your cameras have been configured and the credentials / URL have been changed. Cameradar only guesses using default constructor values if a custom dictionary is not provided. You can use your own dictionaries in which you just have to add your credentials and RTSP routes. To do that, see how the [configuration](#configuration) works. Also, maybe your camera's credentials are not yet known, in which case if you find them it would be very nice to add them to the Cameradar dictionaries to help other people in the future.
|
Maybe your cameras have been configured, and the credentials / URL have been changed. Cameradar only guesses using default constructor values if a custom dictionary is not provided. You can use your own dictionaries in which you just have to add your credentials and RTSP routes. To do that, see how the [configuration](#configuration) works. Also, maybe your camera's credentials are not yet known, in which case if you find them it would be very nice to add them to the Cameradar dictionaries to help other people in the future.
|
||||||
|
|
||||||
> What happened to the C++ version?
|
> What happened to the C++ version?
|
||||||
|
|
||||||
You can still find it under the 1.1.4 tag on this repo, however it was less performant and stable than the current version written in Golang. It is not recommended to use it.
|
You can still find it under the 1.1.4 tag on this repo, however it was slower and less stable than the current version written in Golang. It is not recommended using it.
|
||||||
|
|
||||||
> How to use the Cameradar library for my own project?
|
> How to use the Cameradar library for my own project?
|
||||||
|
|
||||||
See the example in `/cmd/cameradar`. You just need to run `go get github.com/ullaakut/cameradar` and to use the `cameradar` package in your code. You can find the documentation on [godoc](https://godoc.org/github.com/ullaakut/cameradar).
|
See the example in `/cmd/cameradar`. You just need to run `go get github.com/Ullaakut/cameradar` and to use the `cameradar` package in your code. You can find the documentation on [godoc](https://godoc.org/github.com/ullaakut/cameradar).
|
||||||
|
|
||||||
> I want to scan my own localhost for some reason and it does not work! What's going on?
|
> I want to scan my own localhost for some reason, and it does not work! What's going on?
|
||||||
|
|
||||||
Use the `--net=host` flag when launching the cameradar image, or use the binary by running `go run cameradar/cameradar.go` or [installing it](#installing-the-binary).
|
Use the `--net=host` flag when launching the cameradar image, or use the binary by running `go run cameradar/cameradar.go` or [installing it](#go-build).
|
||||||
|
|
||||||
> I don't see a colored output:(
|
> I don't see a colored output:(
|
||||||
|
|
||||||
You forgot the `-t` flag before `ullaakut/cameradar` in your command-line. This tells docker to allocate a pseudo-tty for cameradar, which makes it able to use colors.
|
You forgot the `-t` flag before `ullaakut/cameradar` in your command-line. This tells docker to allocate a pseudo-tty for cameradar, which makes it able to use colors.
|
||||||
|
|
||||||
> I don't have a camera but I'd like to try Cameradar!
|
> I don't have a camera, but I'd like to try Cameradar!
|
||||||
|
|
||||||
Simply run `docker run -p 8554:8554 -e RTSP_USERNAME=admin -e RTSP_PASSWORD=12345 -e RTSP_PORT=8554 ullaakut/rtspatt` and then run cameradar and it should guess that the username is admin and the password is 12345. You can try this with any default constructor credentials (they can be found [here](dictionaries/credentials.json)).
|
Simply run `docker run -p 8554:8554 -e RTSP_USERNAME=admin -e RTSP_PASSWORD=12345 -e RTSP_PORT=8554 ullaakut/rtspatt` and then run cameradar, and it should guess that the username is admin and that the password is 12345. You can try this with any default constructor credentials (they can be found [here](dictionaries/credentials.json)).
|
||||||
|
|
||||||
> What authentication types does Cameradar support?
|
> What authentication types does Cameradar support?
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
curl "github.com/ullaakut/go-curl"
|
"github.com/Ullaakut/go-curl"
|
||||||
)
|
)
|
||||||
|
|
||||||
// HTTP responses.
|
// HTTP responses.
|
||||||
@@ -21,10 +21,20 @@ const (
|
|||||||
rtspSetup = 4
|
rtspSetup = 4
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Authentication types.
|
||||||
|
const (
|
||||||
|
authNone = 0
|
||||||
|
authBasic = 1
|
||||||
|
authDigest = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
// Route that should never be a constructor default.
|
||||||
|
const dummyRoute = "/0x8b6c42"
|
||||||
|
|
||||||
// Attack attacks the given targets and returns the accessed streams.
|
// Attack attacks the given targets and returns the accessed streams.
|
||||||
func (s *Scanner) Attack(targets []Stream) ([]Stream, error) {
|
func (s *Scanner) Attack(targets []Stream) ([]Stream, error) {
|
||||||
if len(targets) == 0 {
|
if len(targets) == 0 {
|
||||||
return nil, fmt.Errorf("unable to attack empty list of targets")
|
return nil, fmt.Errorf("no stream found")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Most cameras will be accessed successfully with these two attacks.
|
// Most cameras will be accessed successfully with these two attacks.
|
||||||
@@ -63,6 +73,7 @@ func (s *Scanner) Attack(targets []Stream) ([]Stream, error) {
|
|||||||
func (s *Scanner) ValidateStreams(targets []Stream) []Stream {
|
func (s *Scanner) ValidateStreams(targets []Stream) []Stream {
|
||||||
for i := range targets {
|
for i := range targets {
|
||||||
targets[i].Available = s.validateStream(targets[i])
|
targets[i].Available = s.validateStream(targets[i])
|
||||||
|
time.Sleep(s.attackInterval)
|
||||||
}
|
}
|
||||||
|
|
||||||
return targets
|
return targets
|
||||||
@@ -75,20 +86,13 @@ func (s *Scanner) AttackCredentials(targets []Stream) []Stream {
|
|||||||
defer close(resChan)
|
defer close(resChan)
|
||||||
|
|
||||||
for i := range targets {
|
for i := range targets {
|
||||||
// TODO: Perf Improvement: Skip cameras with no auth type detected, and set their
|
|
||||||
// CredentialsFound value to true.
|
|
||||||
go s.attackCameraCredentials(targets[i], resChan)
|
go s.attackCameraCredentials(targets[i], resChan)
|
||||||
}
|
}
|
||||||
|
|
||||||
attackResults := []Stream{}
|
|
||||||
// TODO: Change this into a for+select and make a successful result close the chan.
|
|
||||||
for range targets {
|
for range targets {
|
||||||
attackResults = append(attackResults, <-resChan)
|
attackResult := <-resChan
|
||||||
}
|
if attackResult.CredentialsFound {
|
||||||
|
targets = replace(targets, attackResult)
|
||||||
for i := range attackResults {
|
|
||||||
if attackResults[i].CredentialsFound {
|
|
||||||
targets = replace(targets, attackResults[i])
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,15 +109,10 @@ func (s *Scanner) AttackRoute(targets []Stream) []Stream {
|
|||||||
go s.attackCameraRoute(targets[i], resChan)
|
go s.attackCameraRoute(targets[i], resChan)
|
||||||
}
|
}
|
||||||
|
|
||||||
attackResults := []Stream{}
|
|
||||||
// TODO: Change this into a for+select and make a successful result close the chan.
|
|
||||||
for range targets {
|
for range targets {
|
||||||
attackResults = append(attackResults, <-resChan)
|
attackResult := <-resChan
|
||||||
}
|
if attackResult.RouteFound {
|
||||||
|
targets = replace(targets, attackResult)
|
||||||
for i := range attackResults {
|
|
||||||
if attackResults[i].RouteFound {
|
|
||||||
targets = replace(targets, attackResults[i])
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,14 +124,15 @@ func (s *Scanner) AttackRoute(targets []Stream) []Stream {
|
|||||||
func (s *Scanner) DetectAuthMethods(targets []Stream) []Stream {
|
func (s *Scanner) DetectAuthMethods(targets []Stream) []Stream {
|
||||||
for i := range targets {
|
for i := range targets {
|
||||||
targets[i].AuthenticationType = s.detectAuthMethod(targets[i])
|
targets[i].AuthenticationType = s.detectAuthMethod(targets[i])
|
||||||
|
time.Sleep(s.attackInterval)
|
||||||
|
|
||||||
var authMethod string
|
var authMethod string
|
||||||
switch targets[i].AuthenticationType {
|
switch targets[i].AuthenticationType {
|
||||||
case 0:
|
case authNone:
|
||||||
authMethod = "no"
|
authMethod = "no"
|
||||||
case 1:
|
case authBasic:
|
||||||
authMethod = "basic"
|
authMethod = "basic"
|
||||||
case 2:
|
case authDigest:
|
||||||
authMethod = "digest"
|
authMethod = "digest"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,6 +153,7 @@ func (s *Scanner) attackCameraCredentials(target Stream, resChan chan<- Stream)
|
|||||||
resChan <- target
|
resChan <- target
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
time.Sleep(s.attackInterval)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,17 +162,27 @@ func (s *Scanner) attackCameraCredentials(target Stream, resChan chan<- Stream)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Scanner) attackCameraRoute(target Stream, resChan chan<- Stream) {
|
func (s *Scanner) attackCameraRoute(target Stream, resChan chan<- Stream) {
|
||||||
|
// If the stream responds positively to the dummy route, it means
|
||||||
|
// it doesn't require (or respect the RFC) a route and the attack
|
||||||
|
// can be skipped.
|
||||||
|
ok := s.routeAttack(target, dummyRoute)
|
||||||
|
if ok {
|
||||||
|
target.RouteFound = true
|
||||||
|
target.Routes = append(target.Routes, "/")
|
||||||
|
resChan <- target
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, bruteforce the routes.
|
||||||
for _, route := range s.routes {
|
for _, route := range s.routes {
|
||||||
ok := s.routeAttack(target, route)
|
ok := s.routeAttack(target, route)
|
||||||
if ok {
|
if ok {
|
||||||
target.RouteFound = true
|
target.RouteFound = true
|
||||||
target.Route = route
|
target.Routes = append(target.Routes, route)
|
||||||
resChan <- target
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
time.Sleep(s.attackInterval)
|
||||||
}
|
}
|
||||||
|
|
||||||
target.RouteFound = false
|
|
||||||
resChan <- target
|
resChan <- target
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,7 +193,7 @@ func (s *Scanner) detectAuthMethod(stream Stream) int {
|
|||||||
"rtsp://%s:%d/%s",
|
"rtsp://%s:%d/%s",
|
||||||
stream.Address,
|
stream.Address,
|
||||||
stream.Port,
|
stream.Port,
|
||||||
stream.Route,
|
stream.Route(),
|
||||||
)
|
)
|
||||||
|
|
||||||
s.setCurlOptions(c)
|
s.setCurlOptions(c)
|
||||||
@@ -191,13 +202,12 @@ func (s *Scanner) detectAuthMethod(stream Stream) int {
|
|||||||
_ = c.Setopt(curl.OPT_URL, attackURL)
|
_ = c.Setopt(curl.OPT_URL, attackURL)
|
||||||
// Set the RTSP STREAM URI as the stream URL.
|
// Set the RTSP STREAM URI as the stream URL.
|
||||||
_ = c.Setopt(curl.OPT_RTSP_STREAM_URI, attackURL)
|
_ = c.Setopt(curl.OPT_RTSP_STREAM_URI, attackURL)
|
||||||
// 2 is CURL_RTSPREQ_DESCRIBE.
|
_ = c.Setopt(curl.OPT_RTSP_REQUEST, rtspDescribe)
|
||||||
_ = c.Setopt(curl.OPT_RTSP_REQUEST, 2)
|
|
||||||
|
|
||||||
// Perform the request.
|
// Perform the request.
|
||||||
err := c.Perform()
|
err := c.Perform()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.term.Errorf("Perform failed: %v", err)
|
s.term.Errorf("Perform failed for %q (auth %d): %v", attackURL, stream.AuthenticationType, err)
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,7 +217,7 @@ func (s *Scanner) detectAuthMethod(stream Stream) int {
|
|||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.verbose {
|
if s.debug {
|
||||||
s.term.Debugln("DESCRIBE", attackURL, "RTSP/1.0 >", authType)
|
s.term.Debugln("DESCRIBE", attackURL, "RTSP/1.0 >", authType)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,13 +246,12 @@ func (s *Scanner) routeAttack(stream Stream, route string) bool {
|
|||||||
_ = c.Setopt(curl.OPT_URL, attackURL)
|
_ = c.Setopt(curl.OPT_URL, attackURL)
|
||||||
// Set the RTSP STREAM URI as the stream URL.
|
// Set the RTSP STREAM URI as the stream URL.
|
||||||
_ = c.Setopt(curl.OPT_RTSP_STREAM_URI, attackURL)
|
_ = c.Setopt(curl.OPT_RTSP_STREAM_URI, attackURL)
|
||||||
// 2 is CURL_RTSPREQ_DESCRIBE.
|
|
||||||
_ = c.Setopt(curl.OPT_RTSP_REQUEST, rtspDescribe)
|
_ = c.Setopt(curl.OPT_RTSP_REQUEST, rtspDescribe)
|
||||||
|
|
||||||
// Perform the request.
|
// Perform the request.
|
||||||
err := c.Perform()
|
err := c.Perform()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.term.Errorf("Perform failed: %v", err)
|
s.term.Errorf("Perform failed for %q (auth %d): %v", attackURL, stream.AuthenticationType, err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -253,7 +262,7 @@ func (s *Scanner) routeAttack(stream Stream, route string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.verbose {
|
if s.debug {
|
||||||
s.term.Debugln("DESCRIBE", attackURL, "RTSP/1.0 >", rc)
|
s.term.Debugln("DESCRIBE", attackURL, "RTSP/1.0 >", rc)
|
||||||
}
|
}
|
||||||
// If it's a 401 or 403, it means that the credentials are wrong but the route might be okay.
|
// If it's a 401 or 403, it means that the credentials are wrong but the route might be okay.
|
||||||
@@ -273,7 +282,7 @@ func (s *Scanner) credAttack(stream Stream, username string, password string) bo
|
|||||||
password,
|
password,
|
||||||
stream.Address,
|
stream.Address,
|
||||||
stream.Port,
|
stream.Port,
|
||||||
stream.Route,
|
stream.Route(),
|
||||||
)
|
)
|
||||||
|
|
||||||
s.setCurlOptions(c)
|
s.setCurlOptions(c)
|
||||||
@@ -286,13 +295,12 @@ func (s *Scanner) credAttack(stream Stream, username string, password string) bo
|
|||||||
_ = c.Setopt(curl.OPT_URL, attackURL)
|
_ = c.Setopt(curl.OPT_URL, attackURL)
|
||||||
// Set the RTSP STREAM URI as the stream URL.
|
// Set the RTSP STREAM URI as the stream URL.
|
||||||
_ = c.Setopt(curl.OPT_RTSP_STREAM_URI, attackURL)
|
_ = c.Setopt(curl.OPT_RTSP_STREAM_URI, attackURL)
|
||||||
// 2 is CURL_RTSPREQ_DESCRIBE.
|
_ = c.Setopt(curl.OPT_RTSP_REQUEST, rtspDescribe)
|
||||||
_ = c.Setopt(curl.OPT_RTSP_REQUEST, 2)
|
|
||||||
|
|
||||||
// Perform the request.
|
// Perform the request.
|
||||||
err := c.Perform()
|
err := c.Perform()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.term.Errorf("Perform failed: %v", err)
|
s.term.Errorf("Perform failed for %q (auth %d): %v", attackURL, stream.AuthenticationType, err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -303,7 +311,7 @@ func (s *Scanner) credAttack(stream Stream, username string, password string) bo
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.verbose {
|
if s.debug {
|
||||||
s.term.Debugln("DESCRIBE", attackURL, "RTSP/1.0 >", rc)
|
s.term.Debugln("DESCRIBE", attackURL, "RTSP/1.0 >", rc)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -324,7 +332,7 @@ func (s *Scanner) validateStream(stream Stream) bool {
|
|||||||
stream.Password,
|
stream.Password,
|
||||||
stream.Address,
|
stream.Address,
|
||||||
stream.Port,
|
stream.Port,
|
||||||
stream.Route,
|
stream.Route(),
|
||||||
)
|
)
|
||||||
|
|
||||||
s.setCurlOptions(c)
|
s.setCurlOptions(c)
|
||||||
@@ -337,7 +345,6 @@ func (s *Scanner) validateStream(stream Stream) bool {
|
|||||||
_ = c.Setopt(curl.OPT_URL, attackURL)
|
_ = c.Setopt(curl.OPT_URL, attackURL)
|
||||||
// Set the RTSP STREAM URI as the stream URL.
|
// Set the RTSP STREAM URI as the stream URL.
|
||||||
_ = c.Setopt(curl.OPT_RTSP_STREAM_URI, attackURL)
|
_ = c.Setopt(curl.OPT_RTSP_STREAM_URI, attackURL)
|
||||||
// 2 is CURL_RTSPREQ_SETUP.
|
|
||||||
_ = c.Setopt(curl.OPT_RTSP_REQUEST, rtspSetup)
|
_ = c.Setopt(curl.OPT_RTSP_REQUEST, rtspSetup)
|
||||||
|
|
||||||
_ = c.Setopt(curl.OPT_RTSP_TRANSPORT, "RTP/AVP;unicast;client_port=33332-33333")
|
_ = c.Setopt(curl.OPT_RTSP_TRANSPORT, "RTP/AVP;unicast;client_port=33332-33333")
|
||||||
@@ -345,7 +352,7 @@ func (s *Scanner) validateStream(stream Stream) bool {
|
|||||||
// Perform the request.
|
// Perform the request.
|
||||||
err := c.Perform()
|
err := c.Perform()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.term.Errorf("Perform failed: %v", err)
|
s.term.Errorf("Perform failed for %q (auth %d): %v", attackURL, stream.AuthenticationType, err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -356,9 +363,10 @@ func (s *Scanner) validateStream(stream Stream) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.verbose {
|
if s.debug {
|
||||||
s.term.Debugln("SETUP", attackURL, "RTSP/1.0 >", rc)
|
s.term.Debugln("SETUP", attackURL, "RTSP/1.0 >", rc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If it's a 200, the stream is accessed successfully.
|
// If it's a 200, the stream is accessed successfully.
|
||||||
if rc == httpOK {
|
if rc == httpOK {
|
||||||
return true
|
return true
|
||||||
@@ -375,6 +383,13 @@ func (s *Scanner) setCurlOptions(c Curler) {
|
|||||||
_ = c.Setopt(curl.OPT_NOBODY, 1)
|
_ = c.Setopt(curl.OPT_NOBODY, 1)
|
||||||
// Set custom timeout.
|
// Set custom timeout.
|
||||||
_ = c.Setopt(curl.OPT_TIMEOUT_MS, int(s.timeout/time.Millisecond))
|
_ = c.Setopt(curl.OPT_TIMEOUT_MS, int(s.timeout/time.Millisecond))
|
||||||
|
|
||||||
|
// Enable verbose logs if verbose mode is on.
|
||||||
|
if s.verbose {
|
||||||
|
_ = c.Setopt(curl.OPT_VERBOSE, 1)
|
||||||
|
} else {
|
||||||
|
_ = c.Setopt(curl.OPT_VERBOSE, 0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// HACK: See https://stackoverflow.com/questions/3572397/lib-curl-in-c-disable-printing
|
// HACK: See https://stackoverflow.com/questions/3572397/lib-curl-in-c-disable-printing
|
||||||
|
|||||||
+103
-4
@@ -6,10 +6,10 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/Ullaakut/disgo"
|
||||||
|
"github.com/Ullaakut/go-curl"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/mock"
|
"github.com/stretchr/testify/mock"
|
||||||
"github.com/ullaakut/disgo"
|
|
||||||
curl "github.com/ullaakut/go-curl"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type CurlerMock struct {
|
type CurlerMock struct {
|
||||||
@@ -89,7 +89,7 @@ func TestAttack(t *testing.T) {
|
|||||||
targets: nil,
|
targets: nil,
|
||||||
|
|
||||||
expectedStreams: nil,
|
expectedStreams: nil,
|
||||||
expectedErr: errors.New("unable to attack empty list of targets"),
|
expectedErr: errors.New("no stream found"),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,7 +109,8 @@ func TestAttack(t *testing.T) {
|
|||||||
term: disgo.NewTerminal(disgo.WithDefaultOutput(ioutil.Discard)),
|
term: disgo.NewTerminal(disgo.WithDefaultOutput(ioutil.Discard)),
|
||||||
curl: curlerMock,
|
curl: curlerMock,
|
||||||
timeout: time.Millisecond,
|
timeout: time.Millisecond,
|
||||||
verbose: false,
|
verbose: true,
|
||||||
|
debug: true,
|
||||||
credentials: fakeCredentials,
|
credentials: fakeCredentials,
|
||||||
routes: fakeRoutes,
|
routes: fakeRoutes,
|
||||||
}
|
}
|
||||||
@@ -251,6 +252,7 @@ func TestAttackCredentials(t *testing.T) {
|
|||||||
curl: curlerMock,
|
curl: curlerMock,
|
||||||
timeout: test.timeout,
|
timeout: test.timeout,
|
||||||
verbose: test.verbose,
|
verbose: test.verbose,
|
||||||
|
debug: test.verbose,
|
||||||
credentials: test.credentials,
|
credentials: test.credentials,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -389,6 +391,102 @@ func TestAttackRoute(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scanner := &Scanner{
|
||||||
|
term: disgo.NewTerminal(disgo.WithDefaultOutput(ioutil.Discard)),
|
||||||
|
curl: curlerMock,
|
||||||
|
timeout: test.timeout,
|
||||||
|
verbose: test.verbose,
|
||||||
|
debug: test.verbose,
|
||||||
|
routes: test.routes,
|
||||||
|
}
|
||||||
|
|
||||||
|
results := scanner.AttackRoute(test.targets)
|
||||||
|
|
||||||
|
assert.Len(t, results, len(test.expectedStreams))
|
||||||
|
|
||||||
|
curlerMock.AssertExpectations(t)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAttackRoute_NoDummyRoute(t *testing.T) {
|
||||||
|
var (
|
||||||
|
stream1 = Stream{
|
||||||
|
Device: "fakeDevice",
|
||||||
|
Address: "fakeAddress",
|
||||||
|
Port: 1337,
|
||||||
|
Available: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
stream2 = Stream{
|
||||||
|
Device: "fakeDevice",
|
||||||
|
Address: "differentFakeAddress",
|
||||||
|
Port: 1337,
|
||||||
|
Available: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
fakeTargets = []Stream{stream1, stream2}
|
||||||
|
fakeRoutes = Routes{"live.sdp", "media.amp"}
|
||||||
|
)
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
description string
|
||||||
|
|
||||||
|
targets []Stream
|
||||||
|
routes Routes
|
||||||
|
timeout time.Duration
|
||||||
|
verbose bool
|
||||||
|
|
||||||
|
status int
|
||||||
|
|
||||||
|
expectedStreams []Stream
|
||||||
|
expectedErr error
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
description: "Route found",
|
||||||
|
|
||||||
|
targets: fakeTargets,
|
||||||
|
routes: fakeRoutes,
|
||||||
|
timeout: 1 * time.Millisecond,
|
||||||
|
|
||||||
|
status: 403,
|
||||||
|
|
||||||
|
expectedStreams: fakeTargets,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Route found",
|
||||||
|
|
||||||
|
targets: fakeTargets,
|
||||||
|
routes: fakeRoutes,
|
||||||
|
timeout: 1 * time.Millisecond,
|
||||||
|
|
||||||
|
status: 401,
|
||||||
|
|
||||||
|
expectedStreams: fakeTargets,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Camera accessed",
|
||||||
|
|
||||||
|
targets: fakeTargets,
|
||||||
|
routes: fakeRoutes,
|
||||||
|
timeout: 1 * time.Millisecond,
|
||||||
|
|
||||||
|
status: 200,
|
||||||
|
|
||||||
|
expectedStreams: fakeTargets,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.description, func(t *testing.T) {
|
||||||
|
curlerMock := &CurlerMock{}
|
||||||
|
curlerMock.On("Setopt", mock.Anything, mock.Anything).Return(nil)
|
||||||
|
curlerMock.On("Perform").Return(nil)
|
||||||
|
|
||||||
|
// 404 on first call to the dummy route.
|
||||||
|
curlerMock.On("Getinfo", mock.Anything).Return(404, nil).Once()
|
||||||
|
curlerMock.On("Getinfo", mock.Anything).Return(test.status, nil)
|
||||||
|
|
||||||
scanner := &Scanner{
|
scanner := &Scanner{
|
||||||
term: disgo.NewTerminal(disgo.WithDefaultOutput(ioutil.Discard)),
|
term: disgo.NewTerminal(disgo.WithDefaultOutput(ioutil.Discard)),
|
||||||
curl: curlerMock,
|
curl: curlerMock,
|
||||||
@@ -534,6 +632,7 @@ func TestValidateStreams(t *testing.T) {
|
|||||||
curl: curlerMock,
|
curl: curlerMock,
|
||||||
timeout: test.timeout,
|
timeout: test.timeout,
|
||||||
verbose: test.verbose,
|
verbose: test.verbose,
|
||||||
|
debug: test.verbose,
|
||||||
}
|
}
|
||||||
|
|
||||||
results := scanner.ValidateStreams(test.targets)
|
results := scanner.ValidateStreams(test.targets)
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@
|
|||||||
// IP Cameras, often for surveillance.
|
// IP Cameras, often for surveillance.
|
||||||
//
|
//
|
||||||
// A simple example usage of the library can be found in
|
// A simple example usage of the library can be found in
|
||||||
// https://github.com/ullaakut/cameradar/tree/master/cameradar
|
// https://github.com/Ullaakut/cameradar/tree/master/cameradar
|
||||||
//
|
//
|
||||||
// The example usage is complete enough for most users to
|
// The example usage is complete enough for most users to
|
||||||
// ignore the library, but for users with specific needs
|
// ignore the library, but for users with specific needs
|
||||||
|
|||||||
+14
-10
@@ -7,11 +7,11 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/Ullaakut/cameradar/v5"
|
||||||
|
"github.com/Ullaakut/disgo"
|
||||||
|
"github.com/Ullaakut/disgo/style"
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
"github.com/ullaakut/cameradar"
|
|
||||||
"github.com/ullaakut/disgo"
|
|
||||||
"github.com/ullaakut/disgo/style"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func parseArguments() error {
|
func parseArguments() error {
|
||||||
@@ -20,11 +20,12 @@ func parseArguments() error {
|
|||||||
|
|
||||||
pflag.StringSliceP("targets", "t", []string{}, "The targets on which to scan for open RTSP streams - required (ex: 172.16.100.0/24)")
|
pflag.StringSliceP("targets", "t", []string{}, "The targets on which to scan for open RTSP streams - required (ex: 172.16.100.0/24)")
|
||||||
pflag.StringSliceP("ports", "p", []string{"554", "5554", "8554"}, "The ports on which to search for RTSP streams")
|
pflag.StringSliceP("ports", "p", []string{"554", "5554", "8554"}, "The ports on which to search for RTSP streams")
|
||||||
pflag.StringP("custom-routes", "r", "${GOPATH}/src/github.com/ullaakut/cameradar/dictionaries/routes", "The path on which to load a custom routes dictionary")
|
pflag.StringP("custom-routes", "r", "${GOPATH}/src/github.com/Ullaakut/cameradar/dictionaries/routes", "The path on which to load a custom routes dictionary")
|
||||||
pflag.StringP("custom-credentials", "c", "${GOPATH}/src/github.com/ullaakut/cameradar/dictionaries/credentials.json", "The path on which to load a custom credentials JSON dictionary")
|
pflag.StringP("custom-credentials", "c", "${GOPATH}/src/github.com/Ullaakut/cameradar/dictionaries/credentials.json", "The path on which to load a custom credentials JSON dictionary")
|
||||||
pflag.IntP("speed", "s", 4, "The nmap speed preset to use for discovery")
|
pflag.IntP("scan-speed", "s", 4, "The nmap speed preset to use for scanning (lower is stealthier)")
|
||||||
pflag.DurationP("timeout", "T", 2*time.Second, "The timeout in miliseconds to use for attack attempts")
|
pflag.DurationP("attack-interval", "I", 0, "The interval between each attack (i.e: 2000ms, higher is stealthier)")
|
||||||
pflag.BoolP("debug", "d", true, "Enable the debug logs")
|
pflag.DurationP("timeout", "T", 2000*time.Millisecond, "The timeout to use for attack attempts (i.e: 2000ms)")
|
||||||
|
pflag.BoolP("debug", "d", false, "Enable the debug logs")
|
||||||
pflag.BoolP("verbose", "v", false, "Enable the verbose logs")
|
pflag.BoolP("verbose", "v", false, "Enable the verbose logs")
|
||||||
pflag.BoolP("help", "h", false, "displays this help message")
|
pflag.BoolP("help", "h", false, "displays this help message")
|
||||||
|
|
||||||
@@ -43,10 +44,12 @@ func parseArguments() error {
|
|||||||
fmt.Println("\tScanning your home network for RTSP streams:\tcameradar -t 192.168.0.0/24")
|
fmt.Println("\tScanning your home network for RTSP streams:\tcameradar -t 192.168.0.0/24")
|
||||||
fmt.Println("\tScanning a remote camera on a specific port:\tcameradar -t 172.178.10.14 -p 18554 -s 2")
|
fmt.Println("\tScanning a remote camera on a specific port:\tcameradar -t 172.178.10.14 -p 18554 -s 2")
|
||||||
fmt.Println("\tScanning an unstable remote network: \t\tcameradar -t 172.178.10.14/24 -s 1 --timeout 10000 -l")
|
fmt.Println("\tScanning an unstable remote network: \t\tcameradar -t 172.178.10.14/24 -s 1 --timeout 10000 -l")
|
||||||
|
fmt.Println("\tStealthily scanning a remote network: \t\tcameradar -t 172.178.10.14/24 -s 1 -I 5000")
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
if viper.GetStringSlice("targets") == nil {
|
if len(viper.GetStringSlice("targets")) == 0 {
|
||||||
|
pflag.Usage()
|
||||||
return errors.New("targets (-t, --targets) argument required\n examples:\n - 172.16.100.0/24\n - localhost\n - 8.8.8.8")
|
return errors.New("targets (-t, --targets) argument required\n examples:\n - 172.16.100.0/24\n - localhost\n - 8.8.8.8")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,7 +69,8 @@ func main() {
|
|||||||
cameradar.WithVerbose(viper.GetBool("verbose")),
|
cameradar.WithVerbose(viper.GetBool("verbose")),
|
||||||
cameradar.WithCustomCredentials(viper.GetString("custom-credentials")),
|
cameradar.WithCustomCredentials(viper.GetString("custom-credentials")),
|
||||||
cameradar.WithCustomRoutes(viper.GetString("custom-routes")),
|
cameradar.WithCustomRoutes(viper.GetString("custom-routes")),
|
||||||
cameradar.WithSpeed(viper.GetInt("speed")),
|
cameradar.WithScanSpeed(viper.GetInt("scan-speed")),
|
||||||
|
cameradar.WithAttackInterval(viper.GetDuration("attack-interval")),
|
||||||
cameradar.WithTimeout(viper.GetDuration("timeout")),
|
cameradar.WithTimeout(viper.GetDuration("timeout")),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package cameradar
|
package cameradar
|
||||||
|
|
||||||
import (
|
import (
|
||||||
curl "github.com/ullaakut/go-curl"
|
curl "github.com/Ullaakut/go-curl"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Curler is an interface that implements the CURL interface of the go-curl library
|
// Curler is an interface that implements the CURL interface of the go-curl library
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
curl "github.com/ullaakut/go-curl"
|
curl "github.com/Ullaakut/go-curl"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCurl(t *testing.T) {
|
func TestCurl(t *testing.T) {
|
||||||
|
|||||||
@@ -17,29 +17,55 @@
|
|||||||
],
|
],
|
||||||
"passwords": [
|
"passwords": [
|
||||||
"",
|
"",
|
||||||
|
"0000",
|
||||||
|
"00000",
|
||||||
"111111",
|
"111111",
|
||||||
"1111111",
|
"1111111",
|
||||||
|
"123",
|
||||||
"1234",
|
"1234",
|
||||||
"12345",
|
"12345",
|
||||||
"123456",
|
"123456",
|
||||||
|
"1234567",
|
||||||
|
"12345678",
|
||||||
|
"123456789",
|
||||||
|
"12345678910",
|
||||||
"4321",
|
"4321",
|
||||||
"666666",
|
"666666",
|
||||||
|
"6fJjMKYx",
|
||||||
"888888",
|
"888888",
|
||||||
"9999",
|
"9999",
|
||||||
"admin",
|
"admin",
|
||||||
|
"Admin",
|
||||||
|
"admin123",
|
||||||
|
"administrator",
|
||||||
|
"Administrator",
|
||||||
"aiphone",
|
"aiphone",
|
||||||
"camera",
|
"camera",
|
||||||
"fliradmin",
|
"fliradmin",
|
||||||
|
"GRwvcj8j",
|
||||||
|
"hikvision",
|
||||||
|
"hikadmin",
|
||||||
"ikwd",
|
"ikwd",
|
||||||
"jvc",
|
"jvc",
|
||||||
|
"kj3TqCWv",
|
||||||
"meinsm",
|
"meinsm",
|
||||||
"pass",
|
"pass",
|
||||||
"password",
|
"password",
|
||||||
|
"password123",
|
||||||
|
"qwerty",
|
||||||
|
"qwerty123",
|
||||||
|
"reolink",
|
||||||
"root",
|
"root",
|
||||||
"service",
|
"service",
|
||||||
"supervisor",
|
"supervisor",
|
||||||
|
"support",
|
||||||
"system",
|
"system",
|
||||||
|
"tlJwpbo6",
|
||||||
|
"toor",
|
||||||
|
"tp-link",
|
||||||
"ubnt",
|
"ubnt",
|
||||||
"wbox123"
|
"user",
|
||||||
|
"wbox123",
|
||||||
|
"Y5eIMz3C"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
+54
-27
@@ -1,4 +1,5 @@
|
|||||||
|
|
||||||
|
/live/ch01_0
|
||||||
0/1:1/main
|
0/1:1/main
|
||||||
0/usrnm:pwd/main
|
0/usrnm:pwd/main
|
||||||
0/video1
|
0/video1
|
||||||
@@ -9,7 +10,29 @@
|
|||||||
11
|
11
|
||||||
12
|
12
|
||||||
125
|
125
|
||||||
|
1080p
|
||||||
|
1440p
|
||||||
|
480p
|
||||||
|
4K
|
||||||
666
|
666
|
||||||
|
720p
|
||||||
|
AVStream1_1
|
||||||
|
CAM_ID.password.mp2
|
||||||
|
CH001.sdp
|
||||||
|
GetData.cgi
|
||||||
|
HD
|
||||||
|
HighResolutionVideo
|
||||||
|
LowResolutionVideo
|
||||||
|
MediaInput/h264
|
||||||
|
MediaInput/mpeg4
|
||||||
|
ONVIF/MediaInput
|
||||||
|
ONVIF/MediaInput?profile=4_def_profile6
|
||||||
|
StdCh1
|
||||||
|
Streaming/Channels/1
|
||||||
|
Streaming/Unicast/channels/101
|
||||||
|
StreamingSetting?version=1.0&action=getRTSPStream&ChannelID=1&ChannelName=Channel1
|
||||||
|
VideoInput/1/h264/1
|
||||||
|
VideoInput/1/mpeg4/1
|
||||||
access_code
|
access_code
|
||||||
access_name_for_stream_1_to_5
|
access_name_for_stream_1_to_5
|
||||||
api/mjpegvideo.cgi
|
api/mjpegvideo.cgi
|
||||||
@@ -17,18 +40,19 @@ av0_0
|
|||||||
av2
|
av2
|
||||||
avc
|
avc
|
||||||
avn=2
|
avn=2
|
||||||
AVStream1_1
|
|
||||||
axis-media/media.amp
|
axis-media/media.amp
|
||||||
axis-media/media.amp?camera=1
|
axis-media/media.amp?camera=1
|
||||||
axis-media/media.amp?videocodec=h264
|
axis-media/media.amp?videocodec=h264
|
||||||
cam
|
cam
|
||||||
CAM_ID.password.mp2
|
|
||||||
cam/realmonitor
|
cam/realmonitor
|
||||||
cam/realmonitor?channel=0&subtype=0
|
cam/realmonitor?channel=0&subtype=0
|
||||||
cam/realmonitor?channel=1&subtype=0
|
cam/realmonitor?channel=1&subtype=0
|
||||||
|
cam/realmonitor?channel=1&subtype=1
|
||||||
cam/realmonitor?channel=1&subtype=1&unicast=true&proto=Onvif
|
cam/realmonitor?channel=1&subtype=1&unicast=true&proto=Onvif
|
||||||
|
cam0
|
||||||
cam0_0
|
cam0_0
|
||||||
cam0_1
|
cam0_1
|
||||||
|
cam1
|
||||||
cam1/h264
|
cam1/h264
|
||||||
cam1/h264/multicast
|
cam1/h264/multicast
|
||||||
cam1/mjpeg
|
cam1/mjpeg
|
||||||
@@ -37,39 +61,43 @@ cam1/mpeg4?user='username'&pwd='password'
|
|||||||
cam1/onvif-h264
|
cam1/onvif-h264
|
||||||
camera.stm
|
camera.stm
|
||||||
ch0
|
ch0
|
||||||
ch0_0.h264
|
|
||||||
ch0_unicast_firststream
|
|
||||||
ch0_unicast_secondstream
|
|
||||||
ch00/0
|
ch00/0
|
||||||
ch001.sdp
|
ch001.sdp
|
||||||
CH001.sdp
|
|
||||||
ch01.264
|
ch01.264
|
||||||
ch01.264?
|
ch01.264?
|
||||||
ch01.264?ptype=tcp
|
ch01.264?ptype=tcp
|
||||||
|
ch1_0
|
||||||
|
ch2_0
|
||||||
|
ch3_0
|
||||||
|
ch4_0
|
||||||
|
ch1/0
|
||||||
|
ch2/0
|
||||||
|
ch3/0
|
||||||
|
ch4/0
|
||||||
|
ch0_0.h264
|
||||||
|
ch0_unicast_firststream
|
||||||
|
ch0_unicast_secondstream
|
||||||
ch1-s1
|
ch1-s1
|
||||||
channel1
|
channel1
|
||||||
GetData.cgi
|
|
||||||
gnz_media/main
|
gnz_media/main
|
||||||
h264
|
h264
|
||||||
h264_vga.sdp
|
|
||||||
h264.sdp
|
h264.sdp
|
||||||
h264/ch1/sub/av_stream
|
h264/ch1/sub/av_stream
|
||||||
h264/media.amp
|
h264/media.amp
|
||||||
h264Preview_01_main
|
h264Preview_01_main
|
||||||
h264Preview_01_sub
|
h264Preview_01_sub
|
||||||
HighResolutionVideo
|
h264_vga.sdp
|
||||||
|
h264_stream
|
||||||
image.mpg
|
image.mpg
|
||||||
img/media.sav
|
img/media.sav
|
||||||
img/media.sav?channel=1
|
img/media.sav?channel=1
|
||||||
img/video.asf
|
img/video.asf
|
||||||
img/video.sav
|
img/video.sav
|
||||||
ioImage/1
|
ioImage/1
|
||||||
|
ipcam.sdp
|
||||||
ipcam_h264.sdp
|
ipcam_h264.sdp
|
||||||
ipcam_mjpeg.sdp
|
ipcam_mjpeg.sdp
|
||||||
ipcam.sdp
|
|
||||||
live
|
live
|
||||||
live_mpeg4.sdp
|
|
||||||
live_st1
|
|
||||||
live.sdp
|
live.sdp
|
||||||
live/av0
|
live/av0
|
||||||
live/ch0
|
live/ch0
|
||||||
@@ -81,16 +109,15 @@ live/main0
|
|||||||
live/mpeg4
|
live/mpeg4
|
||||||
live1.sdp
|
live1.sdp
|
||||||
live3.sdp
|
live3.sdp
|
||||||
|
live_mpeg4.sdp
|
||||||
|
live_st1
|
||||||
livestream
|
livestream
|
||||||
LowResolutionVideo
|
|
||||||
main
|
main
|
||||||
media
|
media
|
||||||
media.amp
|
media.amp
|
||||||
media.amp?streamprofile=Profile1
|
media.amp?streamprofile=Profile1
|
||||||
media/media.amp
|
media/media.amp
|
||||||
media/video1
|
media/video1
|
||||||
MediaInput/h264
|
|
||||||
MediaInput/mpeg4
|
|
||||||
medias2
|
medias2
|
||||||
mjpeg/media.smp
|
mjpeg/media.smp
|
||||||
mp4
|
mp4
|
||||||
@@ -109,8 +136,6 @@ nphMpeg4/g726-640x48
|
|||||||
nphMpeg4/g726-640x480
|
nphMpeg4/g726-640x480
|
||||||
nphMpeg4/nil-320x240
|
nphMpeg4/nil-320x240
|
||||||
onvif-media/media.amp
|
onvif-media/media.amp
|
||||||
ONVIF/MediaInput
|
|
||||||
ONVIF/MediaInput?profile=4_def_profile6
|
|
||||||
onvif1
|
onvif1
|
||||||
pass@10.0.0.5:6667/blinkhd
|
pass@10.0.0.5:6667/blinkhd
|
||||||
play1.sdp
|
play1.sdp
|
||||||
@@ -124,29 +149,30 @@ rtsp_live2
|
|||||||
rtsp_tunnel
|
rtsp_tunnel
|
||||||
rtsph264
|
rtsph264
|
||||||
rtsph2641080p
|
rtsph2641080p
|
||||||
StdCh1
|
snap.jpg
|
||||||
stream
|
stream
|
||||||
|
stream/0
|
||||||
|
stream/1
|
||||||
|
stream/live.sdp
|
||||||
stream.sdp
|
stream.sdp
|
||||||
stream1
|
stream1
|
||||||
streaming/channels/0
|
streaming/channels/0
|
||||||
Streaming/Channels/1
|
|
||||||
streaming/channels/1
|
streaming/channels/1
|
||||||
streaming/channels/101
|
streaming/channels/101
|
||||||
Streaming/Unicast/channels/101
|
|
||||||
StreamingSetting?version=1.0&action=getRTSPStream&ChannelID=1&ChannelName=Channel1
|
|
||||||
tcp/av0_0
|
tcp/av0_0
|
||||||
test
|
test
|
||||||
|
tmpfs/auto.jpg
|
||||||
trackID=1
|
trackID=1
|
||||||
ucast/11
|
ucast/11
|
||||||
udp/av0_0
|
udp/av0_0
|
||||||
udp/unicast/aiphone_H264
|
udp/unicast/aiphone_H264
|
||||||
udpstream
|
udpstream
|
||||||
user_defined
|
|
||||||
user.pin.mp2
|
user.pin.mp2
|
||||||
user=admin_password=?????_channel=1_stream=0.sdp?real_stream
|
|
||||||
user=admin_password=R5XFY888_channel=1_stream=0.sdp?real_stream
|
|
||||||
user=admin&password=&channel=1&stream=0.sdp?
|
user=admin&password=&channel=1&stream=0.sdp?
|
||||||
user=admin&password=&channel=1&stream=0.sdp?real_stream
|
user=admin&password=&channel=1&stream=0.sdp?real_stream
|
||||||
|
user=admin_password=?????_channel=1_stream=0.sdp?real_stream
|
||||||
|
user=admin_password=R5XFY888_channel=1_stream=0.sdp?real_stream
|
||||||
|
user_defined
|
||||||
v2
|
v2
|
||||||
video
|
video
|
||||||
video.3gp
|
video.3gp
|
||||||
@@ -156,12 +182,13 @@ video.mp4
|
|||||||
video.pro1
|
video.pro1
|
||||||
video.pro2
|
video.pro2
|
||||||
video.pro3
|
video.pro3
|
||||||
|
video0
|
||||||
video0.sdp
|
video0.sdp
|
||||||
video1
|
video1
|
||||||
|
video1.sdp
|
||||||
video1+audio1
|
video1+audio1
|
||||||
videoinput_1/h264_1/media.stm
|
|
||||||
VideoInput/1/h264/1
|
|
||||||
VideoInput/1/mpeg4/1
|
|
||||||
videoMain
|
videoMain
|
||||||
|
videoinput_1/h264_1/media.stm
|
||||||
|
videostream.asf
|
||||||
vis
|
vis
|
||||||
wfov
|
wfov
|
||||||
@@ -1,12 +1,17 @@
|
|||||||
module github.com/ullaakut/cameradar
|
module github.com/Ullaakut/cameradar/v5
|
||||||
|
|
||||||
go 1.12
|
go 1.14
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/PuerkitoBio/goquery v1.5.0
|
||||||
|
github.com/Ullaakut/disgo v0.3.1
|
||||||
|
github.com/Ullaakut/go-curl v0.0.0-20190525093431-597e157bbffd
|
||||||
|
github.com/Ullaakut/nmap v2.0.0+incompatible
|
||||||
|
github.com/VividCortex/ewma v1.1.1 // indirect
|
||||||
github.com/fatih/color v1.7.0 // indirect
|
github.com/fatih/color v1.7.0 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.2 // indirect
|
github.com/mattn/go-colorable v0.1.2 // indirect
|
||||||
github.com/spf13/viper v1.4.0 // indirect
|
github.com/spf13/pflag v1.0.3
|
||||||
github.com/ullaakut/disgo v0.3.0
|
github.com/spf13/viper v1.4.0
|
||||||
github.com/ullaakut/go-curl v0.0.0-20190525093431-597e157bbffd
|
github.com/stretchr/testify v1.2.2
|
||||||
github.com/ullaakut/nmap v0.0.0-20190623040344-bb4f2791e14a
|
github.com/vbauerster/mpb v3.4.0+incompatible
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,8 +1,21 @@
|
|||||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
|
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||||
|
github.com/PuerkitoBio/goquery v1.5.0 h1:uGvmFXOA73IKluu/F84Xd1tt/z07GYm8X49XKHP7EJk=
|
||||||
|
github.com/PuerkitoBio/goquery v1.5.0/go.mod h1:qD2PgZ9lccMbQlc7eEOjaeRlFQON7xY8kdmcsrnKqMg=
|
||||||
|
github.com/Ullaakut/disgo v0.3.1 h1:BGGVHynji41KGuGI02ztTCnILRvyzlvmiCRl5bBpjKk=
|
||||||
|
github.com/Ullaakut/disgo v0.3.1/go.mod h1:/CSvpnYVSKOeh2dvUvx9cXshzz2t7T1/lRO/MrFj3fI=
|
||||||
|
github.com/Ullaakut/go-curl v0.0.0-20190525093431-597e157bbffd h1:CMe+dX1CL4pCXNytxIB2U1qp0xZObGMZosJhaQdUlUo=
|
||||||
|
github.com/Ullaakut/go-curl v0.0.0-20190525093431-597e157bbffd/go.mod h1:u8mVgpDT88IPIt1B+Tu8vkrcFfBKGcfGwS9I7wmvMh0=
|
||||||
|
github.com/Ullaakut/nmap v2.0.0+incompatible h1:tNXub052dsnG8+yrgpph9nhVixIBdpRRgzvmQoc8eBA=
|
||||||
|
github.com/Ullaakut/nmap v2.0.0+incompatible/go.mod h1:fkC066hwfcoKwlI7DS2ARTggSVtBTZYCjVH1TzuTMaQ=
|
||||||
|
github.com/VividCortex/ewma v1.1.1 h1:MnEK4VOv6n0RSY4vtRe3h11qjxL3+t0B8yOL8iMXdcM=
|
||||||
|
github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA=
|
||||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
|
github.com/andybalholm/cascadia v1.0.0 h1:hOCXnnZ5A+3eVDX8pvgl4kofXv2ELss0bKcqRySc45o=
|
||||||
|
github.com/andybalholm/cascadia v1.0.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
|
||||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
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/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||||
@@ -13,6 +26,7 @@ github.com/coreos/etcd v3.3.10+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.2.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 v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||||
|
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/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||||
@@ -46,8 +60,10 @@ github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvW
|
|||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
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.1/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/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
|
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.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
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.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
|
github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
|
||||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
@@ -63,6 +79,7 @@ github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn
|
|||||||
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
|
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
|
||||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.0/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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||||
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
||||||
@@ -87,16 +104,14 @@ github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
|
|||||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
github.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU=
|
github.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU=
|
||||||
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
|
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
|
||||||
|
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
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/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||||
github.com/ullaakut/disgo v0.3.0 h1:2zrEyNBfPRgDVDgzM/qLXZ4Yqt3Lxz7ERvZUSmqSY2M=
|
github.com/vbauerster/mpb v3.4.0+incompatible h1:mfiiYw87ARaeRW6x5gWwYRUawxaW1tLAD8IceomUCNw=
|
||||||
github.com/ullaakut/disgo v0.3.0/go.mod h1:UOgLVyqihzJ7yihrHjYZikivT+AHb9NhT3r1OyPCJqg=
|
github.com/vbauerster/mpb v3.4.0+incompatible/go.mod h1:zAHG26FUhVKETRu+MWqYXcI70POlC6N8up9p1dID7SU=
|
||||||
github.com/ullaakut/go-curl v0.0.0-20190525093431-597e157bbffd h1:IzJ7V8S7/NXc4aLOj0QavbQZ5Z/Q2RpCifshHoJ5ytA=
|
|
||||||
github.com/ullaakut/go-curl v0.0.0-20190525093431-597e157bbffd/go.mod h1:FTfXm4jC9Ff1yqc3/HMXCyr+SGO03vJyijJCQlNyF10=
|
|
||||||
github.com/ullaakut/nmap v0.0.0-20190623040344-bb4f2791e14a h1:Q49G/c/ubeAPvrGGMPM0vt13gFDT5RwC6D0yOYsSjBs=
|
|
||||||
github.com/ullaakut/nmap v0.0.0-20190623040344-bb4f2791e14a/go.mod h1:4CQy4PqZA4Snk3+MS26+1oAkJ8dCY8kGH6+kF42yajw=
|
|
||||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
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/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||||
@@ -104,13 +119,16 @@ go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
|||||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/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-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190522155817-f3200d17e092 h1:4QSRKanuywn15aTZvI/mIDEgPQpswuFndXpOj3rKEco=
|
||||||
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@@ -120,7 +138,6 @@ golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5h
|
|||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
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-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
|
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/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 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8=
|
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8=
|
||||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
@@ -136,6 +153,7 @@ google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZi
|
|||||||
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
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-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||||
|
|||||||
+1
-1
@@ -18,7 +18,7 @@ func replace(streams []Stream, new Stream) []Stream {
|
|||||||
|
|
||||||
// GetCameraRTSPURL generates a stream's RTSP URL.
|
// GetCameraRTSPURL generates a stream's RTSP URL.
|
||||||
func GetCameraRTSPURL(stream Stream) string {
|
func GetCameraRTSPURL(stream Stream) string {
|
||||||
return "rtsp://" + stream.Username + ":" + stream.Password + "@" + stream.Address + ":" + fmt.Sprint(stream.Port) + "/" + stream.Route
|
return "rtsp://" + stream.Username + ":" + stream.Password + "@" + stream.Address + ":" + fmt.Sprint(stream.Port) + "/" + stream.Route()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCameraAdminPanelURL returns the URL to the camera's admin panel.
|
// GetCameraAdminPanelURL returns the URL to the camera's admin panel.
|
||||||
|
|||||||
+1
-1
@@ -61,7 +61,7 @@ func TestGetCameraRTSPURL(t *testing.T) {
|
|||||||
Address: "1.2.3.4",
|
Address: "1.2.3.4",
|
||||||
Username: "ullaakut",
|
Username: "ullaakut",
|
||||||
Password: "ba69897483886f0d2b0afb6345b76c0c",
|
Password: "ba69897483886f0d2b0afb6345b76c0c",
|
||||||
Route: "cameradar.sdp",
|
Routes: []string{"cameradar.sdp"},
|
||||||
Port: 1337,
|
Port: 1337,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -8,7 +8,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/ullaakut/disgo"
|
"github.com/Ullaakut/disgo"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/mock"
|
"github.com/stretchr/testify/mock"
|
||||||
|
|||||||
@@ -4,12 +4,12 @@ import "time"
|
|||||||
|
|
||||||
// Stream represents a camera's RTSP stream
|
// Stream represents a camera's RTSP stream
|
||||||
type Stream struct {
|
type Stream struct {
|
||||||
Device string `json:"device"`
|
Device string `json:"device"`
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
Route string `json:"route"`
|
Routes []string `json:"route"`
|
||||||
Address string `json:"address" validate:"required"`
|
Address string `json:"address" validate:"required"`
|
||||||
Port uint16 `json:"port" validate:"required"`
|
Port uint16 `json:"port" validate:"required"`
|
||||||
|
|
||||||
CredentialsFound bool `json:"credentials_found"`
|
CredentialsFound bool `json:"credentials_found"`
|
||||||
RouteFound bool `json:"route_found"`
|
RouteFound bool `json:"route_found"`
|
||||||
@@ -18,6 +18,14 @@ type Stream struct {
|
|||||||
AuthenticationType int `json:"authentication_type"`
|
AuthenticationType int `json:"authentication_type"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Route returns this stream's route if there is one.
|
||||||
|
func (s Stream) Route() string {
|
||||||
|
if len(s.Routes) > 0 {
|
||||||
|
return s.Routes[0]
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
// Credentials is a map of credentials
|
// Credentials is a map of credentials
|
||||||
// usernames are keys and passwords are values
|
// usernames are keys and passwords are values
|
||||||
// creds['admin'] -> 'secure_password'
|
// creds['admin'] -> 'secure_password'
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package cameradar
|
|||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/ullaakut/nmap"
|
"github.com/Ullaakut/nmap"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Scan scans the target networks and tries to find RTSP streams within them.
|
// Scan scans the target networks and tries to find RTSP streams within them.
|
||||||
@@ -25,7 +25,8 @@ func (s *Scanner) Scan() ([]Stream, error) {
|
|||||||
nmapScanner, err := nmap.NewScanner(
|
nmapScanner, err := nmap.NewScanner(
|
||||||
nmap.WithTargets(s.targets...),
|
nmap.WithTargets(s.targets...),
|
||||||
nmap.WithPorts(s.ports...),
|
nmap.WithPorts(s.ports...),
|
||||||
nmap.WithTimingTemplate(nmap.Timing(s.speed)),
|
nmap.WithServiceInfo(),
|
||||||
|
nmap.WithTimingTemplate(nmap.Timing(s.scanSpeed)),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, s.term.FailStepf("unable to create network scanner: %v", err)
|
return nil, s.term.FailStepf("unable to create network scanner: %v", err)
|
||||||
@@ -35,7 +36,10 @@ func (s *Scanner) Scan() ([]Stream, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Scanner) scan(nmapScanner nmap.ScanRunner) ([]Stream, error) {
|
func (s *Scanner) scan(nmapScanner nmap.ScanRunner) ([]Stream, error) {
|
||||||
results, err := nmapScanner.Run()
|
results, warnings, err := nmapScanner.Run()
|
||||||
|
for _, warning := range warnings {
|
||||||
|
s.term.Infoln("[Nmap Warning]", warning)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, s.term.FailStepf("error while scanning network: %v", err)
|
return nil, s.term.FailStepf("error while scanning network: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-17
@@ -6,24 +6,24 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/ullaakut/disgo"
|
"github.com/Ullaakut/disgo"
|
||||||
|
|
||||||
|
"github.com/Ullaakut/nmap"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/mock"
|
"github.com/stretchr/testify/mock"
|
||||||
"github.com/ullaakut/nmap"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type nmapMock struct {
|
type nmapMock struct {
|
||||||
mock.Mock
|
mock.Mock
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *nmapMock) Run() (*nmap.Run, error) {
|
func (m *nmapMock) Run() (*nmap.Run, []string, error) {
|
||||||
args := m.Called()
|
args := m.Called()
|
||||||
|
|
||||||
if args.Get(0) != nil {
|
if args.Get(0) != nil && args.Get(1) != nil {
|
||||||
return args.Get(0).(*nmap.Run), args.Error(1)
|
return args.Get(0).(*nmap.Run), args.Get(1).([]string), args.Error(2)
|
||||||
}
|
}
|
||||||
return nil, args.Error(1)
|
return nil, nil, args.Error(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -77,7 +77,7 @@ func TestScan(t *testing.T) {
|
|||||||
removePath: true,
|
removePath: true,
|
||||||
ports: []string{"80"},
|
ports: []string{"80"},
|
||||||
|
|
||||||
expectedErr: errors.New("unable to create network scanner: 'nmap' binary was not found"),
|
expectedErr: errors.New("unable to create network scanner: nmap binary was not found"),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,10 +88,10 @@ func TestScan(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
scanner := &Scanner{
|
scanner := &Scanner{
|
||||||
term: disgo.NewTerminal(disgo.WithDefaultOutput(ioutil.Discard)),
|
term: disgo.NewTerminal(disgo.WithDefaultOutput(ioutil.Discard)),
|
||||||
targets: test.targets,
|
targets: test.targets,
|
||||||
ports: test.ports,
|
ports: test.ports,
|
||||||
speed: test.speed,
|
scanSpeed: test.speed,
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err := scanner.Scan()
|
result, err := scanner.Scan()
|
||||||
@@ -103,12 +103,12 @@ func TestScan(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestInternalScan(t *testing.T) {
|
func TestInternalScan(t *testing.T) {
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
description string
|
description string
|
||||||
|
|
||||||
nmapResult *nmap.Run
|
nmapResult *nmap.Run
|
||||||
nmapError error
|
nmapWarnings []string
|
||||||
|
nmapError error
|
||||||
|
|
||||||
expectedStreams []Stream
|
expectedStreams []Stream
|
||||||
expectedErr error
|
expectedErr error
|
||||||
@@ -294,8 +294,9 @@ func TestInternalScan(t *testing.T) {
|
|||||||
{
|
{
|
||||||
description: "scan failed",
|
description: "scan failed",
|
||||||
|
|
||||||
nmapError: errors.New("scan failed"),
|
nmapError: errors.New("scan failed"),
|
||||||
expectedErr: errors.New("error while scanning network: scan failed"),
|
nmapWarnings: []string{"invalid host"},
|
||||||
|
expectedErr: errors.New("error while scanning network: scan failed"),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -303,7 +304,7 @@ func TestInternalScan(t *testing.T) {
|
|||||||
t.Run(test.description, func(t *testing.T) {
|
t.Run(test.description, func(t *testing.T) {
|
||||||
nmapMock := &nmapMock{}
|
nmapMock := &nmapMock{}
|
||||||
|
|
||||||
nmapMock.On("Run").Return(test.nmapResult, test.nmapError)
|
nmapMock.On("Run").Return(test.nmapResult, test.nmapWarnings, test.nmapError)
|
||||||
|
|
||||||
scanner := &Scanner{
|
scanner := &Scanner{
|
||||||
term: disgo.NewTerminal(disgo.WithDefaultOutput(ioutil.Discard)),
|
term: disgo.NewTerminal(disgo.WithDefaultOutput(ioutil.Discard)),
|
||||||
|
|||||||
+19
-9
@@ -5,14 +5,14 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ullaakut/disgo"
|
"github.com/Ullaakut/disgo"
|
||||||
"github.com/ullaakut/disgo/style"
|
"github.com/Ullaakut/disgo/style"
|
||||||
curl "github.com/ullaakut/go-curl"
|
curl "github.com/Ullaakut/go-curl"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
defaultCredentialDictionaryPath = "${GOPATH}/src/github.com/ullaakut/cameradar/dictionaries/credentials.json"
|
defaultCredentialDictionaryPath = "${GOPATH}/src/github.com/Ullaakut/cameradar/dictionaries/credentials.json"
|
||||||
defaultRouteDictionaryPath = "${GOPATH}/src/github.com/ullaakut/cameradar/dictionaries/routes"
|
defaultRouteDictionaryPath = "${GOPATH}/src/github.com/Ullaakut/cameradar/dictionaries/routes"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Scanner represents a cameradar scanner. It scans a network and
|
// Scanner represents a cameradar scanner. It scans a network and
|
||||||
@@ -25,7 +25,8 @@ type Scanner struct {
|
|||||||
ports []string
|
ports []string
|
||||||
debug bool
|
debug bool
|
||||||
verbose bool
|
verbose bool
|
||||||
speed int
|
scanSpeed int
|
||||||
|
attackInterval time.Duration
|
||||||
timeout time.Duration
|
timeout time.Duration
|
||||||
credentialDictionaryPath string
|
credentialDictionaryPath string
|
||||||
routeDictionaryPath string
|
routeDictionaryPath string
|
||||||
@@ -134,11 +135,20 @@ func WithCustomRoutes(dictionaryPath string) func(s *Scanner) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithSpeed specifies the speed at which the scan should be executed. Faster
|
// WithScanSpeed specifies the speed at which the scan should be executed. Faster
|
||||||
// means easier to detect, slower has bigger timeout values and is more silent.
|
// means easier to detect, slower has bigger timeout values and is more silent.
|
||||||
func WithSpeed(speed int) func(s *Scanner) {
|
func WithScanSpeed(speed int) func(s *Scanner) {
|
||||||
return func(s *Scanner) {
|
return func(s *Scanner) {
|
||||||
s.speed = speed
|
s.scanSpeed = speed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithAttackInterval specifies the interval of time during which Cameradar
|
||||||
|
// should wait between each attack attempt during bruteforcing.
|
||||||
|
// Setting a high value for this obviously makes attacks much slower.
|
||||||
|
func WithAttackInterval(interval time.Duration) func(s *Scanner) {
|
||||||
|
return func(s *Scanner) {
|
||||||
|
s.attackInterval = interval
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
-3
@@ -7,8 +7,8 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
curl "github.com/Ullaakut/go-curl"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
curl "github.com/ullaakut/go-curl"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNew(t *testing.T) {
|
func TestNew(t *testing.T) {
|
||||||
@@ -22,6 +22,7 @@ func TestNew(t *testing.T) {
|
|||||||
customCredentials string
|
customCredentials string
|
||||||
customRoutes string
|
customRoutes string
|
||||||
speed int
|
speed int
|
||||||
|
attackInterval time.Duration
|
||||||
timeout time.Duration
|
timeout time.Duration
|
||||||
|
|
||||||
loadTargetsFail bool
|
loadTargetsFail bool
|
||||||
@@ -118,7 +119,8 @@ func TestNew(t *testing.T) {
|
|||||||
WithPorts(test.ports),
|
WithPorts(test.ports),
|
||||||
WithDebug(test.debug),
|
WithDebug(test.debug),
|
||||||
WithVerbose(test.verbose),
|
WithVerbose(test.verbose),
|
||||||
WithSpeed(test.speed),
|
WithScanSpeed(test.speed),
|
||||||
|
WithAttackInterval(test.attackInterval),
|
||||||
WithTimeout(test.timeout),
|
WithTimeout(test.timeout),
|
||||||
WithCustomCredentials(test.customCredentials),
|
WithCustomCredentials(test.customCredentials),
|
||||||
WithCustomRoutes(test.customRoutes),
|
WithCustomRoutes(test.customRoutes),
|
||||||
@@ -135,7 +137,8 @@ func TestNew(t *testing.T) {
|
|||||||
assert.Equal(t, test.ports, scanner.ports)
|
assert.Equal(t, test.ports, scanner.ports)
|
||||||
assert.Equal(t, test.debug, scanner.debug)
|
assert.Equal(t, test.debug, scanner.debug)
|
||||||
assert.Equal(t, test.verbose, scanner.verbose)
|
assert.Equal(t, test.verbose, scanner.verbose)
|
||||||
assert.Equal(t, test.speed, scanner.speed)
|
assert.Equal(t, test.speed, scanner.scanSpeed)
|
||||||
|
assert.Equal(t, test.attackInterval, scanner.attackInterval)
|
||||||
assert.Equal(t, test.timeout, scanner.timeout)
|
assert.Equal(t, test.timeout, scanner.timeout)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
+9
-4
@@ -1,8 +1,8 @@
|
|||||||
package cameradar
|
package cameradar
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/ullaakut/disgo/style"
|
"github.com/Ullaakut/disgo/style"
|
||||||
curl "github.com/ullaakut/go-curl"
|
curl "github.com/Ullaakut/go-curl"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PrintStreams prints information on each stream.
|
// PrintStreams prints information on each stream.
|
||||||
@@ -46,11 +46,16 @@ func (s *Scanner) PrintStreams(streams []Stream) {
|
|||||||
s.term.Infof("\tPassword:\t\t%s\n", style.Failure("not found"))
|
s.term.Infof("\tPassword:\t\t%s\n", style.Failure("not found"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s.term.Infoln("\tRTSP routes:")
|
||||||
if stream.RouteFound {
|
if stream.RouteFound {
|
||||||
s.term.Infof("\tRTSP route:\t\t%s\n\n\n", style.Success("/"+stream.Route))
|
for _, route := range stream.Routes {
|
||||||
|
s.term.Infoln(style.Success("\t\t\t\t/" + route))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
s.term.Infof("\tRTSP route:\t\t%s\n\n\n", style.Failure("not found"))
|
s.term.Infoln(style.Failure("not found"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s.term.Info("\n\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
if success > 1 {
|
if success > 1 {
|
||||||
|
|||||||
+2
-2
@@ -4,8 +4,8 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/Ullaakut/disgo"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/ullaakut/disgo"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -39,7 +39,7 @@ var (
|
|||||||
|
|
||||||
routeFound = Stream{
|
routeFound = Stream{
|
||||||
RouteFound: true,
|
RouteFound: true,
|
||||||
Route: "r0ute",
|
Routes: []string{"r0ute"},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -10,10 +10,10 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/ullaakut/disgo/style"
|
"github.com/Ullaakut/disgo/style"
|
||||||
|
|
||||||
"github.com/PuerkitoBio/goquery"
|
"github.com/PuerkitoBio/goquery"
|
||||||
"github.com/ullaakut/disgo"
|
"github.com/Ullaakut/disgo"
|
||||||
"github.com/vbauerster/mpb"
|
"github.com/vbauerster/mpb"
|
||||||
"github.com/vbauerster/mpb/decor"
|
"github.com/vbauerster/mpb/decor"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
module github.com/Ullaakut/cameradar/magefile
|
||||||
|
|
||||||
|
go 1.16
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/Ullaakut/disgo v0.3.1
|
||||||
|
github.com/fatih/color v1.10.0 // indirect
|
||||||
|
github.com/magefile/mage v1.11.0
|
||||||
|
github.com/stretchr/testify v1.7.0 // indirect
|
||||||
|
)
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
github.com/Ullaakut/disgo v0.3.1 h1:BGGVHynji41KGuGI02ztTCnILRvyzlvmiCRl5bBpjKk=
|
||||||
|
github.com/Ullaakut/disgo v0.3.1/go.mod h1:/CSvpnYVSKOeh2dvUvx9cXshzz2t7T1/lRO/MrFj3fI=
|
||||||
|
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg=
|
||||||
|
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
|
||||||
|
github.com/magefile/mage v1.11.0 h1:C/55Ywp9BpgVVclD3lRnSYCwXTYxmSppIgLeDYlNuls=
|
||||||
|
github.com/magefile/mage v1.11.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
|
||||||
|
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.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||||
|
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||||
|
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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
|
||||||
|
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
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=
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
//+build mage
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/magefile/mage/sh"
|
||||||
|
"github.com/Ullaakut/disgo"
|
||||||
|
"github.com/Ullaakut/disgo/style"
|
||||||
|
)
|
||||||
|
|
||||||
|
var supportedPlatforms = map[string]string{
|
||||||
|
"linux/amd64": "ullaakut/cameradar:amd64",
|
||||||
|
"linux/386": "ullaakut/cameradar:386",
|
||||||
|
"linux/arm64": "ullaakut/cameradar:arm64",
|
||||||
|
"linux/arm/v7": "ullaakut/cameradar:armv7",
|
||||||
|
//"linux/riscv64": "ullaakut/cameradar:riscv64", // UNSUPPORTED.
|
||||||
|
//"linux/ppc64le": "ullaakut/cameradar:ppc64le", // UNSUPPORTED.
|
||||||
|
//"linux/s390x": "ullaakut/cameradar:s390x", // UNSUPPORTED.
|
||||||
|
//"linux/arm/v6": "ullaakut/cameradar:armv6", // UNSUPPORTED.
|
||||||
|
}
|
||||||
|
|
||||||
|
var Default = Build
|
||||||
|
|
||||||
|
// Follows https://www.docker.com/blog/multi-platform-docker-builds/.
|
||||||
|
func Build() error {
|
||||||
|
term := disgo.NewTerminal(disgo.WithColors(true))
|
||||||
|
|
||||||
|
term.StartStep("Building images for all platforms")
|
||||||
|
term.Infof("Builds planned for %v\n", supportedPlatforms)
|
||||||
|
for platform, name := range supportedPlatforms {
|
||||||
|
term.Infoln("Building image for", platform, "at", name)
|
||||||
|
|
||||||
|
// docker buildx build --platform linux/arm/v7 -t ullaakut/cameradar:armv7 .
|
||||||
|
if err := sh.Run("docker", "buildx", "build", "--platform", platform, "-t", name, "../../"); err != nil {
|
||||||
|
return term.FailStepf("unable to build image: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
term.Infoln(style.Success("Cross-platform docker build successful."))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Publish() error {
|
||||||
|
term := disgo.NewTerminal(disgo.WithColors(true))
|
||||||
|
|
||||||
|
term.StartStep("Pushing images to DockerHub")
|
||||||
|
term.Infoln("Pushing ullaakut/cameradar:latest")
|
||||||
|
if err := sh.Run("docker", "push", "ullaakut/cameradar:latest"); err != nil {
|
||||||
|
return term.FailStepf("unable to push latest docker images to docker hub: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if version, exists := os.LookupEnv("CAMERADAR_VERSION"); exists {
|
||||||
|
term.Infoln("Pushing ullaakut/cameradar:"+version)
|
||||||
|
if err := sh.Run("docker", "push", "ullaakut/cameradar:"+version); err != nil {
|
||||||
|
return term.FailStepf("unable to push versionned docker images to docker hub: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
term.StartStep("Pushing images to GitHub Packages")
|
||||||
|
term.Infoln("Pushing docker.pkg.github.com/ullaakut/cameradar/cameradar:latest")
|
||||||
|
if err := sh.Run("docker", "tag", "ullaakut/cameradar:latest", "docker.pkg.github.com/ullaakut/cameradar/cameradar:latest"); err != nil {
|
||||||
|
return term.FailStepf("unable to push latest docker images to docker hub: %v", err)
|
||||||
|
}
|
||||||
|
if err := sh.Run("docker", "push", "docker.pkg.github.com/ullaakut/cameradar/cameradar:latest"); err != nil {
|
||||||
|
return term.FailStepf("unable to push latest docker images to docker hub: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if version, exists := os.LookupEnv("CAMERADAR_VERSION"); exists {
|
||||||
|
term.Infoln("Pushing docker.pkg.github.com/ullaakut/cameradar/cameradar:"+version)
|
||||||
|
if err := sh.Run("docker", "tag", "ullaakut/cameradar:"+version, "docker.pkg.github.com/ullaakut/cameradar/cameradar:"+version); err != nil {
|
||||||
|
return term.FailStepf("unable to push latest docker images to docker hub: %v", err)
|
||||||
|
}
|
||||||
|
if err := sh.Run("docker", "push", "ullaakut/cameradar:"+version); err != nil {
|
||||||
|
return term.FailStepf("unable to push versionned docker images to docker hub: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
term.StartStep("Creating manifest(s) for cross platform builds")
|
||||||
|
|
||||||
|
var manifestImages []string
|
||||||
|
for _, image := range supportedPlatforms {
|
||||||
|
manifestImages = append(manifestImages, image)
|
||||||
|
}
|
||||||
|
|
||||||
|
args := []string{"manifest", "create", "--amend", "ullaakut/cameradar:latest"}
|
||||||
|
args = append(args, manifestImages...)
|
||||||
|
|
||||||
|
// docker manifest create ullaakut/cameradar:latest ullaakut/cameradar:amd64 ullaakut/cameradar:armv7 [...]
|
||||||
|
if err := sh.Run("docker", args...); err != nil {
|
||||||
|
return term.FailStepf("unable to create manifest: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if version, exists := os.LookupEnv("CAMERADAR_VERSION"); exists {
|
||||||
|
args = []string{"manifest", "create", "--amend", "ullaakut/cameradar:"+version}
|
||||||
|
args = append(args, manifestImages...)
|
||||||
|
|
||||||
|
if err := sh.Run("docker", args...); err != nil {
|
||||||
|
return term.FailStepf("unable to create manifest: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
term.EndStep()
|
||||||
|
|
||||||
|
term.Infoln(style.Success("Images published successfully."))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user