Skip to content

Commit 2acfe18

Browse files
authored
Merge pull request #652 from andrey-utkin/onvif-combine-tools
ONVIF: combine findings of different discovery tools
2 parents f199601 + 1fc1335 commit 2acfe18

File tree

5 files changed

+146
-51
lines changed

5 files changed

+146
-51
lines changed

debian/control.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ Depends: ${shlibs:Depends}, ssl-cert, ucf, curl, sysstat,
4040
#wheezy php5-sqlite, php5-gd, php5-curl, php5-mysqlnd
4141
#jessie php5-sqlite, php5-gd, php5-curl, php5-mysqlnd
4242
#groovy libapache2-mod-php7.4, mariadb-server, php-mysql, php-curl, php-gd, php-sqlite3
43-
Recommends: mysql-server
43+
Recommends: mysql-server, bluecherry-node-onvif
4444
Suggests: monit, mail-transport-agent
4545
Conflicts: solo6010-dkms
4646
Replaces: solo6010-dkms
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
#!/usr/bin/env node
2+
/**
3+
* Discover ONVIF devices on the network
4+
*
5+
* Created by Roger Hardiman <opensource@rjh.org.uk>
6+
* Adapted by Andriy Utkin at Bluecherry
7+
*/
8+
9+
var onvif = require('onvif');
10+
var xml2js = require('xml2js')
11+
var stripPrefix = require('xml2js').processors.stripPrefix;
12+
13+
onvif.Discovery.on('device', function(cam, rinfo, xml) {
14+
// Function will be called as soon as the NVT responses
15+
16+
17+
// Parsing of Discovery responses taken from my ONVIF-Audit project, part of the 2018 ONVIF Open Source Challenge
18+
// Filter out xml name spaces
19+
xml = xml.replace(/xmlns([^=]*?)=(".*?")/g, '');
20+
21+
let parser = new xml2js.Parser({
22+
attrkey: 'attr',
23+
charkey: 'payload', // this ensures the payload is called .payload regardless of whether the XML Tags have Attributes or not
24+
explicitCharkey: true,
25+
tagNameProcessors: [stripPrefix] // strip namespace eg tt:Data -> Data
26+
});
27+
parser.parseString(xml,
28+
function(err, result) {
29+
if (err) {return;}
30+
let urn = result['Envelope']['Body'][0]['ProbeMatches'][0]['ProbeMatch'][0]['EndpointReference'][0]['Address'][0].payload;
31+
let xaddrs = result['Envelope']['Body'][0]['ProbeMatches'][0]['ProbeMatch'][0]['XAddrs'][0].payload;
32+
let scopes = result['Envelope']['Body'][0]['ProbeMatches'][0]['ProbeMatch'][0]['Scopes'][0].payload;
33+
scopes = scopes.split(" ");
34+
35+
let hardware = "";
36+
let name = "";
37+
for (let i = 0; i < scopes.length; i++) {
38+
if (scopes[i].includes('onvif://www.onvif.org/name')) {name = decodeURI(scopes[i].substring(27));}
39+
if (scopes[i].includes('onvif://www.onvif.org/hardware')) {hardware = decodeURI(scopes[i].substring(31));}
40+
}
41+
//let msg = 'Discovery Reply from ' + rinfo.address + ' (' + name + ') (' + hardware + ') (' + xaddrs + ') (' + urn + ')';
42+
// Hikvision cameras put multiple URLs into the same field.
43+
// Let's take just the first one.
44+
// console.log(result['Envelope']['Body'][0]['ProbeMatches'][0]['ProbeMatch'][0]['XAddrs']);
45+
// ... payload: 'http://192.168.86.200/onvif/device_service http://[fe80::2a57:beff:fecb:cca6]/onvif/device_service'
46+
// ... payload: 'http://192.168.86.109/onvif/device_service http://[fe80::a614:37ff:fed8:5c49]/onvif/device_service'
47+
48+
url = xaddrs.split(' ')[0];
49+
urlobj = new URL(url);
50+
port = urlobj.port ? urlobj.port : '80';
51+
host_port = urlobj.host + ':' + port;
52+
msg = {
53+
'ipv4': rinfo.address,
54+
'manufacturer': name,
55+
'model_name': hardware,
56+
'ipv4_path': url,
57+
'ipv4_port': host_port,
58+
};
59+
console.log(JSON.stringify(msg));
60+
}
61+
);
62+
})
63+
onvif.Discovery.on('error', function(err,xml) {
64+
// The ONVIF library had problems parsing some XML
65+
process.stderr.write('Discovery error ' + err);
66+
process.exit(1);
67+
});
68+
onvif.Discovery.probe();

