/
skybell-sniff.pl
executable file
·138 lines (117 loc) · 3.75 KB
/
skybell-sniff.pl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#!/usr/bin/perl
# Copyright © 2017 Alexander Thoukydides
# Copyright © 2021 Geekvisit
use strict;
use warnings;
my $cmd_sniff="";
use Socket;
my ($skybell_host, $sniffer, $sniffer_tcpdump, $sniffer_tshark, $cmd_action) = @ARGV;
# Ensure that standard output is not buffered
#
$| = 1, select $_ for select STDOUT;
# Process the command line, substituting environment variables
print "Skybell_host is $skybell_host cmd_action is $cmd_action and sniffer is $sniffer\r\n";
# Sniff the SkyBell traffic:
print "Sniffing SkyBell HD\n";
if ($sniffer eq "tcpdump") { #beginning of if
$cmd_sniff = $sniffer_tcpdump;
#
####################################################
# TCPDUMP
####################################################
print "\r\nExecuting tcpdump: $cmd_sniff\r\n";
my $skybell_ip = $skybell_host;
# Timeout (in seconds) to recognise a packet sequence
my $timeout = 10;
# Start Sniffing the SkyBell HD CoAP traffic
open(my $pipe, '-|', $cmd_sniff)
or die "Failed to spawn '$cmd_sniff': $!\n";
# Sniff the SkyBell traffic
print "Sniffing SkyBell HD $skybell_host ($skybell_ip)\n";
my $state = 'idle';
my $time = 0;
my $length = 0;
my $priorlength = 0;
while (<$pipe>)
{
# Parse the tcpdump output
if (!/(\d+):(\d+):(\d+.\d+) IP (\d+(?:\.\d+){3})\.\d+ > [\.\d]+: UDP, length (\d+)\s*$/)
{
print "Unexpected tcpdump format: $_";
next;
}
my $time_delta = (($1 *60) + $2) * 60 + $3;
my $from_skybell = $4 eq $skybell_ip;
$priorlength = $length;
$length = $5 + 0;
if ($length == 49 and $priorlength == 97)
{
print "Button Pressed or Motion Detected\n";
system($cmd_action) == 0
or warn "Failed to execute command: $?\n";
}
# Check for a timeout from the start of the sequence
if ($state ne 'idle' and $timeout < ($time += $time_delta))
{
print "(Returning to idle)\n";
$state = 'idle';
$time = 0;
}
# Process the sniffed packet
if ($state eq 'idle')
{
if ($from_skybell and $length == 465)
# if ($length == 97)
{
print "(Possible motion detected)\n";
$state = 'armed';
}
elsif (not $from_skybell and 800 < $length)
{
print "On-demand requested\n";
$state = 'on-demand';
}
}
elsif ($state eq 'armed')
{
if((not $from_skybell and $length == 49)
or (not $from_skybell and $length == 33))
{
print "Motion detected\n";
$state = 'motion';
system($cmd_action) == 0
or warn "Failed to execute command: $?\n";
}
}
}
} else { #end of if
####################################################
# Wire/Tshark
####################################################
$cmd_sniff = $sniffer_tshark;
print "Executing tshark: $cmd_sniff\r\n";
open(my $pipe, '-|', "$cmd_sniff" ) or die "Failed to start tshark\n";
my $length = 0;
my $priorlength = 0;
while (<$pipe>)
{
$priorlength = $length;
$length = $_;
print sprintf ("Skybell Length is %s..\r\n", $length);
if ($length == 190 && $priorlength != 190) {
print "detected DNS 190. Sleeping ..\n";
sleep (2.0);
next;
}
if (($length == 119 or length == 125 or $length == 126 or $length == 140 or $length == 183 or $length == 190) and $priorlength == 190)
{
print "mod: skybell sniffer: Button Pressed or Motion Detected Length is $length prior is $priorlength\n";
#execute commands to ring bell or whatever
system($cmd_action) == 0
or warn "Failed to execute command: $?\n";
sleep (40); #minimum seconds between bells (prevents second ring)
}
}
}
# Should never reach this point
die "Error: Skybell sniffer process died unexpectedly - run skybell-sniff.pl directly and check for permission or other errors\n";