1
0

net_utils.pm 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. package eyelib::net_utils;
  2. #
  3. # Copyright (C) Roman Dmitiriev, rnd@rajven.ru
  4. #
  5. use utf8;
  6. use open ":encoding(utf8)";
  7. use strict;
  8. use English;
  9. use FindBin qw($Bin);
  10. use lib "/opt/Eye/scripts";
  11. use base 'Exporter';
  12. use vars qw(@EXPORT @ISA);
  13. use FileHandle;
  14. use POSIX;
  15. use eyelib::config;
  16. use eyelib::main;
  17. use Net::Ping;
  18. use Net::Patricia;
  19. use NetAddr::IP;
  20. use Net::DNS;
  21. our @ISA = qw(Exporter);
  22. our @EXPORT = qw(
  23. $RFC1918
  24. $Special_Nets
  25. $Loopback
  26. IPv4Numeric
  27. is_gate_valid
  28. CheckIP
  29. GetDhcpRange
  30. GetIpRange
  31. GetIP
  32. GetSubNet
  33. is_ip
  34. is_ipip_valid
  35. is_ip_valid
  36. print_net
  37. ping
  38. HostIsLive
  39. InitSubnets
  40. mac_simplify
  41. isc_mac_simplify
  42. mac_cisco
  43. mac2dec
  44. mac_splitted
  45. ResolveNames
  46. );
  47. BEGIN
  48. {
  49. #local nets
  50. our $RFC1918;
  51. our $Special_Nets;
  52. our $Loopback;
  53. #------------------------------------------------------------------------------------------------------------
  54. sub ResolveNames {
  55. my $hostname = shift;
  56. my $ns_ip = shift;
  57. my @result=();
  58. my $res = Net::DNS::Resolver->new;
  59. $res->nameservers($ns_ip) if ($ns_ip);
  60. my $query = $res->search($hostname,"A");
  61. my $result;
  62. if ($query) {
  63. foreach my $rr ($query->answer) { push(@result,$result = $rr->address); }
  64. }
  65. return (@result);
  66. }
  67. #------------------------------------------------------------------------------------------------------------
  68. sub IPv4Numeric {
  69. my $ip = shift;
  70. return 0 if (!$ip);
  71. my $net=NetAddr::IP->new($ip);
  72. return $net->numeric();
  73. }
  74. #------------------------------------------------------------------------------------------------------------
  75. sub is_gate_valid {
  76. my $ip_str = trim($_[0]);
  77. if ($ip_str =~ /([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})(\/[0-9]{1,2}){0,1}/) {
  78. my $mask = $5;
  79. return 0 if($1 > 255 || $2 > 255 || $3 > 255 || $4 > 255);
  80. $mask =~s/\/// if ($mask);
  81. $mask = 32 if (!$mask);
  82. return 0 if ($mask > 31);
  83. if ($Special_Nets->match_string($ip_str)) { log_error("$ip_str in illegal net range"); return 0; };
  84. return 1;
  85. }
  86. return 0;
  87. }
  88. #---------------------------------------------------------------------------------------------------------
  89. sub CheckIP {
  90. my $ip_str = shift;
  91. return 0 if (!$ip_str);
  92. $ip_str = trim($ip_str);
  93. if ($ip_str =~ /([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})(\/[0-9]{1,2}){0,1}/) {
  94. my $mask = $5;
  95. return 0 if($1 > 255 || $2 > 255 || $3 > 255 || $4 > 255);
  96. $mask =~s/\/// if ($mask);
  97. $mask = 32 if (!$mask);
  98. my $ip = NetAddr::IP->new($ip_str)->addr();
  99. if ($mask<32) { $ip = $ip."/".$mask; }
  100. return $ip;
  101. }
  102. return 0;
  103. }
  104. #--------------------------------------------------------------------------------------------------------
  105. sub GetDhcpRange {
  106. my $gate_ip = trim($_[0]);
  107. my $mask;
  108. if ($gate_ip =~ /([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})(\/[0-9]{1,2}){0,1}/) {
  109. $mask = $5;
  110. return if($1 > 255 || $2 > 255 || $3 > 255 || $4 > 255);
  111. $mask =~s/\/// if ($mask);
  112. $mask = 32 if ((!$mask) or ($mask >32));
  113. } else { return; }
  114. my $gate = NetAddr::IP->new($gate_ip)->addr();
  115. my $net=NetAddr::IP->new($gate."/".$mask);
  116. my %dhcp;
  117. $dhcp{gate} = $gate;
  118. $dhcp{network} = $net->network()->addr();
  119. $dhcp{broadcast} = $net->broadcast()->addr();
  120. $dhcp{mask} = $net->mask();
  121. $dhcp{masklen} = $net->masklen();
  122. $dhcp{first_ip} = $net->first()->addr();
  123. $dhcp{count} = $net->broadcast() - $net->network() - 2;
  124. if ($mask < 32) {
  125. if ($dhcp{first_ip} eq $dhcp{gate}) {
  126. $dhcp{first_ip} = $net->nth(1)->addr();
  127. }
  128. $dhcp{last_ip} = $net->last()->addr();
  129. if ($dhcp{last_ip} eq $dhcp{gate}) {
  130. $dhcp{last_ip} = $net->nth($dhcp{count}-1)->addr();
  131. }
  132. }
  133. return \%dhcp;
  134. }
  135. #--------------------------------------------------------------------------------------------------------
  136. sub GetIpRange {
  137. my $gate_ip = trim($_[0]);
  138. my $mask = 30;
  139. if ($gate_ip =~ /([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})(\/[0-9]{1,2}){0,1}/) {
  140. $mask = $5;
  141. return if($1 > 255 || $2 > 255 || $3 > 255 || $4 > 255);
  142. $mask =~s/\/// if ($mask);
  143. $mask = 30 if ((!$mask) or ($mask >30));
  144. } else { return; }
  145. my $gate = NetAddr::IP->new($gate_ip)->addr();
  146. my $net=NetAddr::IP->new($gate."/".$mask);
  147. my @range=();
  148. if ($mask >=29) {
  149. my $ip_count = $net->broadcast() - $net->network() - 2;
  150. for (my $index = 1; $index<=$ip_count; $index++) {
  151. my $ip = $net->nth($index)->addr();
  152. next if ($ip eq $gate);
  153. push(@range,$ip."/32");
  154. }
  155. } else {
  156. push(@range,$net->network()->addr()."/".$mask);
  157. }
  158. return \@range;
  159. }
  160. #--------------------------------------------------------------------------------------------------------
  161. sub GetIP {
  162. my $ip_str = trim($_[0]);
  163. if ($ip_str =~ /([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})(\/[0-9]{1,2}){0,1}/) {
  164. return if($1 > 255 || $2 > 255 || $3 > 255 || $4 > 255);
  165. return NetAddr::IP->new($ip_str)->addr();
  166. }
  167. return;
  168. }
  169. #---------------------------------------------------------------------------------------------------------
  170. sub GetSubNet {
  171. my $ip_str = trim($_[0]);
  172. my $mask = 32;
  173. if ($ip_str =~ /([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})(\/[0-9]{1,2}){0,1}/) {
  174. $mask = $5;
  175. return if($1 > 255 || $2 > 255 || $3 > 255 || $4 > 255);
  176. $mask =~s/\/// if ($mask);
  177. $mask = 32 if (!$mask);
  178. }
  179. else { return; }
  180. my $ip = NetAddr::IP->new($ip_str)->network()->addr();
  181. return $ip."/".$mask;
  182. }
  183. #---------------------------------------------------------------------------------------------------------
  184. sub is_ipip_valid {
  185. my $ip1 = shift;
  186. my $ip2 = shift;
  187. my $lo1 = 0;
  188. my $lo2 = 0;
  189. my $ok = 0;
  190. eval {
  191. if ($ip1) {
  192. if ($ip1 ne "0/0") {
  193. $lo1 = $Loopback->match_string($ip1);
  194. $lo1 = 1 if ($lo1);
  195. }
  196. };
  197. if ($ip2) {
  198. if ($ip2 ne "0/0") {
  199. $lo2 = $Loopback->match_string($ip1);
  200. $lo2 = 1 if ($lo2);
  201. }
  202. };
  203. if (!$lo1) { $lo1=0; };
  204. if (!$lo2) { $lo2=0; };
  205. $ok = ((($ip1 ne "0/0") or ($ip2 ne "0/0")) and ($lo1==0) and ($lo2==0));
  206. };
  207. return $ok;
  208. }
  209. #---------------------------------------------------------------------------------------------------------
  210. sub is_ip {
  211. my $ip_str = trim($_[0]);
  212. return 1 if (!$ip_str);
  213. return 1 if ($ip_str eq '0/0');
  214. if ($ip_str =~ /([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})(\/[0-9]{1,2}){0,1}/) {
  215. my $mask = $5;
  216. return 0 if($1 > 255 || $2 > 255 || $3 > 255 || $4 > 255);
  217. $mask =~s/\/// if ($mask);
  218. $mask = 32 if (!$mask);
  219. return 0 if ($mask > 32);
  220. return 1;
  221. }
  222. return 0;
  223. }
  224. #---------------------------------------------------------------------------------------------------------
  225. sub is_ip_valid {
  226. my $ip_str = trim($_[0]);
  227. if ($ip_str =~ /([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})(\/[0-9]{1,2}){0,1}/) {
  228. my $mask = $5;
  229. return 0 if($1 > 255 || $2 > 255 || $3 > 255 || $4 > 255);
  230. $mask =~s/\/// if ($mask);
  231. $mask = 32 if (!$mask);
  232. return 0 if ($mask > 32);
  233. if ($Special_Nets->match_string($ip_str)) { log_error("$ip_str in illegal net range"); return 0; };
  234. return 1;
  235. }
  236. return 0;
  237. }
  238. #---------------------------------------------------------------------------------------------------------
  239. sub print_net {
  240. my $ip = shift;
  241. my $max_mask = shift || 26;
  242. return if (!$ip);
  243. my @result = ();
  244. my $user_ip=NetAddr::IP->new($ip);
  245. my $netmask = $user_ip->masklen();
  246. return if ($netmask<$max_mask);
  247. my $ip_first = $user_ip->network();
  248. my $ip_last = $user_ip->broadcast();
  249. my $ip_count = $ip_last - $ip_first;
  250. if ($ip_count) {
  251. for (my $i=0; $i<=$ip_count; $i++) {
  252. my $ip1 = $ip_first;
  253. $ip1=~s/\/\d+$//g;
  254. push(@result,$ip1);
  255. $ip_first ++;
  256. }
  257. } else {
  258. $ip_first=~s/\/\d+$//g;
  259. push(@result,$ip_first);
  260. }
  261. return @result;
  262. }
  263. #---------------------------------------------------------------------------------------------------------
  264. sub ping {
  265. use Net::Ping;
  266. use Time::HiRes;
  267. my ($host,$time) = @_;
  268. my $p = Net::Ping->new();
  269. $p->hires();
  270. my ($ret, $duration, $ip) = $p->ping($host, $time);
  271. $p->close();
  272. $ret ? return 1: return 0;
  273. }
  274. #---------------------------------------------------------------------------------------------------------
  275. sub HostIsLive {
  276. my $host=shift;
  277. my $proto=shift;
  278. my $ok = 0;
  279. my $p;
  280. if ($proto and $proto=~/(icmp|tcp)/i) {
  281. $p = Net::Ping->new($proto);
  282. $ok = $p->ping($host,5);
  283. $p->close();
  284. return $ok;
  285. }
  286. if (!$proto) {
  287. eval {
  288. $p = Net::Ping->new('icmp');
  289. $ok = $p->ping($host,5);
  290. $p->close();
  291. };
  292. if ($@) {
  293. eval {
  294. $p = Net::Ping->new('tcp');
  295. $ok = $p->ping($host,5);
  296. $p->close();
  297. };
  298. if ($@) { return 0; }
  299. }
  300. }
  301. return $ok;
  302. }
  303. #----------------------------------------------------------------------------------
  304. sub InitSubnets {
  305. $RFC1918 = new Net::Patricia;
  306. #local nets RFC1918
  307. $RFC1918->add_string("192.168.0.0/16");
  308. $RFC1918->add_string("10.0.0.0/8");
  309. $RFC1918->add_string("172.16.0.0/12");
  310. #----------------------------------------------------------------------------------
  311. $Special_Nets = new Net::Patricia;
  312. #"This" Network [RFC1700, page 4]
  313. $Special_Nets->add_string("0.0.0.0/8");
  314. #Public-Data Networks [RFC1700, page 181]
  315. #$Special_Nets->add_string("14.0.0.0/8");
  316. #Cable Television Networks
  317. #$Special_Nets->add_string("24.0.0.0/8");
  318. #Reserved - [RFC1797]
  319. #$Special_Nets->add_string("39.0.0.0/8");
  320. #loopback [RFC1700, page 5]
  321. $Special_Nets->add_string("127.0.0.0/8");
  322. #Reserved
  323. $Special_Nets->add_string("128.0.0.0/16");
  324. #Link Local
  325. $Special_Nets->add_string("169.254.0.0/16");
  326. #Reserved
  327. #$Special_Nets->add_string("191.255.0.0/16");
  328. #Reserved
  329. #$Special_Nets->add_string("192.0.0.0/24");
  330. #Test-Net
  331. #$Special_Nets->add_string("192.0.2.0/24");
  332. #6to4 Relay Anycast [RFC3068]
  333. $Special_Nets->add_string("192.88.99.0/24");
  334. #Network Interconnect Device Benchmark Testing [RFC2544]
  335. #$Special_Nets->add_string("198.18.0.0/15");
  336. #Reserved
  337. #$Special_Nets->add_string("223.255.255.0/24");
  338. #Multicast [RFC3171]
  339. $Special_Nets->add_string("224.0.0.0/4");
  340. #Reserved for Future Use [RFC1700, page 4]
  341. #$Special_Nets->add_string("240.0.0.0/4");
  342. #----------------------------------------------------------------------------------
  343. $Loopback = new Net::Patricia;
  344. #loopback [RFC1700, page 5]
  345. $Loopback->add_string("127.0.0.0/8");
  346. }
  347. #--------------------------------- Utils ------------------------------------------
  348. sub mac_simplify{
  349. my $mac=shift;
  350. return if (!$mac);
  351. $mac=~s/\.//g;
  352. $mac=~s/://g;
  353. $mac=~s/-//g;
  354. $mac=~tr/[A-Z]/[a-z]/;
  355. my $result=substr($mac,0,12);
  356. return $result;
  357. }
  358. #--------------------------------------------------------------------------------
  359. sub mac_cisco{
  360. my $mac=shift;
  361. return if (!$mac);
  362. $mac=mac_simplify($mac);
  363. $mac=~s/(\S{4})(\S{4})(\S{4})/$1\.$2\.$3/g;
  364. return $mac;
  365. }
  366. #--------------------------------------------------------------------------------
  367. sub mac2dec{
  368. my $mac=shift;
  369. return if (!$mac);
  370. $mac=mac_simplify($mac);
  371. $mac=mac_splitted($mac);
  372. my @m=split(":",$mac);
  373. $mac="";
  374. foreach my $i (@m) { $mac=$mac.".".hex($i); }
  375. $mac=~s/^\.//;
  376. return $mac;
  377. }
  378. #--------------------------------------------------------------------------------
  379. sub isc_mac_simplify{
  380. my $mac=shift;
  381. return if (!$mac);
  382. my @mac_array;
  383. foreach my $octet (split(/\:/,$mac)){
  384. my $dec=hex($octet);
  385. push(@mac_array,sprintf("%02x",$dec));
  386. }
  387. $mac=join('',@mac_array);
  388. return $mac;
  389. }
  390. #--------------------------------------------------------------------------------
  391. sub mac_splitted{
  392. my $mac=shift;
  393. return if (!$mac);
  394. my $ch=shift || ":";
  395. $mac=mac_simplify($mac);
  396. $mac=~s/(\S{2})(\S{2})?(\S{2})?(\S{2})?(\S{2})?(\S{2})?/$1:$2:$3:$4:$5:$6/g;
  397. $mac=~s/\:+$//g;
  398. if ($ch ne ":") { $mac=~s/\:/$ch/g; }
  399. return $mac;
  400. }
  401. InitSubnets();
  402. 1;
  403. }