misc/onvif/discovery_json/onvif_tool

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#!/usr/bin/env php
2+
<?php
3+
4+
# test:
5+
#$p = @popen("cat tests/onvif_tool.out", "r");
6+
$p = @popen("/usr/lib/bluecherry/onvif_tool dummyaddr null null discover", "r");
7+
if (!$p) {
8+
exit(1);
9+
}
10+
$wait_ip_line = true;
11+
$cams_i = 0;
12+
while ($str = fgets($p)) {
13+
14+
//IP
15+
//scope strings
16+
//newline
17+
18+
19+
if ($str[0] == "\n" && !$wait_ip_line) {
20+
$wait_ip_line = true;
21+
$cams_i++;
22+
//$res[$cams_i] = $cam;
23+
print(json_encode($cam) . "\n");
24+
}
25+
26+
if ($wait_ip_line){
27+
if (preg_match('/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/', $str, $match)) {
28+
$cam = Array();
29+
$cam['manufacturer'] = '';
30+
$cam['model_name'] = '';
31+
$cam['ipv4_port'] = '';
32+
//$cam['ipv6'] = '';
33+
//$cam['ipv6_path'] = '';
34+
//$cam['onvif'] = true;
35+
//$cam['exists'] = false;
36+
37+
$cam['ipv4'] = $match[0];
38+
$cam['ipv4_path'] = 'http://'.$match[0].'/onvif/device_service';
39+
$cam['ipv4_port'] = $match[0].':80'; // FIXME might not be the case
40+
41+
$wait_ip_line = false;
42+
}
43+
}else{
44+
//match "name/manufacturer"
45+
preg_match_all('#name/([\w/%\-]+)#', $str, $match);
46+
if (!empty($match[1]))
47+
$cam['manufacturer'] = urldecode($match[1][0]);
48+
//match hardware/modelname
49+
preg_match_all('#hardware/([\w/%\-]+)#', $str, $match);
50+
if (!empty($match[1]))
51+
$cam['model_name'] = $match[1][0];
52+
}
53+
}
54+
pclose($p);
55+
56+
//print(json_encode($res));
57+
58+
?>

scripts/build_helper/post_make_install.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ SRC_PATH=$2 #./ or %{_builddir}/%{name}
1111
DST_DIR=$3 # debian/bluecherry or %{buildroot}
1212
VERSION=$4 # bluecherry/version from changelog
1313

14+
set -euo pipefail
1415
mkdir -p ${DST_DIR}/usr/share/bluecherry
1516
cp -a ${SRC_PATH}/misc/sql/* ${DST_DIR}/usr/share/bluecherry/
1617
cp ${SRC_PATH}/misc/remove_untracked_media_files.sh \
@@ -27,6 +28,7 @@ install ${SRC_PATH}/scripts/build_helper/get_distro_release_name.sh \
2728
install ${SRC_PATH}/scripts/update_subdomain_certs.sh \
2829
${DST_DIR}/usr/share/bluecherry/scripts
2930
cp -a ${SRC_PATH}/misc/ponvif* ${DST_DIR}/usr/share/bluecherry/
31+
cp -a ${SRC_PATH}/misc/onvif ${DST_DIR}/usr/share/bluecherry/
3032
rm -rf ${DST_DIR}/usr/share/bluecherry/ponvif*/.git
3133
install -D ${SRC_PATH}/debian/bluecherry.conf.in \
3234
${DST_DIR}/usr/share/bluecherry/bluecherry.conf.in

www/ajax/discoverCameras.php

Lines changed: 17 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -174,56 +174,23 @@ public function postData()
174174
34599
175175
);
176176

177-
//
178-
$p = @popen("/usr/lib/bluecherry/onvif_tool dummyaddr null null discover", "r");
179-
if (!$p) {
180-
data::responseJSON(0);
181-
}
182-
$wait_ip_line = true;
183-
$cams_i = 0;
184-
while ($str = fgets($p)) {
185-
186-
//IP
187-
//scope strings
188-
//newline
189-
190-
if ($str[0] == "\n" && !$wait_ip_line) {
191-
$wait_ip_line = true;
192-
$cams_i++;
193-
}
194-
195-
if ($wait_ip_line){
196-
if (preg_match('/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/', $str, $match)) {
197-
$cam = Array();
198-
$cam['manufacturer'] = '';
199-
$cam['model_name'] = '';
200-
$cam['ipv4_port'] = '';
201-
$cam['ipv6'] = '';
202-
$cam['ipv6_path'] = '';
203-
$cam['onvif'] = true;
204-
$cam['exists'] = false;
205-
206-
$cam['ipv4'] = $match[0];
207-
$ips[] = $match[0];
208-
$cam['ipv4_path'] = 'http://'.$match[0].'/onvif/device_service';
209-
$cam['ipv4_port'] = $match[0].':80';
210-
211-
$wait_ip_line = false;
212-
213-
$res[$cams_i] = $cam;
214-
}
215-
}else{
216-
//match "name/manufacturer"
217-
preg_match_all('#name/([\w/%\-]+)#', $str, $match);
218-
if (!empty($match[1]))
219-
$res[$cams_i]['manufacturer'] = $match[1][0];
220-
//match hardware/modelname
221-
preg_match_all('#hardware/([\w/%\-]+)#', $str, $match);
222-
if (!empty($match[1]))
223-
$res[$cams_i]['model_name'] = $match[1][0];
224-
}
225-
}
226-
pclose($p);
177+
$tools = Array(
178+
"node /usr/share/bluecherry/onvif/discovery_json/node-onvif.js",
179+
"/usr/share/bluecherry/onvif/discovery_json/onvif_tool",
180+
);
181+
foreach ($tools as $tool) {
182+
$p = @popen($tool, "r");
183+
if (!$p) { continue; }
184+
while ($json_str = fgets($p)) {
185+
$cam = json_decode($json_str, true);
186+
$ip = $cam['ipv4'];
187+
// append, unless already reported by earlier tools
188+
if (in_array($ip, $ips)) { continue; }
189+
$res[] = $cam;
190+
$ips[] = $cam['ipv4'];
191+
}
192+
pclose($p);
193+
}
227194

228195
$ips = array_unique($ips);
229196

0 commit comments

Comments
 (0)