74_Nmap.pm 35 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112
  1. # Id ##########################################################################
  2. # $Id: 74_Nmap.pm 14107 2017-04-26 03:51:05Z igami $
  3. # copyright ###################################################################
  4. #
  5. # 74_Nmap.pm
  6. #
  7. # Copyright by igami
  8. #
  9. # This file is part of FHEM.
  10. #
  11. # FHEM is free software: you can redistribute it and/or modify
  12. # it under the terms of the GNU General Public License as published by
  13. # the Free Software Foundation, either version 2 of the License, or
  14. # (at your option) any later version.
  15. #
  16. # FHEM is distributed in the hope that it will be useful,
  17. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. # GNU General Public License for more details.
  20. #
  21. # You should have received a copy of the GNU General Public License
  22. # along with FHEM. If not, see <http://www.gnu.org/licenses/>.
  23. # packages ####################################################################
  24. package main;
  25. use strict;
  26. use warnings;
  27. use Blocking;
  28. # forward declarations ########################################################
  29. sub Nmap_Initialize($);
  30. sub Nmap_Define($$);
  31. sub Nmap_Undefine($$);
  32. sub Nmap_Set($@);
  33. sub Nmap_Attr(@);
  34. sub Nmap_statusRequest($);
  35. sub Nmap_blocking_statusRequest($);
  36. sub Nmap_done($);
  37. sub Nmap_aborted($);
  38. sub Nmap_deleteOldReadings($$);
  39. sub Nmap_updateUptime($$;$);
  40. # initialize ##################################################################
  41. sub Nmap_Initialize($) {
  42. my ($hash) = @_;
  43. my $TYPE = "Nmap";
  44. $hash->{DefFn} = $TYPE."_Define";
  45. $hash->{UndefFn} = $TYPE."_Undefine";
  46. $hash->{SetFn} = $TYPE."_Set";
  47. $hash->{AttrFn} = $TYPE."_Attr";
  48. $hash->{AttrList} = ""
  49. . "absenceThreshold "
  50. . "args "
  51. . "deleteOldReadings "
  52. . "devAlias:textField-long "
  53. . "disable:1,0 "
  54. . "excludeHosts "
  55. . "interval "
  56. . "keepReadings:1,0 "
  57. . "leadingZeros:1,0 "
  58. . "metaReading:alias,hostname,ip,macAddress "
  59. . "path "
  60. . "sudo:1,0 "
  61. . $readingFnAttributes
  62. ;
  63. }
  64. # regular Fn ##################################################################
  65. sub Nmap_Define($$) {
  66. my ($hash, $def) = @_;
  67. my ($SELF, $TYPE, $targets) = split(/[\s]+/, $def, 3);
  68. my $rc = eval{
  69. require Nmap::Parser;
  70. Nmap::Parser->import();
  71. 1;
  72. };
  73. return(
  74. "Error loading Nmap::Parser. Maybe this module is not installed? "
  75. . "\nUnder debian (based) system it can be installed using "
  76. . "\n\"apt-get install libnmap-parser-perl\""
  77. ) unless($rc);
  78. return("Usage: define <name> $TYPE <target specification>") if(!$targets);
  79. my $interval = AttrVal($SELF, "interval", 900);
  80. $interval = 900 if(!looks_like_number($interval));
  81. $interval = 30 if($interval < 30);
  82. $hash->{ARGS} = AttrVal($SELF, "args", "-sn");
  83. $hash->{INTERVAL} = $interval;
  84. $hash->{PATH} = AttrVal($SELF, "path", "/usr/bin/nmap");
  85. readingsSingleUpdate($hash, "state", "Initialized", 1);
  86. RemoveInternalTimer($hash);
  87. InternalTimer(
  88. gettimeofday() + $hash->{INTERVAL}, "Nmap_statusRequest", $hash
  89. );
  90. return;
  91. }
  92. sub Nmap_Undefine($$) {
  93. my ($hash, $arg) = @_;
  94. RemoveInternalTimer($hash);
  95. BlockingKill($hash->{helper}{RUNNING_PID})
  96. if(defined($hash->{helper}{RUNNING_PID}));
  97. return;
  98. }
  99. sub Nmap_Set($@) {
  100. my ($hash, @a) = @_;
  101. my $TYPE = $hash->{TYPE};
  102. return "\"set $TYPE\" needs at least one argument" if(@a < 2);
  103. my $SELF = shift @a;
  104. my $argument = shift @a;
  105. my $value = join(" ", @a) if (@a);
  106. my %Nmap_sets = (
  107. "clear" => "clear:readings",
  108. "deleteOldReadings" => "deleteOldReadings",
  109. "interrupt" => "interrupt:noArg",
  110. "statusRequest" => "statusRequest:noArg"
  111. );
  112. Log3($SELF, 5, "$TYPE ($SELF) - entering Nmap_Set");
  113. return(
  114. "Unknown argument $argument, choose one of "
  115. . join(" ", values %Nmap_sets)
  116. ) if(!exists($Nmap_sets{$argument}));
  117. if($argument eq "clear" && $value eq "readings"){
  118. foreach (keys %{$hash->{READINGS}}) {
  119. delete $hash->{READINGS}->{$_} if($_ ne "state");
  120. }
  121. }
  122. elsif($argument eq "deleteOldReadings" && $value){
  123. my $ret = Nmap_deleteOldReadings($hash, $value);
  124. return($ret) if($ret);
  125. readingsSingleUpdate($hash, "state", "deleteOldReadings $value", 1);
  126. }
  127. elsif(!IsDisabled($SELF)){
  128. if($argument eq "interrupt"){
  129. BlockingKill($hash->{helper}{RUNNING_PID})
  130. if(defined($hash->{helper}{RUNNING_PID}));
  131. Nmap_aborted($hash);
  132. RemoveInternalTimer($hash);
  133. InternalTimer(
  134. gettimeofday() + $hash->{INTERVAL}, "Nmap_statusRequest", $hash
  135. );
  136. }
  137. elsif($argument eq "statusRequest"){
  138. Nmap_statusRequest($hash);
  139. }
  140. }
  141. return;
  142. }
  143. sub Nmap_Attr(@) {
  144. my ($cmd, $SELF, $attribute, $value) = @_;
  145. my $hash = $defs{$SELF};
  146. my $TYPE = $hash->{TYPE};
  147. Log3($SELF, 5, "$TYPE ($SELF) - entering Nmap_Attr");
  148. if($attribute eq "args"){
  149. $hash->{ARGS} = $cmd eq "set" ? $value : "-sn";
  150. }
  151. elsif($attribute eq "devAlias" && $cmd eq "set"){
  152. return(
  153. "$SELF: Value \"$value\" is not allowed for devAlias!\n"
  154. . "Must be \"&lt;ID>:<ALIAS> &lt;ID2>:<ALIAS2> ...\", "
  155. . "e.g. 123abc:MyAndroid\n"
  156. . "Only these characters are allowed: [alphanumeric - _ .]"
  157. )if($value !~ /^([\w\.\-]+:[\w\.\-]+\s*)+$/s);
  158. }
  159. elsif($attribute eq "disable"){
  160. if($value && $value == 1){
  161. BlockingKill($hash->{helper}{RUNNING_PID})
  162. if(defined($hash->{helper}{RUNNING_PID}));
  163. RemoveInternalTimer($hash);
  164. readingsSingleUpdate($hash, "state", "disabled", 1);
  165. }
  166. elsif($cmd eq "del" || !$value){
  167. InternalTimer(
  168. gettimeofday() + $hash->{INTERVAL}, "Nmap_statusRequest", $hash
  169. );
  170. readingsSingleUpdate($hash, "state", "Initialized", 1);
  171. }
  172. }
  173. elsif($attribute eq "leadingZeros"){
  174. foreach (keys %{$hash->{READINGS}}){
  175. my $newkey = $_;
  176. $newkey =~
  177. s/([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/sprintf('%03d',$1).".".sprintf('%03d',$2).".".sprintf('%03d',$3).".".sprintf('%03d',$4)/e
  178. if($value and $value == 1);
  179. $newkey =~
  180. s/([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/sprintf('%00d',$1).".".sprintf('%00d',$2).".".sprintf('%00d',$3).".".sprintf('%00d',$4)/e
  181. if($cmd eq "del" or !$value);
  182. $hash->{READINGS}{$newkey} = delete $hash->{READINGS}{$_};
  183. }
  184. my $knownHosts = ReadingsVal($SELF, ".knownHosts", "");
  185. $knownHosts =~
  186. s/([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/sprintf('%03d',$1).".".sprintf('%03d',$2).".".sprintf('%03d',$3).".".sprintf('%03d',$4)/ge
  187. if($value and $value == 1);
  188. $knownHosts =~
  189. s/([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/sprintf('%00d',$1).".".sprintf('%00d',$2).".".sprintf('%00d',$3).".".sprintf('%00d',$4)/ge
  190. if($cmd eq "del" or !$value);
  191. readingsSingleUpdate($hash, ".knownHosts", $knownHosts, 0);
  192. }
  193. elsif($attribute eq "path"){
  194. $hash->{PATH} = $cmd eq "set" ? $value : "/usr/bin/nmap";
  195. }
  196. return if(IsDisabled($SELF));
  197. if($attribute eq "interval"){
  198. my $interval = $cmd eq "set" ? $value : 900;
  199. $interval = 900 if(!looks_like_number($interval));
  200. $interval = 30 if($interval < 30);
  201. $hash->{INTERVAL} = $interval;
  202. RemoveInternalTimer($hash);
  203. InternalTimer(
  204. gettimeofday() + $hash->{INTERVAL}, "Nmap_statusRequest", $hash
  205. );
  206. }
  207. return;
  208. }
  209. # blocking Fn #################################################################
  210. sub Nmap_statusRequest($) {
  211. my ($hash) = @_;
  212. my $SELF = $hash->{NAME};
  213. my $TYPE = $hash->{TYPE};
  214. my $interval = $hash->{INTERVAL};
  215. my $timeout = $interval - 1;
  216. my $path = $hash->{PATH};
  217. Log3($SELF, 5, "$TYPE ($SELF) - entering Nmap_statusRequest");
  218. BlockingKill($hash->{helper}{RUNNING_PID})
  219. if(defined($hash->{helper}{RUNNING_PID}));
  220. RemoveInternalTimer($hash);
  221. return if(IsDisabled($SELF));
  222. InternalTimer(
  223. gettimeofday() + $interval, "Nmap_statusRequest", $hash
  224. );
  225. unless(-X $path){
  226. readingsSingleUpdate($hash, "state", "aborted", 1);
  227. Log3(
  228. $SELF, 1, "$TYPE ($SELF) - "
  229. . "please check if Nmap ist installed and available at path $path"
  230. );
  231. return;
  232. }
  233. if( AttrVal($SELF, "sudo", 0) == 1
  234. && qx(sudo -n $path -V 2>&1 > /dev/null)
  235. ){
  236. readingsSingleUpdate($hash, "state", "aborted", 1);
  237. Log3($SELF, 1, "$TYPE ($SELF) - sudo password required");
  238. return;
  239. }
  240. readingsSingleUpdate($hash, "state", "running", 1);
  241. Log3($SELF, 3, "$TYPE ($SELF) - starting network scan");
  242. Log3($SELF, 5, "$TYPE ($SELF) - BlockingCall Nmap_blocking_statusRequest");
  243. $hash->{helper}{RUNNING_PID} = BlockingCall(
  244. "Nmap_blocking_statusRequest", $SELF, "Nmap_done"
  245. , $timeout, "Nmap_aborted", $hash
  246. ) unless(exists($hash->{helper}{RUNNING_PID}));
  247. return;
  248. }
  249. sub Nmap_blocking_statusRequest($) {
  250. my ($SELF) = @_;
  251. my ($hash) = $defs{$SELF};
  252. my $TYPE = $hash->{TYPE};
  253. my @ret = $SELF;
  254. my $NP = new Nmap::Parser;
  255. my $path =
  256. (AttrVal($SELF, "sudo", 0) == 1 ? "sudo " : "")
  257. . $hash->{PATH}
  258. ;
  259. my $excludeHosts = AttrVal($SELF, "excludeHosts", undef);
  260. my $args = $hash->{ARGS};
  261. $args .= " --exclude $excludeHosts" if($excludeHosts);
  262. my $STDERR = "";
  263. Log3($SELF, 5, "$TYPE ($SELF) - entering Nmap_blocking_statusRequest");
  264. close STDERR;
  265. open(STDERR, ">", \$STDERR);
  266. $NP->parsescan($path, $args, $hash->{DEF});
  267. close (STDERR);
  268. Log3($SELF, 4, "$TYPE ($SELF) - $_")
  269. foreach(split( "\n", $STDERR));
  270. my $NPS = $NP->get_session();
  271. push(@ret, $NPS->nmap_version());
  272. push(@ret, int($NP->all_hosts()));
  273. push(@ret, $NPS->finish_time() - $NPS->start_time());
  274. my @hostsUp = $NP->all_hosts("up");
  275. foreach (@hostsUp){
  276. my $hostname = $_->hostname() ? $_->hostname() : $_->ipv4_addr();
  277. my $macAddress = $_->mac_addr() ? $_->mac_addr() : "Unknown";
  278. my $macVendor = $_->mac_vendor() ? $_->mac_vendor() : "Unknown";
  279. push(@ret, $_->ipv4_addr()."|$hostname|$macAddress|$macVendor");
  280. }
  281. return (join("||", @ret));
  282. }
  283. sub Nmap_done($) {
  284. my ($string) = @_;
  285. return unless(defined($string));
  286. my ($SELF, $NmapVersion, $hostsScanned, $scanDuration, @hostsUp) =
  287. split("\\|\\|", $string);
  288. my ($hash) = $defs{$SELF};
  289. my $TYPE = $hash->{TYPE};
  290. my $devAliases = AttrVal($SELF, "devAlias", undef);
  291. my %knownHosts = map{$_, 0} split(",", ReadingsVal($SELF, ".knownHosts", ""));
  292. my $metaReadingAttrVal = AttrVal($SELF, "metaReading", "ip");
  293. Log3($SELF, 5, "$TYPE ($SELF) - entering Nmap_done");
  294. delete($hash->{helper}{RUNNING_PID});
  295. readingsBeginUpdate($hash);
  296. readingsBulkUpdate($hash, "NmapVersion", $NmapVersion);
  297. readingsBulkUpdate($hash, "hostsScanned", $hostsScanned);
  298. readingsBulkUpdate($hash, "hostsUp", int(@hostsUp));
  299. readingsBulkUpdate($hash, "scanDuration", $scanDuration);
  300. foreach (@hostsUp){
  301. my ($ip, $hostname, $macAddress, $macVendor) = split("\\|", $_);
  302. my ($oldMetaReading, $metaReading);
  303. my $alias = $hostname;
  304. if(
  305. $devAliases && $devAliases =~ /$macAddress:(.+?)(\s|$)/
  306. || $devAliases && $devAliases =~ /$hostname:(.+?)(\s|$)/
  307. || $devAliases && $devAliases =~ /$ip:(.+?)(\s|$)/
  308. ){
  309. $alias = $1;
  310. }
  311. if($metaReadingAttrVal eq "ip"){
  312. $metaReading = $ip;
  313. }
  314. elsif($metaReadingAttrVal eq "macAddress"){
  315. $metaReading = $macAddress ne "Unknown" ? $macAddress : $ip;
  316. }
  317. elsif($metaReadingAttrVal eq "alias"){
  318. $metaReading = $alias;
  319. }
  320. elsif($metaReadingAttrVal eq "hostname"){
  321. $metaReading = $hostname;
  322. }
  323. $metaReading =~ s/([0-9]+)/sprintf('%03d',$1)/ge
  324. if(AttrVal($SELF, "leadingZeros", 0) == 1 && $metaReading eq $ip);
  325. $metaReading =~ s/:/-/g;
  326. $knownHosts{$metaReading} = 1;
  327. if($macAddress ne "Unknown"){
  328. foreach (keys %knownHosts){
  329. $oldMetaReading = $_
  330. if(ReadingsVal($SELF, $_."_macAddress", "") eq $macAddress);
  331. next unless($oldMetaReading);
  332. last;
  333. }
  334. if( $oldMetaReading
  335. && ReadingsVal($SELF, $oldMetaReading."_ip", "") ne $ip
  336. ){
  337. Log3($SELF, 4, "$TYPE ($SELF) - new IP: $hostname ($ip)");
  338. DoTrigger($SELF, "new IP: $hostname ($ip)");
  339. }
  340. }
  341. unless($hash->{READINGS}{$metaReading."_hostname"} || $oldMetaReading){
  342. Log3($SELF, 4, "$TYPE ($SELF) - new host: $hostname ($ip)");
  343. DoTrigger($SELF, "new host: $hostname ($ip)");
  344. }
  345. if( $oldMetaReading && $oldMetaReading ne $metaReading
  346. && AttrVal($SELF, "keepReadings", 0) == 0
  347. ){
  348. delete $knownHosts{$oldMetaReading};
  349. CommandDeleteReading(undef, "$SELF $oldMetaReading.*");
  350. Log3($SELF, 4, "$TYPE ($SELF) - delete old host: $oldMetaReading");
  351. }
  352. readingsBulkUpdate($hash, $metaReading."_alias", $alias);
  353. readingsBulkUpdate($hash, $metaReading."_hostname", $hostname);
  354. readingsBulkUpdate($hash, $metaReading."_ip", $ip);
  355. readingsBulkUpdate($hash, $metaReading."_lastSeen", TimeNow());
  356. readingsBulkUpdate($hash, $metaReading."_macAddress", $macAddress)
  357. if($macAddress ne "Unknown");
  358. readingsBulkUpdate($hash, $metaReading."_macVendor", $macVendor)
  359. if($macVendor ne "Unknown");
  360. readingsBulkUpdate($hash, $metaReading."_state", "present");
  361. Nmap_updateUptime($hash, $metaReading);
  362. }
  363. foreach (keys %knownHosts){
  364. next if( $knownHosts{$_} == 1
  365. || ReadingsVal($SELF, $_."_state", "present") eq "absent"
  366. );
  367. my $absenceThreshold = ReadingsVal($SELF, ".".$_."_absenceThreshold", 1);
  368. if($absenceThreshold >= AttrVal($SELF, "absenceThreshold", 1)){
  369. delete $hash->{READINGS}{".".$_."_absenceThreshold"};
  370. readingsBulkUpdate($hash, $_."_state", "absent");
  371. Nmap_updateUptime($hash, $_, 0);
  372. }
  373. else{
  374. $absenceThreshold ++;
  375. readingsBulkUpdate($hash, ".".$_."_absenceThreshold", $absenceThreshold);
  376. readingsBulkUpdate($hash, $_."_state", "present");
  377. Nmap_updateUptime($hash, $_);
  378. }
  379. }
  380. readingsBulkUpdate($hash, ".knownHosts", join(",", sort(keys %knownHosts)));
  381. readingsBulkUpdate($hash, "knownHosts", int(keys %knownHosts));
  382. readingsBulkUpdate($hash, "state", "done");
  383. readingsEndUpdate($hash, 1);
  384. my $deleteOldReadings = AttrVal($SELF, "deleteOldReadings", 0);
  385. Nmap_deleteOldReadings($hash, $deleteOldReadings)
  386. if($deleteOldReadings ne "0");
  387. Log3($SELF, 3, "$TYPE ($SELF) - network scan done");
  388. return;
  389. }
  390. sub Nmap_aborted($) {
  391. my ($hash) = @_;
  392. my $SELF = $hash->{NAME};
  393. my $TYPE = $hash->{TYPE};
  394. delete($hash->{helper}{RUNNING_PID});
  395. Log3($SELF, 2, "$TYPE ($SELF) - network scan aborted");
  396. readingsSingleUpdate($hash, "state", "aborted", 1);
  397. return;
  398. }
  399. # module Fn ###################################################################
  400. sub Nmap_deleteOldReadings($$) {
  401. my ($hash, $value) = @_;
  402. my $SELF = $hash->{NAME};
  403. my $TYPE = $hash->{TYPE};
  404. $value = eval($value);
  405. Log3($SELF, 5, "$TYPE ($SELF) - entering Nmap_deleteOldReadings");
  406. unless(looks_like_number($value)){
  407. my $ret = "no numeric value given for deleteOldReadings";
  408. Log3($SELF, 2, "$TYPE ($SELF) - $ret");
  409. return($ret);
  410. }
  411. my %knownHosts =
  412. map{$_, 0} split(",", ReadingsVal($SELF, ".knownHosts", ""));
  413. foreach (keys %knownHosts) {
  414. if(ReadingsAge($SELF, $_."_lastSeen", 0) >= $value){
  415. CommandDeleteReading(undef, "$SELF $_.*");
  416. delete $knownHosts{$_};
  417. }
  418. }
  419. readingsBeginUpdate($hash);
  420. readingsBulkUpdate($hash, ".knownHosts", join(",", sort(keys %knownHosts)));
  421. readingsBulkUpdate($hash, "knownHosts", int(keys %knownHosts));
  422. readingsEndUpdate($hash, 1);
  423. Log3($SELF, 4, "$TYPE ($SELF) - delete Readings older than $value seconds");
  424. return;
  425. }
  426. sub Nmap_updateUptime($$;$) {
  427. my ($hash, $metaReading, $uptime) = @_;
  428. my $SELF = $hash->{NAME};
  429. my $TYPE = $hash->{TYPE};
  430. Log3($SELF, 5, "$TYPE ($SELF) - entering Nmap_updateUptime");
  431. $uptime = (
  432. ReadingsVal($SELF, $metaReading."_uptime", 0)
  433. + ReadingsAge($SELF, $metaReading."_uptime", 0)
  434. ) unless(defined($uptime));
  435. my $s = $uptime;
  436. my $d = int($s / 86400);
  437. $s -= $d * 86400;
  438. my $h = int($s / 3600);
  439. $s -= $h * 3600;
  440. my $m = int($s / 60);
  441. $s -= $m * 60;
  442. my $uptimeText = sprintf(
  443. "%d days, %02d hours, %02d minutes, %02d seconds"
  444. , $d, $h, $m, $s
  445. );
  446. readingsBulkUpdate($hash, $metaReading."_uptime", $uptime);
  447. readingsBulkUpdate($hash, $metaReading."_uptimeText", $uptimeText);
  448. return;
  449. }
  450. 1;
  451. # commandref ##################################################################
  452. =pod
  453. =item device
  454. =item summary Interpret of an Nmap network scans
  455. =item summary_DE Auswertung eines Nmap Netzwerkscans
  456. =begin html
  457. <a name="Nmap"></a>
  458. <h3>Nmap</h3>
  459. ( en | <a href="commandref_DE.html#Nmap"><u>de</u></a> )
  460. <div>
  461. <ul>
  462. Nmap is the FHEM module to perform a network scan with Nmap and to display information about the available network devices.<br>
  463. If a new device is detected, an event
  464. <code>"&lt;name&gt; new host: &lt;hostname&gt; (&lt;IPv4&gt;)"</code>
  465. is generated.<br>
  466. If a device with a known MAC address has been given a new IP, an event
  467. <code>"&lt;name&gt; new IP: &lt;hostname&gt; (&lt;IPv4&gt;)"</code>
  468. is generated.<br>
  469. <br>
  470. Prerequisites:
  471. <ul>
  472. The "Nmap" program and the Perl module "Nmap::Parser" are required.<br>
  473. Under Debian (based) system, these can be installed using
  474. <code>"apt-get install nmap libnmap-parser-perl"</code>
  475. .
  476. </ul>
  477. <br>
  478. <a name="Nmapdefine"></a>
  479. <b>Define</b>
  480. <ul>
  481. <code>define &lt;name&gt; Nmap &lt;target specification&gt;</code><br>
  482. In the &lt;target specification&gt; are all target hosts, which are to be
  483. scanned.<br>
  484. The simplest case is the description of an IP destination address or a
  485. target host name for scanning.<br>
  486. To scan an entire network of neighboring hosts, Nmap supports CIDR-style
  487. addresses. Numbits can be appended to an IPv4 address or hostname, and
  488. Nmap will scan all IP addresses where the first numbits match those of
  489. the given IP or host name. For example, 192.168.10.0/24 would scan the
  490. 256 hosts between 192.168.10.0 and 192.168.10.255. 192.168.10.40/24 would
  491. scan exactly the same targets. It's also possible to scan multiple
  492. networks at the same time. For example 192.168.1.0/24 192.168.2.0/24
  493. would scan the 512 hosts between 192.168.1.0 and 192.168.2.255.<br>
  494. See
  495. <a href="https://nmap.org/man/de/man-target-specification.html">
  496. <u>Nmap Manpage (Specifying Destinations)</u>
  497. </a>.
  498. </ul><br>
  499. <a name="Nmapset"></a>
  500. <b>Set</b>
  501. <ul>
  502. <li>
  503. <code>clear readings</code><br>
  504. Deletes all readings except "state".
  505. </li>
  506. <li>
  507. <code>deleteOldReadings &lt;s&gt;</code><br>
  508. Deletes all readings older than &lt;s&gt; seconds.
  509. </li>
  510. <li>
  511. <code>interrupt</code><br>
  512. Cancels a running scan.
  513. </li>
  514. <li>
  515. <code>statusRequest</code><br>
  516. Starts a network scan.
  517. </li>
  518. </ul><br>
  519. <a name="Nmapreadings"></a>
  520. <b>Readings</b><br>
  521. <ul>
  522. General Readings:
  523. <ul>
  524. <li>
  525. <code>NmapVersion</code><br>
  526. The version number of the installed Nmap program.
  527. </li>
  528. <li>
  529. <code>hostsScanned</code><br>
  530. The number of scanned addresses.
  531. </li>
  532. <li>
  533. <code>hostsUp</code><br>
  534. The number of available network devices.
  535. </li>
  536. <li>
  537. <code>knownHosts</code><br>
  538. The number of known network devices.
  539. </li>
  540. <li>
  541. <code>scanDuration</code><br>
  542. The scan time in seconds.
  543. </li>
  544. <li>
  545. <code>state</code><br>
  546. <ul>
  547. <li>
  548. <code>Initialized</code><br>
  549. Nmap has been defined or enabled.
  550. </li>
  551. <li>
  552. <code>running</code><br>
  553. A network scan is running.
  554. </li>
  555. <li>
  556. <code>done</code><br>
  557. Network scan completed successfully.
  558. </li>
  559. <li>
  560. <code>aborted</code><br>
  561. The network scan was aborted due to a timeout or by the user.
  562. </li>
  563. <li>
  564. <code>disabled</code><br>
  565. Nmap has been disabled.
  566. </li>
  567. </ul>
  568. </li>
  569. </ul>
  570. <br>
  571. Host-specific readings:
  572. <ul>
  573. <li>
  574. <code>&lt;metaReading&gt;_alias</code><br>
  575. Alias ​​which is specified under the attribute "devAlias" for the
  576. network device. If no alias is specified, the hostname is displayed.
  577. </li>
  578. <li>
  579. <code>&lt;metaReading&gt;_hostname</code><br>
  580. Hostname of the network device. If this can not be determined, the IPv4
  581. address is displayed.
  582. </li>
  583. <li>
  584. <code>&lt;metaReading&gt;_ip</code><br>
  585. IPv4 address of the network device.
  586. </li>
  587. <li>
  588. <code>&lt;metaReading&gt;_lastSeen</code><br>
  589. The time at which the network device was last seen as.
  590. </li>
  591. <li>
  592. <code>&lt;metaReading&gt;_macAddress</code><br>
  593. MAC address of the network device. This can only be determined if the
  594. scan is executed with root privileges.
  595. </li>
  596. <li>
  597. <code>&lt;metaReading&gt;_macVendor</code><br>
  598. Probable manufacturer of the network device. This can only be
  599. determined if the scan is executed with root privileges.
  600. </li>
  601. <li>
  602. <code>&lt;metaReading&gt;_state</code><br>
  603. State of the network device. Can be either "absent" or "present".
  604. </li>
  605. <li>
  606. <code>&lt;metaReading&gt;_uptime</code><br>
  607. Time in seconds since the network device is reachable.
  608. </li>
  609. <li>
  610. <code>&lt;metaReading&gt;_uptimeText</code><br>
  611. Time in "d days, hh hours, mm minutes, ss seconds" since the network
  612. device is reachable.
  613. </li>
  614. </ul>
  615. </ul><br>
  616. <a name="Nmapattr"></a>
  617. <b>Attribute</b>
  618. <ul>
  619. <li>
  620. <code>absenceThreshold &lt;n&gt;</code><br>
  621. The number of network cans that must result in "absent" before the
  622. state of a network device changes to "absent". With this function you
  623. can verify the absence of a device before the status is changed to
  624. "absent". If this attribute is set to a value &gt;1, the reading
  625. "&lt;metaReading&gt;_state" remains on "present" until the final status
  626. changes to "absent".
  627. </li>
  628. <li>
  629. <code>args &lt;args&gt;</code><br>
  630. Arguments for the Nmap scan.<br>
  631. The default is "-sn".
  632. </li>
  633. <li>
  634. <code>deleteOldReadings &lt;s&gt;</code><br>
  635. After a network scan, all host-specific readings older than &lt;s&gt;
  636. seconds are deleted
  637. </li>
  638. <li>
  639. <code>
  640. devAlias &lt;ID&gt;:&lt;ALIAS&gt; &lt;ID2&gt;:&lt;ALIAS2&gt; ...
  641. </code><br>
  642. A whitespace separated list of &lt;ID&gt;:&lt;ALIAS&gt; pairs that can be used to give an alias to network devices.<br>
  643. The ID can be MAC address, hostname or IPv4 address.<br>
  644. Examples:
  645. <ul>
  646. MAC address:
  647. <code>
  648. attr &lt;name&gt; devAlias 5C:51:88:A5:94:1F:Michaels_Handy_byMAC
  649. </code><br>
  650. Hostname:
  651. <code>
  652. attr &lt;name&gt; devAlias
  653. android-87c7a6221093d830:Michaels_Handy_byHOST
  654. </code><br>
  655. IPv4 address:
  656. <code>
  657. attr &lt;name&gt; devAlias 192.168.1.130:Michaels_Handy_byIP
  658. </code><br>
  659. </ul>
  660. </li>
  661. <li>
  662. <code>disable 1</code><br>
  663. A running scan is canceled and no new scans are started.
  664. </li>
  665. <li>
  666. <code>excludeHosts &lt;target specification&gt;</code><br>
  667. All target hosts in the &lt;target specification&gt; are skipped during the scan.
  668. </li>
  669. <li>
  670. <code>interval &lt;seconds&gt;</code><br>
  671. Interval in seconds in which the scan is performed.<br>
  672. The default value is 900 seconds and the minimum value is 30 seconds.
  673. </li>
  674. <li>
  675. <code>keepReadings 1</code><br>
  676. If a new IP address is recognized for a device with a known MAC
  677. address, the invalid readings are deleted unless this attribute is set.
  678. </li>
  679. <li>
  680. <code>leadingZeros 1</code><br>
  681. For the readings, the IPv4 addresses are displayed with leading zeros.
  682. </li>
  683. <li>
  684. <code>metaReading &lt;metaReading&gt;</code><br>
  685. You can specify "alias", "hostname", "ip" or "macAddress" as
  686. &lt;metaReading&gt; and is the identifier for the readings.<br>
  687. The default is "ip".
  688. </li>
  689. <li>
  690. <code>path</code><br>
  691. Path under which the Nmap program is to be reached.<br>
  692. The default is "/urs/bin/nmap".
  693. </li>
  694. <li>
  695. <a href="#readingFnAttributes">
  696. <u><code>readingFnAttributes</code></u>
  697. </a>
  698. </li>
  699. <li>
  700. <code>sudo 1</code><br>
  701. The scan runs with root privileges.<br>
  702. The prerequisite is that the user has these rights under the FHEM. For
  703. the user "fhem", on a Debian (based) system, they can be set in the
  704. "/etc/sudoers" file. For this, the line "fhem ALL=(ALL) NOPASSWD:
  705. /usr/bin/nmap" must be inserted in the section "#User privilege
  706. specification".
  707. </li>
  708. </ul>
  709. </ul>
  710. </div>
  711. =end html
  712. =begin html_DE
  713. <a name="Nmap"></a>
  714. <h3>Nmap</h3>
  715. ( <a href="commandref.html#Nmap"><u>en</u></a> | de )
  716. <div>
  717. <ul>
  718. Nmap ist das FHEM Modul um einen Netzwerkscan mit Nmap durchzuf&uuml;hren
  719. und Informationen &uuml;ber die erreichbaren Netzwerkger&auml;te
  720. darzustellen.<br>
  721. Wird ein neues Gerät erkannt wird ein Event
  722. <code>"&lt;name&gt; new host: &lt;hostname&gt; (&lt;IPv4&gt;)"</code>
  723. erzeugt.<br>
  724. Wird erkannt, dass ein Gerät mit bekannter MAC-Adresse eine neue IP
  725. erhalten hat wird ein Event
  726. <code>"&lt;name&gt; new IP: &lt;hostname&gt; (&lt;IPv4&gt;)"</code>
  727. erzeugt.<br>
  728. <br>
  729. Vorraussetzungen:
  730. <ul>
  731. Das Programm "Nmap" sowie das Perl-Modul "Nmap::Parser" werden
  732. ben&ouml;tigt.<br>
  733. Unter Debian (basierten) System, k&ouml;nnen diese mittels
  734. <code>"apt-get install nmap libnmap-parser-perl"</code>
  735. installiert werden.
  736. </ul>
  737. <br>
  738. <a name="Nmapdefine"></a>
  739. <b>Define</b>
  740. <ul>
  741. <code>define &lt;name&gt; Nmap &lt;target specification&gt;</code><br>
  742. In der &lt;target specification&gt; stehen alle Zielhosts, die gescannet
  743. werden sollen. <br>
  744. Der einfachste Fall ist die Beschreibung einer IP-Zieladresse oder eines
  745. Zielhostnamens zum Scannen. <br>
  746. Um ein ganzes Netzwerk benachbarter Hosts zu scannen unterst&uuml;tzt
  747. Nmap Adressen im CIDR-Stil. Es k&ouml;nnen /numbits an eine IPv4-Adresse
  748. oder an einen Hostnamen angef&uuml;gt werden, und Nmap wird alle
  749. IP-Adressen scannen, bei denen die ersten numbits mit denen der gegebenen
  750. IP oder des gegebenen Hostnamens &uuml;bereinstimmen. Zum Beispiel
  751. w&uuml;rde 192.168.10.0/24 die 256 Hosts zwischen 192.168.10.0 und
  752. 192.168.10.255 scannen. 192.168.10.40/24 w&uuml;rde genau dieselben Ziele
  753. scannen. Es ist auch möglich mehrere Netzwerke zur gleichen Zeit zu
  754. scannen. Zum Beispiel w&uuml;rde 192.168.1.0/24 192.168.2.0/24 die 512
  755. Hosts zwischen 192.168.1.0 und 192.168.2.255 scannen.<br>
  756. Siehe
  757. <a href="https://nmap.org/man/de/man-target-specification.html">
  758. <u>Nmap Man Page (Angabe von Zielen)</u>
  759. </a>.
  760. </ul><br>
  761. <a name="Nmapset"></a>
  762. <b>Set</b>
  763. <ul>
  764. <li>
  765. <code>clear readings</code><br>
  766. L&ouml;scht alle Readings außer "state".
  767. </li>
  768. <li>
  769. <code>deleteOldReadings &lt;s&gt;</code><br>
  770. Löscht alle Readings die älter sind als &lt;s&gt; Sekunden.
  771. </li>
  772. <li>
  773. <code>interrupt</code><br>
  774. Bricht einen laufenden Scan ab.
  775. </li>
  776. <li>
  777. <code>statusRequest</code><br>
  778. Startet einen Netzwerkscan.
  779. </li>
  780. </ul><br>
  781. <a name="Nmapreadings"></a>
  782. <b>Readings</b><br>
  783. <ul>
  784. Allgemeine Readings:
  785. <ul>
  786. <li>
  787. <code>NmapVersion</code><br>
  788. Die Versionsnummer des installierten Nmap Programms.
  789. </li>
  790. <li>
  791. <code>hostsScanned</code><br>
  792. Die Anzahl der gescannten Adressen.
  793. </li>
  794. <li>
  795. <code>hostsUp</code><br>
  796. Die Anzahl der erreichbaren Netzwerkger&auml;te.
  797. </li>
  798. <li>
  799. <code>knownHosts</code><br>
  800. Die Anzahl der bekannten Netzwerkger&auml;te.
  801. </li>
  802. <li>
  803. <code>scanDuration</code><br>
  804. Die Scan-Dauer in Sekunden.
  805. </li>
  806. <li>
  807. <code>state</code><br>
  808. <ul>
  809. <li>
  810. <code>Initialized</code><br>
  811. Nmap wurde definiert oder enabled.
  812. </li>
  813. <li>
  814. <code>running</code><br>
  815. Ein Netzwerkscan wird ausgef&uuml;hrt.
  816. </li>
  817. <li>
  818. <code>done</code><br>
  819. Der Netzwerkscan wurde erfolgreich abgeschlossen.
  820. </li>
  821. <li>
  822. <code>aborted</code><br>
  823. Der Netzwerkscan wurde aufgrund einer Zeit&uuml;berschreitung oder
  824. durch den Benutzer abgebrochen.
  825. </li>
  826. <li>
  827. <code>disabled</code><br>
  828. Nmap wurde deaktiviert.
  829. </li>
  830. </ul>
  831. </li>
  832. </ul>
  833. <br>
  834. Hostspezifische Readings:
  835. <ul>
  836. <li>
  837. <code>&lt;metaReading&gt;_alias</code><br>
  838. Alias welcher unter dem Attribut "devAlias" für das Netzwerkger&auml;t
  839. angegeben ist. Ist kein Alias angegeben wird der Hostname angezeigt.
  840. </li>
  841. <li>
  842. <code>&lt;metaReading&gt;_hostname</code><br>
  843. Hostname des Netzwerkger&auml;ts. Kann dieser nicht ermittel werden
  844. wird die IPv4-Adresse angezeigt.
  845. </li>
  846. <li>
  847. <code>&lt;metaReading&gt;_ip</code><br>
  848. IPv4-Adresse des Netzwerkger&auml;ts.
  849. </li>
  850. <li>
  851. <code>&lt;metaReading&gt;_lastSeen</code><br>
  852. Der Zeitpunkt zu dem das Netzwerkger&auml;t das letzte mal als gesehen
  853. wurde.
  854. </li>
  855. <li>
  856. <code>&lt;metaReading&gt;_macAddress</code><br>
  857. MAC-Adresse des Netzwerkger&auml;ts. Diese kann nur ermittelt werden,
  858. wenn der Scan mit Root-Rechten ausgef&uuml;hrt wird.
  859. </li>
  860. <li>
  861. <code>&lt;metaReading&gt;_macVendor</code><br>
  862. Vermutlicher Hersteller des Netzwerkger&auml;ts. Dieser kann nur
  863. ermittelt werden, wenn der Scan mit Root-Rechten ausgef&uuml;hrt wird.
  864. </li>
  865. <li>
  866. <code>&lt;metaReading&gt;_state</code><br>
  867. Status des Netzwerkger&auml;ts. Kann entweder "absent" oder "present"
  868. sein.
  869. </li>
  870. <li>
  871. <code>&lt;metaReading&gt;_uptime</code><br>
  872. Zeit in Sekunden seit der das Netzwerkger&auml;t erreichbar ist.
  873. </li>
  874. <li>
  875. <code>&lt;metaReading&gt;_uptimeText</code><br>
  876. Zeit in "d days, hh hours, mm minutes, ss seconds" seit der das
  877. Netzwerkger&auml;t erreichbar ist.
  878. </li>
  879. </ul>
  880. </ul><br>
  881. <a name="Nmapattr"></a>
  882. <b>Attribute</b>
  883. <ul>
  884. <li>
  885. <code>absenceThreshold &lt;n&gt;</code><br>
  886. Die Anzahl an Netzwerkscans, welche in "absent" resultieren
  887. m&uuml;ssen, bevor der Status eines Netzwerkger&auml;ts auf "absent"
  888. wechselt. Mit dieser Funktion kann man die Abwesenheit eines
  889. Ger&auml;tes verifizieren bevor der Status final auf "absent"
  890. ge&auml;ndert wird. Wenn dieses Attribut auf einen Wert &gt;1 gesetzt
  891. ist, verbleibt das Reading "&lt;metaReading&gt;_state" auf "present",
  892. bis der Status final auf "absent" wechselt.
  893. </li>
  894. <li>
  895. <code>args &lt;args&gt;</code><br>
  896. Argumente für den Nmap-Scan.<br>
  897. Die Vorgabe ist "-sn".
  898. </li>
  899. <li>
  900. <code>deleteOldReadings &lt;s&gt;</code><br>
  901. Nach einem Netzwerkscan werden alle hostspezifischen Readings, die
  902. älter sind als &lt;s&gt; Sekunden, gelöscht
  903. </li>
  904. <li>
  905. <code>
  906. devAlias &lt;ID&gt;:&lt;ALIAS&gt; &lt;ID2&gt;:&lt;ALIAS2&gt; ...
  907. </code><br>
  908. Eine Leerzeichen-getrennte getrennte Liste von &lt;ID&gt;:&lt;ALIAS&gt;
  909. Paaren, die dazu genutzt werden kann um Netzwerkger&auml;ten einen
  910. Alias zu geben.<br>
  911. Die ID kann dabei MAC-Adresse, hostname oder IPv4-Adresse sein.<br>
  912. Beispiele:
  913. <ul>
  914. MAC-Adresse:
  915. <code>
  916. attr &lt;name&gt; devAlias 5C:51:88:A5:94:1F:Michaels_Handy_byMAC
  917. </code><br>
  918. hostname:
  919. <code>
  920. attr &lt;name&gt; devAlias
  921. android-87c7a6221093d830:Michaels_Handy_byHOST
  922. </code><br>
  923. IPv4-Adresse:
  924. <code>
  925. attr &lt;name&gt; devAlias 192.168.1.130:Michaels_Handy_byIP
  926. </code><br>
  927. </ul>
  928. </li>
  929. <li>
  930. <code>disable 1</code><br>
  931. Ein laufender Scan wird abgebrochen und es werden keine neuen Scans
  932. gestartet.
  933. </li>
  934. <li>
  935. <code>excludeHosts &lt;target specification&gt;</code><br>
  936. In der &lt;target specification&gt; stehen alle Zielhosts, die beim
  937. Scan &uuml;bersprungen werden sollen.
  938. </li>
  939. <li>
  940. <code>interval &lt;seconds&gt;</code><br>
  941. Intervall in Sekunden in dem der Scan durchgef&uuml;hrt wird.<br>
  942. Der Vorgabewert ist 900 Sekunden und der Mindestwert 30 Sekunden.
  943. </li>
  944. <li>
  945. <code>keepReadings 1</code><br>
  946. Wird für ein Gertät mit bekannter MAC-Adresse eine neue IP-Adresse
  947. erkannt, werden die ungültig gewordenen Readings gelöscht es sei denn
  948. dieses Attribut ist gesetzt.
  949. </li>
  950. <li>
  951. <code>leadingZeros 1</code><br>
  952. Bei den Readings-Namen werden die IPv4-Adressen mit f&uuml;hrenden
  953. Nullen dargestellt.
  954. </li>
  955. <li>
  956. <code>metaReading &lt;metaReading&gt;</code><br>
  957. Als &lt;metaReading&gt; kann "alias", "hostname", "ip" oder
  958. "macAddress" angegeben werden und ist der Bezeichner für die
  959. Readings.<br>
  960. Die Vorgabe is "ip".
  961. </li>
  962. <li>
  963. <code>path</code><br>
  964. Pfad unter dem das Nmap Programm zu erreichen ist.<br>
  965. Die Vorgabe ist "/urs/bin/nmap".
  966. </li>
  967. <li>
  968. <a href="#readingFnAttributes">
  969. <u><code>readingFnAttributes</code></u>
  970. </a>
  971. </li>
  972. <li>
  973. <code>sudo 1</code><br>
  974. Der Scan wird mit Root-Rechten ausgef&uuml;hrt.<br>
  975. Voraussetzung ist, dass der Benutzer unter dem FHEM ausgef&uuml;hrt
  976. diese Rechte besitzt. F&uuml;r den Benutzer "fhem", auf einem Debian
  977. (basierten) System, lassen sich diese in der Datei "/etc/sudoers"
  978. festlegen. Daf&uuml;r muss im Abschnitt "# User privilege
  979. specification" die Zeile "fhem ALL=(ALL) NOPASSWD: /usr/bin/nmap"
  980. eingef&uuml;gt werden.
  981. </li>
  982. </ul>
  983. </ul>
  984. </div>
  985. =end html_DE
  986. =cut