diff --git a/.clang-format b/.clang-format
deleted file mode 100644
index c4a0e94..0000000
--- a/.clang-format
+++ /dev/null
@@ -1,61 +0,0 @@
----
-Language: Cpp
-# BasedOnStyle: Mozilla
-AccessModifierOffset: -4
-ConstructorInitializerIndentWidth: 0
-AlignEscapedNewlinesLeft: false
-AlignTrailingComments: true
-AllowAllParametersOfDeclarationOnNextLine: true
-AllowShortBlocksOnASingleLine: true
-AllowShortCaseLabelsOnASingleLine: true
-AllowShortIfStatementsOnASingleLine: true
-AllowShortLoopsOnASingleLine: true
-AllowShortFunctionsOnASingleLine: All
-AlwaysBreakAfterDefinitionReturnType: true
-AlwaysBreakTemplateDeclarations: true
-AlwaysBreakBeforeMultilineStrings: true
-BreakBeforeBinaryOperators: None
-BreakBeforeTernaryOperators: true
-BreakConstructorInitializersBeforeComma: true
-BinPackParameters: false
-BinPackArguments: false
-ColumnLimit: 100
-ConstructorInitializerAllOnOneLineOrOnePerLine: true
-DerivePointerAlignment: false
-ExperimentalAutoDetectBinPacking: false
-IndentCaseLabels: false
-IndentWrappedFunctionNames: false
-IndentFunctionDeclarationAfterType: false
-MaxEmptyLinesToKeep: 1
-KeepEmptyLinesAtTheStartOfBlocks: false
-NamespaceIndentation: None
-ObjCSpaceAfterProperty: false
-ObjCSpaceBeforeProtocolList: true
-PenaltyBreakBeforeFirstCallParameter: 19
-PenaltyBreakComment: 300
-PenaltyBreakString: 1000
-PenaltyBreakFirstLessLess: 120
-PenaltyExcessCharacter: 1000000
-PenaltyReturnTypeOnItsOwnLine: 60
-PointerAlignment: Left
-SpacesBeforeTrailingComments: 1
-Cpp11BracedListStyle: false
-Standard: Cpp11
-IndentWidth: 4
-TabWidth: 8
-UseTab: Never
-BreakBeforeBraces: Attach
-SpacesInParentheses: false
-SpacesInSquareBrackets: false
-SpacesInAngles: false
-SpaceInEmptyParentheses: false
-SpacesInCStyleCastParentheses: false
-SpaceAfterCStyleCast: false
-SpacesInContainerLiterals: true
-SpaceBeforeAssignmentOperators: true
-ContinuationIndentWidth: 4
-CommentPragmas: '^ IWYU pragma:'
-ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
-SpaceBeforeParens: ControlStatements
-DisableFormat: false
-...
diff --git a/.gitignore b/.gitignore
index 3f6901c..fa20c39 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,46 +1,15 @@
-# Compiled Object files
-*.slo
-*.lo
-*.o
-*.obj
-
-# Precompiled Headers
-*.gch
-*.pch
-
-# Compiled Dynamic libraries
-*.so
-*.dylib
-*.dll
-
-# Fortran module files
-*.mod
-
-# Compiled Static libraries
-*.lai
-*.la
-*.a
-*.lib
-
-# Executables
-*.exe
-*.out
-*.app
-
# Results
result.json
-test-results.xml
+*.xml
-# Build
-build/
-
-# JetBrains
+# IDE config
.idea/
+.vscode/
# Deps
-deps/boost/
-deps/jsoncpp/
-mysql-connector/
+cpp/deps/jsoncpp/
+cpp/deps/mysql-connector/
+cpp/deployment/cameradar_*_Release_Linux.tar.gz
# Test
test/cameradartest.conf.json
diff --git a/.travis.yml b/.travis.yml
index 90d43d8..2da32a1 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -6,53 +6,13 @@ before_install:
- echo "Testing Docker Hub credentials"
- docker login -u=$DOCKER_USERNAME -p=$DOCKER_PASSWORD
- echo "Docker Hub credentials are working"
-- sudo apt-get update -qq
-- sudo apt-get install -y software-properties-common
-- sudo add-apt-repository -y ppa:mc3man/trusty-media
-- sudo add-apt-repository -y ppa:george-edison55/cmake-3.x
-- sudo apt-get update -qq
-- sudo apt-get install -y nmap
-- sudo apt-get install -y ffmpeg
-- sudo apt-get install -y cmake
-- sudo apt-get install -y libboost-all-dev
-- sudo apt-get install -y libgstreamer1.0-dev
-- sudo apt-get install -y gstreamer1.0-plugins-base
-- sudo apt-get install -y gstreamer1.0-plugins-good
-- sudo apt-get install -y libcurl4-openssl-dev
-- sudo apt-get install -y libmysqlclient18
-- sudo apt-get install -y mysql-client
install:
-- export DEPS_DIR="${TRAVIS_BUILD_DIR}/deps"
-- export PACKAGE_NAME="cameradar_*_Debug_Linux"
-
-matrix:
- include:
- - os: linux
- env: TEST_TYPE='BUILD' WORKDIR='deployment' COMPILER_NAME=gcc CXX=g++-5 CC=gcc-5 CMAKE_CXX_COMPILER=g++-5
- addons:
- apt:
- packages:
- - g++-5
- sources: &sources
- - ubuntu-toolchain-r-test
- - os: linux
- env: TEST_TYPE='TEST' WORKDIR='test' COMPILER_NAME=gcc CXX=g++-5 CC=gcc-5 CMAKE_CXX_COMPILER=g++-5
- addons:
- apt:
- packages:
- - g++-5
- sources: &sources
- - ubuntu-toolchain-r-test
+- docker build -t cameradar .
script:
-- cd ${WORKDIR}
-- ./build_last_package.sh Debug
-- tar xvf ${PACKAGE_NAME}.tar.gz
-- find ${DEPS_DIR} -name "*.so*" -exec cp {} ${PACKAGE_NAME}/libraries \;
-- tar -czvf ${PACKAGE_NAME}.tar.gz ${PACKAGE_NAME}
-- if [[ "$TEST_TYPE" == "BUILD" ]]; then docker build -t cameradar . && docker run -v /tmp/thumbs:/tmp/thumbs cameradar; else ./test.sh ; fi
+- docker run cameradar
after_success:
- echo "Test Success - Branch($TRAVIS_BRANCH) Pull Request($TRAVIS_PULL_REQUEST) Tag($TRAVIS_TAG)"
-- if [[ "$TRAVIS_BRANCH" == "master" ]]; then echo -e "Push Container to Docker Hub" && docker login -u $DOCKER_USERNAME -p $DOCKER_PASSWORD && docker tag cameradar $DOCKER_REPO:$TRAVIS_TAG && docker tag cameradar $DOCKER_REPO:latest && docker push $DOCKER_REPO; fi
+- if [[ "$TRAVIS_BRANCH" == "master" ]]; then echo -e "Push Container to Docker Hub" && docker login -u $DOCKER_USERNAME -p $DOCKER_PASSWORD && docker tag cameradar $DOCKER_REPO:latest && docker push $DOCKER_REPO; fi
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ab87735..e396757 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,9 +2,19 @@
This file lists all versions of the repository and precises all changes.
+## v2.0.0
+
+#### Major changes:
+
+* Cameradar is no longer a C++ application but a Golang library
+* Cameraccess is a Golang application replacing the former C++ one (the C++ Cameradar image can still be used with the tag `1.1.4`)
+* The docker image for Cameraccess is lighter than the one for Cameradar
+* The Cameradar golang library enables users to build their own application around camera discovery and attack. Example of applications could be an automatic camera discovery daemon with scheduled scans, a security audit tool to check if CCTV cameras are protected from attacks by being isolated and having strong passwords, etc.
+
## v1.1.4
-#### Minor changes :
+#### Minor changes:
+
* Simplified use of Docker image
* Renamed MySQL table name to be more explicit
* Refactoring of the Golang functional tester done
@@ -14,18 +24,21 @@ This file lists all versions of the repository and precises all changes.
* Updated dictionaries to add user suggestions for Chinese cameras
* Enhanced `result.json` file's format
-#### Bugfixes :
+#### Bugfixes:
+
* Fixed a bug in the functional testing in which if the `result.json` file was not formatted correctly, the test failed but was still considered a success.
## v1.1.3
-#### Minor changes :
+#### Minor changes:
+
* Added automatic pushes to DockerHub to the travis integration
* Made travis configuration file better
* Changed the package generation scripts to make them report errors
* Removed old etix_rtsp_server binary from the test folder
-#### Bugfixes :
+#### Bugfixes:
+
* Fixed an issue that made it mandatory to launch tests at least once so that they can work the second time
* Fixed an issue that made the golang testing tool not compile in the testing script
* Fixed an issue that made the golang testing tool sometimes ignore some tests
@@ -33,19 +46,22 @@ This file lists all versions of the repository and precises all changes.
## v1.1.2
-#### Minor changes :
+#### Minor changes:
+
* Added travis integration
* Added default environment value for Docker deployment
* Updated docker image description with new easy usage
* Updated README badges style (replaced flat with square-flat)
* Build last package can now also generate a debug package if given the `Debug` command-line argument
-#### Known issues :
+#### Known issues
+
* There is still the issue with Camera Emulation Server, see the [previous version's patchnote](#v1.1.1) for more information.
## v1.1.1
-#### Minor changes :
+#### Minor changes:
+
* Removed unnecessary null pointer checks (thanks to https://github.com/elfring)
* Updated package description
* Removed debug message in CMake build
@@ -60,7 +76,8 @@ This file lists all versions of the repository and precises all changes.
* JUnit output now contains errors which makes debugging much easier
* Added header files where it was forgotten
-#### Bugfixes :
+#### Bugfixes:
+
* Fixed an issue where if you loose your internet connection during thumbnail generation, FFMpeg would get stuck forever and thus Cameradar would never finish
* Fixed an issue where multithreading could cause crashes
* Fixed an issue where the routes dictionary was mistaken for the credentials dictionary
@@ -68,12 +85,14 @@ This file lists all versions of the repository and precises all changes.
* Fixed automated camera generation
* Fixed docker IP address resolution
-#### Known issues :
+#### Known issues:
+
* There is an issue with Camera Emulation Server that makes it impossible for Cameradar to generate thumbnails, which is why right now the verification of the thumbnails presence is commented and it is assumed correct. It is probably an issue with GST-RTSP-Server but requires investigation.
## v1.1.0
-#### Major changes :
+#### Major changes:
+
* There are more command line options
* Port can now be overridden in the command line
* Target can now be overridden in the command line
@@ -81,13 +100,15 @@ This file lists all versions of the repository and precises all changes.
* Thumbnail generation is now multithreaded and will use as many threads as there are discovered cameras
* There are now default configuration values in order to make cameradar easier to use
-#### Minor changes :
+#### Minor changes:
+
* The algorithms take external input into account (so that a 3rd party can change the DB to help Cameradar in real-time) and thus check the persistent data at each iteration
* The default log level is now DEBUG instead of INFO
* The attack logs are now INFO instead of DEBUG
* The thumbnail generation logs are now INFO instead of DEBUG
#### Bugs fixed
+
* Fixed a bug in which the MySQL cache manager would consider a camera with known ids as having a valid path even if it weren't
* Fixed a bug in which TCP RTSP streams would not generate thumbnails
@@ -98,23 +119,23 @@ This file lists all versions of the repository and precises all changes.
## v1.0.4
-#### Bugs fixed :
+#### Bugs fixed:
* Fixed nmap package detection
## v1.0.3
-#### Bugs fixed :
+#### Bugs fixed:
* Corrected GStreamer check
## v1.0.2
-#### Bugs fixed :
+#### Bugs fixed:
* Fixed issues in MySQL Cache Manager
-#### Minor changes :
+#### Minor changes:
* Added useful debug logs
@@ -122,11 +143,11 @@ This file lists all versions of the repository and precises all changes.
### Ubuntu 16.04 Release
-#### Major changes :
+#### Major changes:
* The Docker deployment is now done using Ubuntu 16.04 instead of Ubuntu 15.10, so that it uses more recent packages.
-#### Minor changes :
+#### Minor changes:
* Removed useless dependencies
@@ -134,7 +155,7 @@ This file lists all versions of the repository and precises all changes.
### First production-ready release
-#### Major changes :
+#### Major changes:
* Added functional testing
@@ -142,15 +163,15 @@ This file lists all versions of the repository and precises all changes.
After doing some testing on a weirdly configured camera network in a far away Datacenter, I discovered that some Cameras needed a few tweaks to the Cameradar attack method in order to be accessed.
-#### Major changes :
+#### Major changes:
* Cameradar can access Cameras that are configured to always send 400 Bad Requests responses
-#### Minor changes :
+#### Minor changes:
* Changed iterator name from `it` to `stream` in dumb cache manager to improve code readability
-#### Bugfixes :
+#### Bugfixes:
* Cameradar no longer considers a timing out Camera as an accessible stream
diff --git a/CMakeLists.txt b/CMakeLists.txt
deleted file mode 100644
index 2948c4f..0000000
--- a/CMakeLists.txt
+++ /dev/null
@@ -1,130 +0,0 @@
-## Copyright 2016 Etix Labs
-##
-## Licensed under the Apache License, Version 2.0 (the "License");
-## you may not use this file except in compliance with the License.
-## You may obtain a copy of the License at
-##
-## http://www.apache.org/licenses/LICENSE-2.0
-##
-## Unless required by applicable law or agreed to in writing, software
-## distributed under the License is distributed on an "AS IS" BASIS,
-## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-## See the License for the specific language governing permissions and
-## limitations under the License.
-
-cmake_minimum_required (VERSION 2.8.1)
-cmake_policy(SET CMP0048 OLD)
-
-set (PROJECT_NAME cameradar)
-
-project (${PROJECT_NAME})
-
-set (${PROJECT_NAME}_VERSION_MAJOR 1)
-set (${PROJECT_NAME}_VERSION_MINOR 1)
-set (${PROJECT_NAME}_VERSION_PATCH 4)
-set (${PROJECT_NAME}_VERSION "${${PROJECT_NAME}_VERSION_MAJOR}.${${PROJECT_NAME}_VERSION_MINOR}.${${PROJECT_NAME}_VERSION_PATCH}${${PROJECT_NAME}_SUFFIX}")
-
-find_package(Git REQUIRED)
-
-# compiler flags
-set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14") #enable C++14
-set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -W -Wall -Wextra -Wno-unused-function") # extra warnings
-set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdiagnostics-color") #enable error coloration on gcc
-
-# release specific flags
-set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2")
-
-#debug specific flags
-set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -fprofile-arcs -ftest-coverage")
-
-# rpath enable osx
-set(CMAKE_MACOSX_RPATH 1)
-
-# list of all cache managers
-set (CAMERADAR_CACHE_MANAGERS "")
-
-# dependencies directory
-set(DEPS_DIR ${CMAKE_SOURCE_DIR}/deps)
-
-# output path for cache managers
-set (CAMERADAR_CACHE_MANAGER_OUTPUT_FOLDER cache_managers)
-set (CAMERADAR_CACHE_MANAGER_OUTPUT_PATH ${CMAKE_BINARY_DIR}/${CAMERADAR_CACHE_MANAGER_OUTPUT_FOLDER})
-
-set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
-
-# the place where the version.h file is generated, used from the main.cpp of cameradar
-set (VERSION_INCLUDE_DIR ${PROJECT_BINARY_DIR})
-
-# get the git revision
-message (STATUS "retrieve current git revision SHA1 of cameradar")
-execute_process(
- COMMAND "git" "rev-parse" "HEAD"
- WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
- OUTPUT_VARIABLE CAMERADAR_GIT_SHA1
-)
-
-# remove last character of the git output (\n)
-string(LENGTH ${CAMERADAR_GIT_SHA1} CAMERADAR_GIT_SHA1_LEN)
-math(EXPR CAMERADAR_GIT_SHA1_LEN "${CAMERADAR_GIT_SHA1_LEN} - 1")
-string(SUBSTRING ${CAMERADAR_GIT_SHA1} 0 ${CAMERADAR_GIT_SHA1_LEN} CAMERADAR_GIT_SHA1)
-
-# print the SHA1
-message (STATUS "current cameradar git revision SHA1 is ${CAMERADAR_GIT_SHA1}")
-
-# generate build number from the current timestamp
-string(TIMESTAMP CAMERADAR_VERSION_BUILD "%Y%m%d%H%M%S" "UTC")
-
-# print version
-message (STATUS "current cameradar build version will be ${CAMERADAR_VERSION_BUILD}")
-
-configure_file (
- "${PROJECT_SOURCE_DIR}/version.h.in"
- "${PROJECT_BINARY_DIR}/version.h"
-)
-
-# add all deps libraries to the link directories path
-link_directories (
- # third party libraries
- "deps/jsoncpp/src/deps.jsoncpp/src/lib_json"
- "deps/boost/src/deps.boost/libs"
- "deps/mysql-connector/lib"
-)
-
-include_directories (
- "cameradar_standalone/include"
- "deps/jsoncpp/src/deps.jsoncpp/include"
- "deps/boost/src/deps.boost/include"
- "deps/mysql-connector/include"
-)
-
-set (${CAMERADAR_BINARIES} "")
-set (${CAMERADAR_LIBRARIES} "")
-
-# Build cache managers
-add_subdirectory (deps)
-add_subdirectory (cameradar_standalone)
-add_subdirectory (cache_managers)
-
-list (APPEND CAMERADAR_LIBRARIES ${CAMERADAR_INSTALL_DEPENDENCIES} ${CAMERADAR_LIBRARIES})
-
-install (PROGRAMS ${CAMERADAR_BINARIES} DESTINATION bin)
-install (FILES ${CAMERADAR_CACHE_MANAGERS} DESTINATION cache_managers)
-install (FILES ${CAMERADAR_LIBRARIES} DESTINATION libraries)
-install (DIRECTORY ${CMAKE_SOURCE_DIR}/deps/licenses DESTINATION libraries)
-
-# CPack configuration
-include (InstallRequiredSystemLibraries)
-set (CPACK_PACKAGE_DESCRIPTION_SUMMARY "cameradar")
-set (CPACK_PACKAGE_VENDOR "Etix Labs")
-set (CPACK_PACKAGE_DESCRIPTION_SUMMARY "Cameradar hacks its way into RTSP CCTV cameras")
-set (CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}_${${PROJECT_NAME}_VERSION}_${CMAKE_BUILD_TYPE}_${CMAKE_SYSTEM_NAME}")
-set (CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README.md")
-set (CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
-set (CPACK_PACKAGE_VERSION_MAJOR "0")
-set (CPACK_PACKAGE_VERSION_MINOR "2")
-set (CPACK_PACKAGE_VERSION_PATCH "2")
-set (CPACK_PACKAGE_INSTALL_DIRECTORY "${PROJECT_NAME}_${${PROJECT_NAME}_VERSION}")
-set (CPACK_GENERATOR "TGZ")
-set (CPACK_SOURCE_GENERATOR "TGZ")
-
-include(CPack)
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..735b793
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,23 @@
+FROM golang:alpine
+WORKDIR /go/src/github.com/EtixLabs/cameradar/cameraccess
+
+COPY . /go/src/github.com/EtixLabs/cameradar
+
+RUN apk update && \
+ apk upgrade && \
+ apk add nmap nmap-nselibs nmap-scripts \
+ curl-dev \
+ gcc \
+ libc-dev \
+ git \
+ pkgconfig
+
+RUN go get github.com/andelf/go-curl
+RUN go get github.com/pkg/errors
+RUN go get gopkg.in/go-playground/validator.v9
+RUN go get github.com/jessevdk/go-flags
+RUN go get github.com/fatih/color
+
+RUN go install
+
+ENTRYPOINT /go/bin/cameraccess
diff --git a/README.md b/README.md
index 8328f3c..7f08311 100644
--- a/README.md
+++ b/README.md
@@ -1,259 +1,170 @@
# Cameradar
-## An RTSP surveillance camera access multitool
+## An RTSP stream access tool that comes with its library
[](#license)
[](https://hub.docker.com/r/ullaakut/cameradar/)
[](https://travis-ci.org/EtixLabs/cameradar)
+[](https://goreportcard.com/report/github.com/EtixLabs/cameradar)
[](https://www.codacy.com/app/brendan-le-glaunec/cameradar?utm_source=github.com&utm_medium=referral&utm_content=EtixLabs/cameradar&utm_campaign=Badge_Grade)
[](https://github.com/EtixLabs/cameradar/releases/latest)
-
#### Cameradar allows you to:
-* **Detect open RTSP hosts** on any accessible target
-* Get their public info (hostname, port, camera model, etc.)
-* Launch automated dictionary attacks to get their **stream route** (for example /live.sdp)
+* **Detect open RTSP hosts** on any accessible target host
+* Detect which device model is streaming
+* Launch automated dictionary attacks to get their **stream route** (e.g.: `/live.sdp`)
* Launch automated dictionary attacks to get the **username and password** of the cameras
-* **Generate thumbnails** from them to check if the streams are valid and to have a quick preview of their content
-* Try to create a Gstreamer pipeline to check if they are **properly encoded**
-* Print a summary of all the informations Cameradar could get
-
-#### And all of this in a _single command-line_.
-
-Of course, you can also call for individual tasks if you plug in a Database to Cameradar using the MySQL cache manager for example. You can create your own cache manager by following the simple example of the **dumb cache manager**.
+* Retrieve a complete and user-friendly report of the results

## Table of content
- [Docker Image](#docker-image)
-- [Quick install](#quick-install)
- - [Dependencies](#quick-install###dependencies)
- - [Five steps guide](#quick-install###five-steps-guide)
-- [Manual installation](#manual-installation)
- - [Dependencies](#manual-installation###dependencies)
- - [Steps](#manual-installation###Steps)
-- [Advanced docker deployment](#advanced-docker-deployment)
- - [Dependencies](#advanced-docker-deployment###dependencies)
- - [Deploy a custom version of Cameradar](#advanced-docker-deployment###deploy-a-custom-version-of-cameradar)
- [Configuration](#configuration)
- [Output](#output)
- [Check camera access](#check-camera-access)
- [Command line options](#command-line-options)
-- [Next improvements](#next-improvements)
- [Contribution](#contribution)
- [Frequently Asked Questions](#frequently-asked-questions)
- [License](#license)
-## Docker Image
+## Docker Image for Cameraccess
-This is the fastest and simplest way to use Cameradar. To do this you will just need `docker` on your machine.
+Install [docker](https://docs.docker.com/engine/installation/) on your machine, and run the following command:
-Run
-
-```
-docker run -v /tmp/thumbs/:/tmp/thumbs \
- -e CAMERAS_TARGET=your_target \
- ullaakut/cameradar:tag
+```bash
+docker run ullaakut/cameradar
```
-* `your_target` can be a subnet (e.g.: `172.16.100.0/24`) or even an IP (e.g.: `172.16.100.10`), a range of IPs (e.g.: `172.16.100.10-172.16.100.20`) or a mix of all those separated by commas (e.g.: `172.17.100.0/24,172.16.100.10-172.16.100.20,0.0.0.0`).
-* `tag` allows you to specify a specific version for camerada. If you don't specify any tag, you will use the latest version by default (recommended)
+[See command-line options](#command-line-options).
+
+e.g.: `docker run 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 lots of logs.
+
+* `YOUR_TARGET` can be a subnet (e.g.: `172.16.100.0/24`) or even an IP (e.g.: `172.16.100.10`), a range of IPs (e.g.: `172.16.100.10-172.16.100.20`) or a mix of all those separated by commas (e.g.: `172.17.100.0/24,172.16.100.10-172.16.100.20,0.0.0.0`).
+* 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 use the `-r` and `-c` options to specify your
Check [Cameradar's readme on the Docker Hub](https://hub.docker.com/r/ullaakut/cameradar/) for more information and more command-line options.
-The generated thumbnails will be in `/tmp/thumbs` on both your machine and the `cameradar` container.
-
For more complex use of the Docker image, see the `Environment variables` part of [Cameradar's readme on the Docker Hub](https://hub.docker.com/r/ullaakut/cameradar/).
-## Quick install
+### Library
-The quick install uses docker to build Cameradar without polluting your machine with dependencies and makes it easy to deploy Cameradar in a few commands. **However, it may require networking knowledge, as your docker containers will need access to the cameras subnetwork.**
+### Dependencies of the library
-### Dependencies
+- `curl-dev` / `libcurl` (depending on your OS)
+- `nmap`
+- `github.com/pkg/errors`
+- `gopkg.in/go-playground/validator.v9`
+- `github.com/andelf/go-curl`
-The only dependencies are `docker`, `docker-tools`, `git` and `make`.
+#### Installing the library
-### Five steps guide
+```bash
+ go get github.com/EtixLabs/cameradar
+```
-1. `git clone https://github.com/EtixLabs/cameradar.git`
-2. `cd cameradar/deployment`
-3. Tweak the `conf/cameradar.conf.json` as you need (see [the configuration guide here](#configuration) for more information)
-4. `docker-compose build ; docker-compose up`
+After this command, the *cameradar* library is ready to use. Its source will be in:
-By default, the version of the package in the deployment should be the last stable release.
+ $GOPATH/src/pkg/github.com/EtixLabs/cameradar
-If you want to scan a different target or different ports, change the values `CAMERAS_TARGET` and `CAMERAS_PORTS` in the `docker-compose.yml` file.
+You can use `go get -u` to update the package.
-The generated thumbnails will be in the `cameradar_thumbnails` folder after Cameradar has finished executing.
+Here is an overview of the exposed functions of this library:
-If you want to deploy your custom version of Cameradar using the same method, you should check the [advanced docker deployment](#advanced-docker-deployment) tutorial here.
+#### Discovery
-## Manual installation
+You can use the cameradar library for simple discovery purposes if you don't need to access the cameras but just to be aware of their existence.
-The manual installation is recommended if you want to tweak Cameradar and quickly test them using CMake and running Cameradar in command-line. If you just want to use Cameradar, it is recommended to use the [quick install](#quick-install) instead.
+
+The Discover function calls the RunNmap function as well as the ParseNmapResults function and returns the discovered streams without attempting any attack.
+It will use default values for its calls to RunNmap:
-### Dependencies
+
+This describes the nmap time presets. You can pass a value between 1 and 5 as described in this table, to the RunNmap function.
-To install Cameradar you will need these packages
+
+The RunNmap function will execute nmap and generate an XML file containing the results of the scan.
-* cmake (`cmake`)
-* git (`git`)
-* gstreamer1.x (`libgstreamer1.0-dev`)
-* ffmpeg (`ffmpeg`)
-* boost (`libboost-all-dev`)
-* libcurl (`libcurl4-openssl-dev`)
+
+The ParseNmapResult function will open the specified XML file and return all open RTSP streams found within it.
-### Steps
+#### Attack
-The simplest way would be to follow these steps :
+If you already know which hosts and ports you want to attack, you can also skip the discovery part and use directly the attack functions. The attack functions also take a timeout value as a parameter.
-1. `git clone https://github.com/EtixLabs/cameradar.git`
-2. `cd cameradar`
-3. `mkdir build`
-4. `cd build`
-5. `cmake ..`
-6. `make`
-7. `cd cameradar_standalone`
-8. `./cameradar -s the_target_you_want_to_scan`
+
+The AttackCredentials function takes valid streams as an input (with IP addresses and ports) and will attempt to guess their credentials using the provided dictionary.
-## Advanced Docker deployment
+
+The AttackRoute function takes valid streams as an input (with IP addresses and ports) and will attempt to guess their routes using the provided dictionary.
-In case you want to use Docker to deploy your custom version of Cameradar.
+#### Data models
-### Dependencies
+Here are the different data models useful to use the exposed functions of the cameradar library.
-The only dependencies are `docker` and `docker-compose`.
+
-### Using the package generation script
-1. `git clone https://github.com/EtixLabs/cameradar.git`
-2. `cd cameradar/deployment`
-3. `rm *.tar.gz`
-4. `./build_last_package.sh`
-5. `docker-compose build cameradar`
-6. `docker-compose up cameradar`
+#### Dictionary loaders
-### Deploy a custom version of Cameradar by hand
+The cameradar library also provides two functions that take file paths as inputs and return the appropriate data models filled.
-1. `git clone https://github.com/EtixLabs/cameradar.git`
-2. `cd cameradar`
-3. `mkdir build`
-4. `cd build`
-5. `cmake .. -DCMAKE_BUILD_TYPE=Release`
-6. `make package`
-7. `cp cameradar_*_Release_Linux.tar.gz ../deployment`
-8. `cd ../deployment`
-9. `docker-compose build cameradar`
-10. `docker-compose up cameradar`
+
+
+LoadCredentials takes a JSON file that has the same format as [this one](dictionary/credentials.json).
+
+
+
+LoadRoutes takes a file that has the same format as [this one](dictionary/routes). Warning: This file is not JSON.
### Configuration
-Here is the basic content of the configuration file with simple placeholders :
-```json
-{
- "mysql_db" : {
- "host" : "MYSQL_SERVER_IP_ADDRESS",
- "port" : MYSQL_SERVER_PORT,
- "user": "root",
- "password": "root",
- "db_name": "cmrdr"
- },
- "target" : "target1,target2,target3,[...]",
- "ports" : "PORT1,PORT2,[...]",
- "rtsp_url_file" : "/path/to/url/dictionary",
- "rtsp_ids_file" : "/path/to/url/dictionary",
- "thumbnail_storage_path" : "/valid/path/to/a/storage/directory",
- "cache_manager_path" : "/path/to/cache/manager",
- "cache_manager_name" : "CACHE_MANAGER_NAME"
-}
+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 cameraccess application will scan the 554 and 8554 ports.
+
+e.g.: `docker run ullaakut/cameradar -p "18554,19000-19010" -t localhost` will scan the ports 18554, and the range of ports between 19000 and 19010 on localhost.
+
+You **can use your own files for the ids and routes dictionaries** used to attack the cameras, but the Cameradar repository already gives you a good base that works with most cameras, in the `/dictionaries` folder.
+
+e.g.: ```bash
+docker run -v /my/folder/with/dictionaries:/tmp/dictionaries \
+ ullaakut/cameradar \
+ -r "/tmp/dictionaries/my_routes" \
+ -c "/tmp/dictionaries/my_credentials.json" \
+ -t 172.19.124.0/24
```
-This **configuration is needed only if you want to overwrite the default values**, which are :
-
-```json
-{
- "target" : "localhost",
- "ports" : "554,8554",
- "rtsp_url_file" : "conf/url.json",
- "rtsp_ids_file" : "conf/ids.json",
- "thumbnail_storage_path" : "/tmp",
- "cache_manager_path" : "../cache_managers/dumb_cache_manager",
- "cache_manager_name" : "dumb"
-}
-```
-
-This means that **by default Cameradar will not use a database**, will scan localhost and the ports 554 (default RTSP port) and 8554 (default emulated RTSP port), use the default constructor dictionaries and store the thumbnails in `/tmp`. If you need to override simply the target or ports, you can use the [command line options](#command-line-options).
-
-The targets should be passed separated by commas only, and their target format should be the same as used in nmap.
-```json
-"target" : "172.100.16.0/24,172.100.17.0/24,localhost,192.168.1.13"
-```
-
-The **RTSP ports for most cameras are 554**, so you should probably specify 554 as one of the ports you scan. Not giving any ports in the configuration will scan every port of every host found on the target.
-
-You **can use your own files for the ids and routes dictionaries** used to attack the cameras, but the Cameradar repository already gives you a good base that works with most cameras.
-
-The thumbnail storage path should be a **valid and accessible directory** in which the thumbnails will be stored.
-
-The cache manager path and name variables are used to change the cache manager you want to load into Cameradar. If you want to, you can code your own cache manager using a database, a file, a remote server, [...]. Feel free to share it by creating a merge request on this repository if you developed a generic manager (It must not be specific to your company's infrastructure).
+This will put the contents of your folder containing dictionaries in the docker image and will use it for the dictionary attack instead of the default dictionaries provided in the cameradar repo.
## Output
-For each camera, Cameradar will output these JSON objects :
+For each camera, Cameraccess will output this:
+
+
-```json
-{
- "address" : "173.16.100.45",
- "ids_found" : true,
- "password" : "123456",
- "path_found" : true,
- "port" : 554,
- "product" : "Vivotek FD9381-HTV",
- "protocol" : "tcp",
- "route" : "/live.sdp",
- "service_name" : "rtsp",
- "state" : "open",
- "thumbnail_path" : "/tmp/127.0.0.1/1463735257.jpg",
- "username" : "admin"
-}
-```
## Check camera access
-If you have [VLC Media Player](http://www.videolan.org/vlc/), you should be able to use the GUI to connect to the RTSP stream using this format : `rtsp://username:password@address:port/route`
+If you have [VLC Media Player](http://www.videolan.org/vlc/), you should be able to use the GUI or the command-line to connect to the RTSP stream using this format : `rtsp://username:password@address:port/route`
-With the above result, the RTSP URL would be `rtsp://admin:123456@173.16.100.45:554/live.sdp`
-
-If you're still in your console however, you can go even faster by using **vlc in commmand-line** and just run `vlc rtsp://username:password@address:port/route` with the camera's info instead of the placeholders.
+With the above result, the RTSP URL would be `rtsp://admin:12345@173.16.100.45:554/live.sdp`
## Command line options
-* **"-c"** : Set a custom path to the configuration file (-c /path/to/conf)
-* **"-s"** : Set custom target (overrides configuration) : You can use this argument in many ways, using a subnet (e.g.: `172.16.100.0/24`) or even an IP (e.g.: `172.16.100.10`), a range of IPs (e.g.: `172.16.100.10-172.16.100.20`) or a mix of all those (e.g.: `172.17.100.0/24,172.16.100.10-172.16.100.20,0.0.0.0`)
-* **"-p"** : Set custom ports (overrides configuration)
-* **"-m"** : Set number of threads (*Default value : 1*)
-* **"-l"** : Set log level
- * **"-l 1"** : Log level DEBUG
- * _Will print everything including debugging logs_
- * **"-l 2"** : Log level INFO
- * _Prints every normal information_
- * **"-l 4"** : Log level WARNING
- * _Only prints warning and errors_
- * **"-l 5"** : Log level ERROR
- * _Only prints errors_
- * **"-l 6"** : Log level CRITICAL
- * _Doesn't print anything since Cameradar can't have critical failures right now, however you can use this level to debug your own code easily or if you add new critical layers_
-* **"-d"** : Launch the discovery tool
-* **"-b"** : Launch the dictionary attack tool on all discovered devices
- * Needs either to be launched with the -d option or to use an advanced cache manager (DB, file, ...) with data already present
-* **"-t"** : Generate thumbnails from detected cameras
- * Needs either to be launched with the -d option or to use an advanced cache manager (DB, file, ...) with data already present
-* **"-g"** : Check if the stream can be opened with GStreamer
- * Needs either to be launched with the -d option or to use an advanced cache manager (DB, file, ...) with data already present
-* **"-v"** : Display Cameradar's version
-* **"-h"** : Display this help
-* **"--gst-rtsp-server"** : Use this option if the attack does not seem to work (only detects the username but not the path, or the opposite). This option will switch the order of the attacks to prioritize path over credentials, which is the way priority is handled for cameras that use GStreamer's RTSP server.
+* **"-t, --target"**: Set custom target. Required.
+* **"-p, --ports"**: (Default: `554,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).
+* **"-T, --timeout"**: (Default: `1000`) Set custom timeout value in miliseconds after which an attack attempt without an answer should give up.
+* **"-r, --custom-routes"**: (Default: `dictionaries/routes`) Set custom dictionary path for routes
+* **"-c, --custom-credentials"**: (Default: `dictionaries/credentials.json`) Set custom dictionary path for credentials
+* **"-o, --nmap-output"**: (Default: `/tmp/cameradar_scan.xml`) Set custom nmap output path
+* **"-l, --log"**: Enable debug logs (nmap requests, curl describe requests, etc.)
+* **"-h"** : Display the usage information
+
+## Environment variables
+
+TODO
## Contribution
@@ -261,25 +172,29 @@ See [the contribution document](/CONTRIBUTION.md) to get started.
## Frequently Asked Questions
-> My camera's credentials are guessed by Cameradar but the RTSP URL is not!
-
-Your camera probably uses GST RTSP Server internally. Try the `--gst-rtsp-server` command-line option, and if it does not work, send me the Cameradar output in DEBUG mode (`-l 1`) and I will help you.
-
> Cameradar does not detect any camera!
-That means that either your cameras are not streaming in RTSP or that they are not on the target you are scanning. In most cases, CCTV cameras will be on a private subnetwork. Use the `-s` option to specify your target.
+That means that either your cameras are not streaming in RTSP or that they are not on the target you are scanning. In most cases, CCTV cameras will be on a private subnetwork, isolated from the internet. Use the `-t` option to specify your target.
> 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. However, you can use your own dictionary in which you just have to add your passwords. 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.
-> It does not compile :(
+> What happened to the C++ version?
-You probably missed the part with the dependencies! Use the quick docker deployment, it will be easier and will not pollute your machine with useless dependencies! `;)`
+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.
+
+> How to use the Cameradar library for my own project?
+
+See the cameraccess example. You just need to run `go get github.com/EtixLabs/cameradar/cameradar` and to use the `cmrdr` package in your code.
+
+> 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 cameraccess/main.go`.
## License
-Copyright 2016 Etix Labs
+Copyright 2017 Etix Labs
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
diff --git a/cache_managers/CMakeLists.txt b/cache_managers/CMakeLists.txt
deleted file mode 100644
index 03b9ccd..0000000
--- a/cache_managers/CMakeLists.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-## Copyright 2016 Etix Labs
-##
-## Licensed under the Apache License, Version 2.0 (the "License");
-## you may not use this file except in compliance with the License.
-## You may obtain a copy of the License at
-##
-## http://www.apache.org/licenses/LICENSE-2.0
-##
-## Unless required by applicable law or agreed to in writing, software
-## distributed under the License is distributed on an "AS IS" BASIS,
-## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-## See the License for the specific language governing permissions and
-## limitations under the License.
-
-cmake_minimum_required (VERSION 2.8.1)
-cmake_policy(SET CMP0042 NEW)
-
-# set temporarly the ouput path for all server plugins
-set (LIBRARY_OUTPUT_PATH ${CAMERADAR_CACHE_MANAGER_OUTPUT_PATH})
-
-add_subdirectory(dumb_cache_manager)
-add_subdirectory(mysql_cache_manager)
-
-set (CAMERADAR_CACHE_MANAGERS ${CAMERADAR_CACHE_MANAGERS} PARENT_SCOPE)
diff --git a/cache_managers/dumb_cache_manager/CMakeLists.txt b/cache_managers/dumb_cache_manager/CMakeLists.txt
deleted file mode 100644
index 9ea4b47..0000000
--- a/cache_managers/dumb_cache_manager/CMakeLists.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-## Copyright 2016 Etix Labs
-##
-## Licensed under the Apache License, Version 2.0 (the "License");
-## you may not use this file except in compliance with the License.
-## You may obtain a copy of the License at
-##
-## http://www.apache.org/licenses/LICENSE-2.0
-##
-## Unless required by applicable law or agreed to in writing, software
-## distributed under the License is distributed on an "AS IS" BASIS,
-## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-## See the License for the specific language governing permissions and
-## limitations under the License.
-
-cmake_minimum_required (VERSION 2.8.1)
-cmake_policy(SET CMP0042 NEW)
-
-project(dumb_cache_manager CXX)
-
-find_package(PkgConfig)
-
-include_directories (${PROJECT_SOURCE_DIR}/include ${CAMERADAR_INCLUDES})
-
-include (find_sources)
-find_sources ("src" "include")
-
-add_library (dumb_cache_manager SHARED ${SOURCES})
-set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-undefined")
-target_link_libraries (dumb_cache_manager)
-
-set (CACHE_MANAGER_NAME ${CAMERADAR_CACHE_MANAGER_OUTPUT_PATH}/${CMAKE_SHARED_LIBRARY_PREFIX}dumb_cache_manager${CMAKE_SHARED_LIBRARY_SUFFIX})
-list (APPEND CAMERADAR_CACHE_MANAGERS ${CACHE_MANAGER_NAME})
-set (CAMERADAR_CACHE_MANAGERS ${CAMERADAR_CACHE_MANAGERS} PARENT_SCOPE)
diff --git a/cache_managers/dumb_cache_manager/include/dumb_cache_manager.h b/cache_managers/dumb_cache_manager/include/dumb_cache_manager.h
deleted file mode 100644
index 32a9461..0000000
--- a/cache_managers/dumb_cache_manager/include/dumb_cache_manager.h
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2016 Etix Labs
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#pragma once
-
-#include
-#include
-#include
-#include
-#include
-
-namespace etix {
-namespace cameradar {
-
-class dumb_cache_manager : public cache_manager_base {
-private:
- static const std::string name;
- std::vector streams;
- std::shared_ptr configuration;
-
- std::mutex m;
-
-public:
- using cache_manager_base::cache_manager_base;
- ~dumb_cache_manager();
-
- const std::string& get_name() const override;
- static const std::string& static_get_name();
- bool load_dumb_conf(std::shared_ptr configuration);
- bool configure(std::shared_ptr configuration) override;
-
- bool has_changed(const etix::cameradar::stream_model&);
-
- void set_streams(std::vector model);
-
- void update_stream(const etix::cameradar::stream_model& newmodel);
-
- std::vector get_streams();
-
- std::vector get_valid_streams();
-};
-}
-}
diff --git a/cache_managers/dumb_cache_manager/src/dumb_cache_manager.cpp b/cache_managers/dumb_cache_manager/src/dumb_cache_manager.cpp
deleted file mode 100644
index 041f06b..0000000
--- a/cache_managers/dumb_cache_manager/src/dumb_cache_manager.cpp
+++ /dev/null
@@ -1,104 +0,0 @@
-// Copyright 2016 Etix Labs
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include
-
-namespace etix {
-namespace cameradar {
-
-const std::string dumb_cache_manager::name = "dumb-cache-manager";
-
-dumb_cache_manager::~dumb_cache_manager() {}
-
-const std::string&
-dumb_cache_manager::get_name() const {
- return dumb_cache_manager::static_get_name();
-}
-
-const std::string&
-dumb_cache_manager::static_get_name() {
- return dumb_cache_manager::name;
-}
-
-bool
-dumb_cache_manager::configure(std::shared_ptr configuration) {
- return this->load_dumb_conf(configuration);
-}
-
-bool
-dumb_cache_manager::load_dumb_conf(std::shared_ptr configuration) {
- this->configuration = configuration;
-
- return true;
-}
-
-//! Replaces all cached streams by the content of the vector given as
-//! parameter
-void
-dumb_cache_manager::set_streams(std::vector model) {
- std::lock_guard lock(m);
- this->streams = model;
-}
-
-//! Inserts a single stream to the cache
-void
-dumb_cache_manager::update_stream(const etix::cameradar::stream_model& newmodel) {
- std::lock_guard lock(m);
- for (auto& stream : this->streams) {
- if (stream.address == newmodel.address && stream.port == newmodel.port) {
- stream = newmodel;
- }
- }
-}
-
-//! Gets all cached streams
-std::vector
-dumb_cache_manager::get_streams() {
- std::vector ret;
- for (const auto& stream : this->streams) {
- if (not stream.service_name.compare("rtsp") && not stream.state.compare("open"))
- ret.push_back(stream);
- }
- return ret;
-}
-
-//! Gets all valid streams
-std::vector
-dumb_cache_manager::get_valid_streams() {
- std::vector ret;
- for (const auto& stream : this->streams) {
- if (stream.ids_found && stream.path_found) ret.push_back(stream);
- }
- return ret;
-}
-
-// Returns true if the stream passed as a parameter has changed in the cache
-bool
-dumb_cache_manager::has_changed(const etix::cameradar::stream_model& old) {
- for (const auto& stream : this->streams) {
- if (stream.address == old.address)
- if (stream.path_found != old.path_found || stream.ids_found != old.ids_found)
- return true;
- }
- return false;
-}
-
-extern "C" {
-cache_manager_iface*
-cache_manager_instance_new() {
- return new dumb_cache_manager();
-}
-}
-}
-}
diff --git a/cache_managers/mysql_cache_manager/CMakeLists.txt b/cache_managers/mysql_cache_manager/CMakeLists.txt
deleted file mode 100644
index f181a53..0000000
--- a/cache_managers/mysql_cache_manager/CMakeLists.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-## Copyright 2016 Etix Labs
-##
-## Licensed under the Apache License, Version 2.0 (the "License");
-## you may not use this file except in compliance with the License.
-## You may obtain a copy of the License at
-##
-## http://www.apache.org/licenses/LICENSE-2.0
-##
-## Unless required by applicable law or agreed to in writing, software
-## distributed under the License is distributed on an "AS IS" BASIS,
-## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-## See the License for the specific language governing permissions and
-## limitations under the License.
-
-cmake_minimum_required (VERSION 2.8.1)
-cmake_policy(SET CMP0042 NEW)
-
-project(mysql_cache_manager CXX)
-
-find_package(PkgConfig)
-
-include_directories (${PROJECT_SOURCE_DIR}/include ${CAMERADAR_INCLUDES})
-
-include (find_sources)
-find_sources ("src" "include")
-
-add_library (mysql_cache_manager SHARED ${SOURCES})
-set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-undefined")
-target_link_libraries (mysql_cache_manager jsoncpp mysqlcppconn pthread)
-
-set (CACHE_MANAGER_NAME ${CAMERADAR_CACHE_MANAGER_OUTPUT_PATH}/${CMAKE_SHARED_LIBRARY_PREFIX}mysql_cache_manager${CMAKE_SHARED_LIBRARY_SUFFIX})
-list (APPEND CAMERADAR_CACHE_MANAGERS ${CACHE_MANAGER_NAME})
-set (CAMERADAR_CACHE_MANAGERS ${CAMERADAR_CACHE_MANAGERS} PARENT_SCOPE)
diff --git a/cache_managers/mysql_cache_manager/include/db_conn.h b/cache_managers/mysql_cache_manager/include/db_conn.h
deleted file mode 100644
index 45acc40..0000000
--- a/cache_managers/mysql_cache_manager/include/db_conn.h
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright 2016 Etix Labs
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#pragma once
-
-#include // for ResultSet
-#include // for mutex
-#include // for bool, false
-#include // for string
-#include // for pair, make_pair
-
-#include "query_result.h"
-
-namespace sql {
-class Connection;
-class Driver;
-class ResultSet;
-}
-
-namespace etix {
-
-namespace cameradar {
-
-namespace mysql {
-
-//! MySQL Database connection handling
-//! Abstracts all connection to the database
-class db_connection {
-private:
- static const std::string create_database_query;
-
- //! SQL driver
- sql::Driver* driver = nullptr;
- //! SQL connection
- sql::Connection* connection = nullptr;
- std::mutex access_mtx;
- bool connected = false;
-
- std::string db_name;
-
- //! Create the database if it doesn't exist at connector launch
- empty_result create_database(void);
-
-public:
- db_connection(void);
- ~db_connection(void);
-
- //! Try to connect to the database
- std::pair connect(const std::string& host,
- const std::string& user,
- const std::string& pass,
- const std::string& db_name,
- bool create_db_if_not_exist = true);
-
- //! Execute a MySQL command
- empty_result execute(const std::string& request);
-
- //! Execute a query
- query_result query(const std::string& query);
-
- bool is_connected();
-
- //! Return db_name
- const std::string&
- get_db_name(void) const {
- return this->db_name;
- }
-};
-
-} // mysql
-
-} // cameradar
-
-} // etix
diff --git a/cache_managers/mysql_cache_manager/include/mysql_cache_manager.h b/cache_managers/mysql_cache_manager/include/mysql_cache_manager.h
deleted file mode 100644
index 2d79dd5..0000000
--- a/cache_managers/mysql_cache_manager/include/mysql_cache_manager.h
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright 2016 Etix Labs
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#pragma once
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-namespace etix {
-
-namespace cameradar {
-
-struct mysql_configuration {
- unsigned int port;
- std::string host;
- std::string db_name;
- std::string user;
- std::string password;
-
- mysql_configuration() = default;
-
- mysql_configuration(unsigned int port,
- const std::string& host,
- const std::string& db_name,
- const std::string& user = "",
- const std::string& password = "")
- : port(port), host(host), db_name(db_name), user(user), password(password) {}
-};
-
-class mysql_cache_manager : public cache_manager_base {
-private:
- static const std::string name;
- std::vector streams;
- std::shared_ptr configuration;
- etix::cameradar::mysql_configuration db_conf;
- etix::cameradar::mysql::db_connection connection;
-
- std::mutex m;
-
- static const std::string create_table_query;
- static const std::string insert_with_id_query;
- static const std::string exist_query;
- static const std::string get_results_query;
- static const std::string update_result_query;
-
-public:
- using cache_manager_base::cache_manager_base;
- ~mysql_cache_manager();
-
- // Specific to MySQL
- bool execute_query(const std::string& query);
-
- const std::string& get_name() const override;
- static const std::string& static_get_name();
- bool load_mysql_conf(std::shared_ptr configuration);
- bool configure(std::shared_ptr configuration) override;
-
- bool has_changed(const etix::cameradar::stream_model&);
-
- void set_streams(std::vector model);
-
- void update_stream(const etix::cameradar::stream_model& newmodel);
-
- std::vector get_streams();
-
- std::vector get_valid_streams();
-};
-}
-}
diff --git a/cache_managers/mysql_cache_manager/include/query_result.h b/cache_managers/mysql_cache_manager/include/query_result.h
deleted file mode 100644
index 184f3da..0000000
--- a/cache_managers/mysql_cache_manager/include/query_result.h
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2016 Etix Labs
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#pragma once
-
-namespace etix {
-
-namespace cameradar {
-
-namespace mysql {
-
-enum class execute_result { success, not_found, no_row_updated, sql_error, error };
-
-//! Wrapper of a DB query result
-//! Templated on the data type we want to return (list, bool, whatever)
-template
-struct query_result {
- DataType data;
- execute_result state;
- std::string error_msg;
-
- inline bool
- success(void) const {
- return state == execute_result::success;
- }
- inline bool
- error(void) const {
- return not success();
- }
-};
-
-//! Empty query result for when we just want to return the status
-//! of the request with no associated data
-template <>
-struct query_result {
- execute_result state;
- std::string error_msg;
-
- inline bool
- success(void) const {
- return state == execute_result::success;
- }
- inline bool
- error(void) const {
- return not success();
- }
-};
-typedef query_result empty_result;
-
-} //! mysql
-
-} //! cameradar
-
-} //! etix
diff --git a/cache_managers/mysql_cache_manager/src/db_conn.cpp b/cache_managers/mysql_cache_manager/src/db_conn.cpp
deleted file mode 100644
index c17f0d8..0000000
--- a/cache_managers/mysql_cache_manager/src/db_conn.cpp
+++ /dev/null
@@ -1,138 +0,0 @@
-// Copyright 2016 Etix Labs
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "db_conn.h" // for db_connection
-#include "cppconn/connection.h" // for Connection
-#include "query_result.h" // for queries
-#include // for get_driver_instance, etc
-#include // for SQLException
-#include // for Statement
-#include // for fmt
-#include // for LOG_
-
-namespace etix {
-
-namespace cameradar {
-
-namespace mysql {
-
-const std::string db_connection::create_database_query = "CREATE DATABASE IF NOT EXISTS %s";
-
-db_connection::db_connection() : connected(false) {}
-
-db_connection::~db_connection() { delete this->connection; }
-
-std::pair
-db_connection::connect(const std::string& host,
- const std::string& user,
- const std::string& pass,
- const std::string& db_name,
- bool create_db_if_not_exist) {
- this->db_name = db_name;
-
- try {
- this->driver = get_driver_instance();
- if (this->driver == nullptr) {
- return std::make_pair(false, "Cannot instantiate sql_driver");
- }
- this->connection = driver->connect(host, user, pass);
- if (this->connection == nullptr) return std::make_pair(false, "Cannot connect to mysql");
-
- this->connected = true;
- if (create_db_if_not_exist) {
- auto cdb = this->create_database();
- if (cdb.state == mysql::execute_result::sql_error) { return { false, cdb.error_msg }; }
- this->connection->setSchema(db_name);
- }
- } catch (sql::SQLException& e) {
- this->connected = false;
- return { false, e.what() };
- }
-
- return std::make_pair(true, "");
-}
-
-empty_result
-db_connection::execute(const std::string& request) {
- std::lock_guard lock(this->access_mtx);
-
- sql::Statement* stmt = nullptr;
- empty_result return_value = { execute_result::success, "" };
-
- if (!this->is_connected()) {
- return { execute_result::sql_error, "Error, not connected to MySQL database" };
- }
-
- try {
- stmt = this->connection->createStatement();
- stmt->execute(request);
- if (stmt->getUpdateCount() == 0) {
- return_value = { execute_result::no_row_updated, "No row updated" };
- }
- } catch (sql::SQLException& e) { return_value = { execute_result::sql_error, e.what() }; }
- delete stmt;
-
- return return_value;
-}
-
-query_result
-db_connection::query(const std::string& query) {
- std::lock_guard lock(this->access_mtx);
-
- sql::Statement* stmt = nullptr;
- query_result return_value = { nullptr, execute_result::success, "" };
-
- if (!this->is_connected()) {
- return { nullptr, execute_result::sql_error, "Error, not connected to MySQL database" };
- }
-
- try {
- stmt = this->connection->createStatement();
- return_value = { stmt->executeQuery(query), execute_result::success, "" };
- } catch (sql::SQLException& e) {
- return_value = { nullptr, execute_result::sql_error, e.what() };
- }
- delete stmt;
-
- return return_value;
-}
-
-bool
-db_connection::is_connected() {
- if (this->connection == nullptr) return false;
-
- // check if our connection is always valid
- if (this->connection->isClosed() || not this->connection->isValid()) {
- LOG_INFO_("MySQL database connection is either closed or invalid, try to reconnect.",
- "db_connection");
- this->connection->reconnect();
- if (this->connection->isClosed() || not this->connection->isValid()) {
- this->connected = false;
- LOG_ERR_("Unable to reconnect to MySQL.", "db_connection");
- }
- }
- return this->connected;
-}
-
-empty_result
-db_connection::create_database() {
- auto query = tool::fmt(this->create_database_query, this->db_name.c_str());
- return this->execute(query);
-}
-
-} // mysql
-
-} // cameradar
-
-} // etix
diff --git a/cache_managers/mysql_cache_manager/src/mysql_cache_manager.cpp b/cache_managers/mysql_cache_manager/src/mysql_cache_manager.cpp
deleted file mode 100644
index 0c3cec6..0000000
--- a/cache_managers/mysql_cache_manager/src/mysql_cache_manager.cpp
+++ /dev/null
@@ -1,292 +0,0 @@
-// Copyright 2016 Etix Labs
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include
-
-/* DATA FORMAT
-**
-** Example :
-**
-** "address" : "173.16.100.45",
-** "ids_found" : true,
-** "password" : "123456",
-** "path_found" : true,
-** "port" : 554,
-** "product" : "Vivotek FD9381-HTV",
-** "protocol" : "tcp",
-** "route" : "/live.sdp",
-** "service_name" : "rtsp",
-** "state" : "open",
-** "thumbnail_path" : "/tmp/127.0.0.1/1463735257.jpg",
-** "username" : "admin"
-**
-*/
-
-namespace etix {
-
-namespace cameradar {
-
-const std::string mysql_cache_manager::create_table_query =
- "CREATE TABLE IF NOT EXISTS `cameradar_results` ("
- "`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT, "
- "`address` tinytext NOT NULL, "
- "`password` tinytext NOT NULL, "
- "`product` tinytext NOT NULL, "
- "`protocol` tinytext NOT NULL, "
- "`route` tinytext NOT NULL, "
- "`service_name` tinytext NOT NULL, "
- "`state` tinytext NOT NULL, "
- "`thumbnail_path` tinytext NOT NULL, "
- "`username` tinytext NOT NULL, "
- "`port` int(11) UNSIGNED NOT NULL, "
- "`ids_found` tinytext NOT NULL, "
- "`path_found` tinytext NOT NULL, "
- "PRIMARY KEY (`id`));";
-
-const std::string mysql_cache_manager::insert_with_id_query =
- "INSERT INTO `%s`.`cameradar_results`"
- " (`address`, `password`, `product`, `protocol`, `route`, `service_name`, `state`, "
- "`thumbnail_path`, `username`, `port`, `ids_found`, `path_found`)"
- " VALUES ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s')";
-
-const std::string mysql_cache_manager::update_result_query =
- "UPDATE `%s`.`cameradar_results` SET"
- " `cameradar_results`.`address` = '%s',"
- " `cameradar_results`.`password` = '%s',"
- " `cameradar_results`.`product` = '%s',"
- " `cameradar_results`.`protocol` = '%s',"
- " `cameradar_results`.`route` = '%s',"
- " `cameradar_results`.`service_name` = '%s',"
- " `cameradar_results`.`state` = '%s',"
- " `cameradar_results`.`thumbnail_path` = '%s',"
- " `cameradar_results`.`username` = '%s',"
- " `cameradar_results`.`port` = '%s',"
- " `cameradar_results`.`ids_found` = '%s',"
- " `cameradar_results`.`path_found` = '%s'"
- " WHERE `cameradar_results`.`address` LIKE '%s'";
-
-const std::string mysql_cache_manager::exist_query =
- "SELECT * FROM `%s`.`cameradar_results` WHERE `cameradar_results`.`address` = '%s'";
-
-const std::string mysql_cache_manager::get_results_query = "SELECT * FROM `%s`.`cameradar_results`";
-
-const std::string mysql_cache_manager::name = "mysql-cache-manager";
-
-mysql_cache_manager::~mysql_cache_manager() {}
-
-const std::string&
-mysql_cache_manager::get_name() const {
- return mysql_cache_manager::static_get_name();
-}
-
-const std::string&
-mysql_cache_manager::static_get_name() {
- return mysql_cache_manager::name;
-}
-
-bool
-mysql_cache_manager::configure(std::shared_ptr configuration) {
- return this->load_mysql_conf(configuration);
-}
-
-bool
-mysql_cache_manager::execute_query(const std::string& query) {
- auto check_err = [](const auto& res) {
- if (res.state == mysql::execute_result::sql_error) {
- LOG_WARN_(res.error_msg, "mysql_cache_manager");
- return false;
- }
- return true;
- };
- return check_err(this->connection.execute(query));
-}
-
-bool
-mysql_cache_manager::load_mysql_conf(
- std::shared_ptr configuration) {
- this->configuration = configuration;
-
- try {
- this->db_conf.host = configuration->raw_conf["mysql_db"]["host"].asString();
- this->db_conf.port = configuration->raw_conf["mysql_db"]["port"].asUInt();
- this->db_conf.user = configuration->raw_conf["mysql_db"]["user"].asString();
- this->db_conf.password = configuration->raw_conf["mysql_db"]["password"].asString();
- this->db_conf.db_name = configuration->raw_conf["mysql_db"]["db_name"].asString();
- } catch (const std::exception& e) {
- LOG_ERR_("Configuration of the MySQL db failed : " + std::string(e.what()),
- "mysql_cache_manager");
- return false;
- }
-
- if (not this->connection
- .connect(db_conf.host + ":" + std::to_string(db_conf.port),
- db_conf.user,
- db_conf.password,
- db_conf.db_name)
- .first) {
- LOG_ERR_("Configuration of the MySQL DB failed", "mysql_cache_manager");
- return false;
- }
-
- // Tries to create the Result table in the DB and returns the success state
- return (execute_query(create_table_query));
-}
-
-//! Replaces all cached streams by the content of the vector given as
-//! parameter
-void
-mysql_cache_manager::set_streams(std::vector models) {
- LOG_DEBUG_("Beginning stream list DB insertion", "mysql_cache_manager");
- std::lock_guard lock(m);
- for (const auto& model : models) {
- if (!model.service_name.compare("rtsp") && !model.state.compare("open")) {
- auto query = tool::fmt(
- this->exist_query, this->connection.get_db_name().c_str(), model.address.c_str());
- auto result = this->connection.query(query);
-
- if (result.data->next()) continue;
-
- query = tool::fmt(this->insert_with_id_query,
- this->connection.get_db_name().c_str(),
- model.address.c_str(),
- model.password.c_str(),
- model.product.c_str(),
- model.protocol.c_str(),
- model.route.c_str(),
- model.service_name.c_str(),
- model.state.c_str(),
- model.thumbnail_path.c_str(),
- model.username.c_str(),
- std::to_string(model.port).c_str(),
- std::to_string(model.ids_found).c_str(),
- std::to_string(model.path_found).c_str());
- execute_query(query);
- }
- }
-}
-
-//! Inserts a single stream to the cache
-void
-mysql_cache_manager::update_stream(const etix::cameradar::stream_model& model) {
- auto query = tool::fmt(this->update_result_query,
- this->connection.get_db_name().c_str(),
- model.address.c_str(),
- model.password.c_str(),
- model.product.c_str(),
- model.protocol.c_str(),
- model.route.c_str(),
- model.service_name.c_str(),
- model.state.c_str(),
- model.thumbnail_path.c_str(),
- model.username.c_str(),
- std::to_string(model.port).c_str(),
- std::to_string(model.ids_found).c_str(),
- std::to_string(model.path_found).c_str(),
- model.address.c_str());
- std::lock_guard lock(m);
- execute_query(query);
-}
-
-//! Gets all cached streams
-std::vector
-mysql_cache_manager::get_streams() {
- auto query = tool::fmt(this->get_results_query, this->connection.get_db_name().c_str());
- auto result = this->connection.query(query);
-
- if (not result.data) {
- delete result.data;
- return {};
- }
-
- std::vector lst;
- while (result.data->next()) {
- // If it's an open RTSP stream
- if (not result.data->getString("state").compare("open") &&
- not result.data->getString("service_name").compare("rtsp")) {
- stream_model s{
- result.data->getString("address"), result.data->getUInt("port"),
- result.data->getString("username"), result.data->getString("password"),
- result.data->getString("route"), result.data->getString("service_name"),
- result.data->getString("product"), result.data->getString("protocol"),
- result.data->getString("state"), result.data->getBoolean("path_found"),
- result.data->getBoolean("ids_found"), result.data->getString("thumbnail_path")
- };
- lst.push_back(s);
- }
- }
-
- delete result.data;
- return lst;
-}
-
-//! Gets all valid streams
-std::vector
-mysql_cache_manager::get_valid_streams() {
- auto query = tool::fmt(this->get_results_query, this->connection.get_db_name().c_str());
- auto result = this->connection.query(query);
-
- if (not result.data) {
- delete result.data;
- return {};
- }
-
- std::vector lst;
- while (result.data->next()) {
- // If the ID and the Path were found add this stream
- if (not result.data->getString("ids_found").compare("1") &&
- not result.data->getString("path_found").compare("1")) {
- stream_model s{
- result.data->getString("address"), result.data->getUInt("port"),
- result.data->getString("username"), result.data->getString("password"),
- result.data->getString("route"), result.data->getString("service_name"),
- result.data->getString("product"), result.data->getString("protocol"),
- result.data->getString("state"), result.data->getBoolean("path_found"),
- result.data->getBoolean("ids_found"), result.data->getString("thumbnail_path")
- };
- lst.push_back(s);
- }
- }
-
- delete result.data;
- return lst;
-}
-
-// Returns true if the stream passed as a parameter has changed in the cache
-bool
-mysql_cache_manager::has_changed(const etix::cameradar::stream_model& old) {
- auto query = tool::fmt(this->get_results_query, this->connection.get_db_name().c_str());
- auto result = this->connection.query(query);
-
- if (not result.data) {
- delete result.data;
- return {};
- }
-
- while (result.data->next()) {
- if (result.data->getString("address") == old.address)
- if (result.data->getBoolean("ids_found") != old.ids_found ||
- result.data->getBoolean("path_found") != old.path_found)
- return true;
- }
- return false;
-}
-
-extern "C" {
-cache_manager_iface*
-cache_manager_instance_new() {
- return new mysql_cache_manager();
-}
-}
-}
-}
diff --git a/cameraccess/main.go b/cameraccess/main.go
new file mode 100644
index 0000000..3362ce0
--- /dev/null
+++ b/cameraccess/main.go
@@ -0,0 +1,106 @@
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package main
+
+import (
+ "fmt"
+ "os"
+ "time"
+
+ "github.com/EtixLabs/cameradar/cameradar"
+ "github.com/fatih/color"
+ "github.com/jessevdk/go-flags"
+)
+
+type options struct {
+ Target string `short:"t" long:"target" description:"The target on which to scan for open RTSP streams - required" required:"true"`
+ Ports string `short:"p" long:"ports" description:"The ports on which to search for RTSP streams" default:"554,8554"`
+ OutputFile string `short:"o" long:"nmap-output" description:"The path where nmap will create its XML result file" default:"/tmp/cameradar_scan.xml"`
+ Routes string `short:"r" long:"custom-routes" description:"The path on which to load a custom routes dictionary" default:"./dictionaries/routes"`
+ Credentials string `short:"c" long:"custom-credentials" description:"The path on which to load a custom credentials JSON dictionary" default:"./dictionaries/credentials.json"`
+ Speed int `short:"s" long:"speed" description:"The nmap speed preset to use" default:"4"`
+ Timeout int `short:"T" long:"timeout" description:"The timeout in miliseconds to use for attack attempts" default:"1000"`
+ EnableLogs bool `short:"l" long:"log" description:"Enable the logs for nmap's output to stdout"`
+}
+
+func main() {
+ var options options
+ _, err := flags.ParseArgs(&options, os.Args[1:])
+ if err != nil {
+ os.Exit(0)
+ }
+
+ credentials, err := cmrdr.LoadCredentials(options.Credentials)
+ if err != nil {
+ color.Red("Invalid credentials dictionary: %s", err.Error())
+ return
+ }
+
+ routes, err := cmrdr.LoadRoutes(options.Routes)
+ if err != nil {
+ color.Red("Invalid routes dictionary: %s", err.Error())
+ return
+ }
+
+ streams, _ := cmrdr.Discover(options.Target, options.Ports, options.OutputFile, options.Speed, options.EnableLogs)
+ streams, _ = cmrdr.AttackRoute(streams, routes, time.Duration(options.Timeout)*time.Millisecond, options.EnableLogs)
+ streams, _ = cmrdr.AttackCredentials(streams, credentials, time.Duration(options.Timeout)*time.Millisecond, options.EnableLogs)
+
+ prettyPrint(streams)
+}
+
+func prettyPrint(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
+
+ if len(streams) > 0 {
+ for _, stream := range streams {
+ if stream.CredentialsFound && stream.RouteFound {
+ fmt.Printf("%s\tDevice RTSP URL:\t%s\n", green("\xE2\x96\xB6"), blue(cmrdr.RTSPURL(stream)))
+ success++
+ } else {
+ fmt.Printf("%s\tAdmin panel URL:\t%s %s\n", red("\xE2\x96\xB6"), yellow(cmrdr.AdminPanelURL(stream)), white("You can use this URL to try attacking the camera's admin panel instead."))
+ }
+
+ fmt.Printf("\tDevice model:\t\t%s\n\n", stream.Device)
+ fmt.Printf("\tIP address:\t\t%s\n", stream.Address)
+ fmt.Printf("\tRTSP port:\t\t%d\n", stream.Port)
+ if stream.CredentialsFound {
+ fmt.Printf("\tUsername:\t\t%s\n", green(stream.Username))
+ fmt.Printf("\tPassword:\t\t%s\n", green(stream.Password))
+ } else {
+ fmt.Printf("\tUsername:\t\t%s\n", red("not found"))
+ fmt.Printf("\tPassword:\t\t%s\n", red("not found"))
+ }
+ if stream.RouteFound {
+ fmt.Printf("\tRTSP route:\t\t%s\n\n\n", green("/"+stream.Route))
+ } else {
+ fmt.Printf("\tRTSP route:\t\t%s\n\n\n", red("not found"))
+ }
+ }
+ if success > 1 {
+ fmt.Printf("%s Successful attack: %s devices were accessed", green("\xE2\x9C\x94"), green(len(streams)))
+ } else if success == 1 {
+ fmt.Printf("%s Successful attack: %s device was accessed", green("\xE2\x9C\x94"), green(len(streams)))
+ } 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.", red("\xE2\x9C\x96"))
+ }
+ } else {
+ fmt.Printf("%s No streams were found. Please make sure that your target is on an accessible network.", red("\xE2\x9C\x96"))
+ }
+}
diff --git a/cameradar/attack.go b/cameradar/attack.go
new file mode 100644
index 0000000..4934e9d
--- /dev/null
+++ b/cameradar/attack.go
@@ -0,0 +1,232 @@
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cmrdr
+
+import (
+ "fmt"
+ "time"
+
+ curl "github.com/andelf/go-curl"
+ "github.com/pkg/errors"
+ v "gopkg.in/go-playground/validator.v9"
+)
+
+// HACK: See https://stackoverflow.com/questions/3572397/lib-curl-in-c-disable-printing
+func doNotWrite([]uint8, interface{}) bool {
+ return true
+}
+
+func routeAttack(camera Stream, route string, timeout time.Duration, enableLogs bool) bool {
+ easy := curl.EasyInit()
+ defer easy.Cleanup()
+
+ if easy != nil {
+ attackURL := fmt.Sprintf(
+ "rtsp://%s:%s@%s:%d/%s",
+ camera.Username,
+ camera.Password,
+ camera.Address,
+ camera.Port,
+ route,
+ )
+
+ if enableLogs {
+ // Debug logs when logs are enabled
+ easy.Setopt(curl.OPT_VERBOSE, 1)
+ } else {
+ // Do not write sdp in stdout
+ easy.Setopt(curl.OPT_WRITEFUNCTION, doNotWrite)
+ }
+
+ // Do not send a body in the describe request
+ easy.Setopt(curl.OPT_NOBODY, 1)
+ // Send a request to the URL of the camera we want to attack
+ easy.Setopt(curl.OPT_URL, attackURL)
+ // Set the RTSP STREAM URI as the camera URL
+ easy.Setopt(curl.OPT_RTSP_STREAM_URI, attackURL)
+ // 2 is CURL_RTSPREQ_DESCRIBE
+ easy.Setopt(curl.OPT_RTSP_REQUEST, 2)
+ // Set custom timeout
+ easy.Setopt(curl.OPT_TIMEOUT_MS, int(timeout/time.Millisecond))
+
+ // Perform the request
+ easy.Perform()
+
+ // Get return code for the request
+ rc, err := easy.Getinfo(curl.INFO_RESPONSE_CODE)
+ if err != nil {
+ return false
+ }
+
+ // If it's a 404, it means that the route was not valid
+ if rc == 404 {
+ return false
+ }
+
+ return true
+ }
+ return false
+}
+
+func credAttack(camera Stream, username string, password string, timeout time.Duration, enableLogs bool) bool {
+ easy := curl.EasyInit()
+ defer easy.Cleanup()
+
+ if easy != nil {
+ attackURL := fmt.Sprintf(
+ "rtsp://%s:%s@%s:%d/%s",
+ username,
+ password,
+ camera.Address,
+ camera.Port,
+ camera.Route,
+ )
+
+ if enableLogs {
+ // Debug logs when logs are enabled
+ easy.Setopt(curl.OPT_VERBOSE, 1)
+ } else {
+ // Do not write sdp in stdout
+ easy.Setopt(curl.OPT_WRITEFUNCTION, doNotWrite)
+ }
+
+ // Do not send a body in the describe request
+ easy.Setopt(curl.OPT_NOBODY, 1)
+ // Send a request to the URL of the camera we want to attack
+ easy.Setopt(curl.OPT_URL, attackURL)
+ // Set the RTSP STREAM URI as the camera URL
+ easy.Setopt(curl.OPT_RTSP_STREAM_URI, attackURL)
+ // 2 is CURL_RTSPREQ_DESCRIBE
+ easy.Setopt(curl.OPT_RTSP_REQUEST, 2)
+ // Set custom timeout
+ easy.Setopt(curl.OPT_TIMEOUT_MS, int(timeout/time.Millisecond))
+
+ // Perform the request
+ easy.Perform()
+
+ // Get return code for the request
+ rc, err := easy.Getinfo(curl.INFO_RESPONSE_CODE)
+ if err != nil {
+ return false
+ }
+
+ // If it's a 403 or a 401, it means that the credentials are not correct
+ if rc == 403 || rc == 401 {
+ return false
+ }
+
+ return true
+ }
+ return false
+}
+
+func attackCameraCredentials(target Stream, credentials Credentials, resultsChan chan<- Stream, timeout time.Duration, log bool) {
+ for _, username := range credentials.Usernames {
+ for _, password := range credentials.Passwords {
+ ok := credAttack(target, username, password, timeout, log)
+ if ok {
+ target.CredentialsFound = true
+ target.Username = username
+ target.Password = password
+ resultsChan <- target
+ return
+ }
+ }
+ }
+ target.CredentialsFound = false
+ resultsChan <- target
+}
+
+func attackCameraRoute(target Stream, routes Routes, resultsChan chan<- Stream, timeout time.Duration, log bool) {
+ for _, route := range routes {
+ ok := routeAttack(target, route, timeout, log)
+ if ok {
+ target.RouteFound = true
+ target.Route = route
+ resultsChan <- target
+ return
+ }
+ }
+ target.RouteFound = false
+ resultsChan <- target
+}
+
+// AttackCredentials attempts to guess the provided targets' credentials using the given
+// dictionary or the default dictionary if none was provided by the user
+func AttackCredentials(targets []Stream, credentials Credentials, timeout time.Duration, log bool) (results []Stream, err error) {
+ attacks := make(chan Stream)
+ defer close(attacks)
+
+ validate := v.New()
+ for _, target := range targets {
+ err := validate.Struct(target)
+ if err != nil {
+ return targets, errors.Wrap(err, "invalid streams")
+ }
+
+ go attackCameraCredentials(target, credentials, attacks, timeout, log)
+ }
+
+ attackResults := []Stream{}
+ for _ = range targets {
+ attackResults = append(attackResults, <-attacks)
+ }
+
+ found := 0
+ for _, result := range attackResults {
+ if result.CredentialsFound == true {
+ targets = replace(targets, result)
+ found++
+ }
+ }
+ if found == 0 {
+ return targets, errors.New("No credentials found")
+ }
+
+ return targets, nil
+}
+
+// AttackRoute attempts to guess the provided targets' streaming routes using the given
+// dictionary or the default dictionary if none was provided by the user
+func AttackRoute(targets []Stream, routes Routes, timeout time.Duration, log bool) (results []Stream, err error) {
+ attacks := make(chan Stream)
+ defer close(attacks)
+
+ validate := v.New()
+ for _, target := range targets {
+ err := validate.Struct(target)
+ if err != nil {
+ return targets, errors.Wrap(err, "invalid streams")
+ }
+
+ go attackCameraRoute(target, routes, attacks, timeout, log)
+ }
+
+ attackResults := []Stream{}
+ for _ = range targets {
+ attackResults = append(attackResults, <-attacks)
+ }
+
+ found := 0
+ for _, result := range attackResults {
+ if result.RouteFound == true {
+ targets = replace(targets, result)
+ found++
+ }
+ }
+ if found == 0 {
+ return targets, errors.New("No routes found")
+ }
+
+ return targets, nil
+}
diff --git a/cameradar/discover.go b/cameradar/discover.go
new file mode 100644
index 0000000..6f28ed5
--- /dev/null
+++ b/cameradar/discover.go
@@ -0,0 +1,152 @@
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cmrdr
+
+import (
+ "bufio"
+ "encoding/xml"
+ "fmt"
+ "io/ioutil"
+ "log"
+ "os/exec"
+
+ "github.com/pkg/errors"
+ 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 (
+ // PARANOID 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
+)
+
+// RunNmap runs nmap on the specified targets's specified ports, using the given nmap speed
+func RunNmap(targets, ports string, resultFilePath string, nmapSpeed int, enableLogs bool) error {
+ // Prepare nmap command
+ cmd := exec.Command(
+ "nmap",
+ fmt.Sprintf("-T%d", nmapSpeed),
+ "-A",
+ targets,
+ "-p",
+ ports,
+ "-oX",
+ resultFilePath,
+ )
+
+ // 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 {
+ log.Printf(in.Text())
+ }
+ }
+ if err := in.Err(); err != nil {
+ if enableLogs {
+ log.Printf("error: %s", err)
+ }
+ }
+
+ return nil
+}
+
+// ParseNmapResult returns a slice of streams from an NMap XML result file
+// To generate one yourself, use the -X option when running NMap
+func ParseNmapResult(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
+ }
+ streams = append(streams, Stream{
+ Device: port.Service.Product,
+ Address: host.Address.Addr,
+ Port: port.PortID,
+ })
+ }
+ }
+
+ return streams, nil
+}
+
+// Discover scans the target networks and tries to find RTSP streams within them
+// targets - string: The addresses
+// - a subnet (e.g.: 172.16.100.0/24)
+// - an IP (e.g.: 172.16.100.10)
+// - a hostname (e.g.: localhost)
+// - a range of IPs (e.g.: 172.16.100.10-172.16.100.20)
+// - a mix of all those separated by commas (e.g.: localhost,172.17.100.0/24,172.16.100.10-172.16.100.20,0.0.0.0).
+// ports - string :
+// - one or multiple ports and port ranges separated by commas (e.g.: 554,8554-8560,18554-28554)
+func Discover(targets string, ports string, nmapResultPath string, speed int, log bool) ([]Stream, error) {
+ var streams []Stream
+
+ // Run nmap command to discover open ports on the specified targets & ports
+ err := RunNmap(targets, ports, nmapResultPath, speed, log)
+ if err != nil {
+ return streams, err
+ }
+
+ // Get found streams from nmap results
+ streams, err = ParseNmapResult(nmapResultPath)
+ if err != nil {
+ return streams, err
+ }
+
+ return streams, nil
+}
diff --git a/cameradar/helpers.go b/cameradar/helpers.go
new file mode 100644
index 0000000..1af81c0
--- /dev/null
+++ b/cameradar/helpers.go
@@ -0,0 +1,38 @@
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cmrdr
+
+import "fmt"
+
+func replace(streams []Stream, new Stream) []Stream {
+ updatedSlice := streams[:0]
+
+ for _, old := range streams {
+ if old.Address == new.Address && old.Port == new.Port {
+ updatedSlice = append(updatedSlice, new)
+ } else {
+ updatedSlice = append(updatedSlice, old)
+ }
+ }
+ return updatedSlice
+}
+
+// RTSPURL generates a stream's RTSP URL
+func RTSPURL(stream Stream) string {
+ return "rtsp://" + stream.Username + ":" + stream.Password + "@" + stream.Address + ":" + fmt.Sprint(stream.Port) + "/" + stream.Route
+}
+
+// AdminPanelURL returns the URL to the camera's admin panel
+func AdminPanelURL(stream Stream) string {
+ return "http://" + stream.Address + "/"
+}
diff --git a/cameradar/loaders.go b/cameradar/loaders.go
new file mode 100644
index 0000000..5b88101
--- /dev/null
+++ b/cameradar/loaders.go
@@ -0,0 +1,58 @@
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cmrdr
+
+import (
+ "bufio"
+ "encoding/json"
+ "io/ioutil"
+ "os"
+
+ "github.com/pkg/errors"
+)
+
+// LoadCredentials opens a dictionary file and returns its contents as a Credentials structure
+func LoadCredentials(path string) (Credentials, error) {
+ var creds Credentials
+
+ // Open & Read XML file
+ content, err := ioutil.ReadFile(path)
+ if err != nil {
+ return creds, errors.Wrap(err, "Could not read credentials dictionary file at "+path+":")
+ }
+
+ // Unmarshal content of JSON file into data structure
+ err = json.Unmarshal(content, &creds)
+ if err != nil {
+ return creds, err
+ }
+
+ return creds, nil
+}
+
+// LoadRoutes opens a dictionary file and returns its contents as a Routes structure
+func LoadRoutes(path string) (Routes, error) {
+ file, err := os.Open(path)
+ if err != nil {
+ return nil, err
+ }
+ defer file.Close()
+
+ var routes Routes
+ scanner := bufio.NewScanner(file)
+ for scanner.Scan() {
+ routes = append(routes, scanner.Text())
+ }
+
+ return routes, scanner.Err()
+}
diff --git a/cameradar/models.go b/cameradar/models.go
new file mode 100644
index 0000000..4c9654f
--- /dev/null
+++ b/cameradar/models.go
@@ -0,0 +1,38 @@
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cmrdr
+
+// Stream represents a camera's RTSP stream
+type Stream struct {
+ Device string
+ Username string
+ Password string
+ Route string
+ Address string `validate:"required"`
+ Port uint `validate:"required"`
+
+ CredentialsFound bool
+ RouteFound bool
+}
+
+// Credentials is a map of credentials
+// usernames are keys and passwords are values
+// creds['admin'] -> 'secure_password'
+type Credentials struct {
+ Usernames []string `json:"usernames"`
+ Passwords []string `json:"passwords"`
+}
+
+// Routes is a slice of Routes
+// ['/live.sdp', '/media.amp', ...]
+type Routes []string
diff --git a/cameradar/xml_models.go b/cameradar/xml_models.go
new file mode 100644
index 0000000..d3d25a5
--- /dev/null
+++ b/cameradar/xml_models.go
@@ -0,0 +1,62 @@
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+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"`
+ Address 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"`
+}
+
+// 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"`
+}
diff --git a/cameradar_standalone/CMakeLists.txt b/cameradar_standalone/CMakeLists.txt
deleted file mode 100644
index b122c95..0000000
--- a/cameradar_standalone/CMakeLists.txt
+++ /dev/null
@@ -1,60 +0,0 @@
-## Copyright 2016 Etix Labs
-##
-## Licensed under the Apache License, Version 2.0 (the "License");
-## you may not use this file except in compliance with the License.
-## You may obtain a copy of the License at
-##
-## http://www.apache.org/licenses/LICENSE-2.0
-##
-## Unless required by applicable law or agreed to in writing, software
-## distributed under the License is distributed on an "AS IS" BASIS,
-## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-## See the License for the specific language governing permissions and
-## limitations under the License.
-
-cmake_minimum_required (VERSION 2.8.1)
-cmake_policy(SET CMP0048 OLD)
-
-project(cameradar CXX)
-
-# find gstreamer 1.x libraries
-include(FindPkgConfig)
-
-pkg_search_module(GSTREAMER REQUIRED gstreamer-1.0)
-find_library(LIB_GSTREAMER NAMES ${GSTREAMER_LIBRARIES} HINTS ${GSTREAMER_LIBRARY_DIRS})
-
-include_directories (
- ${GSTREAMER_INCLUDE_DIRS}
- ${PROJECT_SOURCE_DIR}/include
- ${VERSION_INCLUDE_DIR}
-)
-
-link_directories (
- ${GSTREAMER_LIBRARY_DIRS}
- "../deps/jsoncpp/src/deps.jsoncpp/src/lib_json"
-)
-
-if ("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang")
- # search special osx gstreamer libs
- pkg_search_module(GSTREAMER_APP REQUIRED gstreamer-app-1.0)
- find_library(LIB_GSTREAMER NAMES ${GSTREAMER_APP_LIBRARIES} HINTS ${GSTREAMER_APP_LIBRARY_DIRS})
-
- include_directories (${GSTREAMER_APP_INCLUDE_DIRS})
-
- link_directories (${GSTREAMER_APP_LIBRARY_DIRS})
-endif()
-
-include (find_sources)
-find_sources ("src" "include" "src/tasks")
-
-add_executable (cameradar ${SOURCES})
-target_link_libraries (cameradar pthread jsoncpp dl curl ${GSTREAMER_LIBRARIES})
-
-# Add the conf files to the build dir
-add_custom_command(TARGET cameradar PRE_BUILD
- COMMAND ${CMAKE_COMMAND} -E copy_directory
- ${CMAKE_SOURCE_DIR}/cameradar_standalone/conf $/conf/)
-
-set (BINARIES_NAME ${PROJECT_BINARY_DIR}/cameradar)
-list (APPEND CAMERADAR_BINARIES ${BINARIES_NAME})
-set (CAMERADAR_BINARIES ${CAMERADAR_BINARIES} PARENT_SCOPE)
diff --git a/cameradar_standalone/conf/cameradar.conf.json b/cameradar_standalone/conf/cameradar.conf.json
deleted file mode 100644
index 86f7308..0000000
--- a/cameradar_standalone/conf/cameradar.conf.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "mysql_db" : {
- "host" : "cameradar-database",
- "port" : 3306,
- "user": "root",
- "password": "root",
- "db_name": "cmrdr"
- },
- "target" : "localhost",
- "ports" : "554,8554",
- "rtsp_url_file" : "/cameradar/conf/url.json",
- "rtsp_ids_file" : "/cameradar/conf/ids.json",
- "thumbnail_storage_path" : "/tmp/thumbs",
- "cache_manager_path" : "/cameradar/cache_managers",
- "cache_manager_name" : "dumb"
-}
diff --git a/cameradar_standalone/conf/ids.json b/cameradar_standalone/conf/ids.json
deleted file mode 100644
index 046b60c..0000000
--- a/cameradar_standalone/conf/ids.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "username": [
- "",
- "admin",
- "Admin",
- "root",
- "supervisor",
- "ubnt"
- ],
- "password" : [
- "",
- "admin",
- "9999",
- "123456",
- "pass",
- "camera",
- "1234",
- "12345",
- "fliradmin",
- "system",
- "jvc",
- "meinsm",
- "root",
- "4321",
- "1111111",
- "password",
- "ikwd",
- "supervisor",
- "ubnt"
- ]
-}
\ No newline at end of file
diff --git a/cameradar_standalone/conf/url.json b/cameradar_standalone/conf/url.json
deleted file mode 100644
index 23af730..0000000
--- a/cameradar_standalone/conf/url.json
+++ /dev/null
@@ -1,117 +0,0 @@
-{
- "urls" : [
- "/",
- "/1.AMP",
- "/1/stream1",
- "/CAM_ID.password.mp2",
- "/GetData.cgi",
- "/MediaInput/h264",
- "/MediaInput/mpeg4",
- "/VideoInput/1/h264/1",
- "/access_code",
- "/access_name_for_stream_1_to_5",
- "/av0_0",
- "/av2",
- "/avn=2",
- "/axis-media/media.amp",
- "/cam",
- "/cam0_0",
- "/cam0_1",
- "/cam1/h264",
- "/cam1/h264/multicast",
- "/cam1/mjpeg",
- "/cam1/mpeg4",
- "/camera.stm",
- "/ch0",
- "/ch001.sdp",
- "/ch01.264",
- "/ch0_unicast_firststream",
- "/ch0_unicast_secondstream",
- "/channel1",
- "/h264",
- "/h264/media.amp",
- "/image.mpg",
- "/img/media.sav",
- "/img/video.asf",
- "/img/video.sav",
- "/ioImage/1",
- "/ipcam.sdp",
- "/ipcam_h264.sdp",
- "/live.sdp",
- "/live/h264",
- "/live/mpeg4",
- "/live_mpeg4.sdp",
- "/livestream",
- "/livestream/",
- "/media/media.amp",
- "/media/video1",
- "/mjpeg/media.smp",
- "/mp4",
- "/mpeg4",
- "/mpeg4/1/media.amp",
- "/mpeg4/media.amp",
- "/mpeg4/media.smp",
- "/mpeg4unicast",
- "/mpg4/rtsp.amp",
- "/multicaststream",
- "/now.mp4",
- "/nph-h264.cgi",
- "/nphMpeg4/g726-640x",
- "/nphMpeg4/g726-640x480",
- "/nphMpeg4/nil-320x240",
- "/play1.sdp",
- "/play2.sdp",
- "/rtpvideo1.sdp",
- "/rtsp_live0",
- "/rtsp_live1",
- "/rtsp_live2",
- "/rtsp_tunnel",
- "/rtsph264",
- "/stream1",
- "/user.pin.mp2",
- "/user_defined",
- "/video",
- "/video.3gp",
- "/video.mp4",
- "/video1",
- "/video1+audio1",
- "/vis",
- "/wfov",
- "/video.h264",
- "/11",
- "/12",
- "/ch1-s1",
- "/live3.sdp",
- "/onvif-media/media.amp",
- "/axis-media/media.amp",
- "/axis-media/media.amp?videocodec=h264",
- "/mpeg4/media.amp",
- "/stream",
- "/cam/realmonitor",
- "/live",
- "/video.pro2",
- "/videoMain",
- "/VideoInput/1/mpeg4/1",
- "/VideoInput/1/h264/1",
- "/video.pro3",
- "/video.pro1",
- "/video.mjpg",
- "/h264_vga.sdp",
- "/media.amp",
- "/media",
- "/ONVIF/MediaInput",
- "/nphMpeg4/g726-640x48",
- "/MediaInput/mpeg4",
- "/MediaInput/h264",
- "/Streaming/Channels/1",
- "/ch0_0.h264",
- "/rtsph2641080p",
- "/live/av0",
- "/cam1/onvif-h264",
- "/ucast/11",
- "/LowResolutionVideo",
- "/1",
- "/live/ch00_0",
- "/medias2"
- ]
-}
diff --git a/cameradar_standalone/include/cachemanager.h b/cameradar_standalone/include/cachemanager.h
deleted file mode 100644
index d077ff4..0000000
--- a/cameradar_standalone/include/cachemanager.h
+++ /dev/null
@@ -1,185 +0,0 @@
-// Copyright 2016 Etix Labs
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#pragma once
-
-#include
-#include
-#include
-#include
-#include
-
-namespace etix {
-namespace cameradar {
-
-// The interface a cache_manager should implement to be valid
-class cache_manager_iface {
-public:
- virtual ~cache_manager_iface() {}
-
- // Launches the manager configuration
- // \return false if failed
- virtual bool configure(std::shared_ptr configuration) = 0;
-
- // get the name of the cache manager
- virtual const std::string& get_name() const = 0;
-
- // Replaces all cached streams by the content of the vector given as
- // parameter
- virtual void set_streams(std::vector model) = 0;
-
- // Inserts a single stream to the cache
- virtual void update_stream(const etix::cameradar::stream_model& newmodel) = 0;
-
- // Returns true if the stream passed as a parameter has changed in the cache
- virtual bool has_changed(const etix::cameradar::stream_model&) = 0;
-
- // Gets all cached streams
- virtual std::vector get_streams() = 0;
-
- // Gets all valid streams which have been accessed
- virtual std::vector get_valid_streams() = 0;
-};
-
-class cache_manager_base : public cache_manager_iface {
-public:
- cache_manager_base() = default;
- virtual ~cache_manager_base() = default;
-
- // Launches the cache manager configuration
- // \return false if failed
- virtual bool configure(std::shared_ptr configuration) = 0;
-
- // get the name of the cache manager
- virtual const std::string& get_name() const = 0;
-
- // Replaces all cached streams by the content of the vector given as
- // parameter
- virtual void set_streams(std::vector model) = 0;
-
- // Returns true if the stream passed as a parameter has changed in the cache
- virtual bool has_changed(const etix::cameradar::stream_model&) = 0;
-
- // Updates a single stream to the cache
- virtual void update_stream(const etix::cameradar::stream_model& newmodel) = 0;
-
- // Gets all cached streams
- virtual std::vector get_streams() = 0;
-
- // Gets all valid streams which have been accessed
- virtual std::vector get_valid_streams() = 0;
-
- // Get the manager's instance
- cache_manager_base& get_instance();
-
- template
- std::shared_ptr
- get() {
- static_assert(std::is_base_of::value,
- "I must implement cache_manager_base");
- std::shared_ptr cache_manager(dynamic_cast(this));
- if (not cache_manager) return nullptr;
- return cache_manager->template get();
- }
-};
-
-// The representation of a cache manager
-//
-// This class loads a shared library, and tries to call an extern "C"
-// function which should instanciate a new instance of the plugin.
-class cache_manager {
-private:
- static const std::string PLUGIN_EXT;
- static const std::string default_symbol;
-
- // The name of the cache manager
- std::string name;
-
- // The write mutex to avoid conflicts when multithreading
- std::mutex m;
-
- // The path where the manager is located
- // should be specified in the configuration file
- std::string path;
-
- // The symbol entry point of the manager to
- // call to create an instance from the shared library
- std::string symbol;
-
- // The handle to the shared library where is stored the manager
- void* handle = nullptr;
-
- // The cache manager instance if it is successfully loaded
- cache_manager_iface* ptr = nullptr;
-
- // Internal function that creates the full path of the cache manager
- //
- // full path is composed of: the path, the name, the string "_cache-manager"
- // and the extension PLUGIN_EXT depending of the platform
- std::string make_full_path();
-
-public:
- // Delete constructor
- cache_manager() = delete;
-
- // The manager needs a path and a symbol to be instantiated.
- // The symbol can be changed if the plugin entry point
- // is different than the standard one.
- cache_manager(const std::string& path,
- const std::string& name,
- const std::string& symbol = default_symbol);
-
- // // Copy constructor
- // cache_manager(cache_manager &other);
-
- // Move constructor
- cache_manager(cache_manager&& old);
-
- ~cache_manager();
-
- // Creates the instance of the cache_manager
- //
- // \return false if the cache_manager failed to be instantiated or if
- // the cache_manager is not a valid cache manager, true otherwise
- bool make_instance();
-
- template
- std::shared_ptr
- get() {
- static_assert(std::is_base_of::value,
- "I must implement plugin_base");
- return this->get();
- }
-
- // Helper to access internal loaded cache_manager
- //
- // Gives access to the methods of the cache_manager using the operator
- // -> (e.g.: cache_manager->get_name());
- cache_manager_iface* operator->();
- const cache_manager_iface* operator->() const;
-
- // helper function to check if a cache_manager is instantiated or not
- friend bool operator==(std::nullptr_t nullp, const cache_manager& p);
-
- // helper function to check if a cache_manager is instantiated or not
- friend bool operator==(const cache_manager& p, std::nullptr_t nullp);
-
- // helper function to check if a cache_manager is instantiated or not
- friend bool operator!=(std::nullptr_t nullp, const cache_manager& p);
-
- // helper function to check if a cache_manager is instantiated or not
- friend bool operator!=(const cache_manager& p, std::nullptr_t nullp);
-};
-}
-}
diff --git a/cameradar_standalone/include/cameradar_task.h b/cameradar_standalone/include/cameradar_task.h
deleted file mode 100644
index 6ca116d..0000000
--- a/cameradar_standalone/include/cameradar_task.h
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2016 Etix Labs
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#pragma once
-
-#include // std::string
-#include // std::shared_ptr
-#include // conf
-
-namespace etix {
-
-namespace cameradar {
-
-class cameradar_task {
-public:
- virtual bool run() const = 0;
-};
-}
-}
diff --git a/cameradar_standalone/include/configuration.h b/cameradar_standalone/include/configuration.h
deleted file mode 100644
index 1a66cd6..0000000
--- a/cameradar_standalone/include/configuration.h
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2016 Etix Labs
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#pragma once
-
-#include // Json::Value
-#include // Json::Value
-#include // _LOG_
-#include // parsing opt
-#include // std::string
-#include // std::pair
-
-namespace etix {
-
-namespace cameradar {
-
-static const std::string default_configuration_path = "conf/cameradar.conf.json";
-
-static const std::string default_ports = "554,8554";
-static const std::string default_target = "localhost,168.0.0.0/24";
-static const std::string default_thumbnail_storage_path = "/tmp";
-static const std::string default_rtsp_url_file = "conf/url.json";
-static const std::string default_rtsp_ids_file = "conf/ids.json";
-static const std::string default_cache_manager_path = "../cache_managers/dumb_cache_manager";
-static const std::string default_cache_manager_name = "dumb";
-
-struct configuration {
- std::string thumbnail_storage_path;
- std::string target;
- std::string rtsp_url_file;
- std::string rtsp_ids_file;
- std::string ports;
- std::string cache_manager_path;
- std::string cache_manager_name;
- std::vector paths;
- std::vector usernames;
- std::vector passwords;
-
- Json::Value raw_conf;
-
- configuration() = default;
- configuration(const std::string& thumbnail_storage_path,
- const std::string& target,
- const std::string& rtsp_url_file,
- const std::string& rtsp_ids_file,
- const std::string& cache_manager_path,
- const std::string& cache_manager_name,
- const std::string& ports)
- : thumbnail_storage_path(thumbnail_storage_path)
- , target(target)
- , rtsp_url_file(rtsp_url_file)
- , rtsp_ids_file(rtsp_ids_file)
- , ports(ports)
- , cache_manager_path(cache_manager_path)
- , cache_manager_name(cache_manager_name) {}
-
- static const std::string name_;
-
- bool load_ids();
- bool load_url();
-
- Json::Value get_raw() const;
-};
-
-std::pair read_file(const std::string& path);
-std::pair load(const std::pair& args);
-}
-}
diff --git a/cameradar_standalone/include/describe.h b/cameradar_standalone/include/describe.h
deleted file mode 100644
index c04a252..0000000
--- a/cameradar_standalone/include/describe.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2016 Etix Labs
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#pragma once
-
-#include // std::shared_ptr
-#include // LOG
-#include // cURL client for discovery
-#include // b64
-
-namespace etix {
-namespace cameradar {
-bool curl_describe(const std::string& path, bool logs);
-}
-}
diff --git a/cameradar_standalone/include/dispatcher.h b/cameradar_standalone/include/dispatcher.h
deleted file mode 100644
index af54667..0000000
--- a/cameradar_standalone/include/dispatcher.h
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright 2016 Etix Labs
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#pragma once
-
-#include // sig
-#include // std::shared_ptr
-#include // parsing opt
-#include // LOG
-#include // conf
-#include // std::thread
-#include // operator""ms
-#include // sig
-
-// All the tasks managed by the dispatcher
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-namespace etix {
-namespace cameradar {
-
-enum class task {
- init,
- preparation,
- mapping,
- parsing,
- path_attack,
- creds_attack,
- thumb_generation,
- print,
- finished
-};
-
-class dispatcher {
-private:
- bool busy;
- task current;
- std::string nmap_output;
- const configuration& conf;
- std::shared_ptr cache;
- const std::pair& opts;
- std::list queue;
-
-public:
- dispatcher() = delete;
- dispatcher(const configuration& conf,
- std::shared_ptr cache,
- const std::pair& opts)
- : busy(false)
- , current(task::init)
- , nmap_output("/tmp/scans/scan" + std::to_string(std::chrono::system_clock::to_time_t(
- std::chrono::system_clock::now())) +
- ".xml")
- , conf(conf)
- , cache(cache)
- , opts(opts){};
- ~dispatcher() = default;
- bool
- doing_stuff() const {
- return this->busy;
- }
-
- void do_stuff();
-
- void run();
-};
-}
-}
diff --git a/cameradar_standalone/include/encode.h b/cameradar_standalone/include/encode.h
deleted file mode 100644
index 03ea1e4..0000000
--- a/cameradar_standalone/include/encode.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- base64.cpp and base64.h
- Copyright (C) 2004-2008 René Nyffenegger
- This source code is provided 'as-is', without any express or implied
- warranty. In no event will the author be held liable for any damages
- arising from the use of this software.
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
- 1. The origin of this source code must not be misrepresented; you must not
- claim that you wrote the original source code. If you use this source code
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original source code.
- 3. This notice may not be removed or altered from any source distribution.
- René Nyffenegger rene.nyffenegger@adp-gmbh.ch
-*/
-#pragma once
-
-#include
-
-namespace etix {
-
-namespace tool {
-
-namespace encode {
-
-std::string encode64(const std::string& str_to_encode);
-
-std::string base64_encode(unsigned char const*, unsigned int len);
-std::string base64_decode(std::string const& s);
-
-} // encode
-
-} // tool
-
-} // etix
diff --git a/cameradar_standalone/include/fmt.h b/cameradar_standalone/include/fmt.h
deleted file mode 100644
index 3847065..0000000
--- a/cameradar_standalone/include/fmt.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2016 Etix Labs
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#pragma once
-
-#include
-#include
-#include
-
-namespace etix {
-
-namespace tool {
-
-static std::mutex mutex;
-
-// Format a string with the given arguments
-// same behavior as sprintf.
-template
-std::string
-fmt(const std::string& base, Args... args) {
- std::lock_guard guard(mutex);
- static char buf[512];
-
- std::sprintf(buf, base.c_str(), args...);
-
- return std::string(buf);
-}
-
-} // tool
-
-} // etix
diff --git a/cameradar_standalone/include/fs.h b/cameradar_standalone/include/fs.h
deleted file mode 100644
index 265e36c..0000000
--- a/cameradar_standalone/include/fs.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2016 Etix Labs
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#pragma once
-
-#include
-#include
-#include
-#include
-#include
-
-namespace etix {
-
-namespace tool {
-
-namespace fs {
-
-enum class fs_error { is_dir, is_not_dir, dont_exist };
-
-fs_error is_folder(const std::string& folder);
-bool get_or_create_folder(const std::string& folder);
-bool create_folder(const std::string& folder);
-bool create_recursive_folder(const std::string& folder);
-std::string home();
-
-// this functions take a copy because we need to make some operations on the string
-// for example, we need to apply std::string::pop_back
-std::string get_file_folder(std::string full_file_path);
-
-bool copy(const std::string& src, const std::string& dst);
-
-} // fs
-
-} // tool
-
-} // etix
diff --git a/cameradar_standalone/include/launch_command.h b/cameradar_standalone/include/launch_command.h
deleted file mode 100644
index 2909440..0000000
--- a/cameradar_standalone/include/launch_command.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2016 Etix Labs
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#pragma once
-
-#include // std::string
-#include // LOG
-#include // system
-
-namespace etix {
-namespace cameradar {
-bool launch_command(const std::string& cmd);
-}
-}
diff --git a/cameradar_standalone/include/logger.h b/cameradar_standalone/include/logger.h
deleted file mode 100644
index ddfadbf..0000000
--- a/cameradar_standalone/include/logger.h
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright 2016 Etix Labs
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#pragma once
-
-#include "spdlog/spdlog.h"
-#include
-#include
-
-namespace etix {
-
-namespace tool {
-
-enum class loglevel { DEBUG = 1, INFO = 2, WARN = 4, ERR = 5, CRITICAL = 6 };
-
-inline std::string
-format_output(const std::string& from, const std::string& message) {
- auto ss = std::stringstream{};
-
- ss << "(" << from << "): ";
- ss << message;
-
- return ss.str();
-}
-
-class logger {
- std::string name;
- std::shared_ptr console;
-
- logger(const std::string& plugin)
- : name(plugin), console(spdlog::stdout_logger_mt("cameradar")) {}
-
-public:
- static logger&
- get_instance(const std::string& name = "") {
- static logger self(name);
- return self;
- }
- void
- set_level(loglevel level) {
- switch (level) {
- case loglevel::DEBUG: this->console->set_level(spdlog::level::level_enum::debug); break;
-
- case loglevel::INFO: this->console->set_level(spdlog::level::level_enum::info); break;
-
- case loglevel::WARN: this->console->set_level(spdlog::level::level_enum::warn); break;
-
- case loglevel::ERR: this->console->set_level(spdlog::level::level_enum::err); break;
-
- case loglevel::CRITICAL:
- this->console->set_level(spdlog::level::level_enum::critical);
- break;
- }
- }
-
- static void
- info(const std::string& message) {
- etix::tool::logger::get_instance().console->info(message);
- }
-
- static void
- warn(const std::string& message) {
- etix::tool::logger::get_instance().console->warn(message);
- }
-
- static void
- err(const std::string& message) {
- etix::tool::logger::get_instance().console->error(message);
- }
-
- static void
- debug(const std::string& message) {
- etix::tool::logger::get_instance().console->debug(message);
- }
-};
-}
-}
-
-// Should be replaced to calls to spdlog::logger::getlogger(const std::string&
-// name)
-#define LOG_WARN_(message, from) \
- etix::tool::logger::get_instance().warn(etix::tool::format_output( \
- std::string(from) + "::" + __FUNCTION__ + ":" + std::to_string(__LINE__), message))
-#define LOG_ERR_(message, from) \
- etix::tool::logger::get_instance().err(etix::tool::format_output( \
- std::string(from) + "::" + __FUNCTION__ + ":" + std::to_string(__LINE__), message))
-#define LOG_DEBUG_(message, from) \
- etix::tool::logger::get_instance().debug(etix::tool::format_output( \
- std::string(from) + "::" + __FUNCTION__ + ":" + std::to_string(__LINE__), message))
-#define LOG_INFO_(message, from) \
- etix::tool::logger::get_instance().info(etix::tool::format_output( \
- std::string(from) + "::" + __FUNCTION__ + ":" + std::to_string(__LINE__), message))
diff --git a/cameradar_standalone/include/opt_parse.h b/cameradar_standalone/include/opt_parse.h
deleted file mode 100644
index 38edf48..0000000
--- a/cameradar_standalone/include/opt_parse.h
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright 2016 Etix Labs
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#pragma once
-
-#include // for string
-#include // for unordered_map
-#include // for pair
-#include // for vector
-
-namespace etix {
-
-namespace tool {
-
-class opt_parse {
-private:
- struct opt_param {
- bool required;
- bool need_arg;
- std::string name;
- std::string desc;
- std::string argument;
- bool is_passed = false;
-
- opt_param(bool required, bool need_arg, std::string name, std::string desc)
- : required(required), need_arg(need_arg), name(name), desc(desc) {}
- };
-
- std::unordered_map params;
- int argc;
- char** argv;
- int params_cnt = 0;
-
-public:
- class iterator {
- private:
- std::vector> args;
- unsigned int opt_pos = 0;
-
- public:
- iterator(std::vector> args, unsigned int opt_pos)
- : args(args), opt_pos(opt_pos) {}
- iterator operator++() {
- this->opt_pos += 1;
- return *this;
- }
- std::pair& operator*() { return this->args.at(this->opt_pos); }
- bool
- operator==(const iterator& rhs) const {
- return this->opt_pos == rhs.opt_pos;
- }
- bool
- operator!=(const iterator& rhs) const {
- return this->opt_pos != rhs.opt_pos;
- }
- };
-
- opt_parse() = delete;
-
- opt_parse(int argc, char* argv[]);
-
- ~opt_parse();
-
- void required(const std::string& name, const std::string& desc = "", bool need_arg = true);
-
- void optional(const std::string& name, const std::string& desc = "", bool need_arg = true);
-
- bool execute();
-
- iterator begin() const;
-
- iterator end() const;
-
- void print_usage() const;
-
- void print_help() const;
-
- bool has_error() const;
-
- bool exist(const std::string& opt) const;
-
- std::string operator[](const std::string& opt) const;
-};
-
-} // tool
-
-} // etix
diff --git a/cameradar_standalone/include/rtsp_path.h b/cameradar_standalone/include/rtsp_path.h
deleted file mode 100644
index 2a2208a..0000000
--- a/cameradar_standalone/include/rtsp_path.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2016 Etix Labs
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#pragma once
-
-#include // for string
-#include // for stream_model
-
-namespace etix {
-
-namespace cameradar {
-
-const std::string make_path(const stream_model& model);
-}
-}
diff --git a/cameradar_standalone/include/signal_handler.h b/cameradar_standalone/include/signal_handler.h
deleted file mode 100644
index 9813182..0000000
--- a/cameradar_standalone/include/signal_handler.h
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2016 Etix Labs
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#pragma once
-
-#include // assert
-#include // sigint
-#include // stc::cout
-
-// To avoid an unused warning for the asserted in handle_signal
-#define _unused(x) ((void)(x))
-
-namespace etix {
-
-namespace cameradar {
-
-enum class stop_priority { running, stop, force_stop };
-
-class event_handler {
-public:
- event_handler(void) : ss(stop_priority::running) {}
-
- virtual int
- handle_signal(int signum) {
- assert(signum == SIGINT);
- _unused(signum);
- std::cout << "\b\b\b\033[K";
- if (this->ss == stop_priority::running)
- this->ss = stop_priority::stop;
- else
- this->ss = stop_priority::force_stop;
- return 0;
- }
-
- etix::cameradar::stop_priority
- should_stop(void) const {
- return this->ss;
- }
-
-private:
- stop_priority ss;
-};
-
-class signal_handler {
-private:
- signal_handler(void);
- signal_handler(const signal_handler&);
- signal_handler& operator=(const signal_handler&);
-
- static void call_handler(int signum);
-
- static event_handler handler;
-
-public:
- static signal_handler& instance(void);
- etix::cameradar::stop_priority should_stop(void) const;
-};
-}
-}
diff --git a/cameradar_standalone/include/spdlog/async_logger.h b/cameradar_standalone/include/spdlog/async_logger.h
deleted file mode 100644
index 3e45c0f..0000000
--- a/cameradar_standalone/include/spdlog/async_logger.h
+++ /dev/null
@@ -1,71 +0,0 @@
-//
-// Copyright(c) 2015 Gabi Melman.
-// Distributed under the MIT License (http://opensource.org/licenses/MIT)
-//
-
-#pragma once
-
-// Very fast asynchronous logger (millions of logs per second on an average desktop)
-// Uses pre allocated lockfree queue for maximum throughput even under large number of threads.
-// Creates a single back thread to pop messages from the queue and log them.
-//
-// Upon each log write the logger:
-// 1. Checks if its log level is enough to log the message
-// 2. Push a new copy of the message to a queue (or block the caller until space is available in
-// the queue)
-// 3. will throw spdlog_ex upon log exceptions
-// Upong destruction, logs all remaining messages in the queue before destructing..
-
-#include
-#include
-#include "common.h"
-#include "logger.h"
-#include "spdlog.h"
-
-namespace spdlog {
-
-namespace details {
-class async_log_helper;
-}
-
-class async_logger : public logger {
-public:
- template
- async_logger(
- const std::string& name,
- const It& begin,
- const It& end,
- size_t queue_size,
- const async_overflow_policy overflow_policy = async_overflow_policy::block_retry,
- const std::function& worker_warmup_cb = nullptr,
- const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero());
-
- async_logger(
- const std::string& logger_name,
- sinks_init_list sinks,
- size_t queue_size,
- const async_overflow_policy overflow_policy = async_overflow_policy::block_retry,
- const std::function& worker_warmup_cb = nullptr,
- const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero());
-
- async_logger(
- const std::string& logger_name,
- sink_ptr single_sink,
- size_t queue_size,
- const async_overflow_policy overflow_policy = async_overflow_policy::block_retry,
- const std::function& worker_warmup_cb = nullptr,
- const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero());
-
- void flush() override;
-
-protected:
- void _log_msg(details::log_msg& msg) override;
- void _set_formatter(spdlog::formatter_ptr msg_formatter) override;
- void _set_pattern(const std::string& pattern) override;
-
-private:
- std::unique_ptr _async_log_helper;
-};
-}
-
-#include "./details/async_logger_impl.h"
diff --git a/cameradar_standalone/include/spdlog/common.h b/cameradar_standalone/include/spdlog/common.h
deleted file mode 100644
index 0f25667..0000000
--- a/cameradar_standalone/include/spdlog/common.h
+++ /dev/null
@@ -1,88 +0,0 @@
-//
-// Copyright(c) 2015 Gabi Melman.
-// Distributed under the MIT License (http://opensource.org/licenses/MIT)
-//
-
-#pragma once
-
-#include
-#include
-#include
-#include
-
-// visual studio does not support noexcept yet
-#ifndef _MSC_VER
-#define SPDLOG_NOEXCEPT noexcept
-#else
-#define SPDLOG_NOEXCEPT throw()
-#endif
-
-namespace spdlog {
-
-class formatter;
-
-namespace sinks {
-class sink;
-}
-
-// Common types across the lib
-using log_clock = std::chrono::system_clock;
-using sink_ptr = std::shared_ptr;
-using sinks_init_list = std::initializer_list;
-using formatter_ptr = std::shared_ptr;
-
-// Log level enum
-namespace level {
-typedef enum {
- trace = 0,
- debug = 1,
- info = 2,
- notice = 3,
- warn = 4,
- err = 5,
- critical = 6,
- alert = 7,
- emerg = 8,
- off = 9
-} level_enum;
-
-static const char* level_names[]{ "trace", "debug", "info", "notice", "warning",
- "error", "critical", "alert", "emerg", "off" };
-
-static const char* short_level_names[]{ "T", "D", "I", "N", "W", "E", "C", "A", "M", "O" };
-
-inline const char*
-to_str(spdlog::level::level_enum l) {
- return level_names[l];
-}
-
-inline const char*
-to_short_str(spdlog::level::level_enum l) {
- return short_level_names[l];
-}
-} // level
-
-//
-// Async overflow policy - block by default.
-//
-enum class async_overflow_policy {
- block_retry, // Block / yield / sleep until message can be enqueued
- discard_log_msg // Discard the message it enqueue fails
-};
-
-//
-// Log exception
-//
-class spdlog_ex : public std::exception {
-public:
- explicit spdlog_ex(const std::string& msg) : _msg(msg) {}
- const char*
- what() const SPDLOG_NOEXCEPT override {
- return _msg.c_str();
- }
-
-private:
- std::string _msg;
-};
-
-} // spdlog
diff --git a/cameradar_standalone/include/spdlog/details/async_log_helper.h b/cameradar_standalone/include/spdlog/details/async_log_helper.h
deleted file mode 100644
index 3501039..0000000
--- a/cameradar_standalone/include/spdlog/details/async_log_helper.h
+++ /dev/null
@@ -1,313 +0,0 @@
-//
-// Copyright(c) 2015 Gabi Melman.
-// Distributed under the MIT License (http://opensource.org/licenses/MIT)
-//
-
-// async log helper :
-// Process logs asynchronously using a back thread.
-//
-// If the internal queue of log messages reaches its max size,
-// then the client call will block until there is more room.
-//
-// If the back thread throws during logging, a spdlog::spdlog_ex exception
-// will be thrown in client's thread when tries to log the next message
-
-#pragma once
-
-#include
-#include
-#include
-
-#include "../common.h"
-#include "../sinks/sink.h"
-#include "./mpmc_bounded_q.h"
-#include "./log_msg.h"
-#include "./format.h"
-#include "./os.h"
-
-namespace spdlog {
-namespace details {
-
-class async_log_helper {
- // Async msg to move to/from the queue
- // Movable only. should never be copied
- enum class async_msg_type { log, flush, terminate };
- struct async_msg {
- std::string logger_name;
- level::level_enum level;
- log_clock::time_point time;
- size_t thread_id;
- std::string txt;
- async_msg_type msg_type;
-
- async_msg() = default;
- ~async_msg() = default;
-
- async_msg(async_msg&& other) SPDLOG_NOEXCEPT : logger_name(std::move(other.logger_name)),
- level(std::move(other.level)),
- time(std::move(other.time)),
- txt(std::move(other.txt)),
- msg_type(std::move(other.msg_type)) {}
-
- async_msg(async_msg_type m_type) : msg_type(m_type){};
-
- async_msg& operator=(async_msg&& other) SPDLOG_NOEXCEPT {
- logger_name = std::move(other.logger_name);
- level = other.level;
- time = std::move(other.time);
- thread_id = other.thread_id;
- txt = std::move(other.txt);
- msg_type = other.msg_type;
- return *this;
- }
-
- // never copy or assign. should only be moved..
- async_msg(const async_msg&) = delete;
- async_msg& operator=(async_msg& other) = delete;
-
- // construct from log_msg
- async_msg(const details::log_msg& m)
- : logger_name(m.logger_name)
- , level(m.level)
- , time(m.time)
- , thread_id(m.thread_id)
- , txt(m.raw.data(), m.raw.size())
- , msg_type(async_msg_type::log) {}
-
- // copy into log_msg
- void
- fill_log_msg(log_msg& msg) {
- msg.clear();
- msg.logger_name = logger_name;
- msg.level = level;
- msg.time = time;
- msg.thread_id = thread_id;
- msg.raw << txt;
- }
- };
-
-public:
- using item_type = async_msg;
- using q_type = details::mpmc_bounded_queue;
-
- using clock = std::chrono::steady_clock;
-
- async_log_helper(
- formatter_ptr formatter,
- const std::vector& sinks,
- size_t queue_size,
- const async_overflow_policy overflow_policy = async_overflow_policy::block_retry,
- const std::function& worker_warmup_cb = nullptr,
- const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero());
-
- void log(const details::log_msg& msg);
-
- // stop logging and join the back thread
- ~async_log_helper();
-
- void set_formatter(formatter_ptr);
-
- void flush();
-
-private:
- formatter_ptr _formatter;
- std::vector> _sinks;
-
- // queue of messages to log
- q_type _q;
-
- bool _flush_requested;
-
- bool _terminate_requested;
-
- // last exception thrown from the worker thread
- std::shared_ptr _last_workerthread_ex;
-
- // overflow policy
- const async_overflow_policy _overflow_policy;
-
- // worker thread warmup callback - one can set thread priority, affinity, etc
- const std::function _worker_warmup_cb;
-
- // auto periodic sink flush parameter
- const std::chrono::milliseconds _flush_interval_ms;
-
- // worker thread
- std::thread _worker_thread;
-
- void push_msg(async_msg&& new_msg);
- // throw last worker thread exception or if worker thread is not active
-
- void throw_if_bad_worker();
-
- // worker thread main loop
- void worker_loop();
-
- // pop next message from the queue and process it. will set the last_pop to the pop time
- // return false if termination of the queue is required
- bool process_next_msg(log_clock::time_point& last_pop, log_clock::time_point& last_flush);
-
- void handle_flush_interval(log_clock::time_point& now, log_clock::time_point& last_flush);
-
- // sleep,yield or return immediatly using the time passed since last message as a hint
- static void sleep_or_yield(const spdlog::log_clock::time_point& now,
- const log_clock::time_point& last_op_time);
-};
-}
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// async_sink class implementation
-///////////////////////////////////////////////////////////////////////////////
-inline spdlog::details::async_log_helper::async_log_helper(
- formatter_ptr formatter,
- const std::vector& sinks,
- size_t queue_size,
- const async_overflow_policy overflow_policy,
- const std::function& worker_warmup_cb,
- const std::chrono::milliseconds& flush_interval_ms)
-: _formatter(formatter)
-, _sinks(sinks)
-, _q(queue_size)
-, _flush_requested(false)
-, _terminate_requested(false)
-, _overflow_policy(overflow_policy)
-, _worker_warmup_cb(worker_warmup_cb)
-, _flush_interval_ms(flush_interval_ms)
-, _worker_thread(&async_log_helper::worker_loop, this) {}
-
-// Send to the worker thread termination message(level=off)
-// and wait for it to finish gracefully
-inline spdlog::details::async_log_helper::~async_log_helper() {
- try {
- push_msg(async_msg(async_msg_type::terminate));
- _worker_thread.join();
- } catch (...) // don't crash in destructor
- {}
-}
-
-// Try to push and block until succeeded
-inline void
-spdlog::details::async_log_helper::log(const details::log_msg& msg) {
- push_msg(async_msg(msg));
-}
-
-// Try to push and block until succeeded
-inline void
-spdlog::details::async_log_helper::push_msg(details::async_log_helper::async_msg&& new_msg) {
- throw_if_bad_worker();
- if (!_q.enqueue(std::move(new_msg)) &&
- _overflow_policy != async_overflow_policy::discard_log_msg) {
- auto last_op_time = details::os::now();
- auto now = last_op_time;
- do {
- now = details::os::now();
- sleep_or_yield(now, last_op_time);
- } while (!_q.enqueue(std::move(new_msg)));
- }
-}
-
-inline void
-spdlog::details::async_log_helper::flush() {
- push_msg(async_msg(async_msg_type::flush));
-}
-
-inline void
-spdlog::details::async_log_helper::worker_loop() {
- try {
- if (_worker_warmup_cb) _worker_warmup_cb();
- auto last_pop = details::os::now();
- auto last_flush = last_pop;
- while (process_next_msg(last_pop, last_flush))
- ;
- } catch (const std::exception& ex) {
- _last_workerthread_ex = std::make_shared(
- std::string("async_logger worker thread exception: ") + ex.what());
- } catch (...) {
- _last_workerthread_ex = std::make_shared("async_logger worker thread exception");
- }
-}
-
-// process next message in the queue
-// return true if this thread should still be active (no msg with level::off was received)
-inline bool
-spdlog::details::async_log_helper::process_next_msg(log_clock::time_point& last_pop,
- log_clock::time_point& last_flush) {
- async_msg incoming_async_msg;
- log_msg incoming_log_msg;
-
- if (_q.dequeue(incoming_async_msg)) {
- last_pop = details::os::now();
- switch (incoming_async_msg.msg_type) {
- case async_msg_type::flush: _flush_requested = true; break;
-
- case async_msg_type::terminate:
- _flush_requested = true;
- _terminate_requested = true;
- break;
-
- default:
- incoming_async_msg.fill_log_msg(incoming_log_msg);
- _formatter->format(incoming_log_msg);
- for (auto& s : _sinks) s->log(incoming_log_msg);
- }
- return true;
- }
-
- // Handle empty queue..
- // This is the only place where the queue can terminate or flush to avoid losing messages
- // already in the queue
- else {
- auto now = details::os::now();
- handle_flush_interval(now, last_flush);
- sleep_or_yield(now, last_pop);
- return !_terminate_requested;
- }
-}
-
-inline void
-spdlog::details::async_log_helper::handle_flush_interval(log_clock::time_point& now,
- log_clock::time_point& last_flush) {
- auto should_flush =
- _flush_requested || (_flush_interval_ms != std::chrono::milliseconds::zero() &&
- now - last_flush >= _flush_interval_ms);
- if (should_flush) {
- for (auto& s : _sinks) s->flush();
- now = last_flush = details::os::now();
- _flush_requested = false;
- }
-}
-inline void
-spdlog::details::async_log_helper::set_formatter(formatter_ptr msg_formatter) {
- _formatter = msg_formatter;
-}
-
-// sleep,yield or return immediatly using the time passed since last message as a hint
-inline void
-spdlog::details::async_log_helper::sleep_or_yield(
- const spdlog::log_clock::time_point& now, const spdlog::log_clock::time_point& last_op_time) {
- using std::chrono::milliseconds;
- using namespace std::this_thread;
-
- auto time_since_op = now - last_op_time;
-
- // spin upto 1 ms
- if (time_since_op <= milliseconds(1)) return;
-
- // yield upto 10ms
- if (time_since_op <= milliseconds(10)) return yield();
-
- // sleep for half of duration since last op
- if (time_since_op <= milliseconds(100)) return sleep_for(time_since_op / 2);
-
- return sleep_for(milliseconds(100));
-}
-
-// throw if the worker thread threw an exception or not active
-inline void
-spdlog::details::async_log_helper::throw_if_bad_worker() {
- if (_last_workerthread_ex) {
- auto ex = std::move(_last_workerthread_ex);
- throw * ex;
- }
-}
diff --git a/cameradar_standalone/include/spdlog/details/async_logger_impl.h b/cameradar_standalone/include/spdlog/details/async_logger_impl.h
deleted file mode 100644
index 368eaaa..0000000
--- a/cameradar_standalone/include/spdlog/details/async_logger_impl.h
+++ /dev/null
@@ -1,72 +0,0 @@
-//
-// Copyright(c) 2015 Gabi Melman.
-// Distributed under the MIT License (http://opensource.org/licenses/MIT)
-//
-
-#pragma once
-
-// Async Logger implementation
-// Use an async_sink (queue per logger) to perform the logging in a worker thread
-
-#include "./async_log_helper.h"
-
-template
-inline spdlog::async_logger::async_logger(const std::string& logger_name,
- const It& begin,
- const It& end,
- size_t queue_size,
- const async_overflow_policy overflow_policy,
- const std::function& worker_warmup_cb,
- const std::chrono::milliseconds& flush_interval_ms)
-: logger(logger_name, begin, end)
-, _async_log_helper(new details::async_log_helper(
- _formatter, _sinks, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms)) {}
-
-inline spdlog::async_logger::async_logger(const std::string& logger_name,
- sinks_init_list sinks,
- size_t queue_size,
- const async_overflow_policy overflow_policy,
- const std::function& worker_warmup_cb,
- const std::chrono::milliseconds& flush_interval_ms)
-: async_logger(logger_name,
- sinks.begin(),
- sinks.end(),
- queue_size,
- overflow_policy,
- worker_warmup_cb,
- flush_interval_ms) {}
-
-inline spdlog::async_logger::async_logger(const std::string& logger_name,
- sink_ptr single_sink,
- size_t queue_size,
- const async_overflow_policy overflow_policy,
- const std::function& worker_warmup_cb,
- const std::chrono::milliseconds& flush_interval_ms)
-: async_logger(logger_name,
- { single_sink },
- queue_size,
- overflow_policy,
- worker_warmup_cb,
- flush_interval_ms) {}
-
-inline void
-spdlog::async_logger::flush() {
- _async_log_helper->flush();
-}
-
-inline void
-spdlog::async_logger::_set_formatter(spdlog::formatter_ptr msg_formatter) {
- _formatter = msg_formatter;
- _async_log_helper->set_formatter(_formatter);
-}
-
-inline void
-spdlog::async_logger::_set_pattern(const std::string& pattern) {
- _formatter = std::make_shared(pattern);
- _async_log_helper->set_formatter(_formatter);
-}
-
-inline void
-spdlog::async_logger::_log_msg(details::log_msg& msg) {
- _async_log_helper->log(msg);
-}
diff --git a/cameradar_standalone/include/spdlog/details/file_helper.h b/cameradar_standalone/include/spdlog/details/file_helper.h
deleted file mode 100644
index 5e1fe43..0000000
--- a/cameradar_standalone/include/spdlog/details/file_helper.h
+++ /dev/null
@@ -1,117 +0,0 @@
-//
-// Copyright(c) 2015 Gabi Melman.
-// Distributed under the MIT License (http://opensource.org/licenses/MIT)
-//
-
-#pragma once
-
-// Helper class for file sink
-// When failing to open a file, retry several times(5) with small delay between the tries(10 ms)
-// Can be set to auto flush on every line
-// Throw spdlog_ex exception on errors
-
-#include
-#include
-#include
-#include "os.h"
-#include "log_msg.h"
-
-namespace spdlog {
-namespace details {
-
-class file_helper {
-public:
- const int open_tries = 5;
- const int open_interval = 10;
-
- explicit file_helper(bool force_flush) : _fd(nullptr), _force_flush(force_flush) {}
-
- file_helper(const file_helper&) = delete;
- file_helper& operator=(const file_helper&) = delete;
-
- ~file_helper() { close(); }
-
- void
- open(const std::string& fname, bool truncate = false) {
- close();
- const char* mode = truncate ? "wb" : "ab";
- _filename = fname;
- for (int tries = 0; tries < open_tries; ++tries) {
- if (!os::fopen_s(&_fd, fname, mode)) return;
-
- std::this_thread::sleep_for(std::chrono::milliseconds(open_interval));
- }
-
- throw spdlog_ex("Failed opening file " + fname + " for writing");
- }
-
- void
- reopen(bool truncate) {
- if (_filename.empty()) throw spdlog_ex("Failed re opening file - was not opened before");
- open(_filename, truncate);
- }
-
- void
- flush() {
- std::fflush(_fd);
- }
-
- void
- close() {
- if (_fd) {
- std::fclose(_fd);
- _fd = nullptr;
- }
- }
-
- void
- write_string(const std::string& msg) {
- if (std::fwrite(msg.c_str(), 1, msg.size(), _fd) != msg.size())
- throw spdlog_ex("Failed writing to file " + _filename);
-
- if (_force_flush) std::fflush(_fd);
- }
-
- void
- write(const log_msg& msg) {
- size_t msg_size = msg.formatted.size();
- auto data = msg.formatted.data();
- if (std::fwrite(data, 1, msg_size, _fd) != msg_size)
- throw spdlog_ex("Failed writing to file " + _filename);
-
- if (_force_flush) std::fflush(_fd);
- }
-
- long
- size() {
- if (!_fd) throw spdlog_ex("Cannot use size() on closed file " + _filename);
-
- auto pos = ftell(_fd);
- if (fseek(_fd, 0, SEEK_END) != 0) throw spdlog_ex("fseek failed on file " + _filename);
-
- auto file_size = ftell(_fd);
-
- if (fseek(_fd, pos, SEEK_SET) != 0) throw spdlog_ex("fseek failed on file " + _filename);
-
- if (file_size == -1) throw spdlog_ex("ftell failed on file " + _filename);
-
- return file_size;
- }
-
- const std::string&
- filename() const {
- return _filename;
- }
-
- static bool
- file_exists(const std::string& name) {
- return os::file_exists(name);
- }
-
-private:
- FILE* _fd;
- std::string _filename;
- bool _force_flush;
-};
-}
-}
diff --git a/cameradar_standalone/include/spdlog/details/format.cc b/cameradar_standalone/include/spdlog/details/format.cc
deleted file mode 100644
index e396688..0000000
--- a/cameradar_standalone/include/spdlog/details/format.cc
+++ /dev/null
@@ -1,934 +0,0 @@
-/*
-Formatting library for C++
-
-Copyright (c) 2012 - 2015, Victor Zverovich
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
-list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright notice,
-this list of conditions and the following disclaimer in the documentation
-and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
-#include "format.h"
-
-#include
-
-#include
-#include
-#include
-#include
-#include
-#include // for std::ptrdiff_t
-
-#if defined(_WIN32) && defined(__MINGW32__)
-#include
-#endif
-
-#if FMT_USE_WINDOWS_H
-#if defined(NOMINMAX) || defined(FMT_WIN_MINMAX)
-#include
-#else
-#define NOMINMAX
-#include
-#undef NOMINMAX
-#endif
-#endif
-
-using fmt::internal::Arg;
-
-#if FMT_EXCEPTIONS
-#define FMT_TRY try
-#define FMT_CATCH(x) catch (x)
-#else
-#define FMT_TRY if (true)
-#define FMT_CATCH(x) if (false)
-#endif
-
-#ifdef FMT_HEADER_ONLY
-#define FMT_FUNC inline
-#else
-#define FMT_FUNC
-#endif
-
-#ifdef _MSC_VER
-#pragma warning(push)
-#pragma warning(disable : 4127) // conditional expression is constant
-#pragma warning(disable : 4702) // unreachable code
-// Disable deprecation warning for strerror. The latter is not called but
-// MSVC fails to detect it.
-#pragma warning(disable : 4996)
-#endif
-
-// Dummy implementations of strerror_r and strerror_s called if corresponding
-// system functions are not available.
-static inline fmt::internal::Null<>
-strerror_r(int, char*, ...) {
- return fmt::internal::Null<>();
-}
-static inline fmt::internal::Null<>
-strerror_s(char*, std::size_t, ...) {
- return fmt::internal::Null<>();
-}
-
-namespace fmt {
-namespace {
-
-#ifndef _MSC_VER
-#define FMT_SNPRINTF snprintf
-#else // _MSC_VER
-inline int
-fmt_snprintf(char* buffer, size_t size, const char* format, ...) {
- va_list args;
- va_start(args, format);
- int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
- va_end(args);
- return result;
-}
-#define FMT_SNPRINTF fmt_snprintf
-#endif // _MSC_VER
-
-#if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
-#define FMT_SWPRINTF snwprintf
-#else
-#define FMT_SWPRINTF swprintf
-#endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
-
-// Checks if a value fits in int - used to avoid warnings about comparing
-// signed and unsigned integers.
-template
-struct IntChecker {
- template
- static bool
- fits_in_int(T value) {
- unsigned max = INT_MAX;
- return value <= max;
- }
- static bool
- fits_in_int(bool) {
- return true;
- }
-};
-
-template <>
-struct IntChecker {
- template
- static bool
- fits_in_int(T value) {
- return value >= INT_MIN && value <= INT_MAX;
- }
- static bool
- fits_in_int(int) {
- return true;
- }
-};
-
-const char RESET_COLOR[] = "\x1b[0m";
-
-typedef void (*FormatFunc)(fmt::Writer&, int, fmt::StringRef);
-
-// Portable thread-safe version of strerror.
-// Sets buffer to point to a string describing the error code.
-// This can be either a pointer to a string stored in buffer,
-// or a pointer to some static immutable string.
-// Returns one of the following values:
-// 0 - success
-// ERANGE - buffer is not large enough to store the error message
-// other - failure
-// Buffer should be at least of size 1.
-int
-safe_strerror(int error_code, char*& buffer, std::size_t buffer_size) FMT_NOEXCEPT {
- FMT_ASSERT(buffer != 0 && buffer_size != 0, "invalid buffer");
-
- class StrError {
- private:
- int error_code_;
- char*& buffer_;
- std::size_t buffer_size_;
-
- // A noop assignment operator to avoid bogus warnings.
- void operator=(const StrError&) {}
-
- // Handle the result of XSI-compliant version of strerror_r.
- int
- handle(int result) {
- // glibc versions before 2.13 return result in errno.
- return result == -1 ? errno : result;
- }
-
- // Handle the result of GNU-specific version of strerror_r.
- int
- handle(char* message) {
- // If the buffer is full then the message is probably truncated.
- if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1) return ERANGE;
- buffer_ = message;
- return 0;
- }
-
- // Handle the case when strerror_r is not available.
- int handle(fmt::internal::Null<>) {
- return fallback(strerror_s(buffer_, buffer_size_, error_code_));
- }
-
- // Fallback to strerror_s when strerror_r is not available.
- int
- fallback(int result) {
- // If the buffer is full then the message is probably truncated.
- return result == 0 && strlen(buffer_) == buffer_size_ - 1 ? ERANGE : result;
- }
-
- // Fallback to strerror if strerror_r and strerror_s are not available.
- int fallback(fmt::internal::Null<>) {
- errno = 0;
- buffer_ = strerror(error_code_);
- return errno;
- }
-
- public:
- StrError(int err_code, char*& buf, std::size_t buf_size)
- : error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {}
-
- int
- run() {
- strerror_r(0, 0, ""); // Suppress a warning about unused strerror_r.
- return handle(strerror_r(error_code_, buffer_, buffer_size_));
- }
- };
- return StrError(error_code, buffer, buffer_size).run();
-}
-
-void
-format_error_code(fmt::Writer& out, int error_code, fmt::StringRef message) FMT_NOEXCEPT {
- // Report error code making sure that the output fits into
- // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential
- // bad_alloc.
- out.clear();
- static const char SEP[] = ": ";
- static const char ERROR_STR[] = "error ";
- fmt::internal::IntTraits::MainType ec_value = error_code;
- // Subtract 2 to account for terminating null characters in SEP and ERROR_STR.
- std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2;
- error_code_size += fmt::internal::count_digits(ec_value);
- if (message.size() <= fmt::internal::INLINE_BUFFER_SIZE - error_code_size)
- out << message << SEP;
- out << ERROR_STR << error_code;
- assert(out.size() <= fmt::internal::INLINE_BUFFER_SIZE);
-}
-
-void
-report_error(FormatFunc func, int error_code, fmt::StringRef message) FMT_NOEXCEPT {
- fmt::MemoryWriter full_message;
- func(full_message, error_code, message);
- // Use Writer::data instead of Writer::c_str to avoid potential memory
- // allocation.
- std::fwrite(full_message.data(), full_message.size(), 1, stderr);
- std::fputc('\n', stderr);
-}
-
-// IsZeroInt::visit(arg) returns true iff arg is a zero integer.
-class IsZeroInt : public fmt::internal::ArgVisitor {
-public:
- template
- bool
- visit_any_int(T value) {
- return value == 0;
- }
-};
-
-// Checks if an argument is a valid printf width specifier and sets
-// left alignment if it is negative.
-class WidthHandler : public fmt::internal::ArgVisitor {
-private:
- fmt::FormatSpec& spec_;
-
- FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler);
-
-public:
- explicit WidthHandler(fmt::FormatSpec& spec) : spec_(spec) {}
-
- void
- report_unhandled_arg() {
- FMT_THROW(fmt::FormatError("width is not integer"));
- }
-
- template
- unsigned
- visit_any_int(T value) {
- typedef typename fmt::internal::IntTraits::MainType UnsignedType;
- UnsignedType width = value;
- if (fmt::internal::is_negative(value)) {
- spec_.align_ = fmt::ALIGN_LEFT;
- width = 0 - width;
- }
- if (width > INT_MAX) FMT_THROW(fmt::FormatError("number is too big"));
- return static_cast(width);
- }
-};
-
-class PrecisionHandler : public fmt::internal::ArgVisitor {
-public:
- void
- report_unhandled_arg() {
- FMT_THROW(fmt::FormatError("precision is not integer"));
- }
-
- template
- int
- visit_any_int(T value) {
- if (!IntChecker::is_signed>::fits_in_int(value))
- FMT_THROW(fmt::FormatError("number is too big"));
- return static_cast(value);
- }
-};
-
-// Converts an integer argument to an integral type T for printf.
-template
-class ArgConverter : public fmt::internal::ArgVisitor, void> {
-private:
- fmt::internal::Arg& arg_;
- wchar_t type_;
-
- FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter);
-
-public:
- ArgConverter(fmt::internal::Arg& arg, wchar_t type) : arg_(arg), type_(type) {}
-
- void
- visit_bool(bool value) {
- if (type_ != 's') visit_any_int(value);
- }
-
- template
- void
- visit_any_int(U value) {
- bool is_signed = type_ == 'd' || type_ == 'i';
- using fmt::internal::Arg;
- if (sizeof(T) <= sizeof(int)) {
- // Extra casts are used to silence warnings.
- if (is_signed) {
- arg_.type = Arg::INT;
- arg_.int_value = static_cast(static_cast(value));
- } else {
- arg_.type = Arg::UINT;
- arg_.uint_value = static_cast(
- static_cast::Type>(value));
- }
- } else {
- if (is_signed) {
- arg_.type = Arg::LONG_LONG;
- arg_.long_long_value =
- static_cast::Type>(value);
- } else {
- arg_.type = Arg::ULONG_LONG;
- arg_.ulong_long_value =
- static_cast::Type>(value);
- }
- }
- }
-};
-
-// Converts an integer argument to char for printf.
-class CharConverter : public fmt::internal::ArgVisitor {
-private:
- fmt::internal::Arg& arg_;
-
- FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter);
-
-public:
- explicit CharConverter(fmt::internal::Arg& arg) : arg_(arg) {}
-
- template
- void
- visit_any_int(T value) {
- arg_.type = Arg::CHAR;
- arg_.int_value = static_cast(value);
- }
-};
-} // namespace
-
-namespace internal {
-
-template
-class PrintfArgFormatter : public ArgFormatterBase, Char> {
- void
- write_null_pointer() {
- this->spec().type_ = 0;
- this->write("(nil)");
- }
-
- typedef ArgFormatterBase, Char> Base;
-
-public:
- PrintfArgFormatter(BasicWriter& w, FormatSpec& s)
- : ArgFormatterBase, Char>(w, s) {}
-
- void
- visit_bool(bool value) {
- FormatSpec& fmt_spec = this->spec();
- if (fmt_spec.type_ != 's') return this->visit_any_int(value);
- fmt_spec.type_ = 0;
- this->write(value);
- }
-
- void
- visit_char(int value) {
- const FormatSpec& fmt_spec = this->spec();
- BasicWriter& w = this->writer();
- if (fmt_spec.type_ && fmt_spec.type_ != 'c') w.write_int(value, fmt_spec);
- typedef typename BasicWriter::CharPtr CharPtr;
- CharPtr out = CharPtr();
- if (fmt_spec.width_ > 1) {
- Char fill = ' ';
- out = w.grow_buffer(fmt_spec.width_);
- if (fmt_spec.align_ != ALIGN_LEFT) {
- std::fill_n(out, fmt_spec.width_ - 1, fill);
- out += fmt_spec.width_ - 1;
- } else {
- std::fill_n(out + 1, fmt_spec.width_ - 1, fill);
- }
- } else {
- out = w.grow_buffer(1);
- }
- *out = static_cast(value);
- }
-
- void
- visit_cstring(const char* value) {
- if (value)
- Base::visit_cstring(value);
- else if (this->spec().type_ == 'p')
- write_null_pointer();
- else
- this->write("(null)");
- }
-
- void
- visit_pointer(const void* value) {
- if (value) return Base::visit_pointer(value);
- this->spec().type_ = 0;
- write_null_pointer();
- }
-
- void
- visit_custom(Arg::CustomValue c) {
- BasicFormatter formatter(ArgList(), this->writer());
- const Char format_str[] = { '}', 0 };
- const Char* format = format_str;
- c.format(&formatter, c.value, &format);
- }
-};
-} // namespace internal
-} // namespace fmt
-
-FMT_FUNC void
-fmt::SystemError::init(int err_code, CStringRef format_str, ArgList args) {
- error_code_ = err_code;
- MemoryWriter w;
- internal::format_system_error(w, err_code, format(format_str, args));
- std::runtime_error& base = *this;
- base = std::runtime_error(w.str());
-}
-
-template
-int
-fmt::internal::CharTraits::format_float(
- char* buffer, std::size_t size, const char* format, unsigned width, int precision, T value) {
- if (width == 0) {
- return precision < 0 ? FMT_SNPRINTF(buffer, size, format, value)
- : FMT_SNPRINTF(buffer, size, format, precision, value);
- }
- return precision < 0 ? FMT_SNPRINTF(buffer, size, format, width, value)
- : FMT_SNPRINTF(buffer, size, format, width, precision, value);
-}
-
-template
-int
-fmt::internal::CharTraits::format_float(wchar_t* buffer,
- std::size_t size,
- const wchar_t* format,
- unsigned width,
- int precision,
- T value) {
- if (width == 0) {
- return precision < 0 ? FMT_SWPRINTF(buffer, size, format, value)
- : FMT_SWPRINTF(buffer, size, format, precision, value);
- }
- return precision < 0 ? FMT_SWPRINTF(buffer, size, format, width, value)
- : FMT_SWPRINTF(buffer, size, format, width, precision, value);
-}
-
-template
-const char fmt::internal::BasicData::DIGITS[] =
- "0001020304050607080910111213141516171819"
- "2021222324252627282930313233343536373839"
- "4041424344454647484950515253545556575859"
- "6061626364656667686970717273747576777879"
- "8081828384858687888990919293949596979899";
-
-#define FMT_POWERS_OF_10(factor) \
- factor * 10, factor * 100, factor * 1000, factor * 10000, factor * 100000, factor * 1000000, \
- factor * 10000000, factor * 100000000, factor * 1000000000
-
-template
-const uint32_t fmt::internal::BasicData::POWERS_OF_10_32[] = { 0, FMT_POWERS_OF_10(1) };
-
-template
-const uint64_t fmt::internal::BasicData::POWERS_OF_10_64[] = {
- 0,
- FMT_POWERS_OF_10(1),
- FMT_POWERS_OF_10(fmt::ULongLong(1000000000)),
- // Multiply several constants instead of using a single long long constant
- // to avoid warnings about C++98 not supporting long long.
- fmt::ULongLong(1000000000) * fmt::ULongLong(1000000000) * 10
-};
-
-FMT_FUNC void
-fmt::internal::report_unknown_type(char code, const char* type) {
- (void)type;
- if (std::isprint(static_cast(code))) {
- FMT_THROW(fmt::FormatError(fmt::format("unknown format code '{}' for {}", code, type)));
- }
- FMT_THROW(fmt::FormatError(
- fmt::format("unknown format code '\\x{:02x}' for {}", static_cast