Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3b082ea736 | |||
| b6ebd468c6 | |||
| ceb210f281 | |||
| fcb627dccd | |||
| 098460702b | |||
| 5849898283 | |||
| 878ca9f032 | |||
| 24f86b74f5 |
@@ -2,9 +2,6 @@
|
|||||||
.idea/
|
.idea/
|
||||||
.vscode/
|
.vscode/
|
||||||
|
|
||||||
# Deps
|
|
||||||
/vendor
|
|
||||||
|
|
||||||
# Golang
|
# Golang
|
||||||
/bin/*
|
/bin/*
|
||||||
/pkg/*
|
/pkg/*
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# https://github.com/golangci/golangci/wiki/Configuration
|
||||||
|
|
||||||
|
service:
|
||||||
|
project-path: github.com/ullaakut/cameradar
|
||||||
|
prepare:
|
||||||
|
- apt-get update && apt-get install -y libcurl4-gnutls-dev
|
||||||
|
- dep ensure
|
||||||
+4
-11
@@ -3,10 +3,10 @@ sudo: required
|
|||||||
language: go
|
language: go
|
||||||
|
|
||||||
env:
|
env:
|
||||||
- DEP_VERSION="0.4.1"
|
- GO111MODULE=on
|
||||||
|
|
||||||
services:
|
services:
|
||||||
- docker
|
- docker
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- echo "Testing Docker Hub credentials"
|
- echo "Testing Docker Hub credentials"
|
||||||
@@ -18,24 +18,17 @@ before_install:
|
|||||||
- sudo apt-get remove docker docker-engine docker.io
|
- sudo apt-get remove docker docker-engine docker.io
|
||||||
- curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
|
- curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
|
||||||
- sudo apt-get update
|
- sudo apt-get update
|
||||||
- sudo apt-get install -y docker-ce
|
- sudo apt-get install -y docker-ce nmap
|
||||||
- go get github.com/mattn/goveralls
|
- go get github.com/mattn/goveralls
|
||||||
- go get github.com/andelf/go-curl
|
|
||||||
- go get github.com/pkg/errors
|
|
||||||
- go get gopkg.in/go-playground/validator.v9
|
|
||||||
- go get github.com/stretchr/testify/assert
|
|
||||||
- docker version
|
- docker version
|
||||||
- curl -L -s https://github.com/golang/dep/releases/download/v${DEP_VERSION}/dep-linux-amd64 -o $GOPATH/bin/dep
|
|
||||||
- chmod +x $GOPATH/bin/dep
|
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- dep ensure
|
|
||||||
- docker build -t cameradar .
|
- docker build -t cameradar .
|
||||||
|
|
||||||
script:
|
script:
|
||||||
# Run unit tests
|
# Run unit tests
|
||||||
- go test -v -covermode=count -coverprofile=coverage.out
|
- go test -v -covermode=count -coverprofile=coverage.out
|
||||||
- $HOME/gopath/bin/goveralls -coverprofile=coverage.out -service=travis-ci -repotoken $COVERALLS_TOKEN
|
- $HOME/gopath/bin/goveralls -coverprofile=coverage.out -service=travis-ci -repotoken=$COVERALLS_TOKEN
|
||||||
# Launch a fake camera to check if cameradar is able to access it
|
# Launch a fake camera to check if cameradar is able to access it
|
||||||
- docker run -d --name=fake_camera -e RTSP_USERNAME=admin -e RTSP_PASSWORD=12345 -p 8554:8554 ullaakut/rtspatt
|
- docker run -d --name=fake_camera -e RTSP_USERNAME=admin -e RTSP_PASSWORD=12345 -p 8554:8554 ullaakut/rtspatt
|
||||||
# Launch cameradar on the local machine
|
# Launch cameradar on the local machine
|
||||||
|
|||||||
+3
-3
@@ -4,7 +4,7 @@ This file will give you guidelines on how to contribute if you want to, and will
|
|||||||
|
|
||||||
If you're not into software development or not into Golang, you can still help. Updating the dictionaries for example, would be a really cool contribution! Just make sure the credentials and routes you add are **default constructor credentials** and not custom credentials.
|
If you're not into software development or not into Golang, you can still help. Updating the dictionaries for example, would be a really cool contribution! Just make sure the credentials and routes you add are **default constructor credentials** and not custom credentials.
|
||||||
|
|
||||||
If you have other cool ideas, feel free to share them with me at [brendan.leglaunec@etixgroup.com](mailto:brendan.leglaunec@etixgroup.com) or to directly [create an issue](https://github.com/Ullaakut/cameradar/issues)!
|
If you have other cool ideas, feel free to share them with me at [brendan.leglaunec@etixgroup.com](mailto:brendan.leglaunec@etixgroup.com) or to directly [create an issue](https://github.com/ullaakut/cameradar/issues)!
|
||||||
|
|
||||||
## Version 2.0.0
|
## Version 2.0.0
|
||||||
|
|
||||||
@@ -67,7 +67,7 @@ Once everything is in order, we will merge your pull request.
|
|||||||
|
|
||||||
Your code should just
|
Your code should just
|
||||||
|
|
||||||
- Not decrease the results of Cameradar on https://goreportcard.com/report/github.com/Ullaakut/cameradar
|
- Not decrease the results of Cameradar on https://goreportcard.com/report/github.com/ullaakut/cameradar
|
||||||
- Pass the code review
|
- Pass the code review
|
||||||
|
|
||||||
#### Golang
|
#### Golang
|
||||||
@@ -77,6 +77,6 @@ Your code should just
|
|||||||
|
|
||||||
## Contributors
|
## Contributors
|
||||||
|
|
||||||
- **Brendan Le Glaunec** - [@Ullaakut](https://github.com/Ullaakut) - brendan.leglaunec@etixgroup.com : *Original developer & Maintainer*
|
- **Brendan Le Glaunec** - [@Ullaakut](https://github.com/ullaakut) - brendan.leglaunec@etixgroup.com : *Original developer & Maintainer*
|
||||||
- **Jeremy Letang** - [@jeremyletang](https://github.com/jeremyletang) - letang.jeremy@gmail.com : *Idea of the project & Mentorship*
|
- **Jeremy Letang** - [@jeremyletang](https://github.com/jeremyletang) - letang.jeremy@gmail.com : *Idea of the project & Mentorship*
|
||||||
- **ishanjain28** - [@ishanjain28](https://github.com/ishanjain28) - ishanjain28@gmail.com : *Implemented the environment variables support*
|
- **ishanjain28** - [@ishanjain28](https://github.com/ishanjain28) - ishanjain28@gmail.com : *Implemented the environment variables support*
|
||||||
+14
-10
@@ -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/cameradar
|
WORKDIR /go/src/github.com/ullaakut/cameradar/cameradar
|
||||||
|
|
||||||
RUN apk update && \
|
RUN apk update && \
|
||||||
apk upgrade && \
|
apk upgrade && \
|
||||||
@@ -12,19 +12,23 @@ RUN apk update && \
|
|||||||
libc-dev \
|
libc-dev \
|
||||||
git \
|
git \
|
||||||
pkgconfig
|
pkgconfig
|
||||||
ENV DEP_VERSION="0.4.1"
|
ENV GO111MODULE=on
|
||||||
RUN curl -L -s https://github.com/golang/dep/releases/download/v${DEP_VERSION}/dep-linux-amd64 -o $GOPATH/bin/dep
|
RUN go version
|
||||||
RUN chmod +x $GOPATH/bin/dep
|
|
||||||
RUN dep ensure
|
|
||||||
RUN go build -o cameradar
|
RUN go build -o cameradar
|
||||||
|
|
||||||
# Final stage
|
# Final stage
|
||||||
FROM alpine
|
FROM alpine
|
||||||
|
|
||||||
RUN apk --update add --no-cache nmap nmap-nselibs nmap-scripts \
|
RUN apk --update add --no-cache nmap \
|
||||||
|
nmap-nselibs \
|
||||||
|
nmap-scripts \
|
||||||
curl-dev
|
curl-dev
|
||||||
|
|
||||||
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/cameradar/ /app/cameradar/
|
COPY --from=build-env /go/src/github.com/ullaakut/cameradar/cameradar/ /app/cameradar/
|
||||||
ENTRYPOINT ["/app/cameradar/cameradar", "-r", "/app/dictionaries/routes", "-c", "/app/dictionaries/credentials.json"]
|
|
||||||
|
ENV CAMERADAR_CUSTOM_ROUTES="/app/dictionaries/routes"
|
||||||
|
ENV CAMERADAR_CUSTOM_CREDENTIALS="/app/dictionaries/credentials.json"
|
||||||
|
|
||||||
|
ENTRYPOINT ["/app/cameradar/cameradar"]
|
||||||
|
|||||||
Generated
-213
@@ -1,213 +0,0 @@
|
|||||||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
|
||||||
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
branch = "master"
|
|
||||||
name = "github.com/andelf/go-curl"
|
|
||||||
packages = ["."]
|
|
||||||
revision = "f8b334df3789fbdf98df3b3b22815e958b956c19"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
name = "github.com/davecgh/go-spew"
|
|
||||||
packages = ["spew"]
|
|
||||||
revision = "346938d642f2ec3594ed81d874461961cd0faa76"
|
|
||||||
version = "v1.1.0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
name = "github.com/fatih/color"
|
|
||||||
packages = ["."]
|
|
||||||
revision = "570b54cabe6b8eb0bc2dfce68d964677d63b5260"
|
|
||||||
version = "v1.5.0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
name = "github.com/fsnotify/fsnotify"
|
|
||||||
packages = ["."]
|
|
||||||
revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9"
|
|
||||||
version = "v1.4.7"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
branch = "master"
|
|
||||||
name = "github.com/gernest/wow"
|
|
||||||
packages = [
|
|
||||||
".",
|
|
||||||
"spin"
|
|
||||||
]
|
|
||||||
revision = "7e0b2a2398989a5d220eebac5742d45422ba7de8"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
name = "github.com/go-playground/locales"
|
|
||||||
packages = [
|
|
||||||
".",
|
|
||||||
"currency"
|
|
||||||
]
|
|
||||||
revision = "e4cbcb5d0652150d40ad0646651076b6bd2be4f6"
|
|
||||||
version = "v0.11.2"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
name = "github.com/go-playground/universal-translator"
|
|
||||||
packages = ["."]
|
|
||||||
revision = "b32fa301c9fe55953584134cb6853a13c87ec0a1"
|
|
||||||
version = "v0.16.0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
branch = "master"
|
|
||||||
name = "github.com/hashicorp/hcl"
|
|
||||||
packages = [
|
|
||||||
".",
|
|
||||||
"hcl/ast",
|
|
||||||
"hcl/parser",
|
|
||||||
"hcl/scanner",
|
|
||||||
"hcl/strconv",
|
|
||||||
"hcl/token",
|
|
||||||
"json/parser",
|
|
||||||
"json/scanner",
|
|
||||||
"json/token"
|
|
||||||
]
|
|
||||||
revision = "23c074d0eceb2b8a5bfdbb271ab780cde70f05a8"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
name = "github.com/magefile/mage"
|
|
||||||
packages = [
|
|
||||||
"mg",
|
|
||||||
"sh",
|
|
||||||
"types"
|
|
||||||
]
|
|
||||||
revision = "ab3ca2f6f85577d7ec82e0a6df721147a2e737f9"
|
|
||||||
version = "v2.0.1"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
name = "github.com/magiconair/properties"
|
|
||||||
packages = ["."]
|
|
||||||
revision = "d419a98cdbed11a922bf76f257b7c4be79b50e73"
|
|
||||||
version = "v1.7.4"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
name = "github.com/mattn/go-colorable"
|
|
||||||
packages = ["."]
|
|
||||||
revision = "167de6bfdfba052fa6b2d3664c8f5272e23c9072"
|
|
||||||
version = "v0.0.9"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
name = "github.com/mattn/go-isatty"
|
|
||||||
packages = ["."]
|
|
||||||
revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39"
|
|
||||||
version = "v0.0.3"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
branch = "master"
|
|
||||||
name = "github.com/mitchellh/mapstructure"
|
|
||||||
packages = ["."]
|
|
||||||
revision = "b4575eea38cca1123ec2dc90c26529b5c5acfcff"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
name = "github.com/pelletier/go-toml"
|
|
||||||
packages = ["."]
|
|
||||||
revision = "acdc4509485b587f5e675510c4f2c63e90ff68a8"
|
|
||||||
version = "v1.1.0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
name = "github.com/pkg/errors"
|
|
||||||
packages = ["."]
|
|
||||||
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
|
|
||||||
version = "v0.8.0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
name = "github.com/pmezard/go-difflib"
|
|
||||||
packages = ["difflib"]
|
|
||||||
revision = "792786c7400a136282c1664665ae0a8db921c6c2"
|
|
||||||
version = "v1.0.0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
name = "github.com/spf13/afero"
|
|
||||||
packages = [
|
|
||||||
".",
|
|
||||||
"mem"
|
|
||||||
]
|
|
||||||
revision = "bb8f1927f2a9d3ab41c9340aa034f6b803f4359c"
|
|
||||||
version = "v1.0.2"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
name = "github.com/spf13/cast"
|
|
||||||
packages = ["."]
|
|
||||||
revision = "acbeb36b902d72a7a4c18e8f3241075e7ab763e4"
|
|
||||||
version = "v1.1.0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
branch = "master"
|
|
||||||
name = "github.com/spf13/jwalterweatherman"
|
|
||||||
packages = ["."]
|
|
||||||
revision = "7c0cea34c8ece3fbeb2b27ab9b59511d360fb394"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
name = "github.com/spf13/pflag"
|
|
||||||
packages = ["."]
|
|
||||||
revision = "e57e3eeb33f795204c1ca35f56c44f83227c6e66"
|
|
||||||
version = "v1.0.0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
name = "github.com/spf13/viper"
|
|
||||||
packages = ["."]
|
|
||||||
revision = "25b30aa063fc18e48662b86996252eabdcf2f0c7"
|
|
||||||
version = "v1.0.0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
name = "github.com/stretchr/objx"
|
|
||||||
packages = ["."]
|
|
||||||
revision = "facf9a85c22f48d2f52f2380e4efce1768749a89"
|
|
||||||
version = "v0.1"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
name = "github.com/stretchr/testify"
|
|
||||||
packages = [
|
|
||||||
"assert",
|
|
||||||
"mock"
|
|
||||||
]
|
|
||||||
revision = "12b6f73e6084dad08a7c6e575284b177ecafbc71"
|
|
||||||
version = "v1.2.1"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
branch = "master"
|
|
||||||
name = "golang.org/x/crypto"
|
|
||||||
packages = ["ssh/terminal"]
|
|
||||||
revision = "1875d0a70c90e57f11972aefd42276df65e895b9"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
branch = "master"
|
|
||||||
name = "golang.org/x/sys"
|
|
||||||
packages = [
|
|
||||||
"unix",
|
|
||||||
"windows"
|
|
||||||
]
|
|
||||||
revision = "8f27ce8a604014414f8dfffc25cbcde83a3f2216"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
branch = "master"
|
|
||||||
name = "golang.org/x/text"
|
|
||||||
packages = [
|
|
||||||
"internal/gen",
|
|
||||||
"internal/triegen",
|
|
||||||
"internal/ucd",
|
|
||||||
"transform",
|
|
||||||
"unicode/cldr",
|
|
||||||
"unicode/norm"
|
|
||||||
]
|
|
||||||
revision = "e19ae1496984b1c655b8044a65c0300a3c878dd3"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
name = "gopkg.in/go-playground/validator.v9"
|
|
||||||
packages = ["."]
|
|
||||||
revision = "48a433ba4bcadc5be9aa16d4bdcb383d3f57a741"
|
|
||||||
version = "v9.9.3"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
branch = "v2"
|
|
||||||
name = "gopkg.in/yaml.v2"
|
|
||||||
packages = ["."]
|
|
||||||
revision = "d670f9405373e636a5a2765eea47fac0c9bc91a4"
|
|
||||||
|
|
||||||
[solve-meta]
|
|
||||||
analyzer-name = "dep"
|
|
||||||
analyzer-version = 1
|
|
||||||
inputs-digest = "cd90160a373567d6046fe1f1f30e822740533c06a766bcb75d2ed83820cd8526"
|
|
||||||
solver-name = "gps-cdcl"
|
|
||||||
solver-version = 1
|
|
||||||
-62
@@ -1,62 +0,0 @@
|
|||||||
# Gopkg.toml example
|
|
||||||
#
|
|
||||||
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
|
|
||||||
# for detailed Gopkg.toml documentation.
|
|
||||||
#
|
|
||||||
# required = ["github.com/user/thing/cmd/thing"]
|
|
||||||
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
|
|
||||||
#
|
|
||||||
# [[constraint]]
|
|
||||||
# name = "github.com/user/project"
|
|
||||||
# version = "1.0.0"
|
|
||||||
#
|
|
||||||
# [[constraint]]
|
|
||||||
# name = "github.com/user/project2"
|
|
||||||
# branch = "dev"
|
|
||||||
# source = "github.com/myfork/project2"
|
|
||||||
#
|
|
||||||
# [[override]]
|
|
||||||
# name = "github.com/x/y"
|
|
||||||
# version = "2.4.0"
|
|
||||||
#
|
|
||||||
# [prune]
|
|
||||||
# non-go = false
|
|
||||||
# go-tests = true
|
|
||||||
# unused-packages = true
|
|
||||||
|
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
branch = "master"
|
|
||||||
name = "github.com/andelf/go-curl"
|
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
name = "github.com/fatih/color"
|
|
||||||
version = "1.5.0"
|
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
branch = "master"
|
|
||||||
name = "github.com/gernest/wow"
|
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
name = "github.com/pkg/errors"
|
|
||||||
version = "0.8.0"
|
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
name = "github.com/spf13/pflag"
|
|
||||||
version = "1.0.0"
|
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
name = "github.com/spf13/viper"
|
|
||||||
version = "1.0.0"
|
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
name = "github.com/stretchr/testify"
|
|
||||||
version = "1.2.1"
|
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
name = "gopkg.in/go-playground/validator.v9"
|
|
||||||
version = "9.9.3"
|
|
||||||
|
|
||||||
[prune]
|
|
||||||
go-tests = true
|
|
||||||
unused-packages = true
|
|
||||||
@@ -17,17 +17,17 @@
|
|||||||
<a href='https://coveralls.io/github/Ullaakut/cameradar?branch=master'>
|
<a href='https://coveralls.io/github/Ullaakut/cameradar?branch=master'>
|
||||||
<img src='https://coveralls.io/repos/github/Ullaakut/cameradar/badge.svg?branch=master' alt='Coverage Status' />
|
<img src='https://coveralls.io/repos/github/Ullaakut/cameradar/badge.svg?branch=master' alt='Coverage Status' />
|
||||||
</a>
|
</a>
|
||||||
<a href="https://golangci.com/r/github.com/Ullaakut/cameradar">
|
<a href="https://golangci.com/r/github.com/ullaakut/cameradar">
|
||||||
<img src="https://golangci.com/badges/github.com/Ullaakut/cameradar.svg" />
|
<img src="https://golangci.com/badges/github.com/ullaakut/cameradar.svg" />
|
||||||
</a>
|
</a>
|
||||||
<a href="https://goreportcard.com/report/github.com/Ullaakut/cameradar">
|
<a href="https://goreportcard.com/report/github.com/ullaakut/cameradar">
|
||||||
<img src="https://goreportcard.com/badge/github.com/Ullaakut/cameradar" />
|
<img src="https://goreportcard.com/badge/github.com/ullaakut/cameradar" />
|
||||||
</a>
|
</a>
|
||||||
<a href="https://github.com/Ullaakut/cameradar/releases/latest">
|
<a href="https://github.com/ullaakut/cameradar/releases/latest">
|
||||||
<img src="https://img.shields.io/github/release/Ullaakut/cameradar.svg?style=flat" />
|
<img src="https://img.shields.io/github/release/Ullaakut/cameradar.svg?style=flat" />
|
||||||
</a>
|
</a>
|
||||||
<a href="https://godoc.org/github.com/Ullaakut/cameradar">
|
<a href="https://godoc.org/github.com/ullaakut/cameradar">
|
||||||
<img src="https://godoc.org/github.com/Ullaakut/cameradar?status.svg" />
|
<img src="https://godoc.org/github.com/ullaakut/cameradar?status.svg" />
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@@ -64,7 +64,7 @@ docker run -t ullaakut/cameradar -t <target> <other command-line options>
|
|||||||
|
|
||||||
[See command-line options](#command-line-options).
|
[See command-line options](#command-line-options).
|
||||||
|
|
||||||
e.g.: `docker run -t ullaakut/cameradar -t 192.168.100.0/24 -l` will scan the ports 554 and 8554 of hosts on the 192.168.100.0/24 subnetwork and attack the discovered RTSP streams and will output debug logs.
|
e.g.: `docker run -t ullaakut/cameradar -t 192.168.100.0/24 -l` will scan the ports 554, 5554 and 8554 of hosts on the 192.168.100.0/24 subnetwork and attack the discovered RTSP streams and will output debug logs.
|
||||||
|
|
||||||
* `YOUR_TARGET` can be a subnet (e.g.: `172.16.100.0/24`), an IP (e.g.: `172.16.100.10`), or a range of IPs (e.g.: `172.16.100.10-20`).
|
* `YOUR_TARGET` can be a subnet (e.g.: `172.16.100.0/24`), an IP (e.g.: `172.16.100.10`), or a range of IPs (e.g.: `172.16.100.10-20`).
|
||||||
* If you want to get the precise results of the nmap scan in the form of an XML file, you can add `-v /your/path:/tmp/cameradar_scan.xml` to the docker run command, before `ullaakut/cameradar`.
|
* If you want to get the precise results of the nmap scan in the form of an XML file, you can add `-v /your/path:/tmp/cameradar_scan.xml` to the docker run command, before `ullaakut/cameradar`.
|
||||||
@@ -88,8 +88,8 @@ Only use this solution if for some reason using docker is not an option for you
|
|||||||
|
|
||||||
Make sure you installed the dependencies mentionned above.
|
Make sure you installed the dependencies mentionned above.
|
||||||
|
|
||||||
1. `go get github.com/Ullaakut/cameradar`
|
1. `go get github.com/ullaakut/cameradar`
|
||||||
2. `cd $GOPATH/src/github.com/Ullaakut/cameradar`
|
2. `cd $GOPATH/src/github.com/ullaakut/cameradar`
|
||||||
3. `dep ensure`
|
3. `dep ensure`
|
||||||
4. `cd cameradar`
|
4. `cd cameradar`
|
||||||
5. `go install`
|
5. `go install`
|
||||||
@@ -101,18 +101,18 @@ The `cameradar` binary is now in your `$GOPATH/bin` ready to be used. See comman
|
|||||||
### Dependencies of the library
|
### Dependencies of the library
|
||||||
|
|
||||||
* `curl-dev` / `libcurl` (depending on your OS)
|
* `curl-dev` / `libcurl` (depending on your OS)
|
||||||
* `nmap`
|
* `github.com/ullaakut/nmap`
|
||||||
* `github.com/pkg/errors`
|
* `github.com/pkg/errors`
|
||||||
* `gopkg.in/go-playground/validator.v9`
|
* `gopkg.in/go-playground/validator.v9`
|
||||||
* `github.com/andelf/go-curl`
|
* `github.com/ullaakut/go-curl`
|
||||||
|
|
||||||
#### Installing the library
|
#### Installing the library
|
||||||
|
|
||||||
`go get github.com/Ullaakut/cameradar`
|
`go get github.com/ullaakut/cameradar`
|
||||||
|
|
||||||
After this command, the _cameradar_ library is ready to use. Its source will be in:
|
After this command, the _cameradar_ library is ready to use. Its source will be in:
|
||||||
|
|
||||||
$GOPATH/src/pkg/github.com/Ullaakut/cameradar
|
$GOPATH/src/pkg/github.com/ullaakut/cameradar
|
||||||
|
|
||||||
You can use `go get -u` to update the package.
|
You can use `go get -u` to update the package.
|
||||||
|
|
||||||
@@ -141,7 +141,7 @@ The cameradar library also provides two functions that take file paths as inputs
|
|||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
The **RTSP port used for most cameras is 554**, so you should probably specify 554 as one of the ports you scan. Not specifying any ports to the cameradar application will scan the 554 and 8554 ports.
|
The **RTSP port used for most cameras is 554**, so you should probably specify 554 as one of the ports you scan. Not specifying any ports to the cameradar application will scan the 554, 5554 and 8554 ports.
|
||||||
|
|
||||||
`docker run -t --net=host ullaakut/cameradar -p "18554,19000-19010" -t localhost` will scan the ports 18554, and the range of ports between 19000 and 19010 on localhost.
|
`docker run -t --net=host ullaakut/cameradar -p "18554,19000-19010" -t localhost` will scan the ports 18554, and the range of ports between 19000 and 19010 on localhost.
|
||||||
|
|
||||||
@@ -165,9 +165,9 @@ With the above result, the RTSP URL would be `rtsp://admin:12345@173.16.100.45:5
|
|||||||
|
|
||||||
## Command line options
|
## Command line options
|
||||||
|
|
||||||
* **"-t, --target"**: 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.
|
* **"-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,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. See [this for more info on the nmap timing templates](https://nmap.org/book/man-performance.html).
|
* **"-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).
|
||||||
* **"-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.
|
* **"-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.
|
||||||
* **"-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
|
||||||
@@ -179,7 +179,7 @@ With the above result, the RTSP URL would be `rtsp://admin:12345@173.16.100.45:5
|
|||||||
|
|
||||||
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
|
||||||
0.0.0.0
|
0.0.0.0
|
||||||
localhost
|
localhost
|
||||||
192.17.0.0/16
|
192.17.0.0/16
|
||||||
@@ -205,7 +205,7 @@ Examples:
|
|||||||
|
|
||||||
This variable is optional and allows you to specify the ports on which to run the scans.
|
This variable is optional and allows you to specify the ports on which to run the scans.
|
||||||
|
|
||||||
Default value: `554,8554`
|
Default value: `554,5554,8554`
|
||||||
|
|
||||||
It is recommended not to change these except if you are certain that cameras have been configured to stream RTSP over a different port. 99.9% of cameras are streaming on these ports.
|
It is recommended not to change these except if you are certain that cameras have been configured to stream RTSP over a different port. 99.9% of cameras are streaming on these ports.
|
||||||
|
|
||||||
@@ -235,7 +235,7 @@ This optional variable allows you to set custom timeout value in miliseconds aft
|
|||||||
|
|
||||||
Default value: `2000`
|
Default value: `2000`
|
||||||
|
|
||||||
### `CAMERADAR_LOGS`
|
### `CAMERADAR_LOGGING`
|
||||||
|
|
||||||
This optional variable allows you to enable a more verbose output to have more information about what is going on.
|
This optional variable allows you to enable a more verbose output to have more information about what is going on.
|
||||||
|
|
||||||
@@ -284,7 +284,7 @@ You can still find it under the 1.1.4 tag on this repo, however it was less perf
|
|||||||
|
|
||||||
> How to use the Cameradar library for my own project?
|
> How to use the Cameradar library for my own project?
|
||||||
|
|
||||||
See the example in `/cameradar`. You just need to run `go get github.com/Ullaakut/cameradar` and to use the `cmrdr` package in your code. You can find the documentation on [godoc](https://godoc.org/github.com/Ullaakut/cameradar).
|
See the example in `/cameradar`. You just need to run `go get github.com/ullaakut/cameradar` and to use the `cmrdr` 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?
|
||||||
|
|
||||||
@@ -310,7 +310,7 @@ Simply run `docker run -p 8554:8554 -e RTSP_USERNAME=admin -e RTSP_PASSWORD=1234
|
|||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
Copyright 2017 Ullaakut
|
Copyright 2019 Ullaakut
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
curl "github.com/andelf/go-curl"
|
curl "github.com/ullaakut/go-curl"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
v "gopkg.in/go-playground/validator.v9"
|
v "gopkg.in/go-playground/validator.v9"
|
||||||
)
|
)
|
||||||
@@ -62,7 +62,6 @@ func routeAttack(c Curler, stream Stream, route string, timeout time.Duration, e
|
|||||||
// Perform the request
|
// Perform the request
|
||||||
err := c.Perform()
|
err := c.Perform()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("\nERROR: curl timeout on stream '%s' reached after %s.\nconsider increasing the timeout (-T, --timeout parameter) to at least 5000ms if scanning an unstable network.\n", stream.Address, timeout.String())
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,7 +113,6 @@ func credAttack(c Curler, stream Stream, username string, password string, timeo
|
|||||||
// Perform the request
|
// Perform the request
|
||||||
err := c.Perform()
|
err := c.Perform()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("\nERROR: curl timeout on stream '%s' reached after %s.\nconsider increasing the timeout (-T, --timeout parameter) to at least 5000ms if scanning an unstable network.\n", stream.Address, timeout.String())
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,7 +166,6 @@ func validateStream(c Curler, stream Stream, timeout time.Duration, enableLogs b
|
|||||||
// Perform the request
|
// Perform the request
|
||||||
err := c.Perform()
|
err := c.Perform()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("\nERROR: curl timeout on stream '%s' reached after %s.\nconsider increasing the timeout (-T, --timeout parameter) to at least 5000ms if scanning an unstable network.\n", stream.Address, timeout.String())
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+13
-2
@@ -7,7 +7,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
curl "github.com/andelf/go-curl"
|
curl "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"
|
||||||
)
|
)
|
||||||
@@ -302,6 +302,7 @@ func TestAttackRoute(t *testing.T) {
|
|||||||
expectedStreams: fakeTargets,
|
expectedStreams: fakeTargets,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, test := range testCases {
|
for i, test := range testCases {
|
||||||
curlerMock := &CurlerMock{}
|
curlerMock := &CurlerMock{}
|
||||||
|
|
||||||
@@ -320,12 +321,14 @@ func TestAttackRoute(t *testing.T) {
|
|||||||
fmt.Printf("unexpected success in AttackRoute test, iteration %d. expected error: %s\n", i, test.expectedErrMsg)
|
fmt.Printf("unexpected success in AttackRoute test, iteration %d. expected error: %s\n", i, test.expectedErrMsg)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Contains(t, err.Error(), test.expectedErrMsg, "wrong error message")
|
assert.Contains(t, err.Error(), test.expectedErrMsg, "wrong error message")
|
||||||
} else {
|
} else {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("unexpected error in AttackRoute test, iteration %d: %v\n", i, err)
|
fmt.Printf("unexpected error in AttackRoute test, iteration %d: %v\n", i, err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, stream := range test.expectedStreams {
|
for _, stream := range test.expectedStreams {
|
||||||
foundStream := false
|
foundStream := false
|
||||||
for _, result := range results {
|
for _, result := range results {
|
||||||
@@ -333,10 +336,13 @@ func TestAttackRoute(t *testing.T) {
|
|||||||
foundStream = true
|
foundStream = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Equal(t, true, foundStream, "wrong streams parsed")
|
assert.Equal(t, true, foundStream, "wrong streams parsed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Equal(t, len(test.expectedStreams), len(results), "wrong streams parsed")
|
assert.Equal(t, len(test.expectedStreams), len(results), "wrong streams parsed")
|
||||||
|
|
||||||
curlerMock.AssertExpectations(t)
|
curlerMock.AssertExpectations(t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -483,12 +489,14 @@ func TestValidateStreams(t *testing.T) {
|
|||||||
fmt.Printf("unexpected success in ValidateStream test, iteration %d. expected error: %s\n", i, tC.expectedErrMsg)
|
fmt.Printf("unexpected success in ValidateStream test, iteration %d. expected error: %s\n", i, tC.expectedErrMsg)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Contains(t, err.Error(), tC.expectedErrMsg, "wrong error message")
|
assert.Contains(t, err.Error(), tC.expectedErrMsg, "wrong error message")
|
||||||
} else {
|
} else {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("unexpected error in ValidateStream test, iteration %d: %v\n", i, err)
|
fmt.Printf("unexpected error in ValidateStream test, iteration %d: %v\n", i, err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, stream := range tC.expectedStreams {
|
for _, stream := range tC.expectedStreams {
|
||||||
foundStream := false
|
foundStream := false
|
||||||
for _, result := range results {
|
for _, result := range results {
|
||||||
@@ -496,15 +504,18 @@ func TestValidateStreams(t *testing.T) {
|
|||||||
foundStream = true
|
foundStream = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Equal(t, true, foundStream, "wrong streams parsed")
|
assert.Equal(t, true, foundStream, "wrong streams parsed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Equal(t, len(tC.expectedStreams), len(results), "wrong streams parsed")
|
assert.Equal(t, len(tC.expectedStreams), len(results), "wrong streams parsed")
|
||||||
|
|
||||||
curlerMock.AssertExpectations(t)
|
curlerMock.AssertExpectations(t)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDotWrite(t *testing.T) {
|
func TestDoNotWrite(t *testing.T) {
|
||||||
assert.Equal(t, true, doNotWrite(nil, nil))
|
assert.Equal(t, true, doNotWrite(nil, nil))
|
||||||
}
|
}
|
||||||
|
|||||||
+58
-71
@@ -7,20 +7,19 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Ullaakut/cameradar"
|
|
||||||
|
|
||||||
curl "github.com/andelf/go-curl"
|
|
||||||
"github.com/fatih/color"
|
|
||||||
"github.com/gernest/wow"
|
"github.com/gernest/wow"
|
||||||
"github.com/gernest/wow/spin"
|
"github.com/gernest/wow/spin"
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
cmrdr "github.com/ullaakut/cameradar"
|
||||||
|
log "github.com/ullaakut/disgo"
|
||||||
|
"github.com/ullaakut/disgo/style"
|
||||||
|
curl "github.com/ullaakut/go-curl"
|
||||||
)
|
)
|
||||||
|
|
||||||
type options struct {
|
type options struct {
|
||||||
Target string
|
Targets []string
|
||||||
Ports string
|
Ports []string
|
||||||
OutputFile string
|
|
||||||
Routes string
|
Routes string
|
||||||
Credentials string
|
Credentials string
|
||||||
Speed int
|
Speed int
|
||||||
@@ -29,22 +28,14 @@ type options struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func parseArguments() error {
|
func parseArguments() error {
|
||||||
|
viper.SetEnvPrefix("cameradar")
|
||||||
|
viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
|
||||||
|
|
||||||
viper.BindEnv("target", "CAMERADAR_TARGET")
|
pflag.StringSliceP("targets", "t", []string{}, "The targets on which to scan for open RTSP streams - required (ex: 172.16.100.0/24)")
|
||||||
viper.BindEnv("ports", "CAMERADAR_PORTS")
|
pflag.StringSliceP("ports", "p", []string{"554", "5554", "8554"}, "The ports on which to search for RTSP streams")
|
||||||
viper.BindEnv("nmap-output", "CAMERADAR_NMAP_OUTPUT_FILE")
|
pflag.StringP("custom-routes", "r", "<GOPATH>/src/github.com/ullaakut/cameradar/dictionaries/routes", "The path on which to load a custom routes dictionary")
|
||||||
viper.BindEnv("custom-routes", "CAMERADAR_CUSTOM_ROUTES")
|
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")
|
||||||
viper.BindEnv("custom-credentials", "CAMERADAR_CUSTOM_CREDENTIALS")
|
pflag.IntP("speed", "s", 4, "The nmap speed preset to use for discovery")
|
||||||
viper.BindEnv("speed", "CAMERADAR_SPEED")
|
|
||||||
viper.BindEnv("timeout", "CAMERADAR_TIMEOUT")
|
|
||||||
viper.BindEnv("envlogs", "CAMERADAR_LOGS")
|
|
||||||
|
|
||||||
pflag.StringP("target", "t", "", "The target on which to scan for open RTSP streams - required (ex: 172.16.100.0/24)")
|
|
||||||
pflag.StringP("ports", "p", "554,8554", "The ports on which to search for RTSP streams")
|
|
||||||
pflag.StringP("nmap-output", "o", "/tmp/cameradar_scan.xml", "The path where nmap will create its XML result file")
|
|
||||||
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.IntP("speed", "s", 4, "The nmap speed preset to use")
|
|
||||||
pflag.IntP("timeout", "T", 2000, "The timeout in miliseconds to use for attack attempts")
|
pflag.IntP("timeout", "T", 2000, "The timeout in miliseconds to use for attack attempts")
|
||||||
pflag.BoolP("log", "l", false, "Enable the logs for nmap's output to stdout")
|
pflag.BoolP("log", "l", false, "Enable the logs for nmap's output to stdout")
|
||||||
pflag.BoolP("help", "h", false, "displays this help message")
|
pflag.BoolP("help", "h", false, "displays this help message")
|
||||||
@@ -67,8 +58,8 @@ func parseArguments() error {
|
|||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
if viper.GetString("target") == "" {
|
if viper.GetStringSlice("targets") == nil {
|
||||||
return errors.New("target (-t, --target) 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")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -76,33 +67,36 @@ func parseArguments() error {
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var options options
|
var options options
|
||||||
|
term := log.NewTerminal()
|
||||||
|
|
||||||
err := parseArguments()
|
err := parseArguments()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
printErr(err)
|
printErr(term, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
options.Credentials = viper.GetString("custom-credentials")
|
options.Credentials = viper.GetString("custom-credentials")
|
||||||
options.EnableLogs = viper.GetBool("log") || viper.GetBool("envlogs")
|
options.EnableLogs = viper.GetBool("log") || viper.GetBool("logging")
|
||||||
options.OutputFile = viper.GetString("nmap-output")
|
options.Ports = viper.GetStringSlice("ports")
|
||||||
options.Ports = viper.GetString("ports")
|
|
||||||
options.Routes = viper.GetString("custom-routes")
|
options.Routes = viper.GetString("custom-routes")
|
||||||
options.Speed = viper.GetInt("speed")
|
options.Speed = viper.GetInt("speed")
|
||||||
options.Timeout = viper.GetInt("timeout")
|
options.Timeout = viper.GetInt("timeout")
|
||||||
options.Target = viper.GetString("target")
|
options.Targets = viper.GetStringSlice("targets")
|
||||||
|
|
||||||
w := startSpinner(options.EnableLogs)
|
w := startSpinner(options.EnableLogs)
|
||||||
|
|
||||||
options.Target, err = cmrdr.ParseTargetsFile(options.Target)
|
if len(options.Targets) == 1 {
|
||||||
if err != nil {
|
options.Targets, err = cmrdr.ParseTargetsFile(options.Targets[0])
|
||||||
printErr(err)
|
if err != nil {
|
||||||
|
printErr(term, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = curl.GlobalInit(curl.GLOBAL_ALL)
|
err = curl.GlobalInit(curl.GLOBAL_ALL)
|
||||||
handle := curl.EasyInit()
|
handle := curl.EasyInit()
|
||||||
if err != nil || handle == nil {
|
if err != nil || handle == nil {
|
||||||
printErr(errors.New("libcurl initialization failed"))
|
printErr(term, errors.New("libcurl initialization failed"))
|
||||||
}
|
}
|
||||||
|
|
||||||
c := &cmrdr.Curl{CURL: handle}
|
c := &cmrdr.Curl{CURL: handle}
|
||||||
defer curl.GlobalCleanup()
|
defer curl.GlobalCleanup()
|
||||||
|
|
||||||
@@ -113,45 +107,45 @@ func main() {
|
|||||||
|
|
||||||
credentials, err := cmrdr.LoadCredentials(options.Credentials)
|
credentials, err := cmrdr.LoadCredentials(options.Credentials)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
color.Red("Invalid credentials dictionary: %s", err.Error())
|
printErr(term, fmt.Errorf("Invalid credentials dictionary %q: %v", options.Credentials, err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
routes, err := cmrdr.LoadRoutes(options.Routes)
|
routes, err := cmrdr.LoadRoutes(options.Routes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
color.Red("Invalid routes dictionary: %s", err.Error())
|
printErr(term, fmt.Errorf("Invalid routes dictionary %q: %v", options.Routes, err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
updateSpinner(w, "Scanning the network...", options.EnableLogs)
|
updateSpinner(w, "Scanning the network...", options.EnableLogs)
|
||||||
streams, err := cmrdr.Discover(options.Target, options.Ports, options.OutputFile, options.Speed, options.EnableLogs)
|
streams, err := cmrdr.Discover(options.Targets, options.Ports, options.Speed)
|
||||||
if err != nil && len(streams) > 0 {
|
if err != nil && len(streams) > 0 {
|
||||||
printErr(err)
|
printErr(term, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Most cameras will be accessed successfully with these two attacks
|
// Most cameras will be accessed successfully with these two attacks
|
||||||
updateSpinner(w, "Found "+fmt.Sprint(len(streams))+" streams. Attacking their routes...", options.EnableLogs)
|
updateSpinner(w, "Found "+fmt.Sprint(len(streams))+" streams. Attacking their routes...", options.EnableLogs)
|
||||||
streams, err = cmrdr.AttackRoute(c, streams, routes, time.Duration(options.Timeout)*time.Millisecond, options.EnableLogs)
|
streams, err = cmrdr.AttackRoute(c, streams, routes, time.Duration(options.Timeout)*time.Millisecond, options.EnableLogs)
|
||||||
if err != nil && len(streams) > 0 {
|
if err != nil && len(streams) > 0 {
|
||||||
printErr(err)
|
printErr(term, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
updateSpinner(w, "Found "+fmt.Sprint(len(streams))+" streams. Attacking their credentials...", options.EnableLogs)
|
updateSpinner(w, "Found "+fmt.Sprint(len(streams))+" streams. Attacking their credentials...", options.EnableLogs)
|
||||||
streams, err = cmrdr.AttackCredentials(c, streams, credentials, time.Duration(options.Timeout)*time.Millisecond, options.EnableLogs)
|
streams, err = cmrdr.AttackCredentials(c, streams, credentials, time.Duration(options.Timeout)*time.Millisecond, options.EnableLogs)
|
||||||
if err != nil && len(streams) > 0 {
|
if err != nil && len(streams) > 0 {
|
||||||
printErr(err)
|
printErr(term, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// But some cameras run GST RTSP Server which prioritizes 401 over 404 contrary to most cameras.
|
// But some cameras run GST RTSP Server which prioritizes 401 over 404 contrary to most cameras.
|
||||||
// For these cameras, running another route attack will solve the problem.
|
// For these cameras, running another route attack will solve the problem.
|
||||||
for _, stream := range streams {
|
for _, stream := range streams {
|
||||||
if !stream.RouteFound || !stream.CredentialsFound {
|
if !stream.RouteFound || !stream.CredentialsFound {
|
||||||
|
|
||||||
updateSpinner(w, "Found "+fmt.Sprint(len(streams))+" streams. Final attack...", options.EnableLogs)
|
updateSpinner(w, "Found "+fmt.Sprint(len(streams))+" streams. Final attack...", options.EnableLogs)
|
||||||
streams, err = cmrdr.AttackRoute(c, streams, routes, time.Duration(options.Timeout)*time.Millisecond, options.EnableLogs)
|
streams, err = cmrdr.AttackRoute(c, streams, routes, time.Duration(options.Timeout)*time.Millisecond, options.EnableLogs)
|
||||||
if err != nil && len(streams) > 0 {
|
if err != nil && len(streams) > 0 {
|
||||||
printErr(err)
|
printErr(term, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -159,69 +153,62 @@ func main() {
|
|||||||
updateSpinner(w, "Found "+fmt.Sprint(len(streams))+" streams. Validating their availability...", options.EnableLogs)
|
updateSpinner(w, "Found "+fmt.Sprint(len(streams))+" streams. Validating their availability...", options.EnableLogs)
|
||||||
streams, err = cmrdr.ValidateStreams(c, streams, time.Duration(options.Timeout)*time.Millisecond, options.EnableLogs)
|
streams, err = cmrdr.ValidateStreams(c, streams, time.Duration(options.Timeout)*time.Millisecond, options.EnableLogs)
|
||||||
if err != nil && len(streams) > 0 {
|
if err != nil && len(streams) > 0 {
|
||||||
printErr(err)
|
printErr(term, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
clearOutput(w, options.EnableLogs)
|
clearOutput(w, options.EnableLogs)
|
||||||
prettyPrint(streams)
|
|
||||||
|
prettyPrint(term, streams)
|
||||||
}
|
}
|
||||||
|
|
||||||
func prettyPrint(streams []cmrdr.Stream) {
|
func prettyPrint(term *log.Terminal, streams []cmrdr.Stream) {
|
||||||
yellow := color.New(color.FgYellow, color.Bold, color.Underline).SprintFunc()
|
|
||||||
blue := color.New(color.FgBlue, color.Underline).SprintFunc()
|
|
||||||
green := color.New(color.FgGreen, color.Bold).SprintFunc()
|
|
||||||
red := color.New(color.FgRed, color.Bold).SprintFunc()
|
|
||||||
white := color.New(color.Italic).SprintFunc()
|
|
||||||
|
|
||||||
success := 0
|
success := 0
|
||||||
|
|
||||||
if len(streams) > 0 {
|
if len(streams) > 0 {
|
||||||
for _, stream := range streams {
|
for _, stream := range streams {
|
||||||
if stream.CredentialsFound && stream.RouteFound && stream.Available {
|
if stream.CredentialsFound && stream.RouteFound && stream.Available {
|
||||||
fmt.Printf("%s\tDevice RTSP URL:\t%s\n", green("\xE2\x96\xB6"), blue(cmrdr.GetCameraRTSPURL(stream)))
|
term.Infof("%s\tDevice RTSP URL:\t%s\n", style.Success(style.SymbolRightTriangle), style.Link(cmrdr.GetCameraRTSPURL(stream)))
|
||||||
success++
|
success++
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("%s\tAdmin panel URL:\t%s %s\n", red("\xE2\x96\xB6"), yellow(cmrdr.GetCameraAdminPanelURL(stream)), white("You can use this URL to try attacking the camera's admin panel instead."))
|
term.Infof("%s\tAdmin panel URL:\t%s You can use this URL to try attacking the camera's admin panel instead.\n", style.Failure(style.SymbolCross), style.Link(cmrdr.GetCameraAdminPanelURL(stream)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("\tDevice model:\t\t%s\n\n", stream.Device)
|
term.Infof("\tDevice model:\t\t%s\n\n", stream.Device)
|
||||||
|
|
||||||
if stream.Available {
|
if stream.Available {
|
||||||
fmt.Printf("\tAvailable:\t\t%s\n", green("yes"))
|
term.Infof("\tAvailable:\t\t%s\n", style.Success(style.SymbolCheck))
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("\tAvailable:\t\t%s\n", red("no"))
|
term.Infof("\tAvailable:\t\t%s\n", style.Failure(style.SymbolCross))
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("\tIP address:\t\t%s\n", stream.Address)
|
term.Infof("\tIP address:\t\t%s\n", stream.Address)
|
||||||
fmt.Printf("\tRTSP port:\t\t%d\n", stream.Port)
|
term.Infof("\tRTSP port:\t\t%d\n", stream.Port)
|
||||||
if stream.CredentialsFound {
|
if stream.CredentialsFound {
|
||||||
fmt.Printf("\tUsername:\t\t%s\n", green(stream.Username))
|
term.Infof("\tUsername:\t\t%s\n", style.Success(stream.Username))
|
||||||
fmt.Printf("\tPassword:\t\t%s\n", green(stream.Password))
|
term.Infof("\tPassword:\t\t%s\n", style.Success(stream.Password))
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("\tUsername:\t\t%s\n", red("not found"))
|
term.Infof("\tUsername:\t\t%s\n", style.Failure("not found"))
|
||||||
fmt.Printf("\tPassword:\t\t%s\n", red("not found"))
|
term.Infof("\tPassword:\t\t%s\n", style.Failure("not found"))
|
||||||
}
|
}
|
||||||
if stream.RouteFound {
|
if stream.RouteFound {
|
||||||
fmt.Printf("\tRTSP route:\t\t%s\n\n\n", green("/"+stream.Route))
|
term.Infof("\tRTSP route:\t\t%s\n\n\n", style.Success("/"+stream.Route))
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("\tRTSP route:\t\t%s\n\n\n", red("not found"))
|
term.Infof("\tRTSP route:\t\t%s\n\n\n", style.Failure("not found"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if success > 1 {
|
if success > 1 {
|
||||||
fmt.Printf("%s Successful attack: %s devices were accessed", green("\xE2\x9C\x94"), green(len(streams)))
|
term.Infof("%s Successful attack: %s devices were accessed", style.Success(style.SymbolCheck), style.Success(len(streams)))
|
||||||
} else if success == 1 {
|
} else if success == 1 {
|
||||||
fmt.Printf("%s Successful attack: %s device was accessed", green("\xE2\x9C\x94"), green(len(streams)))
|
term.Infof("%s Successful attack: %s device was accessed", style.Success(style.SymbolCheck), style.Success(len(streams)))
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("%s Streams were found but none were accessed. They are most likely configured with secure credentials and routes. You can try adding entries to the dictionary or generating your own in order to attempt a bruteforce attack on the cameras.\n", red("\xE2\x9C\x96"))
|
term.Infof("%s Streams were found but none were accessed. They are most likely configured with secure credentials and routes. You can try adding entries to the dictionary or generating your own in order to attempt a bruteforce attack on the cameras.\n", style.Failure("\xE2\x9C\x96"))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("%s No streams were found. Please make sure that your target is on an accessible network.\n", red("\xE2\x9C\x96"))
|
term.Infof("%s No streams were found. Please make sure that your target is on an accessible network.\n", style.Failure(style.SymbolCross))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func printErr(err error) {
|
func printErr(term *log.Terminal, err error) {
|
||||||
red := color.New(color.FgRed, color.Bold).SprintFunc()
|
term.Errorln(style.Failure(style.SymbolCross), err)
|
||||||
fmt.Printf("%s %v\n", red("\xE2\x9C\x96"), err)
|
|
||||||
os.Exit(1)
|
os.Exit(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
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package cmrdr
|
package cmrdr
|
||||||
|
|
||||||
import (
|
import (
|
||||||
curl "github.com/andelf/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
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package cmrdr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
curl "github.com/ullaakut/go-curl"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCurl(t *testing.T) {
|
||||||
|
handle := Curl{
|
||||||
|
CURL: curl.EasyInit(),
|
||||||
|
}
|
||||||
|
|
||||||
|
handle2 := handle.Duphandle()
|
||||||
|
|
||||||
|
if reflect.DeepEqual(handle, handle2) {
|
||||||
|
t.Errorf("unexpected identical handle from duphandle: expected %+v got %+v", handle, handle2)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,41 +1,43 @@
|
|||||||
{
|
{
|
||||||
"usernames": [
|
"usernames": [
|
||||||
"",
|
"",
|
||||||
"admin",
|
|
||||||
"Admin",
|
|
||||||
"Administrator",
|
|
||||||
"root",
|
|
||||||
"supervisor",
|
|
||||||
"ubnt",
|
|
||||||
"service",
|
|
||||||
"Dinion",
|
|
||||||
"administrator",
|
|
||||||
"666666",
|
"666666",
|
||||||
"888888",
|
"888888",
|
||||||
"admin1"
|
"Admin",
|
||||||
|
"admin",
|
||||||
|
"admin1",
|
||||||
|
"administrator",
|
||||||
|
"Administrator",
|
||||||
|
"Dinion",
|
||||||
|
"root",
|
||||||
|
"service",
|
||||||
|
"supervisor",
|
||||||
|
"ubnt"
|
||||||
],
|
],
|
||||||
"passwords" : [
|
"passwords" : [
|
||||||
"",
|
"",
|
||||||
"admin",
|
|
||||||
"9999",
|
|
||||||
"123456",
|
|
||||||
"pass",
|
|
||||||
"camera",
|
|
||||||
"1234",
|
|
||||||
"12345",
|
|
||||||
"fliradmin",
|
|
||||||
"system",
|
|
||||||
"jvc",
|
|
||||||
"meinsm",
|
|
||||||
"root",
|
|
||||||
"4321",
|
|
||||||
"111111",
|
"111111",
|
||||||
"1111111",
|
"1111111",
|
||||||
"password",
|
"1234",
|
||||||
|
"12345",
|
||||||
|
"123456",
|
||||||
|
"4321",
|
||||||
|
"666666",
|
||||||
|
"888888",
|
||||||
|
"9999",
|
||||||
|
"admin",
|
||||||
|
"camera",
|
||||||
|
"fliradmin",
|
||||||
"ikwd",
|
"ikwd",
|
||||||
|
"jvc",
|
||||||
|
"meinsm",
|
||||||
|
"pass",
|
||||||
|
"password",
|
||||||
|
"root",
|
||||||
|
"service",
|
||||||
"supervisor",
|
"supervisor",
|
||||||
|
"system",
|
||||||
"ubnt",
|
"ubnt",
|
||||||
"wbox123",
|
"wbox123"
|
||||||
"service"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
|
|
||||||
1.AMP
|
1.AMP
|
||||||
|
1/h264major
|
||||||
1/stream1
|
1/stream1
|
||||||
CAM_ID.password.mp2
|
CAM_ID.password.mp2
|
||||||
GetData.cgi
|
GetData.cgi
|
||||||
@@ -37,6 +38,8 @@ ipcam.sdp
|
|||||||
ipcam_h264.sdp
|
ipcam_h264.sdp
|
||||||
live.sdp
|
live.sdp
|
||||||
live/h264
|
live/h264
|
||||||
|
live/main
|
||||||
|
live/main0
|
||||||
live/mpeg4
|
live/mpeg4
|
||||||
live_mpeg4.sdp
|
live_mpeg4.sdp
|
||||||
livestream
|
livestream
|
||||||
|
|||||||
+36
-136
@@ -1,138 +1,11 @@
|
|||||||
package cmrdr
|
package cmrdr
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"encoding/xml"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"os/exec"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/ullaakut/nmap"
|
||||||
v "gopkg.in/go-playground/validator.v9"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// These constants detail the different level of nmap speed presets
|
|
||||||
// that determine the timeout values and wether or not nmap makes use of parallelism
|
|
||||||
const (
|
|
||||||
// PARANOIAC NO PARALLELISM | 5min timeout | 100ms to 10s round-trip time timeout | 5mn scan delay
|
|
||||||
PARANOIAC = 0
|
|
||||||
// SNEAKY NO PARALLELISM | 15sec timeout | 100ms to 10s round-trip time timeout | 15s scan delay
|
|
||||||
SNEAKY = 1
|
|
||||||
// POLITE NO PARALLELISM | 1sec timeout | 100ms to 10s round-trip time timeout | 400ms scan delay
|
|
||||||
POLITE = 2
|
|
||||||
// NORMAL PARALLELISM | 1sec timeout | 100ms to 10s round-trip time timeout | 0s scan delay
|
|
||||||
NORMAL = 3
|
|
||||||
// AGGRESSIVE PARALLELISM | 500ms timeout | 100ms to 1250ms round-trip time timeout | 0s scan delay
|
|
||||||
AGGRESSIVE = 4
|
|
||||||
// INSANE PARALLELISM | 250ms timeout | 50ms to 300ms round-trip time timeout | 0s scan delay
|
|
||||||
INSANE = 5
|
|
||||||
)
|
|
||||||
|
|
||||||
// Allows unit tests to override the exec function to avoid launching a real command
|
|
||||||
// during the tests. The NmapRun method will soon be refactored with an adaptor in order
|
|
||||||
// to make it possible to mock all external calls.
|
|
||||||
var execCommand = exec.Command
|
|
||||||
|
|
||||||
// NmapRun runs nmap on the specified targets's specified ports, using the given nmap speed.
|
|
||||||
func NmapRun(targets, ports, resultFilePath string, nmapSpeed int, enableLogs bool) error {
|
|
||||||
if nmapSpeed < PARANOIAC || nmapSpeed > INSANE {
|
|
||||||
return fmt.Errorf("invalid nmap speed value '%d'. Should be between '%d' and '%d'", nmapSpeed, PARANOIAC, INSANE)
|
|
||||||
}
|
|
||||||
|
|
||||||
cmdArgs := fmt.Sprintf(
|
|
||||||
"-T%d -A -p %s -oX %s %s",
|
|
||||||
nmapSpeed,
|
|
||||||
ports,
|
|
||||||
resultFilePath,
|
|
||||||
targets)
|
|
||||||
|
|
||||||
if enableLogs {
|
|
||||||
fmt.Printf("command: nmap %s\n", cmdArgs)
|
|
||||||
}
|
|
||||||
|
|
||||||
args := strings.Split(cmdArgs, " ")
|
|
||||||
|
|
||||||
// Prepare nmap command
|
|
||||||
cmd := execCommand("nmap", args...)
|
|
||||||
|
|
||||||
// Pipe stdout to be able to write the logs in realtime
|
|
||||||
stdout, err := cmd.StdoutPipe()
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "couldn't get stdout pipe")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Execute the nmap command
|
|
||||||
if err := cmd.Start(); err != nil {
|
|
||||||
return errors.Wrap(err, "coudln't run nmap command")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scan the pipe until an end of file or an error occurs
|
|
||||||
in := bufio.NewScanner(stdout)
|
|
||||||
for in.Scan() {
|
|
||||||
if enableLogs {
|
|
||||||
fmt.Println(in.Text())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err := in.Err(); err != nil {
|
|
||||||
if enableLogs {
|
|
||||||
fmt.Printf("error: %s\n", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// NmapParseResults returns a slice of streams from an NMap XML result file.
|
|
||||||
// To generate one yourself, use the -X option when running NMap.
|
|
||||||
func NmapParseResults(nmapResultFilePath string) ([]Stream, error) {
|
|
||||||
var streams []Stream
|
|
||||||
|
|
||||||
// Open & Read XML file
|
|
||||||
content, err := ioutil.ReadFile(nmapResultFilePath)
|
|
||||||
if err != nil {
|
|
||||||
return streams, errors.Wrap(err, "could not read nmap result file at "+nmapResultFilePath+":")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unmarshal content of XML file into data structure
|
|
||||||
result := &nmapResult{}
|
|
||||||
err = xml.Unmarshal(content, &result)
|
|
||||||
if err != nil {
|
|
||||||
return streams, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Iterate on hosts to try to find hosts with ports that
|
|
||||||
// - serve RTSP
|
|
||||||
// - are open
|
|
||||||
validate := v.New()
|
|
||||||
for _, host := range result.Hosts {
|
|
||||||
if host.Ports.Ports == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
for _, port := range host.Ports.Ports {
|
|
||||||
err = validate.Struct(port)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, addr := range host.Addresses {
|
|
||||||
err = validate.Struct(addr)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
streams = append(streams, Stream{
|
|
||||||
Device: port.Service.Product,
|
|
||||||
Address: addr.Addr,
|
|
||||||
Port: port.PortID,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return streams, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Discover scans the target networks and tries to find RTSP streams within them.
|
// Discover scans the target networks and tries to find RTSP streams within them.
|
||||||
//
|
//
|
||||||
// targets can be:
|
// targets can be:
|
||||||
@@ -145,19 +18,46 @@ func NmapParseResults(nmapResultFilePath string) ([]Stream, error) {
|
|||||||
// ports can be:
|
// ports can be:
|
||||||
//
|
//
|
||||||
// - one or multiple ports and port ranges separated by commas (e.g.: 554,8554-8560,18554-28554)
|
// - one or multiple ports and port ranges separated by commas (e.g.: 554,8554-8560,18554-28554)
|
||||||
func Discover(targets, ports, nmapResultPath string, speed int, log bool) ([]Stream, error) {
|
func Discover(targets, ports []string, speed int) ([]Stream, error) {
|
||||||
var streams []Stream
|
|
||||||
|
|
||||||
// Run nmap command to discover open ports on the specified targets & ports
|
// Run nmap command to discover open ports on the specified targets & ports
|
||||||
err := NmapRun(targets, ports, nmapResultPath, speed, log)
|
scanner, err := nmap.NewScanner(
|
||||||
|
nmap.WithTargets(targets...),
|
||||||
|
nmap.WithPorts(ports...),
|
||||||
|
nmap.WithTimingTemplate(nmap.Timing(speed)),
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return streams, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get found streams from nmap results
|
return scan(scanner)
|
||||||
streams, err = NmapParseResults(nmapResultPath)
|
}
|
||||||
|
|
||||||
|
func scan(scanner nmap.ScanRunner) ([]Stream, error) {
|
||||||
|
results, err := scanner.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return streams, err
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var streams []Stream
|
||||||
|
// Get streams from nmap results
|
||||||
|
for _, host := range results.Hosts {
|
||||||
|
for _, port := range host.Ports {
|
||||||
|
if port.Status() != "open" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.Contains(port.Service.Name, "rtsp") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, address := range host.Addresses {
|
||||||
|
streams = append(streams, Stream{
|
||||||
|
Device: port.Service.Product,
|
||||||
|
Address: address.Addr,
|
||||||
|
Port: port.ID,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return streams, nil
|
return streams, nil
|
||||||
|
|||||||
+209
-718
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,18 @@
|
|||||||
|
module github.com/ullaakut/cameradar
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/Ullaakut/nmap v0.0.0-20190306183004-e38898a9bead // indirect
|
||||||
|
github.com/fatih/color v1.7.0 // indirect
|
||||||
|
github.com/gernest/wow v0.1.0 // indirect
|
||||||
|
github.com/go-playground/locales v0.12.1 // indirect
|
||||||
|
github.com/go-playground/universal-translator v0.16.0 // indirect
|
||||||
|
github.com/leodido/go-urn v1.1.0 // indirect
|
||||||
|
github.com/mattn/go-colorable v0.1.1 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.6 // indirect
|
||||||
|
github.com/pkg/errors v0.8.1
|
||||||
|
github.com/spf13/viper v1.3.1 // indirect
|
||||||
|
github.com/ullaakut/disgo v0.3.0 // indirect
|
||||||
|
github.com/ullaakut/go-curl v0.0.0-20190310175419-50acab4cef70
|
||||||
|
github.com/ullaakut/nmap v0.0.0-20190306183004-e38898a9bead
|
||||||
|
gopkg.in/go-playground/validator.v9 v9.27.0
|
||||||
|
)
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
github.com/Ullaakut/nmap v0.0.0-20190306183004-e38898a9bead h1:iclmd4In7CnuZGbbnnaeF1DtSePgXxN71pq5UNI1M7c=
|
||||||
|
github.com/Ullaakut/nmap v0.0.0-20190306183004-e38898a9bead/go.mod h1:fkC066hwfcoKwlI7DS2ARTggSVtBTZYCjVH1TzuTMaQ=
|
||||||
|
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||||
|
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||||
|
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
||||||
|
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
|
||||||
|
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||||
|
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||||
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
|
github.com/gernest/wow v0.1.0 h1:g9xdwCwP0+xgVYlA2sopI0gZHqXe7HjI/7/LykG4fks=
|
||||||
|
github.com/gernest/wow v0.1.0/go.mod h1:dEPabJRi5BneI1Nev1VWo0ZlcTWibHWp43qxKms4elY=
|
||||||
|
github.com/go-playground/locales v0.12.1 h1:2FITxuFt/xuCNP1Acdhv62OzaCiviiE4kotfhkmOqEc=
|
||||||
|
github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
|
||||||
|
github.com/go-playground/universal-translator v0.16.0 h1:X++omBR/4cE2MNg91AoC3rmGrCjJ8eAeUP/K/EKx4DM=
|
||||||
|
github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY=
|
||||||
|
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||||
|
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||||
|
github.com/leodido/go-urn v1.1.0 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8=
|
||||||
|
github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
|
||||||
|
github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
|
||||||
|
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
|
github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg=
|
||||||
|
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
||||||
|
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||||
|
github.com/mattn/go-isatty v0.0.6 h1:SrwhHcpV4nWrMGdNcC2kXpMfcBVYGDuTArqyhocJgvA=
|
||||||
|
github.com/mattn/go-isatty v0.0.6/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||||
|
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
||||||
|
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
|
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/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||||
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
|
||||||
|
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||||
|
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
|
||||||
|
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
|
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
|
||||||
|
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||||
|
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
|
||||||
|
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
|
github.com/spf13/viper v1.3.1 h1:5+8j8FTpnFV4nEImW/ofkzEt8VoOiLXxdYIDsB73T38=
|
||||||
|
github.com/spf13/viper v1.3.1/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
||||||
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
|
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||||
|
github.com/ullaakut/disgo v0.0.0-20190310161027-e17c43d71b3d h1:tObr2ILgSQwrhpQRiVUKHtXF+0V5gYnnd/zBQGAmfuQ=
|
||||||
|
github.com/ullaakut/disgo v0.0.0-20190310161027-e17c43d71b3d/go.mod h1:UOgLVyqihzJ7yihrHjYZikivT+AHb9NhT3r1OyPCJqg=
|
||||||
|
github.com/ullaakut/disgo v0.3.0 h1:2zrEyNBfPRgDVDgzM/qLXZ4Yqt3Lxz7ERvZUSmqSY2M=
|
||||||
|
github.com/ullaakut/disgo v0.3.0/go.mod h1:UOgLVyqihzJ7yihrHjYZikivT+AHb9NhT3r1OyPCJqg=
|
||||||
|
github.com/ullaakut/go-curl v0.0.0-20190310175419-50acab4cef70 h1:3q4hgRu9NT894aYmnoMFl5wPvdNhpHYmdi2+Njyxq5U=
|
||||||
|
github.com/ullaakut/go-curl v0.0.0-20190310175419-50acab4cef70/go.mod h1:FTfXm4jC9Ff1yqc3/HMXCyr+SGO03vJyijJCQlNyF10=
|
||||||
|
github.com/ullaakut/nmap v0.0.0-20190306183004-e38898a9bead h1:Pw5wKSAfxi8GcYJSc3GdcwtPG5tyg7zg9E3hAHbLPO0=
|
||||||
|
github.com/ullaakut/nmap v0.0.0-20190306183004-e38898a9bead/go.mod h1:4CQy4PqZA4Snk3+MS26+1oAkJ8dCY8kGH6+kF42yajw=
|
||||||
|
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||||
|
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
|
golang.org/x/crypto v0.0.0-20190103213133-ff983b9c42bc h1:F5tKCVGp+MUAHhKp5MZtGqAlGX3+oCsiL1Q629FL90M=
|
||||||
|
golang.org/x/crypto v0.0.0-20190103213133-ff983b9c42bc/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
|
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190116161447-11f53e031339 h1:g/Jesu8+QLnA0CPzF3E1pURg0Byr7i6jLoX5sqjcAh0=
|
||||||
|
golang.org/x/sys v0.0.0-20190116161447-11f53e031339/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/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/go-playground/validator.v9 v9.27.0 h1:wCg/0hk9RzcB0CYw8pYV6FiBYug1on0cpco9YZF8jqA=
|
||||||
|
gopkg.in/go-playground/validator.v9 v9.27.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
@@ -12,6 +12,7 @@ func replace(streams []Stream, new Stream) []Stream {
|
|||||||
updatedSlice = append(updatedSlice, old)
|
updatedSlice = append(updatedSlice, old)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return updatedSlice
|
return updatedSlice
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
-5
@@ -61,6 +61,7 @@ func LoadRoutes(path string) (Routes, error) {
|
|||||||
|
|
||||||
var routes Routes
|
var routes Routes
|
||||||
scanner := bufio.NewScanner(file)
|
scanner := bufio.NewScanner(file)
|
||||||
|
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
routes = append(routes, scanner.Text())
|
routes = append(routes, scanner.Text())
|
||||||
}
|
}
|
||||||
@@ -87,22 +88,22 @@ func ParseRoutesFromString(content string) Routes {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ParseTargetsFile parses an input file containing hosts to targets
|
// ParseTargetsFile parses an input file containing hosts to targets
|
||||||
func ParseTargetsFile(path string) (string, error) {
|
func ParseTargetsFile(path string) ([]string, error) {
|
||||||
_, err := fs.Stat(path)
|
_, err := fs.Stat(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return path, nil
|
return []string{path}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
file, err := fs.Open(path)
|
file, err := fs.Open(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return path, err
|
return []string{path}, err
|
||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
|
|
||||||
bytes, err := ioutil.ReadAll(file)
|
bytes, err := ioutil.ReadAll(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return path, err
|
return []string{path}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return strings.Replace(string(bytes), "\n", " ", -1), nil
|
return strings.Split(string(bytes), "\n"), nil
|
||||||
}
|
}
|
||||||
|
|||||||
+26
-6
@@ -122,6 +122,7 @@ func TestLoadCredentials(t *testing.T) {
|
|||||||
input: []byte("{\"invalid\":\"json\"}"),
|
input: []byte("{\"invalid\":\"json\"}"),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, test := range testCases {
|
for i, test := range testCases {
|
||||||
filePath := "/tmp/cameradar_test_load_credentials_" + fmt.Sprint(i) + ".xml"
|
filePath := "/tmp/cameradar_test_load_credentials_" + fmt.Sprint(i) + ".xml"
|
||||||
// create file
|
// create file
|
||||||
@@ -145,12 +146,14 @@ func TestLoadCredentials(t *testing.T) {
|
|||||||
fmt.Printf("unexpected success in LoadCredentials test, iteration %d. expected error: %s\n", i, test.expectedErrMsg)
|
fmt.Printf("unexpected success in LoadCredentials test, iteration %d. expected error: %s\n", i, test.expectedErrMsg)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Contains(t, err.Error(), test.expectedErrMsg, "wrong error message")
|
assert.Contains(t, err.Error(), test.expectedErrMsg, "wrong error message")
|
||||||
} else {
|
} else {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("unexpected error in LoadCredentials test, iteration %d: %v\n", i, err)
|
fmt.Printf("unexpected error in LoadCredentials test, iteration %d: %v\n", i, err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, expectedUsername := range test.expectedOutput.Usernames {
|
for _, expectedUsername := range test.expectedOutput.Usernames {
|
||||||
foundUsername := false
|
foundUsername := false
|
||||||
for _, username := range result.Usernames {
|
for _, username := range result.Usernames {
|
||||||
@@ -158,8 +161,10 @@ func TestLoadCredentials(t *testing.T) {
|
|||||||
foundUsername = true
|
foundUsername = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Equal(t, true, foundUsername, "wrong usernames parsed")
|
assert.Equal(t, true, foundUsername, "wrong usernames parsed")
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, expectedPassword := range test.expectedOutput.Passwords {
|
for _, expectedPassword := range test.expectedOutput.Passwords {
|
||||||
foundPassword := false
|
foundPassword := false
|
||||||
for _, password := range result.Passwords {
|
for _, password := range result.Passwords {
|
||||||
@@ -167,6 +172,7 @@ func TestLoadCredentials(t *testing.T) {
|
|||||||
foundPassword = true
|
foundPassword = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Equal(t, true, foundPassword, "wrong passwords parsed")
|
assert.Equal(t, true, foundPassword, "wrong passwords parsed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -202,8 +208,10 @@ func TestLoadRoutes(t *testing.T) {
|
|||||||
input: []byte(""),
|
input: []byte(""),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, test := range testCases {
|
for i, test := range testCases {
|
||||||
filePath := "/tmp/cameradar_test_load_routes_" + fmt.Sprint(i) + ".xml"
|
filePath := "/tmp/cameradar_test_load_routes_" + fmt.Sprint(i) + ".xml"
|
||||||
|
|
||||||
// create file
|
// create file
|
||||||
if test.fileExists {
|
if test.fileExists {
|
||||||
_, err := os.Create(filePath)
|
_, err := os.Create(filePath)
|
||||||
@@ -231,6 +239,7 @@ func TestLoadRoutes(t *testing.T) {
|
|||||||
fmt.Printf("unexpected error in LoadRoutes test, iteration %d: %v\n", i, err)
|
fmt.Printf("unexpected error in LoadRoutes test, iteration %d: %v\n", i, err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, expectedRoute := range test.expectedOutput {
|
for _, expectedRoute := range test.expectedOutput {
|
||||||
foundRoute := false
|
foundRoute := false
|
||||||
for _, route := range result {
|
for _, route := range result {
|
||||||
@@ -238,6 +247,7 @@ func TestLoadRoutes(t *testing.T) {
|
|||||||
foundRoute = true
|
foundRoute = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Equal(t, true, foundRoute, "wrong routes parsed")
|
assert.Equal(t, true, foundRoute, "wrong routes parsed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -352,7 +362,7 @@ func TestParseTargetsFile(t *testing.T) {
|
|||||||
openError bool
|
openError bool
|
||||||
readError bool
|
readError bool
|
||||||
|
|
||||||
expectedResult string
|
expectedResult []string
|
||||||
expectedError error
|
expectedError error
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
@@ -360,7 +370,7 @@ func TestParseTargetsFile(t *testing.T) {
|
|||||||
|
|
||||||
fileExists: false,
|
fileExists: false,
|
||||||
|
|
||||||
expectedResult: "0.0.0.0",
|
expectedResult: []string{"0.0.0.0"},
|
||||||
expectedError: nil,
|
expectedError: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -368,7 +378,7 @@ func TestParseTargetsFile(t *testing.T) {
|
|||||||
|
|
||||||
fileExists: true,
|
fileExists: true,
|
||||||
|
|
||||||
expectedResult: "0.0.0.0 localhost 192.17.0.0/16 192.168.1.140-255 192.168.2-3.0-255",
|
expectedResult: []string{"0.0.0.0", "localhost", "192.17.0.0/16", "192.168.1.140-255", "192.168.2-3.0-255"},
|
||||||
expectedError: nil,
|
expectedError: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -377,7 +387,7 @@ func TestParseTargetsFile(t *testing.T) {
|
|||||||
fileExists: true,
|
fileExists: true,
|
||||||
openError: true,
|
openError: true,
|
||||||
|
|
||||||
expectedResult: "test_does_not_really_exist",
|
expectedResult: []string{"test_does_not_really_exist"},
|
||||||
expectedError: os.ErrNotExist,
|
expectedError: os.ErrNotExist,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -386,7 +396,7 @@ func TestParseTargetsFile(t *testing.T) {
|
|||||||
fileExists: true,
|
fileExists: true,
|
||||||
readError: true,
|
readError: true,
|
||||||
|
|
||||||
expectedResult: "test_does_not_really_exist",
|
expectedResult: []string{"test_does_not_really_exist"},
|
||||||
expectedError: os.ErrNotExist,
|
expectedError: os.ErrNotExist,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -399,10 +409,20 @@ func TestParseTargetsFile(t *testing.T) {
|
|||||||
readError: test.readError,
|
readError: test.readError,
|
||||||
}
|
}
|
||||||
mfs.fileMock.On("Close").Return(nil)
|
mfs.fileMock.On("Close").Return(nil)
|
||||||
mfs.fileMock.WriteString("0.0.0.0 localhost 192.17.0.0/16 192.168.1.140-255 192.168.2-3.0-255")
|
mfs.fileMock.WriteString("0.0.0.0\nlocalhost\n192.17.0.0/16\n192.168.1.140-255\n192.168.2-3.0-255")
|
||||||
|
|
||||||
result, err := ParseTargetsFile(test.input)
|
result, err := ParseTargetsFile(test.input)
|
||||||
assert.Equal(t, test.expectedResult, result, "unexpected result, parse error")
|
assert.Equal(t, test.expectedResult, result, "unexpected result, parse error")
|
||||||
assert.Equal(t, test.expectedError, err, "unexpected error")
|
assert.Equal(t, test.expectedError, err, "unexpected error")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is completely useless and just lets me
|
||||||
|
// not look at these two red lines on the coverage
|
||||||
|
// any longer.
|
||||||
|
func TestFS(t *testing.T) {
|
||||||
|
fs := osFS{}
|
||||||
|
|
||||||
|
fs.Open("test")
|
||||||
|
fs.Stat("test")
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ type Stream struct {
|
|||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
Route string `json:"route"`
|
Route string `json:"route"`
|
||||||
Address string `json:"address" validate:"required"`
|
Address string `json:"address" validate:"required"`
|
||||||
Port uint `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"`
|
||||||
@@ -30,9 +30,8 @@ type Routes []string
|
|||||||
|
|
||||||
// Options contains all options needed to launch a complete cameradar scan
|
// Options contains all options needed to launch a complete cameradar scan
|
||||||
type Options struct {
|
type Options struct {
|
||||||
Target string `json:"target" validate:"required"`
|
Targets []string `json:"target" validate:"required"`
|
||||||
Ports string `json:"ports"`
|
Ports []string `json:"ports"`
|
||||||
OutputFile string `json:"output_file"`
|
|
||||||
Routes Routes `json:"routes"`
|
Routes Routes `json:"routes"`
|
||||||
Credentials Credentials `json:"credentials"`
|
Credentials Credentials `json:"credentials"`
|
||||||
Speed int `json:"speed"`
|
Speed int `json:"speed"`
|
||||||
|
|||||||
@@ -1,50 +0,0 @@
|
|||||||
package cmrdr
|
|
||||||
|
|
||||||
import "encoding/xml"
|
|
||||||
|
|
||||||
// NmapResult is the structure that holds all the information from an NMap scan
|
|
||||||
type nmapResult struct {
|
|
||||||
XMLName xml.Name `xml:"nmaprun"`
|
|
||||||
Hosts []host `xml:"host" validate:"required"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Host represents a host discovered during a scan
|
|
||||||
type host struct {
|
|
||||||
XMLName xml.Name `xml:"host"`
|
|
||||||
Addresses []address `xml:"address"`
|
|
||||||
Ports ports `xml:"ports"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Address is a host's address discovered during a scan
|
|
||||||
type address struct {
|
|
||||||
XMLName xml.Name `xml:"address"`
|
|
||||||
Addr string `xml:"addr,attr"`
|
|
||||||
AddrType string `xml:"addrtype,attr" validate:"required,eq=ipv4|eq=ipv6"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ports is the list of openned ports on a host
|
|
||||||
type ports struct {
|
|
||||||
XMLName xml.Name `xml:"ports"`
|
|
||||||
Ports []port `xml:"port"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Port is a port found on a host during a scan
|
|
||||||
type port struct {
|
|
||||||
XMLName xml.Name `xml:"port"`
|
|
||||||
PortID uint `xml:"portid,attr"`
|
|
||||||
State state `xml:"state"`
|
|
||||||
Service service `xml:"service"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// State is the state of a port
|
|
||||||
type state struct {
|
|
||||||
XMLName xml.Name `xml:"state"`
|
|
||||||
State string `xml:"state,attr" validate:"required,eq=open"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Service represents the service that a port provides
|
|
||||||
type service struct {
|
|
||||||
XMLName xml.Name `xml:"service"`
|
|
||||||
Name string `xml:"name,attr" validate:"required,eq=rtsp"`
|
|
||||||
Product string `xml:"product,attr"`
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user