1<?php 2 3/** 4 * phpIPAM IP addresses class 5 */ 6 7class Addresses extends Common_functions { 8 9 10 /** 11 * (array of objects) to store addresses, address ID is array index 12 * 13 * (default value: array) 14 * 15 * @var mixed 16 * @access public 17 */ 18 public $addresses = array(); 19 20 /** 21 * Address types array 22 * 23 * @var mixed 24 * @access public 25 */ 26 public $address_types = array(); 27 28 /** 29 * Mail changelog or not 30 * 31 * (default value: true) 32 * 33 * @var bool 34 * @access public 35 */ 36 public $mail_changelog = true; 37 38 /** 39 * Last insert id 40 * 41 * (default value: false) 42 * 43 * @var bool 44 * @access public 45 */ 46 public $lastId = false; 47 48 /** 49 * Subnets object 50 * 51 * @var mixed 52 * @access protected 53 */ 54 protected $Subnets; 55 56 /** 57 * PowerDNS object 58 * 59 * @var mixed 60 * @access private 61 */ 62 private $PowerDNS; 63 64 65 66 67 /** 68 * __construct function 69 * 70 * @access public 71 */ 72 public function __construct (Database_PDO $Database) { 73 parent::__construct(); 74 75 # Save database object 76 $this->Database = $Database; 77 # initialize Result 78 $this->Result = new Result (); 79 80 # Log object 81 $this->Log = new Logging ($this->Database); 82 } 83 84 85 86 87 88 89 90 91 92 /** 93 * @address tag methods 94 * ------------------------------- 95 */ 96 97 /** 98 * Returns array of address types. 99 * 100 * @access public 101 * @return array of address types and parameters 102 */ 103 public function addresses_types_fetch () { 104 # fetch 105 $types = $this->fetch_all_objects ("ipTags", "id"); 106 107 # save to array 108 $types_out = array(); 109 foreach($types as $t) { 110 $types_out[$t->id] = (array) $t; 111 } 112 # save 113 $this->address_types = $types_out; 114 # return 115 return $types_out; 116 } 117 118 /** 119 * Sets address tag 120 * 121 * @access public 122 * @param int $state 123 * @return mixed tag 124 */ 125 public function address_type_format_tag ($state) { 126 # fetch address states 127 $this->addresses_types_fetch(); 128 # result 129 if(!isset($this->address_types[$state])) { 130 return ""; 131 } 132 else { 133 if($this->address_types[$state]['showtag']==1) { 134 return "<i class='fa fa-".$this->address_types[$state]['type']." fa-tag state' rel='tooltip' style='color:".$this->address_types[$state]['bgcolor']."' title='"._($this->address_types[$state]['type'])."'></i>"; 135 } 136 } 137 } 138 139 /** 140 * returns address type from index 141 * 142 * 1 > Offline 143 * 144 * @access public 145 * @param int $index 146 * @return mixed address type 147 */ 148 public function address_type_index_to_type ($index) { 149 # fetch address states 150 $this->addresses_types_fetch(); 151 # return 152 if(isset($this->address_types[$index])) { 153 return $this->address_types[$index]['type']; 154 } 155 else { 156 return $index; 157 } 158 } 159 160 /** 161 * Returns address index from type 162 * 163 * Offline > 1 164 * 165 * @access public 166 * @param mixed $type 167 * @return void 168 */ 169 public function address_type_type_to_index ($type = "Used") { 170 # null of no length 171 $type = strlen($type)==0 || is_null($type) ? "Used" : $type; 172 # fetch address states 173 $this->addresses_types_fetch(); 174 # reindex 175 $states_assoc = array(); 176 foreach($this->address_types as $s) { 177 $states_assoc[$s['type']] = $s; 178 } 179 # return 180 if(isset($states_assoc[$type])) { 181 return $states_assoc[$type]['id']; 182 } 183 else { 184 return $type; 185 } 186 } 187 188 189 190 191 192 193 194 195 196 197 198 199 /** 200 * @address methods 201 * ------------------------------- 202 */ 203 204 /** 205 * Fetches address by specified method 206 * 207 * @access public 208 * @param string $method (default: "id") 209 * @param mixed $id 210 * @return object address 211 */ 212 public function fetch_address ($method, $id) { 213 # null method 214 $method = is_null($method) ? "id" : $method; 215 # check cache first 216 if(isset($this->addresses[$id])) { 217 return $this->addresses[$id]; 218 } 219 else { 220 try { $address = $this->Database->getObjectQuery("SELECT * FROM `ipaddresses` where `$method` = ? limit 1;", array($id)); } 221 catch (Exception $e) { 222 $this->Result->show("danger", _("Error: ").$e->getMessage()); 223 return false; 224 } 225 # save to addresses cache 226 if(!is_null($address)) { 227 # add decimal format 228 $address->ip = $this->transform_to_dotted ($address->ip_addr); 229 # save to subnets 230 $this->addresses[$id] = (object) $address; 231 } 232 #result 233 return !is_null($address) ? $address : false; 234 } 235 } 236 237 /** 238 * Fetch addresses on int ip_addr and subnetId 239 * 240 * @access public 241 * @param mixed $ip_addr 242 * @param mixed $subnetId 243 * @return void 244 */ 245 public function fetch_address_multiple_criteria ($ip_addr, $subnetId) { 246 try { $address = $this->Database->getObjectQuery("SELECT * FROM `ipaddresses` where `ip_addr` = ? and `subnetId` = ? limit 1;", array($ip_addr, $subnetId)); } 247 catch (Exception $e) { 248 $this->Result->show("danger", _("Error: ").$e->getMessage()); 249 return false; 250 } 251 # save to addresses cache 252 if(is_object($address)) { 253 # add decimal format 254 $address->ip = $this->transform_to_dotted ($address->ip_addr); 255 # save to subnets 256 $this->addresses[$address->id] = (object) $address; 257 } 258 #result 259 return !is_null($address) ? $address : false; 260 } 261 262 /** 263 * Bulk fetch similar addresses. 264 * 265 * The subnets details page will call search_similar_addresses() for EVERY IP in the subnet. 266 * Bulk request and cache this information on the first call. Sort returned IPs by ip_addr. 267 * 268 * Returns an array indexed by $value. $bulk_search[$value] = Array of similar IPs with same $value 269 * 270 * @access public 271 * @param object $address 272 * @param mixed $linked_field 273 * @param mixed $value 274 * @return void 275 */ 276 private function bulk_fetch_similar_addresses($address, $linked_field, $value) { 277 // Check cache 278 $cached_item = $this->cache_check("similar_addresses", "f=$linked_field id=$address->subnetId"); 279 if (is_object($cached_item)) 280 return $cached_item->result; 281 282 // Fetch all similar addresses for entire subnet. 283 try { 284 $query = "SELECT * FROM `ipaddresses` WHERE `state`<>4 AND `$linked_field` IN (SELECT `$linked_field` FROM `ipaddresses` WHERE `subnetId`=? AND LENGTH(`$linked_field`)>0) ORDER BY LPAD(ip_addr,39,0)"; 285 $linked_subnet_addrs = $this->Database->getObjectsQuery($query, array($address->subnetId)); 286 } catch (Exception $e) { 287 $this->Result->show("danger", _("Error: ").$e->getMessage()); 288 return false; 289 } 290 291 $bulk_search = []; 292 if (is_array($linked_subnet_addrs)) { 293 foreach($linked_subnet_addrs as $linked) { 294 // Index by $linked->{$linked_field} for easy searching. 295 $bulk_search[$linked->{$linked_field}][] = $linked; 296 } 297 } 298 299 // Save to cache and return 300 $this->cache_write ("similar_addresses", (object) ["id"=>"f=$linked_field id=$address->subnetId", "result" => $bulk_search]); 301 return $bulk_search; 302 } 303 304 /** 305 * Searches database for similar addresses 306 * 307 * @access public 308 * @param object $address 309 * @param mixed $linked_field 310 * @param mixed $value 311 * @return void 312 */ 313 public function search_similar_addresses ($address, $linked_field, $value) { 314 // sanity checks 315 if(!is_object($address) || !property_exists($address, $linked_field) || strlen($value)==0) 316 return false; 317 318 $bulk_search = $this->bulk_fetch_similar_addresses($address, $linked_field, $value); 319 320 // Check if similar addresses exist with the specifed $value 321 if (!isset($bulk_search[$address->{$linked_field}])) 322 return false; 323 324 $results = $bulk_search[$address->{$linked_field}]; 325 // Remove $address from results 326 foreach ($results as $i => $similar) { 327 if ($similar->id == $address->id) unset($results[$i]); 328 } 329 330 return !empty($results) ? $results : false; 331 } 332 333 /** 334 * Address modification 335 * 336 * @access public 337 * @param mixed $address 338 * @param bool $mail_changelog (default: true) 339 * @return void 340 */ 341 public function modify_address ($address, $mail_changelog = true) { 342 # save changelog 343 $this->mail_changelog = $mail_changelog; 344 # null empty values 345 $address = $this->reformat_empty_array_fields ($address, null); 346 # strip tags 347 $address = $this->strip_input_tags ($address); 348 # execute based on action 349 if($address['action']=="add") { return $this->modify_address_add ($address); } //create new address 350 elseif($address['action']=="edit") { return $this->modify_address_edit ($address); } //modify existing address 351 elseif($address['action']=="delete") { return $this->modify_address_delete ($address); } //delete address 352 elseif($address['action']=="move") { return $this->modify_address_move ($address); } //move to new subnet 353 else { return $this->Result->show("danger", _("Invalid action"), true); } 354 } 355 356 /** 357 * Inserts new IP address to table 358 * 359 * @access protected 360 * @param array $address 361 * @return boolean success/failure 362 */ 363 protected function modify_address_add ($address) { 364 # user - permissions 365 $User = new User ($this->Database); 366 # set insert array 367 $insert = array( 368 "ip_addr" => $this->transform_address($address['ip_addr'],"decimal"), 369 "subnetId" => $address['subnetId'], 370 "description" => @$address['description'], 371 "hostname" => @$address['hostname'], 372 "mac" => @$address['mac'], 373 "owner" => @$address['owner'], 374 "state" => @$address['state'], 375 "port" => @$address['port'], 376 "note" => @$address['note'], 377 "is_gateway" => @$address['is_gateway'], 378 "excludePing" => @$address['excludePing'], 379 "PTRignore" => @$address['PTRignore'], 380 "firewallAddressObject" => @$address['firewallAddressObject'], 381 "lastSeen" => @$address['lastSeen'] 382 ); 383 # permissions 384 if($this->api===true || $User->get_module_permissions ("devices")>1) { 385 if (array_key_exists('switch', $address)) { 386 if (empty($address['switch']) || is_numeric($address['switch'])) 387 $insert['switch'] = $address['switch'] > 0 ? $address['switch'] : NULL; 388 } 389 } 390 # customer 391 if($this->api===true || $User->get_module_permissions ("customers")>1) { 392 if (array_key_exists('customer_id', $address)) { 393 if (empty($address['customer_id']) || is_numeric($address['customer_id'])) 394 $insert['customer_id'] = $address['customer_id'] > 0 ? $address['customer_id'] : NULL; 395 } 396 } 397 # location 398 if ($this->api===true || $User->get_module_permissions ("locations")>1) { 399 if (array_key_exists('location_item', $address)) { 400 if (empty($address['location_item']) || is_numeric($address['location_item'])) 401 $insert['location'] = $address['location_item'] > 0 ? $address['location_item'] : NULL; 402 } 403 if (array_key_exists('location', $address)) { 404 if (empty($address['location']) || is_numeric($address['location'])) 405 $insert['location'] = $address['location'] > 0 ? $address['location'] : NULL; 406 } 407 } 408 # custom fields, append to array 409 foreach($this->set_custom_fields() as $c) { 410 $insert[$c['name']] = !empty($address[$c['name']]) ? $address[$c['name']] : $c['Default']; 411 } 412 413 # null empty values 414 $insert = $this->reformat_empty_array_fields ($insert, null); 415 416 # remove gateway 417 if($address['is_gateway']==1) { $this->remove_gateway ($address['subnetId']); } 418 419 # execute 420 try { $this->Database->insertObject("ipaddresses", $insert); } 421 catch (Exception $e) { 422 $this->Log->write( "Address create", "Failed to create new address<hr>".$e->getMessage()."<hr>".$this->array_to_log($this->reformat_empty_array_fields ($address, "NULL")), 2); 423 $this->Result->show("danger", _("Error: ").$e->getMessage(), false); 424 return false; 425 } 426 # save id 427 $this->lastId = $this->Database->lastInsertId(); 428 429 # log and changelog 430 $address['id'] = $this->lastId; 431 $this->Log->write( "Address created", "New address created<hr>".$this->array_to_log($this->reformat_empty_array_fields ($address, "NULL")), 0); 432 $this->Log->write_changelog('ip_addr', "add", 'success', array(), $address, $this->mail_changelog); 433 434 # edit DNS PTR record 435 $this->ptr_modify ("add", $insert); 436 437 # threshold alert 438 $this->threshold_check($address); 439 440 # ok 441 return true; 442 } 443 444 /** 445 * Modifies address in table or whole range if requested 446 * 447 * @access protected 448 * @param array $address 449 * @return boolean success/failure 450 */ 451 protected function modify_address_edit ($address) { 452 # fetch old details for logging 453 $address_old = $this->fetch_address (null, $address['id']); 454 if (isset($address['section'])) $address_old->section = $address['section']; 455 # user - permissions 456 $User = new User ($this->Database); 457 # set update array 458 $insert = array( 459 "id" =>$address['id'], 460 "subnetId" =>$address['subnetId'], 461 "ip_addr" =>$this->transform_address($address['ip_addr'], "decimal"), 462 "description" =>@$address['description'], 463 "hostname" =>@$address['hostname'], 464 "mac" =>@$address['mac'], 465 "owner" =>@$address['owner'], 466 "state" =>@$address['state'], 467 "port" =>@$address['port'], 468 "note" =>@$address['note'], 469 "is_gateway" =>@$address['is_gateway'], 470 "excludePing" =>@$address['excludePing'], 471 "PTRignore" =>@$address['PTRignore'], 472 "lastSeen" =>@$address['lastSeen'] 473 ); 474 # permissions 475 if($this->api===true || $User->get_module_permissions ("devices")>1) { 476 if (array_key_exists('switch', $address)) { 477 if (empty($address['switch']) || is_numeric($address['switch'])) 478 $insert['switch'] = $address['switch'] > 0 ? $address['switch'] : NULL; 479 } 480 } 481 # customer 482 if($this->api===true || $User->get_module_permissions ("customers")>1) { 483 if (array_key_exists('customer_id', $address)) { 484 if (empty($address['customer_id']) || is_numeric($address['customer_id'])) 485 $insert['customer_id'] = $address['customer_id'] > 0 ? $address['customer_id'] : NULL; 486 } 487 } 488 # location 489 if ($this->api===true || $User->get_module_permissions ("locations")>1) { 490 if (array_key_exists('location_item', $address)) { 491 if (empty($address['location_item']) || is_numeric($address['location_item'])) 492 $insert['location'] = $address['location_item'] > 0 ? $address['location_item'] : NULL; 493 } 494 if (array_key_exists('location', $address)) { 495 if (empty($address['location']) || is_numeric($address['location'])) 496 $insert['location'] = $address['location'] > 0 ? $address['location'] : NULL; 497 } 498 } 499 # custom fields, append to array 500 foreach($this->set_custom_fields() as $c) { 501 $insert[$c['name']] = !empty($address[$c['name']]) ? $address[$c['name']] : $c['Default']; 502 } 503 504 # set primary key for update 505 if($address['type']=="series") { 506 $id1 = "subnetId"; 507 $id2 = "ip_addr"; 508 unset($insert['id']); 509 } else { 510 $id1 = "id"; 511 $id2 = null; 512 } 513 514 # remove gateway 515 if($address['is_gateway']==1) { $this->remove_gateway ($address['subnetId']); } 516 517 # execute 518 try { $this->Database->updateObject("ipaddresses", $insert, $id1, $id2); } 519 catch (Exception $e) { 520 $this->Log->write( "Address edit", "Failed to edit address $address[ip_addr]<hr>".$e->getMessage()."<hr>".$this->array_to_log($this->reformat_empty_array_fields ($address, "NULL")), 2); 521 $this->Result->show("danger", _("Error: ").$e->getMessage(), false); 522 return false; 523 } 524 525 # set the firewall address object to avoid logging 526 $address['firewallAddressObject'] = $address_old->firewallAddressObject; 527 528 # log and changelog 529 $this->Log->write( "Address updated", "Address $address[ip_addr] updated<hr>".$this->array_to_log($this->reformat_empty_array_fields ($address, "NULL")), 0); 530 $this->Log->write_changelog('ip_addr', "edit", 'success', (array) $address_old, $address, $this->mail_changelog); 531 532 # edit DNS PTR record 533 $insert['PTR']=@$address['PTR']; 534 $this->ptr_modify ("edit", $insert); 535 536 # ok 537 return true; 538 } 539 540 /** 541 * Deletes address or address range. 542 * 543 * @access protected 544 * @param array $address 545 * @return boolean success/failure 546 */ 547 protected function modify_address_delete ($address) { 548 # fetch old details for logging 549 $address_old = $this->fetch_address (null, $address['id']); 550 if (isset($address['section'])) $address_old->section = $address['section']; 551 552 # series? 553 if($address['type']=="series") { 554 $field = "subnetId"; $value = $address['subnetId']; 555 $field2 = "ip_addr"; $value2 = $this->transform_address ($address['ip_addr'], "decimal"); 556 } else { 557 $field = "id"; $value = $address['id']; 558 $field2 = null; $value2 = null; 559 } 560 # execute 561 try { $this->Database->deleteRow("ipaddresses", $field, $value, $field2, $value2); } 562 catch (Exception $e) { 563 $this->Log->write( "Address delete", "Failed to delete address $address[ip_addr]<hr>".$e->getMessage()."<hr>".$this->array_to_log((array) $address_old), 2); 564 $this->Result->show("danger", _("Error: ").$e->getMessage(), false); 565 return false; 566 } 567 568 # log and changelog 569 $this->Log->write( "Address deleted", "Address $address[ip_addr] deleted<hr>".$this->array_to_log((array) $address_old), 0); 570 $this->Log->write_changelog('ip_addr', "delete", 'success', (array) $address_old, array(), $this->mail_changelog); 571 572 # edit DNS PTR record 573 $this->ptr_modify ("delete", $address); 574 575 # remove all referenced records 576 if(@$address['remove_all_dns_records']=="1") { 577 $this->pdns_remove_ip_and_hostname_records ($address); 578 } 579 # remove from NAT 580 $this->remove_address_nat_items ($address['id'], true); 581 # ok 582 return true; 583 } 584 585 /** 586 * Moves address to new subnet 587 * 588 * @access protected 589 * @param array $address 590 * @return boolean success/failure 591 */ 592 protected function modify_address_move ($address) { 593 # execute 594 try { $this->Database->updateObject("ipaddresses", array("subnetId"=>$address['newSubnet'], "id"=>$address['id'])); } 595 catch (Exception $e) { 596 $this->Result->show("danger", _("Error: ").$e->getMessage(), false); 597 return false; 598 } 599 # ok 600 return true; 601 } 602 603 /** 604 * Remove item from nat when item is removed 605 * 606 * @method remove_nat_item 607 * 608 * @param int $obj_id 609 * @param bool $print 610 * 611 * @return int 612 */ 613 public function remove_address_nat_items ($obj_id = 0, $print = true) { 614 # set found flag for returns 615 $found = 0; 616 # fetch all nats 617 try { $all_nats = $this->Database->getObjectsQuery ("select * from `nat` where `src` like :id or `dst` like :id", array ("id"=>'%"'.$obj_id.'"%')); } 618 catch (Exception $e) { 619 $this->Result->show("danger", _("Error: ").$e->getMessage()); 620 return false; 621 } 622 # loop and check for object ids 623 if(!empty($all_nats)) { 624 # init admin object 625 $Admin = new Admin ($this->Database, false); 626 # loop 627 foreach ($all_nats as $nat) { 628 # remove item from nat 629 $s = json_decode($nat->src, true); 630 $d = json_decode($nat->dst, true); 631 632 if(is_array($s['ipaddresses'])) 633 $s['ipaddresses'] = array_diff($s['ipaddresses'], array($obj_id)); 634 if(is_array($d['ipaddresses'])) 635 $d['ipaddresses'] = array_diff($d['ipaddresses'], array($obj_id)); 636 637 # save back and update 638 $src_new = json_encode(array_filter($s)); 639 $dst_new = json_encode(array_filter($d)); 640 641 # update only if diff found 642 if($s!=$src_new || $d!=$dst_new) { 643 $found++; 644 645 if($Admin->object_modify ("nat", "edit", "id", array("id"=>$nat->id, "src"=>$src_new, "dst"=>$dst_new))!==false) { 646 if($print) { 647 $this->Result->show("success", "Address removed from NAT", false); 648 } 649 } 650 } 651 } 652 } 653 # return 654 return $found; 655 } 656 657 /** 658 * Updates hostname for IP addresses 659 * 660 * @method update_address_hostname 661 * 662 * @param mixed $ip 663 * @param int $id 664 * @param string $hostname 665 * 666 * @return void 667 */ 668 public function update_address_hostname ($ip, $id, $hostname = "") { 669 if(is_numeric($id) && strlen($hostname)>0) { 670 try { $this->Database->updateObject("ipaddresses", array("id"=>$id, "hostname"=>$hostname)); } 671 catch (Exception $e) { 672 return false; 673 } 674 // save log 675 $this->Log->write( "Address DNS resolved", "Address $ip resolved<hr>".$this->array_to_log((array) $hostname), 0); 676 $this->Log->write_changelog('ip_addr', "edit", 'success', array ("id"=>$id, "hostname"=>""), array("id"=>$id, "hostname"=>$hostname), $this->mail_changelog); 677 } 678 } 679 680 /** 681 * Checks if subnet usage is over threshold and sends alert 682 * 683 * @access private 684 * @param mixed $address 685 * @return void 686 */ 687 private function threshold_check ($address) { 688 $address = (object) $address; 689 $content = array(); 690 $content_plain = array(); 691 692 # fetch settings 693 $this->get_settings (); 694 # enabled ? 695 if ($this->settings->enableThreshold=="1") { 696 # object 697 if (!is_object($this->Subnets)) { 698 $this->Subnets = new Subnets ($this->Database); 699 } 700 # fetch subnet 701 $subnet = $this->Subnets->fetch_subnet("id", $address->subnetId); 702 # threshold set ? 703 if ($subnet->threshold>0) { 704 # calculate subnet usage 705 $subnet_usage = $this->Subnets->calculate_subnet_usage ($subnet); 706 # if over send mail 707 if (gmp_strval(gmp_sub(100,(int) round($subnet_usage['freehosts_percent'], 0))) > $subnet->threshold) { 708 // fetch mail settings 709 $Tools = new Tools ($this->Database); 710 $admins = $Tools->fetch_multiple_objects ("users", "role", "Administrator"); 711 // if some recipients 712 if ($admins !== false) { 713 # try to send 714 try { 715 // mail settings 716 $mail_settings = $Tools->fetch_object ("settingsMail", "id", 1); 717 // mail class 718 $phpipam_mail = new phpipam_mail ($this->settings, $mail_settings); 719 720 // set parameters 721 $subject = "Subnet threshold limit reached"." (".$this->transform_address($subnet->subnet,"dotted")."/".$subnet->mask.")"; 722 $content[] = "<table style='margin-left:10px;margin-top:5px;width:auto;padding:0px;border-collapse:collapse;'>"; 723 $content[] = "<tr><td style='padding:5px;margin:0px;color:#333;font-size:16px;text-shadow:1px 1px 1px white;border-bottom:1px solid #eeeeee;' colspan='2'>$this->mail_font_style<strong>$subject</font></td></tr>"; 724 $content[] = '<tr><td style="padding: 0px;padding-left:10px;margin:0px;line-height:18px;text-align:left;">'.$this->mail_font_style.''._('Subnet').'</a></font></td> <td style="padding: 0px;padding-left:15px;margin:0px;line-height:18px;text-align:left;padding-top:10px;"><a href="'.$this->createURL().''.create_link("subnets",$subnet->sectionId, $subnet->id).'">'.$this->mail_font_style_href . $this->transform_address($subnet->subnet,"dotted")."/".$subnet->mask .'</font></a></td></tr>'; 725 $content[] = '<tr><td style="padding: 0px;padding-left:10px;margin:0px;line-height:18px;text-align:left;">'.$this->mail_font_style.''._('Description').'</font></td> <td style="padding: 0px;padding-left:15px;margin:0px;line-height:18px;text-align:left;">'.$this->mail_font_style.''. $subnet->description .'</font></td></tr>'; 726 $content[] = '<tr><td style="padding: 0px;padding-left:10px;margin:0px;line-height:18px;text-align:left;">'.$this->mail_font_style.''._('Usage').' (%)</font></td> <td style="padding: 0px;padding-left:15px;margin:0px;line-height:18px;text-align:left;">'.$this->mail_font_style.''. gmp_strval(gmp_sub(100,(int) round($subnet_usage['freehosts_percent'], 0))) .'</font></td></tr>'; 727 $content[] = "</table>"; 728 // plain 729 $content_plain[] = "$subject"."\r\n------------------------------\r\n"; 730 $content_plain[] = _("Subnet").": ".$this->transform_address($subnet->subnet,"dotted")."/".$subnet->mask; 731 $content_plain[] = _("Usage")." (%) : ".gmp_strval(gmp_sub(100,(int) round($subnet_usage['freehosts_percent'], 0))); 732 733 # set content 734 $content = $phpipam_mail->generate_message (implode("\r\n", $content)); 735 $content_plain = implode("\r\n",$content_plain); 736 737 $phpipam_mail->Php_mailer->setFrom($mail_settings->mAdminMail, $mail_settings->mAdminName); 738 //add all admins to CC 739 $recipients = $this->changelog_mail_get_recipients ($subnet->id); 740 741 if ($recipients!==false) { 742 foreach($recipients as $a) { 743 $phpipam_mail->Php_mailer->addAddress($a->email); 744 } 745 746 $phpipam_mail->Php_mailer->Subject = $subject; 747 $phpipam_mail->Php_mailer->msgHTML($content); 748 $phpipam_mail->Php_mailer->AltBody = $content_plain; 749 //send 750 $phpipam_mail->Php_mailer->send(); 751 } 752 else { 753 return true; 754 } 755 } catch (phpmailerException $e) { 756 $this->Result->show("danger", "Mailer Error: ".$e->errorMessage(), true); 757 } catch (Exception $e) { 758 $this->Result->show("danger", "Mailer Error: ".$e->getMessage(), true); 759 } 760 } 761 } 762 } 763 else { 764 return true; 765 } 766 } 767 else { 768 return true; 769 } 770 } 771 772 /** 773 * Removes gateway if it exists 774 * 775 * @access public 776 * @param mixed $subnetId 777 * @return void 778 */ 779 public function remove_gateway ($subnetId) { 780 try { $this->Database->updateObject("ipaddresses", array("subnetId"=>$subnetId, "is_gateway"=>0), "subnetId"); } 781 catch (Exception $e) { 782 $this->Result->show("danger", _("Error: ").$e->getMessage()); 783 return false; 784 } 785 } 786 787 /** 788 * Fetches custom IP address fields 789 * 790 * @access public 791 * @return object custom address fields 792 */ 793 public function set_custom_fields () { 794 # Tools object 795 $Tools = new Tools ($this->Database); 796 # fetch 797 return $Tools->fetch_custom_fields ('ipaddresses'); 798 } 799 800 /** 801 * Checks if address already exists in subnet 802 * 803 * if cnt is false we will return id if it exists and false ifnot 804 * 805 * @access public 806 * @param int $address 807 * @param int $subnetId 808 * @param int $subnetId 809 * @return boolean success/failure 810 */ 811 public function address_exists ($address, $subnetId, $cnt = true) { 812 # make sure it is in decimal format 813 $address = $this->transform_address($address, "decimal"); 814 # check 815 if($cnt===true) { $query = "select count(*) as `cnt` from `ipaddresses` where `subnetId`=? and `ip_addr`=?;"; } 816 else { $query = "select `id` from `ipaddresses` where `subnetId`=? and `ip_addr`=?;"; } 817 # fetch 818 try { $count = $this->Database->getObjectQuery($query, array($subnetId, $address)); } 819 catch (Exception $e) { 820 $this->Result->show("danger", _("Error: ").$e->getMessage()); 821 return false; 822 } 823 # result 824 if ($cnt===true) { return $count->cnt==0 ? false : true; } 825 else { return is_null($count->id) ? false : $count->id; } 826 } 827 828 /** 829 * Calculates diff between two IP addresses 830 * 831 * @access public 832 * @param int $ip1 833 * @param int $ip2 834 * @return void 835 */ 836 public function calculate_address_diff ($ip1, $ip2) { 837 return gmp_strval(gmp_sub($ip2, $ip1)); 838 } 839 840 841 /** 842 * Returns first available subnet address, false if none 843 * 844 * @access public 845 * @param int $subnetId 846 * @param obj $Subnets 847 * @return int / false 848 */ 849 public function get_first_available_address ($subnetId, $Subnets) { 850 851 # fetch all addresses in subnet and subnet 852 $addresses = $this->fetch_subnet_addresses ($subnetId, "ip_addr", "asc", array("ip_addr")); 853 if (!is_array($addresses)) { $addresses = array(); } 854 $subnet = (array) $Subnets->fetch_subnet(null, $subnetId); 855 856 # if folder return false 857 if ($subnet['isFolder']=="1") { return false; } 858 859 # false if slaves 860 $this->Subnets = new Subnets ($this->Database); 861 if($this->Subnets->has_slaves ($subnetId)) { return false; } 862 863 # get max hosts 864 $max_hosts = $Subnets->get_max_hosts ($subnet['mask'], $this->identify_address($subnet['subnet'])); 865 866 # full subnet? 867 if(sizeof($addresses)>=$max_hosts) { return false; } //full subnet 868 869 # set type 870 $ip_version = $this->identify_address ($subnet['subnet']); 871 # get first diff > 1 872 if(sizeof($addresses)>0) { 873 foreach($addresses as $k=>$ipaddress) { 874 # check subnet and first IP 875 if($k==0) { 876 # /31 fix 877 if($subnet['mask']==31) { 878 if(gmp_strval(gmp_sub($addresses[$k]->ip_addr, $subnet['subnet']))>0) { return gmp_strval($subnet['subnet']); } 879 } else { 880 if(gmp_strval(gmp_sub($addresses[$k]->ip_addr, $subnet['subnet']))>1) { return gmp_strval(gmp_add($subnet['subnet'], 1)); } 881 elseif($ip_version=="IPv6") { 882 if(sizeof($addresses)==1) { 883 if(gmp_strval(gmp_sub($addresses[$k]->ip_addr, $subnet['subnet']))==0) { return gmp_strval(gmp_add($subnet['subnet'], 1)); } 884 } 885 } 886 } 887 } 888 else { 889 if(gmp_strval(gmp_sub($addresses[$k]->ip_addr, $addresses[$k-1]->ip_addr))>1) { return gmp_strval(gmp_add($addresses[$k-1]->ip_addr, 1)); } 890 } 891 } 892 # all consecutive, last + 1 893 { return gmp_strval(gmp_add($addresses[$k]->ip_addr, 1)); } 894 } 895 # no addresses 896 else { 897 # /32, /31 898 if($subnet['mask']==32 || $subnet['mask']==31 || $ip_version=="IPv6") { return $subnet['subnet']; } 899 else { return gmp_strval(gmp_add($subnet['subnet'], 1)); } 900 } 901 } 902 903 904 905 906 907 908 909 910 911 /** 912 * @powerDNS 913 * ------------------------------- 914 */ 915 916 /** 917 * Modifes powerDNS PTR record 918 * 919 * @access public 920 * @param mixed $action 921 * @param mixed $address 922 * @param bool $print_error (default: true) 923 * @return void 924 */ 925 public function ptr_modify ($action, $address, $print_error = true) { 926 // fetch settings 927 $this->get_settings (); 928 //check if powerdns enabled 929 if ($this->settings->enablePowerDNS!=1) { 930 return false; 931 } 932 //enabled, proceed 933 else { 934 // first check if subnet selected for PTR records 935 $this->initialize_subnets_object (); 936 $subnet = $this->Subnets->fetch_subnet ("id", $address['subnetId']); 937 if ($subnet->DNSrecursive!="1") { return false; } 938 939 // ignore if PTRignore set 940 if ($address['PTRignore']=="1") { 941 // validate db 942 $this->pdns_validate_connection (); 943 // remove if it exists 944 if ($this->ptr_exists ($address['PTR'])) { 945 $this->ptr_delete ($address, false); 946 { return false; } 947 } 948 else { 949 { return true; } 950 } 951 } 952 // validate db 953 $this->pdns_validate_connection (); 954 955 // to object 956 $address = (object) $address; 957 # execute based on action 958 if($action=="add") { return $this->ptr_add ($address, $print_error); } //create new PTR 959 elseif($action=="edit") { return $this->ptr_edit ($address, $print_error); } //modify existing PTR 960 elseif($action=="delete") { return $this->ptr_delete ($address, $print_error); } //delete PTR 961 else { return $this->Result->show("danger", _("Invalid PDNS action"), true); } 962 } 963 } 964 965 /** 966 * This function removes all records - ip and hostname referenced by address. 967 * 968 * @access public 969 * @param mixed $address 970 * @return void 971 */ 972 public function pdns_remove_ip_and_hostname_records ($address) { 973 // fetch settings 974 $this->get_settings (); 975 //check if powerdns enabled 976 if ($this->settings->enablePowerDNS!=1) { 977 return false; 978 } 979 // validate db 980 $this->pdns_validate_connection (); 981 // execute 982 return $this->PowerDNS->pdns_remove_ip_and_hostname_records ($address['hostname'], $address['ip_addr']); 983 } 984 985 /** 986 * Validates pdns database connection 987 * 988 * @access public 989 * @param bool $die (default: false) 990 * @return void 991 */ 992 public function pdns_validate_connection ($die = true) { 993 # powerDNS class 994 $this->PowerDNS = new PowerDNS ($this->Database); 995 # add API info 996 if(isset($this->api)) { 997 $this->PowerDNS->api = $this->api; 998 } 999 # check connection 1000 if($this->PowerDNS->db_check()===false && $die) { $this->Result->show("danger", _("Cannot connect to powerDNS database"), true); } 1001 # get settings 1002 $this->get_settings (); 1003 } 1004 1005 /** 1006 * Set zone name and fetch domain details 1007 * 1008 * @access private 1009 * @param mixed $subnet_id 1010 * @return array|false 1011 */ 1012 private function pdns_fetch_domain ($subnet_id) { 1013 # initialize subnets 1014 $this->initialize_subnets_object (); 1015 // fetch subnet 1016 $subnet = $this->Subnets->fetch_subnet ("id", $subnet_id); 1017 if($subnet===false) { $this->Result->show("danger", _("Invalid subnet Id"), true); } 1018 1019 // set PTR zone name from IP/mash 1020 $zone = $this->PowerDNS->get_ptr_zone_name ($this->transform_address ($subnet->subnet, "dotted"), $subnet->mask); 1021 // try to fetch 1022 return $this->PowerDNS->fetch_domain_by_name ($zone); 1023 } 1024 1025 /** 1026 * Create new PTR record when adding new IP address 1027 * 1028 * @access public 1029 * @param mixed $address 1030 * @param mixed $print_error (default: true) 1031 * @param mixed $id (default: NULL) 1032 * @return void 1033 */ 1034 public function ptr_add ($address, $print_error = true, $id = null) { 1035 // decode values 1036 $values = json_decode($this->settings->powerDNS); 1037 1038 // set default hostname for PTR if set 1039 if (strlen($address->hostname)==0) { 1040 if (strlen($values->def_ptr_domain)>0) { 1041 $address->hostname = $values->def_ptr_domain; 1042 } 1043 } 1044 // validate hostname 1045 if ($this->validate_hostname ($address->hostname)===false) { return false; } 1046 // fetch domain 1047 $domain = $this->pdns_fetch_domain ($address->subnetId); 1048 1049 // formulate new record 1050 $record = $this->PowerDNS->formulate_new_record ($domain->id, $this->PowerDNS->get_ip_ptr_name ($this->transform_address ($address->ip_addr, "dotted")), "PTR", $address->hostname, $values->ttl); 1051 // insert record 1052 $this->PowerDNS->add_domain_record ($record, false); 1053 // link to address 1054 $id = $id===null ? $this->lastId : $id; 1055 $this->ptr_link ($id, $this->PowerDNS->lastId); 1056 // ok 1057 if ($print_error && php_sapi_name()!="cli") 1058 $this->Result->show("success", "PTR record created", false); 1059 1060 return true; 1061 } 1062 1063 /** 1064 * Edits PTR 1065 * 1066 * @access public 1067 * @param mixed $address 1068 * @param mixed $print_error (default: true) 1069 * @return void 1070 */ 1071 public function ptr_edit ($address, $print_error = true) { 1072 // validate hostname 1073 if ($this->validate_hostname ($address->hostname)===false) { 1074 // remove pointer if it exists! 1075 if ($this->ptr_exists ($address->PTR)===true) { $this->ptr_delete ($address, $print_error); } 1076 else { return false; } 1077 } 1078 1079 // new record 1080 if ($this->ptr_exists ($address->PTR)===false) { 1081 // fake lastid 1082 $this->lastId = $address->id; 1083 // new ptr record 1084 $this->ptr_add ($address, true); 1085 } 1086 // update PTR 1087 else { 1088 // fetch domain 1089 $domain = $this->pdns_fetch_domain ($address->subnetId); 1090 1091 // fetch old 1092 $old_record = $this->PowerDNS->fetch_record ($address->PTR); 1093 1094 // create insert array 1095 $update = $this->PowerDNS->formulate_update_record ($this->PowerDNS->get_ip_ptr_name ($this->transform_address ($address->ip_addr, "dotted")), null, $address->hostname, null, null, null, $old_record->change_date); 1096 $update['id'] = $address->PTR; 1097 1098 // update 1099 $this->PowerDNS->update_domain_record ($domain->id, $update, $print_error); 1100 // ok 1101 if ($print_error && php_sapi_name()!="cli") 1102 $this->Result->show("success", "PTR record updated", false); 1103 } 1104 } 1105 1106 /** 1107 * Remove PTR from database 1108 * 1109 * @access public 1110 * @param mixed $address 1111 * @param mixed $print_error 1112 * @return void 1113 */ 1114 public function ptr_delete ($address, $print_error) { 1115 $address = (object) $address; 1116 1117 // remove link from ipaddresses 1118 $this->ptr_unlink ($address->id); 1119 1120 // exists 1121 if ($this->ptr_exists ($address->PTR)!==false) { 1122 // fetch domain 1123 $domain = $this->pdns_fetch_domain ($address->subnetId); 1124 //remove 1125 $this->PowerDNS->remove_domain_record ($domain->id, $address->PTR); 1126 // ok 1127 if ($print_error && php_sapi_name()!="cli") 1128 $this->Result->show("success", "PTR record removed", false); 1129 } 1130 } 1131 1132 /** 1133 * Links PTR record with address record 1134 * 1135 * @access public 1136 * @param mixed $address_id 1137 * @param mixed $ptr_id 1138 * @return void 1139 */ 1140 public function ptr_link ($address_id, $ptr_id) { 1141 # execute 1142 try { $this->Database->updateObject("ipaddresses", array("id"=>$address_id, "PTR"=>$ptr_id)); } 1143 catch (Exception $e) { 1144 $this->Result->show("danger", _("Error: ").$e->getMessage(), false); 1145 return false; 1146 } 1147 } 1148 1149 /** 1150 * Remove PTR link if it exists 1151 * 1152 * @access private 1153 * @param mixed $address_id 1154 * @return void 1155 */ 1156 private function ptr_unlink ($address_id) { 1157 # execute 1158 try { $this->Database->updateObject("ipaddresses", array("id"=>$address_id, "PTR"=>0)); } 1159 catch (Exception $e) { 1160 $this->Result->show("danger", _("Error: ").$e->getMessage(), false); 1161 return false; 1162 } 1163 } 1164 1165 /** 1166 * Removes all PTR references for all hosts in subnet 1167 * 1168 * @access public 1169 * @param mixed $subnet_id 1170 * @return void 1171 */ 1172 public function ptr_unlink_subnet_addresses ($subnet_id) { 1173 try { $this->Database->runQuery("update `ipaddresses` set `PTR` = 0 where `subnetId` = ?;", array($subnet_id)); } 1174 catch (Exception $e) { 1175 $this->Result->show("danger", _("Error: ").$e->getMessage()); 1176 return false; 1177 } 1178 #result 1179 return true; 1180 } 1181 1182 /** 1183 * Checks if PTR record exists 1184 * 1185 * @access private 1186 * @param mixed $ptr_id (default: 0) 1187 * @return void 1188 */ 1189 private function ptr_exists ($ptr_id = 0) { 1190 return $this->PowerDNS->record_id_exists ($ptr_id); 1191 } 1192 1193 /** 1194 * Returns array of all ptr indexes in surrent subnet 1195 * 1196 * @access public 1197 * @param mixed $subnetId 1198 * @return void 1199 */ 1200 public function ptr_get_subnet_indexes ($subnetId) { 1201 try { $indexes = $this->Database->getObjectsQuery("select `PTR` from `ipaddresses` where `PTR` != 0 and `subnetId` = ?;", array($subnetId)); } 1202 catch (Exception $e) { 1203 $this->Result->show("danger", _("Error: ").$e->getMessage()); 1204 return false; 1205 } 1206 # parse 1207 if (sizeof($indexes)>0) { 1208 $out = array(); 1209 // loop 1210 foreach ($indexes as $i) { 1211 $out[] = $i->PTR; 1212 } 1213 return $out; 1214 } 1215 else { 1216 return array(); 1217 } 1218 } 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 /** 1234 * @import address methods 1235 * ------------------------------- 1236 */ 1237 1238 /** 1239 * Import single line from csv to database 1240 * 1241 * @access public 1242 * @param array $address 1243 * @param int $subnetId 1244 * @return void 1245 */ 1246 public function import_address_from_csv ($address, $subnetId) { 1247 # Subnets object 1248 $this->initialize_subnets_object (); 1249 1250 # fetch subnet details 1251 $subnet = (array) $this->Subnets->fetch_subnet(null, $subnetId); 1252 1253 # verify address 1254 if($this->verify_address( $address[0], $this->transform_to_dotted($subnet['subnet'])."/".$subnet['mask'], false, false)!==false) { return false; } 1255 # check for duplicates 1256 if ($this->address_exists($address[0], $subnetId)) { return _('IP address already exists').' - '.$address[0]; } 1257 1258 # format insert array 1259 $address_insert = array("subnetId"=>$subnetId, 1260 "ip_addr"=>$address[0], 1261 "state"=>$address[1], 1262 "description"=>$address[2], 1263 "hostname"=>$address[3], 1264 "mac"=>$address[4], 1265 "owner"=>$address[5], 1266 "switch"=>$address[6], 1267 "port"=>$address[7], 1268 "note"=>$address[8] 1269 ); 1270 1271 # switch to 0, state to active 1272 $address_insert['switch'] = strlen($address_insert['switch'])==0 ? 0 : $address_insert['switch']; 1273 $address_insert['state'] = strlen($address_insert['state'])==0 ? 1 : $address_insert['state']; 1274 1275 # custom fields, append to array 1276 $m=9; 1277 $custom_fields = $this->set_custom_fields(); 1278 if(sizeof($custom_fields) > 0) { 1279 foreach($custom_fields as $c) { 1280 $address_insert[$c['name']] = $address[$m]; 1281 $m++; 1282 } 1283 } 1284 1285 # insert 1286 return $this->modify_address_add ($address_insert); 1287 } 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 /** 1299 * @address subnet methods 1300 * ------------------------------- 1301 */ 1302 1303 /** 1304 * Opens new Subnets connection if not already opened 1305 * 1306 * @access private 1307 * @return void 1308 */ 1309 private function initialize_subnets_object () { 1310 if(!is_object($this->Subnets)) { $this->Subnets = new Subnets ($this->Database); } 1311 } 1312 1313 /** 1314 * Fetches all IP addresses in subnet 1315 * 1316 * @access public 1317 * @param mixed $subnetId 1318 * @param mixed $order (default: null) 1319 * @param mixed $order_direction (default: null) 1320 * @param string $fields (default: "*") 1321 * @return void 1322 */ 1323 public function fetch_subnet_addresses ($subnetId, $order=null, $order_direction=null, $fields = "*") { 1324 # set order 1325 if(!is_null($order)) { $order = array($order, $order_direction); } 1326 else { $order = array("ip_addr", "asc"); } 1327 1328 # fields 1329 if($fields!="*") { 1330 $fields = implode(",", $fields); 1331 } 1332 1333 # escape ordering 1334 $order[0] = $this->Database->escape ($order[0]); 1335 $order[1] = $this->Database->escape ($order[1]); 1336 1337 try { $addresses = $this->Database->getObjectsQuery("SELECT $fields FROM `ipaddresses` where `subnetId` = ? order by `$order[0]` $order[1];", array($subnetId)); } 1338 catch (Exception $e) { 1339 $this->Result->show("danger", _("Error: ").$e->getMessage()); 1340 return false; 1341 } 1342 # save to addresses cache 1343 if(sizeof($addresses)>0) { 1344 foreach($addresses as $k=>$address) { 1345 # add decimal format 1346 $address->ip = $this->transform_to_dotted ($address->ip_addr); 1347 # save to subnets 1348 $this->addresses[$address->id] = (object) $address; 1349 $addresses[$k]->ip = $address->ip; 1350 } 1351 } 1352 # result 1353 return sizeof($addresses)>0 ? $addresses : array(); 1354 } 1355 1356 /** 1357 * Count number of IP addresses in subnet 1358 * 1359 * Returns number of addresses in subnet 1360 * 1361 * @access public 1362 * @param int $subnetId 1363 * @return int 1364 */ 1365 public function count_subnet_addresses ($subnetId) { 1366 try { $count = $this->Database->numObjectsFilter("ipaddresses", "subnetId", $subnetId); } 1367 catch (Exception $e) { 1368 $this->Result->show("danger", _("Error: ").$e->getMessage()); 1369 return false; 1370 } 1371 # result 1372 return (int) $count; 1373 } 1374 1375 /** 1376 * Count number of addresses in multiple subnets 1377 * 1378 * we provide array of all subnet ids 1379 * 1380 * @access public 1381 * @param mixed $subnets 1382 * @return void 1383 */ 1384 public function count_addresses_in_multiple_subnets ($subnets) { 1385 # empty 1386 if(empty($subnets)) { return 0; } 1387 1388 # create query 1389 $tmp = array(); 1390 foreach($subnets as $k=>$s) { 1391 if (is_object($s)) { $tmp[] = " `subnetId`=$s->id "; } 1392 else { $tmp[] = " `subnetId`=$s "; } 1393 } 1394 $query = "select count(*) as `cnt` from `ipaddresses` where ".implode("or", $tmp).";"; 1395 1396 # fetch 1397 try { $addresses = $this->Database->getObjectsQuery($query); } 1398 catch (Exception $e) { 1399 $this->Result->show("danger", _("Error: ").$e->getMessage()); 1400 return false; 1401 } 1402 # return count 1403 return $addresses[0]->cnt; 1404 } 1405 1406 1407 /** 1408 * Fetch IP addresses for all recursive slaves 1409 * 1410 * count returns count only, else whole subnets 1411 * 1412 * @access public 1413 * @param int $subnetId 1414 * @param bool $count 1415 * @return void 1416 */ 1417 public function fetch_subnet_addresses_recursive ($subnetId, $count = false, $order=null, $order_direction=null ) { 1418 # initialize subnets 1419 $this->initialize_subnets_object (); 1420 $this->Subnets = new Subnets ($this->Database); 1421 $this->Subnets->reset_subnet_slaves_recursive(); //reset array of slaves before continuing 1422 $this->Subnets->fetch_subnet_slaves_recursive($subnetId); //fetch array of slaves 1423 $this->Subnets->slaves = array_unique($this->Subnets->slaves); //remove possible duplicates 1424 1425 # ip address order 1426 if(!is_null($order)) { $order_addr = array($order, $order_direction); } 1427 else { $order_addr = array("ip_addr", "asc"); } 1428 1429 # escape ordering 1430 $order_addr[0] = $this->Database->escape ($order_addr[0]); 1431 $order_addr[1] = $this->Database->escape ($order_addr[1]); 1432 1433 $ids = array(); 1434 $ids[] = $subnetId; 1435 1436 # set query to fetch all ip addresses for specified subnets or just count 1437 if($count) { $query = 'select count(*) as cnt from `ipaddresses` where `subnetId` = ? '; } 1438 else { $query = 'select * from `ipaddresses` where `subnetId` = ? '; } 1439 foreach($this->Subnets->slaves as $subnetId2) { 1440 # ignore orphaned 1441 if($subnetId2 != $subnetId) { 1442 $query .= " or `subnetId` = ? "; 1443 $ids[] = $subnetId2; 1444 } 1445 } 1446 1447 $query .= "order by `$order_addr[0]` $order_addr[1];"; 1448 # fetch 1449 try { $addresses = $this->Database->getObjectsQuery($query, $ids); } 1450 catch (Exception $e) { 1451 $this->Result->show("danger", _("Error: ").$e->getMessage()); 1452 return false; 1453 } 1454 # return ip address array or just count 1455 return $count ? (int) $addresses[0]->cnt : $addresses; 1456 } 1457 1458 /** 1459 * Search for unused address space between 2 IP addresses 1460 * 1461 * possible unused addresses by type 1462 * 1463 * @access public 1464 * @param int $address1 1465 * @param int $address2 1466 * @param int $netmask 1467 * @param bool $empty (default: false) 1468 * @param bool $is_subnet (default: false) 1469 * @param bool $is_broadcast (default: false) 1470 * @return void 1471 */ 1472 public function find_unused_addresses ($address1, $address2, $netmask, $empty=false, $is_subnet=false, $is_broadcast=false) { 1473 # make sure addresses are in decimal format 1474 $address1 = $this->transform_address ($address1, "decimal"); 1475 $address2 = $this->transform_address ($address2, "decimal"); 1476 # check for space 1477 return $this->identify_address($address1)=="IPv6" ? $this->find_unused_addresses_IPv6 ($address1, $address2, $netmask, $empty, $is_subnet, $is_broadcast) : $this->find_unused_addresses_IPv4 ($address1, $address2, $netmask, $empty); 1478 } 1479 1480 /** 1481 * Search for unused address space between 2 IPv4 addresses. 1482 * 1483 * unused address range or false if none available 1484 * 1485 * @access protected 1486 * @param int $address1 1487 * @param int $address2 1488 * @param int $netmask 1489 * @param bool $empty 1490 * @return void 1491 */ 1492 protected function find_unused_addresses_IPv4 ($address1, $address2, $netmask, $empty) { 1493 # calculate diff 1494 $diff = $this->calculate_address_diff ($address1, $address2); 1495 # 32 subnets 1496 if($netmask==32) { 1497 if($empty) { 1498 return array("ip"=>$this->transform_to_dotted($address1), "hosts"=>1); 1499 } 1500 else { 1501 return false; 1502 } 1503 } 1504 # 31 subnets 1505 elseif($netmask==31) { 1506 1507 if($empty) { 1508 return array("ip"=>$this->transform_to_dotted($address1), "hosts"=>2); 1509 } 1510 elseif($diff==1) { 1511 if($this->is_network($address1, $netmask)) { 1512 return array("ip"=>$this->transform_to_dotted($address2), "hosts"=>1); 1513 } 1514 elseif($this->is_broadcast($address2, $netmask)) { 1515 return array("ip"=>$this->transform_to_dotted($address1), "hosts"=>1); 1516 } 1517 else { 1518 return false; 1519 } 1520 } 1521 else { 1522 return false; 1523 } 1524 } 1525 # if diff is less than 2 return false */ 1526 elseif ( $diff < 2 ) { 1527 return false; 1528 } 1529 # if diff is 2 return 1 IP address in the middle */ 1530 elseif ( $diff == 2 ) { 1531 return array("ip"=>$this->transform_to_dotted($address1+1), "hosts"=>1); 1532 } 1533 # if diff is more than 2 return pool */ 1534 else { 1535 return array("ip"=>$this->transform_to_dotted($address1+1)." - ".$this->transform_to_dotted(($address2-1)), "hosts"=>gmp_strval(gmp_sub($diff, 1))); 1536 } 1537 # default false 1538 return false; 1539 } 1540 1541 /** 1542 * Search for unused address space between 2 IPv6 addresses 1543 * 1544 * Return unused address range or false if none available 1545 * 1546 * @access protected 1547 * @param int $address1 1548 * @param int $address2 1549 * @param int $netmask 1550 * @param bool $empty (default: false) 1551 * @param bool $is_subnet (default: false) 1552 * @param bool $is_broadcast (default: false) 1553 * @return void 1554 */ 1555 protected function find_unused_addresses_IPv6 ($address1, $address2, $netmask, $empty = false, $is_subnet = false, $is_broadcast = false) { 1556 # Initialize PEAR NET object 1557 $this->initialize_pear_net_IPv6 (); 1558 1559 if($empty) { 1560 $Subnets = new Subnets ($this->Database); 1561 return array("ip"=>$this->transform_to_dotted(gmp_strval($address1))." - ".$this->transform_to_dotted(gmp_strval($address2)), "hosts"=>$Subnets->get_max_hosts ($netmask, "IPv6")); 1562 } 1563 else { 1564 # calculate diff 1565 $diff = $this->calculate_address_diff ($address1, $address2); 1566 1567 # /128 1568 if($netmask == 128) { 1569 if($diff>1) { 1570 return array("ip"=>$this->transform_to_dotted(gmp_strval($address1)), "hosts"=>1); 1571 } 1572 } 1573 # /127 1574 elseif($netmask == 127) { 1575 if($diff==1 && $this->is_network($address1, $netmask)) { 1576 return array("ip"=>$this->transform_to_dotted($address2), "hosts"=>1); 1577 } 1578 elseif($diff==1 && $this->is_broadcast($address2, $netmask)) { 1579 return array("ip"=>$this->transform_to_dotted($address1), "hosts"=>1); 1580 } 1581 elseif($diff==0) { 1582 return false; 1583 } 1584 else { 1585 return array("ip"=>$this->transform_to_dotted($address1), "hosts"=>2); 1586 } 1587 } 1588 # null 1589 elseif ($diff==0) { 1590 return false; 1591 } 1592 # diff 1 1593 elseif ($diff==1) { 1594 if($is_subnet) { 1595 return array("ip"=>$this->transform_to_dotted(gmp_strval($address1)), "hosts"=>1); 1596 } 1597 elseif($is_broadcast) { 1598 return array("ip"=>$this->transform_to_dotted(gmp_strval($address2)), "hosts"=>1); 1599 } 1600 else { 1601 return false; 1602 } 1603 } 1604 # diff 2 1605 elseif ($diff==2 && !$is_subnet && !$is_broadcast) { 1606 return array("ip"=>$this->transform_to_dotted(gmp_strval(gmp_add($address1,1))), "hosts"=>1); 1607 } 1608 # default 1609 else { 1610 if($is_subnet) { 1611 return array("ip"=>$this->transform_to_dotted(gmp_strval($address1))." - ".$this->transform_to_dotted(gmp_strval(gmp_sub($address2,1))), "hosts"=>$this->reformat_number(gmp_strval(gmp_sub($diff,0)))); 1612 } 1613 elseif($is_broadcast) { 1614 return array("ip"=>$this->transform_to_dotted(gmp_strval(gmp_add($address1,1)))." - ".$this->transform_to_dotted(gmp_strval($address2)), "hosts"=>$this->reformat_number(gmp_strval(gmp_sub($diff,0)))); 1615 } 1616 else { 1617 return array("ip"=>$this->transform_to_dotted(gmp_strval(gmp_add($address1,1)))." - ".$this->transform_to_dotted(gmp_strval(gmp_sub($address2,1))), "hosts"=>$this->reformat_number(gmp_strval(gmp_strval(gmp_sub($diff,1))))); 1618 } 1619 } 1620 1621 # default false 1622 return false; 1623 } 1624 } 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 /** 1637 * @address verification methods 1638 * ------------------------------- 1639 */ 1640 1641 /** 1642 * Verify IP address 1643 * 1644 * @access public 1645 * @param int $address 1646 * @param mixed $subnet (CIDR) 1647 * @param bool $no_strict (default: false) 1648 * @param bool $die (default: false) 1649 * @return boolean 1650 */ 1651 public function verify_address( $address, $subnet, $no_strict = false, $die=true ) { 1652 # subnet should be in CIDR format 1653 $this->initialize_subnets_object (); 1654 if(strlen($error = $this->Subnets->verify_cidr ($subnet))>1) { $this->Result->show("danger", $error, $die); return true; } 1655 1656 # make checks 1657 return $this->identify_address ($address)=="IPv6" ? $this->verify_address_IPv6 ($address, $subnet, $die) : $this->verify_address_IPv4 ($address, $subnet, $no_strict, $die); 1658 } 1659 1660 /** 1661 * Verify IPv4 address 1662 * 1663 * @access public 1664 * @param int $address 1665 * @param mixed $subnet (CIDR) 1666 * @param bool $no_strict 1667 * @param bool $die 1668 * @return boolean 1669 */ 1670 public function verify_address_IPv4 ($address, $subnet, $no_strict, $die) { 1671 # Initialize PEAR NET object 1672 $this->initialize_pear_net_IPv4 (); 1673 # fetch mask part 1674 $mask = explode("/", $subnet); 1675 1676 # is address valid? 1677 if (!$this->Net_IPv4->validateIP($address)) { $this->Result->show("danger", _("IP address not valid")."! ($address)", $die); return true; } 1678 # is address in provided subnet 1679 elseif (!$this->Net_IPv4->ipInNetwork($address, $subnet)) { $this->Result->show("danger", _("IP address not in selected subnet")."! ($address)", $die); return true; } 1680 # ignore /31 and /32 subnet broadcast and subnet checks! 1681 elseif ($mask[1] == 31 || $mask[1] == 32 || $no_strict == true) { } 1682 # It cannot be subnet or broadcast 1683 else { 1684 $net = $this->Net_IPv4->parseAddress($subnet); 1685 1686 if ($net->network == $address) { $this->Result->show("danger", _("Cannot add subnet as IP address!"), $die); return true; } 1687 elseif ($net->broadcast == $address) { $this->Result->show("danger", _("Cannot add broadcast as IP address!"), $die); return true; } 1688 } 1689 # default 1690 return false; 1691 } 1692 1693 /** 1694 * Verify IPv6 address 1695 * 1696 * @access public 1697 * @param int $address 1698 * @param mixed $subnet (CIDR) 1699 * @param bool $die 1700 * @return boolean 1701 */ 1702 public function verify_address_IPv6 ($address, $subnet, $die) { 1703 # Initialize PEAR NET object 1704 $this->initialize_pear_net_IPv6 (); 1705 1706 # is it valid? 1707 if (!$this->Net_IPv6->checkIPv6($address)) { $this->Result->show("danger", _("IP address not valid")."! ($address)", $die); return true; } 1708 # it must be in provided subnet 1709 elseif (!$this->Net_IPv6->isInNetmask($address, $subnet)) { $this->Result->show("danger", _("IP address not in selected subnet")."! ($address)", $die); return true; } 1710 # default 1711 return false; 1712 } 1713 1714 /** 1715 * Validates IP address 1716 * 1717 * @access public 1718 * @param mixed $address 1719 * @return void 1720 */ 1721 public function validate_address ($address) { 1722 # Initialize PEAR NET object 1723 $this->initialize_pear_net_IPv4 (); 1724 $this->initialize_pear_net_IPv6 (); 1725 1726 // no null 1727 if($this->transform_address ($address, "decimal")==0) { 1728 return false; 1729 } 1730 // transform 1731 $address = $this->transform_address ($address, "dotted"); 1732 // ipv6 1733 if($this->identify_address ($address)=="IPv6") { 1734 return $this->Net_IPv6->checkIPv6($address) ? true : false; 1735 } 1736 // ipv4 1737 else { 1738 return $this->Net_IPv4->validateIP($address) ? true : false; 1739 } 1740 } 1741 1742 /** 1743 * Checks if address is subnet for IPv4 addresses 1744 * 1745 * @access public 1746 * @param mixed $address 1747 * @param int $netmask 1748 * @return boolean 1749 */ 1750 public function is_network ($address, $netmask) { 1751 $this->initialize_subnets_object (); 1752 $boundaries = $this->Subnets->get_network_boundaries ($address, $netmask); 1753 return $this->transform_address($address,"dotted")==$boundaries['network'] ? true : false; 1754 } 1755 1756 /** 1757 * Checks if address is broadcast for IPv4 addresses 1758 * 1759 * @access public 1760 * @param mixed $address 1761 * @param int $netmask 1762 * @return boolean 1763 */ 1764 public function is_broadcast ($address, $netmask) { 1765 $this->initialize_subnets_object (); 1766 $boundaries = $this->Subnets->get_network_boundaries ($address, $netmask); 1767 return $this->transform_address($address,"dotted")==$boundaries['broadcast'] ? true : false; 1768 } 1769 1770 /** 1771 * Checks if hostname in database is unique 1772 * 1773 * @access public 1774 * @param mixed $hostname 1775 * @return boolean 1776 */ 1777 public function is_hostname_unique ($hostname) { 1778 try { $cnt = $this->Database->numObjectsFilter("ipaddresses", "hostname", $hostname); } 1779 catch (Exception $e) { 1780 $this->Result->show("danger", _("Error: ").$e->getMessage()); 1781 return false; 1782 } 1783 return $cnt==0 ? true : false; 1784 } 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 /** 1799 * @transform address methods 1800 * ------------------------------- 1801 */ 1802 1803 /** 1804 * This function compresses all ranges 1805 * 1806 * input is array of ip addresses 1807 * output compresses address range 1808 * 1809 * @access public 1810 * @param array $addresses 1811 * @return void 1812 */ 1813 public function compress_address_ranges ($addresses, $state=4) { 1814 # set size 1815 $size = sizeof($addresses); 1816 // vars 1817 $addresses_formatted = array(); 1818 1819 # loop through IP addresses 1820 for($c=0; $c<$size; $c++) { 1821 # ignore already comressed range 1822 if($addresses[$c]->class!="compressed-range") { 1823 # gap between this and previous 1824 if(gmp_strval( @gmp_sub($addresses[$c]->ip_addr, $addresses[$c-1]->ip_addr)) != 1) { 1825 # remove index flag 1826 unset($fIndex); 1827 # save IP address 1828 $addresses_formatted[$c] = $addresses[$c]; 1829 $addresses_formatted[$c]->class = "ip"; 1830 1831 # no gap this -> next 1832 if(gmp_strval( @gmp_sub($addresses[$c]->ip_addr, $addresses[$c+1]->ip_addr)) == -1 && $addresses[$c]->state==$state) { 1833 //is state the same? 1834 if($addresses[$c]->state==$addresses[$c+1]->state) { 1835 $fIndex = $c; 1836 $addresses_formatted[$fIndex]->startIP = $addresses[$c]->ip_addr; 1837 $addresses_formatted[$c]->class = "compressed-range"; 1838 } 1839 } 1840 } 1841 # no gap between this and previous 1842 else { 1843 # is state same as previous? 1844 if($addresses[$c]->state==$addresses[$c-1]->state && $addresses[$c]->state==$state) { 1845 $addresses_formatted[$fIndex]->stopIP = $addresses[$c]->ip_addr; //adds dhcp state 1846 $addresses_formatted[$fIndex]->numHosts = gmp_strval( gmp_add(@gmp_sub($addresses[$c]->ip_addr, $addresses_formatted[$fIndex]->ip_addr),1)); //add number of hosts 1847 } 1848 # different state 1849 else { 1850 # remove index flag 1851 unset($fIndex); 1852 # save IP address 1853 $addresses_formatted[$c] = $addresses[$c]; 1854 $addresses_formatted[$c]->class = "ip"; 1855 # check if state is same as next to start range 1856 if($addresses[$c]->state==@$addresses[$c+1]->state && gmp_strval( @gmp_sub($addresses[$c]->ip_addr, $addresses[$c+1]->ip_addr)) == -1 && $addresses[$c]->state==$state) { 1857 $fIndex = $c; 1858 $addresses_formatted[$fIndex]->startIP = $addresses[$c]->ip_addr; 1859 $addresses_formatted[$c]->class = "compressed-range"; 1860 } 1861 } 1862 } 1863 } 1864 else { 1865 # save already compressed 1866 $addresses_formatted[$c] = $addresses[$c]; 1867 } 1868 } 1869 # overrwrite ipaddresses and rekey 1870 $addresses = @array_values($addresses_formatted); 1871 # return 1872 return $addresses; 1873 } 1874 1875 /** 1876 * Finds invalid addresses - that have subnetId that does not exist 1877 * 1878 * @access public 1879 * @return void 1880 */ 1881 public function find_invalid_addresses () { 1882 // init 1883 $false = array(); 1884 // find unique ids 1885 $ids = $this->find_unique_subnetids (); 1886 1887 // validate 1888 if (!is_array($ids)) 1889 return false; 1890 1891 foreach ($ids as $id) { 1892 if ($this->verify_subnet_id ($id->subnetId)===false) { 1893 $false[] = $this->fetch_subnet_addresses ($id->subnetId); 1894 } 1895 } 1896 // filter 1897 $false = array_filter($false); 1898 // return 1899 return sizeof($false)>0 ? $false : false; 1900 } 1901 1902 /** 1903 * Finds all unique master subnet ids 1904 * 1905 * @access private 1906 * @return void 1907 */ 1908 private function find_unique_subnetids () { 1909 try { $res = $this->Database->getObjectsQuery("select distinct(`subnetId`) from `ipaddresses` order by `subnetId` asc;"); } 1910 catch (Exception $e) { 1911 $this->Result->show("danger", _("Error: ").$e->getMessage()); 1912 return false; 1913 } 1914 # return 1915 return sizeof($res)>0 ? $res : false; 1916 } 1917 1918 /** 1919 * Verifies that subnetid exists 1920 * 1921 * @access private 1922 * @param mixed $id 1923 * @return void 1924 */ 1925 private function verify_subnet_id ($id) { 1926 try { $res = $this->Database->numObjectsFilter("subnets", "id", $id ); } 1927 catch (Exception $e) { 1928 $this->Result->show("danger", _("Error: ").$e->getMessage()); 1929 return false; 1930 } 1931 # return 1932 return $res==0 ? false : true; 1933 } 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 /** 1946 * @permission address methods 1947 * ------------------------------- 1948 */ 1949 1950 /** 1951 * Checks permission for specified subnet 1952 * 1953 * we provide user details and subnetId 1954 * 1955 * @access public 1956 * @param object $user 1957 * @param int $subnetId 1958 * @return int permission level 1959 */ 1960 public function check_permission ($user, $subnetId) { 1961 1962 # get all user groups 1963 $groups = json_decode($user->groups); 1964 1965 # if user is admin then return 3, otherwise check 1966 if($user->role == "Administrator") { return 3; } 1967 1968 # object 1969 if (!is_object($this->Subnets)) { 1970 $this->Subnets = new Subnets ($this->Database); 1971 } 1972 # fetch subnet 1973 $subnet = $this->Subnets->fetch_subnet("id", $subnetId); 1974 # set subnet permissions 1975 $subnetP = json_decode($subnet->permissions); 1976 1977 # set section permissions 1978 $Section = new Section ($this->Database); 1979 $section = $Section->fetch_section ("id", $subnet->sectionId); 1980 $sectionP = json_decode($section->permissions); 1981 1982 # default permission 1983 $out = 0; 1984 1985 # for each group check permissions, save highest to $out 1986 if(sizeof($sectionP) > 0) { 1987 foreach($sectionP as $sk=>$sp) { 1988 # check each group if user is in it and if so check for permissions for that group 1989 foreach($groups as $uk=>$up) { 1990 if($uk == $sk) { 1991 if($sp > $out) { $out = $sp; } 1992 } 1993 } 1994 } 1995 } 1996 else { 1997 return 0; 1998 } 1999 2000 # if section permission == 0 then return 0 2001 if($out == 0) { 2002 return 0; 2003 } 2004 else { 2005 $out = 0; 2006 # ok, user has section access, check also for any higher access from subnet 2007 if(sizeof($subnetP) > 0) { 2008 foreach($subnetP as $sk=>$sp) { 2009 # check each group if user is in it and if so check for permissions for that group 2010 foreach($groups as $uk=>$up) { 2011 if($uk == $sk) { 2012 if($sp > $out) { $out = $sp; } 2013 } 2014 } 2015 } 2016 } 2017 } 2018 2019 # return result 2020 return $out; 2021 } 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 /** 2033 * @misc address methods 2034 * ------------------------------- 2035 */ 2036 2037 /** 2038 * Present numbers in pow 10, only for IPv6 2039 * 2040 * @access public 2041 * @param mixed $number 2042 * @return void 2043 */ 2044 public function reformat_number ($number) { 2045 $length = strlen($number); 2046 $pos = $length - 3; 2047 2048 if ($length > 8) { 2049 $number = "~". substr($number, 0, $length - $pos) . "·10^<sup>". $pos ."</sup>"; 2050 } 2051 return $number; 2052 } 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 /** 2064 * @nat methods 2065 * ------------------------------- 2066 */ 2067 /** 2068 * Prints nat link 2069 * 2070 * @access public 2071 * @param array $all_nats 2072 * @param array $all_nats_per_object 2073 * @param object $subnet 2074 * @param object $address 2075 * @param mixed $address 2076 * @return void 2077 */ 2078 public function print_nat_link ($all_nats, $all_nats_per_object, $subnet, $address, $type="ipaddress") { 2079 // cast 2080 $subnet = (object) $subnet; 2081 $address = (object) $address; 2082 2083 // cnt 2084 $html = array(); 2085 $html[] = '<table class="popover_table">'; 2086 2087 $cnt = 0; 2088 2089 // subnets 2090 if(isset($all_nats_per_object['subnets'][$subnet->id])) { 2091 foreach ($all_nats_per_object['subnets'][$subnet->id] as $nat) { 2092 // set object 2093 $n = $all_nats[$nat]; 2094 // print 2095 $html[] = str_replace("'", "\"", $this->print_nat_link_line ($n, false, "subnets", $subnet->id)); 2096 } 2097 $cnt++; 2098 } 2099 2100 // addresses 2101 if(isset($all_nats_per_object['ipaddresses'][$address->id])) { 2102 foreach ($all_nats_per_object['ipaddresses'][$address->id] as $nat) { 2103 // set object 2104 $n = $all_nats[$nat]; 2105 // print 2106 $html[] = str_replace("'", "\"", $this->print_nat_link_line ($n, false, "ipaddresses", $address->id)); 2107 $cnt++; 2108 } 2109 } 2110 2111 // print if some 2112 if ($cnt>0) { 2113 $html[] = "</table>"; 2114 if($type=="subnet") { 2115 print " <a href='".create_link("subnets",$subnet->sectionId, $subnet->id, "nat")."' class='btn btn-xs btn-default show_popover fa fa-exchange' style='font-size:11px;margin-top:-3px;padding:1px 3px;' data-toggle='popover' title='"._('Object is Natted')."' data-trigger='hover' data-html='true' data-content='".implode("\n", $html)."'></a>"; 2116 } 2117 else { 2118 print " <a href='".create_link("subnets",$subnet->sectionId, $subnet->id, "address-details", $address->id, "nat")."' class='btn btn-xs btn-default show_popover fa fa-exchange' style='font-size:11px;margin-top:-3px;padding:1px 3px;' data-toggle='popover' title='"._('Object is Natted')."' data-trigger='hover' data-html='true' data-content='".implode("\n", $html)."'></a>"; 2119 } 2120 } 2121 } 2122 2123 /** 2124 * Prints single NAT for display in devices, subnets, addresses. 2125 * 2126 * @access public 2127 * @param mixed $n 2128 * @param bool|int $nat_id (default: false) 2129 * @param bool|mixed $object_type (default: false) 2130 * @param bool $object_id (default: false) 2131 * @return void 2132 */ 2133 public function print_nat_link_line ($n, $nat_id = false, $object_type = false, $object_id=false) { 2134 // cast to object to be sure if array provided 2135 $n = (object) $n; 2136 2137 // translate json to array, links etc 2138 $sources = $this->translate_nat_objects_for_popup ($n->src, $nat_id, false, $object_type, $object_id); 2139 $destinations = $this->translate_nat_objects_for_popup ($n->dst, $nat_id, false, $object_type, $object_id); 2140 2141 // no src/dst 2142 if ($sources===false) 2143 $sources = array("<span class='badge badge1 badge5 alert-danger'>"._("None")."</span>"); 2144 if ($destinations===false) 2145 $destinations = array("<span class='badge badge1 badge5 alert-danger'>"._("None")."</span>"); 2146 2147 2148 // icon 2149 $icon = $n->type=="static" ? "fa-arrows-h" : "fa-long-arrow-right"; 2150 2151 // to html 2152 $html = array(); 2153 $html[] = "<tr>"; 2154 $html[] = "<td colspan='3'>"; 2155 $html[] = "<strong>$n->name</strong> <span class='badge badge1 badge5'>".ucwords($n->type)."</span>"; 2156 $html[] = "</td>"; 2157 $html[] = "</tr>"; 2158 2159 // append ports 2160 if(($n->type=="static" || $n->type=="destination") && (strlen($n->src_port)>0 && strlen($n->dst_port)>0)) { 2161 $sources = implode("<br>", $sources)." /".$n->src_port; 2162 $destinations = implode("<br>", $destinations)." /".$n->dst_port; 2163 } 2164 else { 2165 $sources = implode("<br>", $sources); 2166 $destinations = implode("<br>", $destinations); 2167 } 2168 2169 $html[] = "<tr>"; 2170 $html[] = "<td>$sources</td>"; 2171 $html[] = "<td><i class='fa $icon'></i></td>"; 2172 $html[] = "<td>$destinations</td>"; 2173 $html[] = "</tr>"; 2174 $html[] = "<tr><td colspan='3' style='padding-top:20px;'></td></tr>"; 2175 2176 $html[] = "<tr>"; 2177 $html[] = "<td colspan='3'><hr></td>"; 2178 $html[] = "</tr>"; 2179 2180 // return 2181 return implode("\n", $html); 2182 } 2183 2184 /** 2185 * Translates NAT objects to be shown on page 2186 * 2187 * @access public 2188 * @param json $json_objects 2189 * @param int|bool $nat_id (default: false) 2190 * @param bool $json_objects (default: false) 2191 * @param bool $object_type (default: false) - to bold it (ipaddresses / subnets) 2192 * @param int|bool object_id (default: false) - to bold it 2193 * @return void 2194 */ 2195 public function translate_nat_objects_for_popup ($json_objects, $nat_id = false, $admin = false, $object_type = false, $object_id=false) { 2196 // to array "subnets"=>array(1,2,3) 2197 $objects = json_decode($json_objects, true); 2198 // init out array 2199 $out = array(); 2200 // check 2201 if(is_array($objects)) { 2202 if(sizeof($objects)>0) { 2203 foreach ($objects as $ot=>$ids) { 2204 if (sizeof($ids)>0) { 2205 foreach ($ids as $id) { 2206 // fetch 2207 $item = $this->fetch_object($ot, "id", $id); 2208 if($item!==false) { 2209 // bold 2210 $bold = $item->id==$object_id && $ot==$object_type ? "<span class='strong'>" : "<span>"; 2211 // subnets 2212 if ($ot=="subnets") { 2213 $out[] = "$bold".$this->transform_address($item->subnet, "dotted")."/".$item->mask."</span></span>"; 2214 } 2215 // addresses 2216 else { 2217 $out[] = "$bold".$this->transform_address($item->ip_addr, "dotted")."</span>"; 2218 } 2219 } 2220 } 2221 } 2222 } 2223 } 2224 } 2225 // result 2226 return sizeof($out)>0 ? $out : false; 2227 } 2228 2229} 2230