mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-02-11 13:12:00 +00:00
1113 lines
36 KiB
Perl
1113 lines
36 KiB
Perl
# Id ##########################################################################
|
||
# $Id$
|
||
|
||
# copyright ###################################################################
|
||
#
|
||
# 74_Nmap.pm
|
||
#
|
||
# Copyright by igami
|
||
#
|
||
# This file is part of FHEM.
|
||
#
|
||
# FHEM is free software: you can redistribute it and/or modify
|
||
# it under the terms of the GNU General Public License as published by
|
||
# the Free Software Foundation, either version 2 of the License, or
|
||
# (at your option) any later version.
|
||
#
|
||
# FHEM is distributed in the hope that it will be useful,
|
||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
# GNU General Public License for more details.
|
||
#
|
||
# You should have received a copy of the GNU General Public License
|
||
# along with FHEM. If not, see <http://www.gnu.org/licenses/>.
|
||
|
||
# packages ####################################################################
|
||
package main;
|
||
use strict;
|
||
use warnings;
|
||
|
||
use Blocking;
|
||
|
||
# forward declarations ########################################################
|
||
sub Nmap_Initialize($);
|
||
|
||
sub Nmap_Define($$);
|
||
sub Nmap_Undefine($$);
|
||
sub Nmap_Set($@);
|
||
sub Nmap_Attr(@);
|
||
|
||
sub Nmap_statusRequest($);
|
||
sub Nmap_blocking_statusRequest($);
|
||
sub Nmap_done($);
|
||
sub Nmap_aborted($);
|
||
|
||
sub Nmap_deleteOldReadings($$);
|
||
sub Nmap_updateUptime($$;$);
|
||
|
||
# initialize ##################################################################
|
||
sub Nmap_Initialize($) {
|
||
my ($hash) = @_;
|
||
my $TYPE = "Nmap";
|
||
|
||
$hash->{DefFn} = $TYPE."_Define";
|
||
$hash->{UndefFn} = $TYPE."_Undefine";
|
||
$hash->{SetFn} = $TYPE."_Set";
|
||
$hash->{AttrFn} = $TYPE."_Attr";
|
||
|
||
$hash->{AttrList} = ""
|
||
. "absenceThreshold "
|
||
. "args "
|
||
. "deleteOldReadings "
|
||
. "devAlias:textField-long "
|
||
. "disable:1,0 "
|
||
. "excludeHosts "
|
||
. "interval "
|
||
. "keepReadings:1,0 "
|
||
. "leadingZeros:1,0 "
|
||
. "metaReading:alias,hostname,ip,macAddress "
|
||
. "path "
|
||
. "sudo:1,0 "
|
||
. $readingFnAttributes
|
||
;
|
||
}
|
||
|
||
# regular Fn ##################################################################
|
||
sub Nmap_Define($$) {
|
||
my ($hash, $def) = @_;
|
||
my ($SELF, $TYPE, $targets) = split(/[\s]+/, $def, 3);
|
||
my $rc = eval{
|
||
require Nmap::Parser;
|
||
Nmap::Parser->import();
|
||
1;
|
||
};
|
||
|
||
return(
|
||
"Error loading Nmap::Parser. Maybe this module is not installed? "
|
||
. "\nUnder debian (based) system it can be installed using "
|
||
. "\n\"apt-get install libnmap-parser-perl\""
|
||
) unless($rc);
|
||
return("Usage: define <name> $TYPE <target specification>") if(!$targets);
|
||
|
||
my $interval = AttrVal($SELF, "interval", 900);
|
||
$interval = 900 if(!looks_like_number($interval));
|
||
$interval = 30 if($interval < 30);
|
||
|
||
$hash->{ARGS} = AttrVal($SELF, "args", "-sn");
|
||
$hash->{INTERVAL} = $interval;
|
||
$hash->{PATH} = AttrVal($SELF, "path", "/usr/bin/nmap");
|
||
|
||
readingsSingleUpdate($hash, "state", "Initialized", 1);
|
||
|
||
RemoveInternalTimer($hash);
|
||
InternalTimer(
|
||
gettimeofday() + $hash->{INTERVAL}, "Nmap_statusRequest", $hash
|
||
);
|
||
|
||
return;
|
||
}
|
||
|
||
sub Nmap_Undefine($$) {
|
||
my ($hash, $arg) = @_;
|
||
|
||
RemoveInternalTimer($hash);
|
||
BlockingKill($hash->{helper}{RUNNING_PID})
|
||
if(defined($hash->{helper}{RUNNING_PID}));
|
||
|
||
return;
|
||
}
|
||
|
||
sub Nmap_Set($@) {
|
||
my ($hash, @a) = @_;
|
||
my $TYPE = $hash->{TYPE};
|
||
|
||
return "\"set $TYPE\" needs at least one argument" if(@a < 2);
|
||
|
||
my $SELF = shift @a;
|
||
my $argument = shift @a;
|
||
my $value = join(" ", @a) if (@a);
|
||
my %Nmap_sets = (
|
||
"clear" => "clear:readings",
|
||
"deleteOldReadings" => "deleteOldReadings",
|
||
"interrupt" => "interrupt:noArg",
|
||
"statusRequest" => "statusRequest:noArg"
|
||
);
|
||
|
||
Log3($SELF, 5, "$TYPE ($SELF) - entering Nmap_Set");
|
||
|
||
return(
|
||
"Unknown argument $argument, choose one of "
|
||
. join(" ", values %Nmap_sets)
|
||
) if(!exists($Nmap_sets{$argument}));
|
||
|
||
if($argument eq "clear" && $value eq "readings"){
|
||
foreach (keys %{$hash->{READINGS}}) {
|
||
delete $hash->{READINGS}->{$_} if($_ ne "state");
|
||
}
|
||
}
|
||
elsif($argument eq "deleteOldReadings" && $value){
|
||
my $ret = Nmap_deleteOldReadings($hash, $value);
|
||
|
||
return($ret) if($ret);
|
||
|
||
readingsSingleUpdate($hash, "state", "deleteOldReadings $value", 1);
|
||
}
|
||
elsif(!IsDisabled($SELF)){
|
||
if($argument eq "interrupt"){
|
||
BlockingKill($hash->{helper}{RUNNING_PID})
|
||
if(defined($hash->{helper}{RUNNING_PID}));
|
||
|
||
Nmap_aborted($hash);
|
||
|
||
RemoveInternalTimer($hash);
|
||
InternalTimer(
|
||
gettimeofday() + $hash->{INTERVAL}, "Nmap_statusRequest", $hash
|
||
);
|
||
}
|
||
elsif($argument eq "statusRequest"){
|
||
Nmap_statusRequest($hash);
|
||
}
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
sub Nmap_Attr(@) {
|
||
my ($cmd, $SELF, $attribute, $value) = @_;
|
||
my $hash = $defs{$SELF};
|
||
my $TYPE = $hash->{TYPE};
|
||
|
||
Log3($SELF, 5, "$TYPE ($SELF) - entering Nmap_Attr");
|
||
|
||
if($attribute eq "args"){
|
||
$hash->{ARGS} = $cmd eq "set" ? $value : "-sn";
|
||
}
|
||
elsif($attribute eq "devAlias" && $cmd eq "set"){
|
||
return(
|
||
"$SELF: Value \"$value\" is not allowed for devAlias!\n"
|
||
. "Must be \"<ID>:<ALIAS> <ID2>:<ALIAS2> ...\", "
|
||
. "e.g. 123abc:MyAndroid\n"
|
||
. "Only these characters are allowed: [alphanumeric - _ .]"
|
||
)if($value !~ /^([\w\.\-]+:[\w\.\-]+\s*)+$/s);
|
||
}
|
||
elsif($attribute eq "disable"){
|
||
if($value && $value == 1){
|
||
BlockingKill($hash->{helper}{RUNNING_PID})
|
||
if(defined($hash->{helper}{RUNNING_PID}));
|
||
RemoveInternalTimer($hash);
|
||
readingsSingleUpdate($hash, "state", "disabled", 1);
|
||
}
|
||
elsif($cmd eq "del" || !$value){
|
||
InternalTimer(
|
||
gettimeofday() + $hash->{INTERVAL}, "Nmap_statusRequest", $hash
|
||
);
|
||
readingsSingleUpdate($hash, "state", "Initialized", 1);
|
||
}
|
||
}
|
||
elsif($attribute eq "leadingZeros"){
|
||
foreach (keys %{$hash->{READINGS}}){
|
||
my $newkey = $_;
|
||
$newkey =~
|
||
s/([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/sprintf('%03d',$1).".".sprintf('%03d',$2).".".sprintf('%03d',$3).".".sprintf('%03d',$4)/e
|
||
if($value and $value == 1);
|
||
$newkey =~
|
||
s/([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/sprintf('%00d',$1).".".sprintf('%00d',$2).".".sprintf('%00d',$3).".".sprintf('%00d',$4)/e
|
||
if($cmd eq "del" or !$value);
|
||
$hash->{READINGS}{$newkey} = delete $hash->{READINGS}{$_};
|
||
}
|
||
|
||
my $knownHosts = ReadingsVal($SELF, ".knownHosts", "");
|
||
$knownHosts =~
|
||
s/([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/sprintf('%03d',$1).".".sprintf('%03d',$2).".".sprintf('%03d',$3).".".sprintf('%03d',$4)/ge
|
||
if($value and $value == 1);
|
||
$knownHosts =~
|
||
s/([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/sprintf('%00d',$1).".".sprintf('%00d',$2).".".sprintf('%00d',$3).".".sprintf('%00d',$4)/ge
|
||
if($cmd eq "del" or !$value);
|
||
|
||
readingsSingleUpdate($hash, ".knownHosts", $knownHosts, 0);
|
||
}
|
||
elsif($attribute eq "path"){
|
||
$hash->{PATH} = $cmd eq "set" ? $value : "/usr/bin/nmap";
|
||
}
|
||
|
||
return if(IsDisabled($SELF));
|
||
|
||
if($attribute eq "interval"){
|
||
my $interval = $cmd eq "set" ? $value : 900;
|
||
$interval = 900 if(!looks_like_number($interval));
|
||
$interval = 30 if($interval < 30);
|
||
|
||
$hash->{INTERVAL} = $interval;
|
||
|
||
RemoveInternalTimer($hash);
|
||
InternalTimer(
|
||
gettimeofday() + $hash->{INTERVAL}, "Nmap_statusRequest", $hash
|
||
);
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
# blocking Fn #################################################################
|
||
sub Nmap_statusRequest($) {
|
||
my ($hash) = @_;
|
||
my $SELF = $hash->{NAME};
|
||
my $TYPE = $hash->{TYPE};
|
||
my $interval = $hash->{INTERVAL};
|
||
my $timeout = $interval - 1;
|
||
my $path = $hash->{PATH};
|
||
|
||
Log3($SELF, 5, "$TYPE ($SELF) - entering Nmap_statusRequest");
|
||
|
||
BlockingKill($hash->{helper}{RUNNING_PID})
|
||
if(defined($hash->{helper}{RUNNING_PID}));
|
||
RemoveInternalTimer($hash);
|
||
|
||
return if(IsDisabled($SELF));
|
||
|
||
InternalTimer(
|
||
gettimeofday() + $interval, "Nmap_statusRequest", $hash
|
||
);
|
||
|
||
unless(-X $path){
|
||
readingsSingleUpdate($hash, "state", "aborted", 1);
|
||
Log3(
|
||
$SELF, 1, "$TYPE ($SELF) - "
|
||
. "please check if Nmap ist installed and available at path $path"
|
||
);
|
||
|
||
return;
|
||
}
|
||
|
||
if( AttrVal($SELF, "sudo", 0) == 1
|
||
&& qx(sudo -n $path -V 2>&1 > /dev/null)
|
||
){
|
||
readingsSingleUpdate($hash, "state", "aborted", 1);
|
||
Log3($SELF, 1, "$TYPE ($SELF) - sudo password required");
|
||
|
||
return;
|
||
}
|
||
|
||
readingsSingleUpdate($hash, "state", "running", 1);
|
||
Log3($SELF, 3, "$TYPE ($SELF) - starting network scan");
|
||
Log3($SELF, 5, "$TYPE ($SELF) - BlockingCall Nmap_blocking_statusRequest");
|
||
|
||
$hash->{helper}{RUNNING_PID} = BlockingCall(
|
||
"Nmap_blocking_statusRequest", $SELF, "Nmap_done"
|
||
, $timeout, "Nmap_aborted", $hash
|
||
) unless(exists($hash->{helper}{RUNNING_PID}));
|
||
|
||
return;
|
||
}
|
||
|
||
sub Nmap_blocking_statusRequest($) {
|
||
my ($SELF) = @_;
|
||
my ($hash) = $defs{$SELF};
|
||
my $TYPE = $hash->{TYPE};
|
||
my @ret = $SELF;
|
||
my $NP = new Nmap::Parser;
|
||
my $path =
|
||
(AttrVal($SELF, "sudo", 0) == 1 ? "sudo " : "")
|
||
. $hash->{PATH}
|
||
;
|
||
my $excludeHosts = AttrVal($SELF, "excludeHosts", undef);
|
||
my $args = $hash->{ARGS};
|
||
$args .= " --exclude $excludeHosts" if($excludeHosts);
|
||
my $STDERR = "";
|
||
|
||
Log3($SELF, 5, "$TYPE ($SELF) - entering Nmap_blocking_statusRequest");
|
||
|
||
close STDERR;
|
||
open(STDERR, ">", \$STDERR);
|
||
|
||
$NP->parsescan($path, $args, $hash->{DEF});
|
||
|
||
close (STDERR);
|
||
|
||
Log3($SELF, 4, "$TYPE ($SELF) - $_")
|
||
foreach(split( "\n", $STDERR));
|
||
|
||
my $NPS = $NP->get_session();
|
||
|
||
push(@ret, $NPS->nmap_version());
|
||
push(@ret, int($NP->all_hosts()));
|
||
push(@ret, $NPS->finish_time() - $NPS->start_time());
|
||
|
||
my @hostsUp = $NP->all_hosts("up");
|
||
|
||
foreach (@hostsUp){
|
||
my $hostname = $_->hostname() ? $_->hostname() : $_->ipv4_addr();
|
||
my $macAddress = $_->mac_addr() ? $_->mac_addr() : "Unknown";
|
||
my $macVendor = $_->mac_vendor() ? $_->mac_vendor() : "Unknown";
|
||
|
||
push(@ret, $_->ipv4_addr()."|$hostname|$macAddress|$macVendor");
|
||
}
|
||
|
||
return (join("||", @ret));
|
||
}
|
||
|
||
sub Nmap_done($) {
|
||
my ($string) = @_;
|
||
|
||
return unless(defined($string));
|
||
|
||
my ($SELF, $NmapVersion, $hostsScanned, $scanDuration, @hostsUp) =
|
||
split("\\|\\|", $string);
|
||
my ($hash) = $defs{$SELF};
|
||
my $TYPE = $hash->{TYPE};
|
||
my $devAliases = AttrVal($SELF, "devAlias", undef);
|
||
my %knownHosts = map{$_, 0} split(",", ReadingsVal($SELF, ".knownHosts", ""));
|
||
my $metaReadingAttrVal = AttrVal($SELF, "metaReading", "ip");
|
||
|
||
Log3($SELF, 5, "$TYPE ($SELF) - entering Nmap_done");
|
||
|
||
delete($hash->{helper}{RUNNING_PID});
|
||
|
||
readingsBeginUpdate($hash);
|
||
readingsBulkUpdate($hash, "NmapVersion", $NmapVersion);
|
||
readingsBulkUpdate($hash, "hostsScanned", $hostsScanned);
|
||
readingsBulkUpdate($hash, "hostsUp", int(@hostsUp));
|
||
readingsBulkUpdate($hash, "scanDuration", $scanDuration);
|
||
|
||
foreach (@hostsUp){
|
||
my ($ip, $hostname, $macAddress, $macVendor) = split("\\|", $_);
|
||
my ($oldMetaReading, $metaReading);
|
||
my $alias = $hostname;
|
||
|
||
if(
|
||
$devAliases && $devAliases =~ /$macAddress:(.+?)(\s|$)/
|
||
|| $devAliases && $devAliases =~ /$hostname:(.+?)(\s|$)/
|
||
|| $devAliases && $devAliases =~ /$ip:(.+?)(\s|$)/
|
||
){
|
||
$alias = $1;
|
||
}
|
||
|
||
if($metaReadingAttrVal eq "ip"){
|
||
$metaReading = $ip;
|
||
}
|
||
elsif($metaReadingAttrVal eq "macAddress"){
|
||
$metaReading = $macAddress ne "Unknown" ? $macAddress : $ip;
|
||
}
|
||
elsif($metaReadingAttrVal eq "alias"){
|
||
$metaReading = $alias;
|
||
}
|
||
elsif($metaReadingAttrVal eq "hostname"){
|
||
$metaReading = $hostname;
|
||
}
|
||
|
||
$metaReading =~ s/([0-9]+)/sprintf('%03d',$1)/ge
|
||
if(AttrVal($SELF, "leadingZeros", 0) == 1 && $metaReading eq $ip);
|
||
$metaReading =~ s/:/-/g;
|
||
$knownHosts{$metaReading} = 1;
|
||
|
||
if($macAddress ne "Unknown"){
|
||
foreach (keys %knownHosts){
|
||
$oldMetaReading = $_
|
||
if(ReadingsVal($SELF, $_."_macAddress", "") eq $macAddress);
|
||
|
||
next unless($oldMetaReading);
|
||
|
||
last;
|
||
}
|
||
if( $oldMetaReading
|
||
&& ReadingsVal($SELF, $oldMetaReading."_ip", "") ne $ip
|
||
){
|
||
Log3($SELF, 4, "$TYPE ($SELF) - new IP: $hostname ($ip)");
|
||
|
||
DoTrigger($SELF, "new IP: $hostname ($ip)");
|
||
}
|
||
}
|
||
|
||
unless($hash->{READINGS}{$metaReading."_hostname"} || $oldMetaReading){
|
||
Log3($SELF, 4, "$TYPE ($SELF) - new host: $hostname ($ip)");
|
||
|
||
DoTrigger($SELF, "new host: $hostname ($ip)");
|
||
}
|
||
|
||
if( $oldMetaReading && $oldMetaReading ne $metaReading
|
||
&& AttrVal($SELF, "keepReadings", 0) == 0
|
||
){
|
||
delete $knownHosts{$oldMetaReading};
|
||
CommandDeleteReading(undef, "$SELF $oldMetaReading.*");
|
||
|
||
Log3($SELF, 4, "$TYPE ($SELF) - delete old host: $oldMetaReading");
|
||
}
|
||
|
||
readingsBulkUpdate($hash, $metaReading."_alias", $alias);
|
||
readingsBulkUpdate($hash, $metaReading."_hostname", $hostname);
|
||
readingsBulkUpdate($hash, $metaReading."_ip", $ip);
|
||
readingsBulkUpdate($hash, $metaReading."_lastSeen", TimeNow());
|
||
readingsBulkUpdate($hash, $metaReading."_macAddress", $macAddress)
|
||
if($macAddress ne "Unknown");
|
||
readingsBulkUpdate($hash, $metaReading."_macVendor", $macVendor)
|
||
if($macVendor ne "Unknown");
|
||
readingsBulkUpdate($hash, $metaReading."_state", "present");
|
||
|
||
Nmap_updateUptime($hash, $metaReading);
|
||
}
|
||
|
||
foreach (keys %knownHosts){
|
||
next if( $knownHosts{$_} == 1
|
||
|| ReadingsVal($SELF, $_."_state", "present") eq "absent"
|
||
);
|
||
|
||
my $absenceThreshold = ReadingsVal($SELF, ".".$_."_absenceThreshold", 1);
|
||
|
||
if($absenceThreshold >= AttrVal($SELF, "absenceThreshold", 1)){
|
||
delete $hash->{READINGS}{".".$_."_absenceThreshold"};
|
||
|
||
readingsBulkUpdate($hash, $_."_state", "absent");
|
||
|
||
Nmap_updateUptime($hash, $_, 0);
|
||
}
|
||
else{
|
||
$absenceThreshold ++;
|
||
|
||
readingsBulkUpdate($hash, ".".$_."_absenceThreshold", $absenceThreshold);
|
||
readingsBulkUpdate($hash, $_."_state", "present");
|
||
|
||
Nmap_updateUptime($hash, $_);
|
||
}
|
||
}
|
||
|
||
readingsBulkUpdate($hash, ".knownHosts", join(",", sort(keys %knownHosts)));
|
||
readingsBulkUpdate($hash, "knownHosts", int(keys %knownHosts));
|
||
readingsBulkUpdate($hash, "state", "done");
|
||
readingsEndUpdate($hash, 1);
|
||
|
||
my $deleteOldReadings = AttrVal($SELF, "deleteOldReadings", 0);
|
||
Nmap_deleteOldReadings($hash, $deleteOldReadings)
|
||
if($deleteOldReadings ne "0");
|
||
|
||
Log3($SELF, 3, "$TYPE ($SELF) - network scan done");
|
||
|
||
return;
|
||
}
|
||
|
||
sub Nmap_aborted($) {
|
||
my ($hash) = @_;
|
||
my $SELF = $hash->{NAME};
|
||
my $TYPE = $hash->{TYPE};
|
||
|
||
delete($hash->{helper}{RUNNING_PID});
|
||
|
||
Log3($SELF, 2, "$TYPE ($SELF) - network scan aborted");
|
||
readingsSingleUpdate($hash, "state", "aborted", 1);
|
||
|
||
return;
|
||
}
|
||
|
||
# module Fn ###################################################################
|
||
sub Nmap_deleteOldReadings($$) {
|
||
my ($hash, $value) = @_;
|
||
my $SELF = $hash->{NAME};
|
||
my $TYPE = $hash->{TYPE};
|
||
$value = eval($value);
|
||
|
||
Log3($SELF, 5, "$TYPE ($SELF) - entering Nmap_deleteOldReadings");
|
||
|
||
unless(looks_like_number($value)){
|
||
my $ret = "no numeric value given for deleteOldReadings";
|
||
|
||
Log3($SELF, 2, "$TYPE ($SELF) - $ret");
|
||
|
||
return($ret);
|
||
}
|
||
|
||
my %knownHosts =
|
||
map{$_, 0} split(",", ReadingsVal($SELF, ".knownHosts", ""));
|
||
|
||
foreach (keys %knownHosts) {
|
||
if(ReadingsAge($SELF, $_."_lastSeen", 0) >= $value){
|
||
CommandDeleteReading(undef, "$SELF $_.*");
|
||
delete $knownHosts{$_};
|
||
}
|
||
}
|
||
|
||
readingsBeginUpdate($hash);
|
||
readingsBulkUpdate($hash, ".knownHosts", join(",", sort(keys %knownHosts)));
|
||
readingsBulkUpdate($hash, "knownHosts", int(keys %knownHosts));
|
||
readingsEndUpdate($hash, 1);
|
||
|
||
Log3($SELF, 4, "$TYPE ($SELF) - delete Readings older than $value seconds");
|
||
|
||
return;
|
||
}
|
||
|
||
sub Nmap_updateUptime($$;$) {
|
||
my ($hash, $metaReading, $uptime) = @_;
|
||
my $SELF = $hash->{NAME};
|
||
my $TYPE = $hash->{TYPE};
|
||
|
||
Log3($SELF, 5, "$TYPE ($SELF) - entering Nmap_updateUptime");
|
||
|
||
$uptime = (
|
||
ReadingsVal($SELF, $metaReading."_uptime", 0)
|
||
+ ReadingsAge($SELF, $metaReading."_uptime", 0)
|
||
) unless(defined($uptime));
|
||
|
||
my $s = $uptime;
|
||
my $d = int($s / 86400);
|
||
$s -= $d * 86400;
|
||
my $h = int($s / 3600);
|
||
$s -= $h * 3600;
|
||
my $m = int($s / 60);
|
||
$s -= $m * 60;
|
||
|
||
my $uptimeText = sprintf(
|
||
"%d days, %02d hours, %02d minutes, %02d seconds"
|
||
, $d, $h, $m, $s
|
||
);
|
||
|
||
readingsBulkUpdate($hash, $metaReading."_uptime", $uptime);
|
||
readingsBulkUpdate($hash, $metaReading."_uptimeText", $uptimeText);
|
||
|
||
return;
|
||
}
|
||
|
||
1;
|
||
|
||
__END__
|
||
|
||
# commandref ##################################################################
|
||
=pod
|
||
=encoding utf8
|
||
=item device
|
||
=item summary Interpret of an Nmap network scans
|
||
=item summary_DE Auswertung eines Nmap Netzwerkscans
|
||
|
||
=begin html
|
||
|
||
<a id="Nmap"></a>
|
||
<h3>Nmap</h3>
|
||
<div>
|
||
<ul>
|
||
Nmap is the FHEM module to perform a network scan with Nmap and to display information about the available network devices.<br>
|
||
If a new device is detected, an event
|
||
<code>"<name> new host: <hostname> (<IPv4>)"</code>
|
||
is generated.<br>
|
||
If a device with a known MAC address has been given a new IP, an event
|
||
<code>"<name> new IP: <hostname> (<IPv4>)"</code>
|
||
is generated.<br>
|
||
<br>
|
||
Prerequisites:
|
||
<ul>
|
||
The "Nmap" program and the Perl module "Nmap::Parser" are required.<br>
|
||
Under Debian (based) system, these can be installed using
|
||
<code>"apt-get install nmap libnmap-parser-perl"</code>
|
||
.
|
||
</ul>
|
||
<br>
|
||
<a id="Nmap-define"></a>
|
||
<h4>Define</h4>
|
||
<ul>
|
||
<code>define <name> Nmap <target specification></code><br>
|
||
In the <target specification> are all target hosts, which are to be
|
||
scanned.<br>
|
||
The simplest case is the description of an IP destination address or a
|
||
target host name for scanning.<br>
|
||
To scan an entire network of neighboring hosts, Nmap supports CIDR-style
|
||
addresses. Numbits can be appended to an IPv4 address or hostname, and
|
||
Nmap will scan all IP addresses where the first numbits match those of
|
||
the given IP or host name. For example, 192.168.10.0/24 would scan the
|
||
256 hosts between 192.168.10.0 and 192.168.10.255. 192.168.10.40/24 would
|
||
scan exactly the same targets. It's also possible to scan multiple
|
||
networks at the same time. For example 192.168.1.0/24 192.168.2.0/24
|
||
would scan the 512 hosts between 192.168.1.0 and 192.168.2.255.<br>
|
||
See
|
||
<a href="https://nmap.org/man/de/man-target-specification.html">
|
||
<u>Nmap Manpage (Specifying Destinations)</u>
|
||
</a>.
|
||
</ul>
|
||
<a id="Nmap-set"></a>
|
||
<h4>Set</h4>
|
||
<ul>
|
||
<a id="Nmap-set-clear"></a><li>
|
||
<code>clear readings</code><br>
|
||
Deletes all readings except "state".
|
||
</li>
|
||
<a id="Nmap-set-deleteOldReadings"></a><li>
|
||
<code>deleteOldReadings <s></code><br>
|
||
Deletes all readings older than <s> seconds.
|
||
</li>
|
||
<a id="Nmap-set-interrupt"></a><li>
|
||
<code>interrupt</code><br>
|
||
Cancels a running scan.
|
||
</li>
|
||
<a id="Nmap-set-statusRequest"></a><li>
|
||
<code>statusRequest</code><br>
|
||
Starts a network scan.
|
||
</li>
|
||
</ul>
|
||
<a id="Nmap-readings"></a>
|
||
<h4>Readings</h4>
|
||
<ul>
|
||
General Readings:
|
||
<ul>
|
||
<li>
|
||
<code>NmapVersion</code><br>
|
||
The version number of the installed Nmap program.
|
||
</li>
|
||
<li>
|
||
<code>hostsScanned</code><br>
|
||
The number of scanned addresses.
|
||
</li>
|
||
<li>
|
||
<code>hostsUp</code><br>
|
||
The number of available network devices.
|
||
</li>
|
||
<li>
|
||
<code>knownHosts</code><br>
|
||
The number of known network devices.
|
||
</li>
|
||
<li>
|
||
<code>scanDuration</code><br>
|
||
The scan time in seconds.
|
||
</li>
|
||
<li>
|
||
<code>state</code><br>
|
||
<ul>
|
||
<li>
|
||
<code>Initialized</code><br>
|
||
Nmap has been defined or enabled.
|
||
</li>
|
||
<li>
|
||
<code>running</code><br>
|
||
A network scan is running.
|
||
</li>
|
||
<li>
|
||
<code>done</code><br>
|
||
Network scan completed successfully.
|
||
</li>
|
||
<li>
|
||
<code>aborted</code><br>
|
||
The network scan was aborted due to a timeout or by the user.
|
||
</li>
|
||
<li>
|
||
<code>disabled</code><br>
|
||
Nmap has been disabled.
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
<br>
|
||
Host-specific readings:
|
||
<ul>
|
||
<li>
|
||
<code><metaReading>_alias</code><br>
|
||
Alias which is specified under the attribute "devAlias" for the
|
||
network device. If no alias is specified, the hostname is displayed.
|
||
</li>
|
||
<li>
|
||
<code><metaReading>_hostname</code><br>
|
||
Hostname of the network device. If this can not be determined, the IPv4
|
||
address is displayed.
|
||
</li>
|
||
<li>
|
||
<code><metaReading>_ip</code><br>
|
||
IPv4 address of the network device.
|
||
</li>
|
||
<li>
|
||
<code><metaReading>_lastSeen</code><br>
|
||
The time at which the network device was last seen as.
|
||
</li>
|
||
<li>
|
||
<code><metaReading>_macAddress</code><br>
|
||
MAC address of the network device. This can only be determined if the
|
||
scan is executed with root privileges.
|
||
</li>
|
||
<li>
|
||
<code><metaReading>_macVendor</code><br>
|
||
Probable manufacturer of the network device. This can only be
|
||
determined if the scan is executed with root privileges.
|
||
</li>
|
||
<li>
|
||
<code><metaReading>_state</code><br>
|
||
State of the network device. Can be either "absent" or "present".
|
||
</li>
|
||
<li>
|
||
<code><metaReading>_uptime</code><br>
|
||
Time in seconds since the network device is reachable.
|
||
</li>
|
||
<li>
|
||
<code><metaReading>_uptimeText</code><br>
|
||
Time in "d days, hh hours, mm minutes, ss seconds" since the network
|
||
device is reachable.
|
||
</li>
|
||
</ul>
|
||
</ul>
|
||
<a id="Nmap-attr"></a>
|
||
<h4>Attributes</h4>
|
||
<ul>
|
||
<a id="Nmap-attr-absenceThreshold"></a><li>
|
||
<code>absenceThreshold <n></code><br>
|
||
The number of network cans that must result in "absent" before the
|
||
state of a network device changes to "absent". With this function you
|
||
can verify the absence of a device before the status is changed to
|
||
"absent". If this attribute is set to a value >1, the reading
|
||
"<metaReading>_state" remains on "present" until the final status
|
||
changes to "absent".
|
||
</li>
|
||
<a id="Nmap-attr-args"></a><li>
|
||
<code>args <args></code><br>
|
||
Arguments for the Nmap scan.<br>
|
||
The default is "-sn".
|
||
</li>
|
||
<a id="Nmap-attr-deleteOldReadings"></a><li>
|
||
<code>deleteOldReadings <s></code><br>
|
||
After a network scan, all host-specific readings older than <s>
|
||
seconds are deleted
|
||
</li>
|
||
<a id="Nmap-attr-devAlias"></a><li>
|
||
<code>
|
||
devAlias <ID>:<ALIAS> <ID2>:<ALIAS2> ...
|
||
</code><br>
|
||
A whitespace separated list of <ID>:<ALIAS> pairs that can be used to give an alias to network devices.<br>
|
||
The ID can be MAC address, hostname or IPv4 address.<br>
|
||
Examples:
|
||
<ul>
|
||
MAC address:
|
||
<code>
|
||
attr <name> devAlias 5C:51:88:A5:94:1F:Michaels_Handy_byMAC
|
||
</code><br>
|
||
Hostname:
|
||
<code>
|
||
attr <name> devAlias
|
||
android-87c7a6221093d830:Michaels_Handy_byHOST
|
||
</code><br>
|
||
IPv4 address:
|
||
<code>
|
||
attr <name> devAlias 192.168.1.130:Michaels_Handy_byIP
|
||
</code><br>
|
||
</ul>
|
||
</li>
|
||
<a id="Nmap-attr-disable"></a><li>
|
||
<code>disable 1</code><br>
|
||
A running scan is canceled and no new scans are started.
|
||
</li>
|
||
<a id="Nmap-attr-excludeHosts"></a><li>
|
||
<code>excludeHosts <target specification></code><br>
|
||
All target hosts in the <target specification> are skipped during the scan.
|
||
</li>
|
||
<a id="Nmap-attr-interval"></a><li>
|
||
<code>interval <seconds></code><br>
|
||
Interval in seconds in which the scan is performed.<br>
|
||
The default value is 900 seconds and the minimum value is 30 seconds.
|
||
</li>
|
||
<a id="Nmap-attr-keepReadings"></a><li>
|
||
<code>keepReadings 1</code><br>
|
||
If a new IP address is recognized for a device with a known MAC
|
||
address, the invalid readings are deleted unless this attribute is set.
|
||
</li>
|
||
<a id="Nmap-attr-leadingZeros"></a><li>
|
||
<code>leadingZeros 1</code><br>
|
||
For the readings, the IPv4 addresses are displayed with leading zeros.
|
||
</li>
|
||
<a id="Nmap-attr-metaReading"></a><li>
|
||
<code>metaReading <metaReading></code><br>
|
||
You can specify "alias", "hostname", "ip" or "macAddress" as
|
||
<metaReading> and is the identifier for the readings.<br>
|
||
The default is "ip".
|
||
</li>
|
||
<a id="Nmap-attr-path"></a><li>
|
||
<code>path</code><br>
|
||
Path under which the Nmap program is to be reached.<br>
|
||
The default is "/urs/bin/nmap".
|
||
</li>
|
||
<li>
|
||
<a href="#readingFnAttributes">
|
||
<u><code>readingFnAttributes</code></u>
|
||
</a>
|
||
</li>
|
||
<a id="Nmap-attr-sudo"></a><li>
|
||
<code>sudo 1</code><br>
|
||
The scan runs with root privileges.<br>
|
||
The prerequisite is that the user has these rights under the FHEM. For
|
||
the user "fhem", on a Debian (based) system, they can be set in the
|
||
"/etc/sudoers" file. For this, the line "fhem ALL=(ALL) NOPASSWD:
|
||
/usr/bin/nmap" must be inserted in the section "#User privilege
|
||
specification".
|
||
</li>
|
||
</ul>
|
||
</ul>
|
||
</div>
|
||
|
||
=end html
|
||
|
||
=begin html_DE
|
||
|
||
<a id="Nmap"></a>
|
||
<h3>Nmap</h3>
|
||
<div>
|
||
<ul>
|
||
Nmap ist das FHEM Modul um einen Netzwerkscan mit Nmap durchzuführen
|
||
und Informationen über die erreichbaren Netzwerkgeräte
|
||
darzustellen.<br>
|
||
Wird ein neues Gerät erkannt wird ein Event
|
||
<code>"<name> new host: <hostname> (<IPv4>)"</code>
|
||
erzeugt.<br>
|
||
Wird erkannt, dass ein Gerät mit bekannter MAC-Adresse eine neue IP
|
||
erhalten hat wird ein Event
|
||
<code>"<name> new IP: <hostname> (<IPv4>)"</code>
|
||
erzeugt.<br>
|
||
<br>
|
||
Vorraussetzungen:
|
||
<ul>
|
||
Das Programm "Nmap" sowie das Perl-Modul "Nmap::Parser" werden
|
||
benötigt.<br>
|
||
Unter Debian (basierten) System, können diese mittels
|
||
<code>"apt-get install nmap libnmap-parser-perl"</code>
|
||
installiert werden.
|
||
</ul>
|
||
<br>
|
||
<a id="Nmap-define"></a>
|
||
<h4>Define</h4>
|
||
<ul>
|
||
<code>define <name> Nmap <target specification></code><br>
|
||
In der <target specification> stehen alle Zielhosts, die gescannet
|
||
werden sollen. <br>
|
||
Der einfachste Fall ist die Beschreibung einer IP-Zieladresse oder eines
|
||
Zielhostnamens zum Scannen. <br>
|
||
Um ein ganzes Netzwerk benachbarter Hosts zu scannen unterstützt
|
||
Nmap Adressen im CIDR-Stil. Es können /numbits an eine IPv4-Adresse
|
||
oder an einen Hostnamen angefügt werden, und Nmap wird alle
|
||
IP-Adressen scannen, bei denen die ersten numbits mit denen der gegebenen
|
||
IP oder des gegebenen Hostnamens übereinstimmen. Zum Beispiel
|
||
würde 192.168.10.0/24 die 256 Hosts zwischen 192.168.10.0 und
|
||
192.168.10.255 scannen. 192.168.10.40/24 würde genau dieselben Ziele
|
||
scannen. Es ist auch möglich mehrere Netzwerke zur gleichen Zeit zu
|
||
scannen. Zum Beispiel würde 192.168.1.0/24 192.168.2.0/24 die 512
|
||
Hosts zwischen 192.168.1.0 und 192.168.2.255 scannen.<br>
|
||
Siehe
|
||
<a href="https://nmap.org/man/de/man-target-specification.html">
|
||
<u>Nmap Man Page (Angabe von Zielen)</u>
|
||
</a>.
|
||
</ul>
|
||
<a id="Nmap-set"></a>
|
||
<h4>Set</h4>
|
||
<ul>
|
||
<a id="Nmap-set-clear"></a><li>
|
||
<code>clear readings</code><br>
|
||
Löscht alle Readings außer "state".
|
||
</li>
|
||
<a id="Nmap-set-deleteOldReadings"></a><li>
|
||
<code>deleteOldReadings <s></code><br>
|
||
Löscht alle Readings die älter sind als <s> Sekunden.
|
||
</li>
|
||
<a id="Nmap-set-interrupt"></a><li>
|
||
<code>interrupt</code><br>
|
||
Bricht einen laufenden Scan ab.
|
||
</li>
|
||
<a id="Nmap-set-statusRequest"></a><li>
|
||
<code>statusRequest</code><br>
|
||
Startet einen Netzwerkscan.
|
||
</li>
|
||
</ul>
|
||
<a id="Nmap-readings"></a>
|
||
<h4>Readings</h4>
|
||
<ul>
|
||
Allgemeine Readings:
|
||
<ul>
|
||
<li>
|
||
<code>NmapVersion</code><br>
|
||
Die Versionsnummer des installierten Nmap Programms.
|
||
</li>
|
||
<li>
|
||
<code>hostsScanned</code><br>
|
||
Die Anzahl der gescannten Adressen.
|
||
</li>
|
||
<li>
|
||
<code>hostsUp</code><br>
|
||
Die Anzahl der erreichbaren Netzwerkgeräte.
|
||
</li>
|
||
<li>
|
||
<code>knownHosts</code><br>
|
||
Die Anzahl der bekannten Netzwerkgeräte.
|
||
</li>
|
||
<li>
|
||
<code>scanDuration</code><br>
|
||
Die Scan-Dauer in Sekunden.
|
||
</li>
|
||
<li>
|
||
<code>state</code><br>
|
||
<ul>
|
||
<li>
|
||
<code>Initialized</code><br>
|
||
Nmap wurde definiert oder enabled.
|
||
</li>
|
||
<li>
|
||
<code>running</code><br>
|
||
Ein Netzwerkscan wird ausgeführt.
|
||
</li>
|
||
<li>
|
||
<code>done</code><br>
|
||
Der Netzwerkscan wurde erfolgreich abgeschlossen.
|
||
</li>
|
||
<li>
|
||
<code>aborted</code><br>
|
||
Der Netzwerkscan wurde aufgrund einer Zeitüberschreitung oder
|
||
durch den Benutzer abgebrochen.
|
||
</li>
|
||
<li>
|
||
<code>disabled</code><br>
|
||
Nmap wurde deaktiviert.
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
<br>
|
||
Hostspezifische Readings:
|
||
<ul>
|
||
<li>
|
||
<code><metaReading>_alias</code><br>
|
||
Alias welcher unter dem Attribut "devAlias" für das Netzwerkgerät
|
||
angegeben ist. Ist kein Alias angegeben wird der Hostname angezeigt.
|
||
</li>
|
||
<li>
|
||
<code><metaReading>_hostname</code><br>
|
||
Hostname des Netzwerkgeräts. Kann dieser nicht ermittel werden
|
||
wird die IPv4-Adresse angezeigt.
|
||
</li>
|
||
<li>
|
||
<code><metaReading>_ip</code><br>
|
||
IPv4-Adresse des Netzwerkgeräts.
|
||
</li>
|
||
<li>
|
||
<code><metaReading>_lastSeen</code><br>
|
||
Der Zeitpunkt zu dem das Netzwerkgerät das letzte mal als gesehen
|
||
wurde.
|
||
</li>
|
||
<li>
|
||
<code><metaReading>_macAddress</code><br>
|
||
MAC-Adresse des Netzwerkgeräts. Diese kann nur ermittelt werden,
|
||
wenn der Scan mit Root-Rechten ausgeführt wird.
|
||
</li>
|
||
<li>
|
||
<code><metaReading>_macVendor</code><br>
|
||
Vermutlicher Hersteller des Netzwerkgeräts. Dieser kann nur
|
||
ermittelt werden, wenn der Scan mit Root-Rechten ausgeführt wird.
|
||
</li>
|
||
<li>
|
||
<code><metaReading>_state</code><br>
|
||
Status des Netzwerkgeräts. Kann entweder "absent" oder "present"
|
||
sein.
|
||
</li>
|
||
<li>
|
||
<code><metaReading>_uptime</code><br>
|
||
Zeit in Sekunden seit der das Netzwerkgerät erreichbar ist.
|
||
</li>
|
||
<li>
|
||
<code><metaReading>_uptimeText</code><br>
|
||
Zeit in "d days, hh hours, mm minutes, ss seconds" seit der das
|
||
Netzwerkgerät erreichbar ist.
|
||
</li>
|
||
</ul>
|
||
</ul>
|
||
<a id="Nmap-attr"></a>
|
||
<h4>Attribute</h4>
|
||
<ul>
|
||
<a id="Nmap-attr-absenceThreshold"></a><li>
|
||
<code>absenceThreshold <n></code><br>
|
||
Die Anzahl an Netzwerkscans, welche in "absent" resultieren
|
||
müssen, bevor der Status eines Netzwerkgeräts auf "absent"
|
||
wechselt. Mit dieser Funktion kann man die Abwesenheit eines
|
||
Gerätes verifizieren bevor der Status final auf "absent"
|
||
geändert wird. Wenn dieses Attribut auf einen Wert >1 gesetzt
|
||
ist, verbleibt das Reading "<metaReading>_state" auf "present",
|
||
bis der Status final auf "absent" wechselt.
|
||
</li>
|
||
<a id="Nmap-attr-args"></a><li>
|
||
<code>args <args></code><br>
|
||
Argumente für den Nmap-Scan.<br>
|
||
Die Vorgabe ist "-sn".
|
||
</li>
|
||
<a id="Nmap-attr-deleteOldReadings"></a><li>
|
||
<code>deleteOldReadings <s></code><br>
|
||
Nach einem Netzwerkscan werden alle hostspezifischen Readings, die
|
||
älter sind als <s> Sekunden, gelöscht
|
||
</li>
|
||
<a id="Nmap-attr-devAlias"></a><li>
|
||
<code>
|
||
devAlias <ID>:<ALIAS> <ID2>:<ALIAS2> ...
|
||
</code><br>
|
||
Eine Leerzeichen-getrennte getrennte Liste von <ID>:<ALIAS>
|
||
Paaren, die dazu genutzt werden kann um Netzwerkgeräten einen
|
||
Alias zu geben.<br>
|
||
Die ID kann dabei MAC-Adresse, hostname oder IPv4-Adresse sein.<br>
|
||
Beispiele:
|
||
<ul>
|
||
MAC-Adresse:
|
||
<code>
|
||
attr <name> devAlias 5C:51:88:A5:94:1F:Michaels_Handy_byMAC
|
||
</code><br>
|
||
hostname:
|
||
<code>
|
||
attr <name> devAlias
|
||
android-87c7a6221093d830:Michaels_Handy_byHOST
|
||
</code><br>
|
||
IPv4-Adresse:
|
||
<code>
|
||
attr <name> devAlias 192.168.1.130:Michaels_Handy_byIP
|
||
</code><br>
|
||
</ul>
|
||
</li>
|
||
<a id="Nmap-attr-disable"></a><li>
|
||
<code>disable 1</code><br>
|
||
Ein laufender Scan wird abgebrochen und es werden keine neuen Scans
|
||
gestartet.
|
||
</li>
|
||
<a id="Nmap-attr-excludeHosts"></a><li>
|
||
<code>excludeHosts <target specification></code><br>
|
||
In der <target specification> stehen alle Zielhosts, die beim
|
||
Scan übersprungen werden sollen.
|
||
</li>
|
||
<a id="Nmap-attr-interval"></a><li>
|
||
<code>interval <seconds></code><br>
|
||
Intervall in Sekunden in dem der Scan durchgeführt wird.<br>
|
||
Der Vorgabewert ist 900 Sekunden und der Mindestwert 30 Sekunden.
|
||
</li>
|
||
<a id="Nmap-attr-keepReadings"></a><li>
|
||
<code>keepReadings 1</code><br>
|
||
Wird für ein Gertät mit bekannter MAC-Adresse eine neue IP-Adresse
|
||
erkannt, werden die ungültig gewordenen Readings gelöscht es sei denn
|
||
dieses Attribut ist gesetzt.
|
||
</li>
|
||
<a id="Nmap-attr-leadingZeros"></a><li>
|
||
<code>leadingZeros 1</code><br>
|
||
Bei den Readings-Namen werden die IPv4-Adressen mit führenden
|
||
Nullen dargestellt.
|
||
</li>
|
||
<a id="Nmap-attr-metaReading"></a><li>
|
||
<code>metaReading <metaReading></code><br>
|
||
Als <metaReading> kann "alias", "hostname", "ip" oder
|
||
"macAddress" angegeben werden und ist der Bezeichner für die
|
||
Readings.<br>
|
||
Die Vorgabe is "ip".
|
||
</li>
|
||
<a id="Nmap-attr-path"></a><li>
|
||
<code>path</code><br>
|
||
Pfad unter dem das Nmap Programm zu erreichen ist.<br>
|
||
Die Vorgabe ist "/urs/bin/nmap".
|
||
</li>
|
||
<li>
|
||
<a href="#readingFnAttributes">
|
||
<u><code>readingFnAttributes</code></u>
|
||
</a>
|
||
</li>
|
||
<a id="Nmap-attr-sudo"></a><li>
|
||
<code>sudo 1</code><br>
|
||
Der Scan wird mit Root-Rechten ausgeführt.<br>
|
||
Voraussetzung ist, dass der Benutzer unter dem FHEM ausgeführt
|
||
diese Rechte besitzt. Für den Benutzer "fhem", auf einem Debian
|
||
(basierten) System, lassen sich diese in der Datei "/etc/sudoers"
|
||
festlegen. Dafür muss im Abschnitt "# User privilege
|
||
specification" die Zeile "fhem ALL=(ALL) NOPASSWD: /usr/bin/nmap"
|
||
eingefügt werden.
|
||
</li>
|
||
</ul>
|
||
</ul>
|
||
</div>
|
||
|
||
=end html_DE
|
||
=cut
|