- Timestamp:
- 01/14/05 18:03:44 (20 years ago)
- Location:
- branches/stable
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/stable/cgi-bin/IPDB.pm
r76 r125 14 14 use warnings; 15 15 use Exporter; 16 use DBI; 16 17 use Net::SMTP; 17 18 use POSIX; 18 19 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); 19 20 20 $VERSION = 1.0;21 $VERSION = 2.0; 21 22 @ISA = qw(Exporter); 22 @EXPORT_OK = qw(&connectDB &checkDBSanity &allocateBlock &mailNotify); 23 @EXPORT_OK = qw( 24 %disp_alloctypes %list_alloctypes @citylist @poplist @masterblocks 25 %allocated %free %routed %bigfree 26 &initIPDBGlobals &connectDB &finish &checkDBSanity &allocateBlock &deleteBlock 27 &mailNotify 28 ); 23 29 24 30 @EXPORT = (); # Export nothing by default. 25 %EXPORT_TAGS = ( ALL => [qw( &connectDB &checkDBSanity &allocateBlock &mailNotify)] 26 ); 27 28 31 %EXPORT_TAGS = ( ALL => [qw( 32 %disp_alloctypes %list_alloctypes @citylist @poplist @masterblocks 33 %allocated %free %routed %bigfree 34 &initIPDBGlobals &connectDB &finish &checkDBSanity &allocateBlock 35 &deleteBlock &mailNotify 36 )] 37 ); 38 39 ## 40 ## Global variables 41 ## 42 our %disp_alloctypes; 43 our %list_alloctypes; 44 our @citylist; 45 our @poplist; 46 our @masterblocks; 47 our %allocated; 48 our %free; 49 our %routed; 50 our %bigfree; 51 52 # Let's initialize the globals. 53 ## IPDB::initIPDBGlobals() 54 # Initialize all globals. Takes a database handle, returns a success or error code 55 sub initIPDBGlobals { 56 my $dbh = $_[0]; 57 my $sth; 58 59 # Initialize alloctypes hashes 60 $sth = $dbh->prepare("select * from alloctypes order by listorder"); 61 $sth->execute; 62 while (my @data = $sth->fetchrow_array) { 63 $disp_alloctypes{$data[0]} = $data[2]; 64 if ($data[3] < 900) { 65 $list_alloctypes{$data[0]} = $data[1]; 66 } 67 } 68 69 # City and POP listings 70 $sth = $dbh->prepare("select * from cities"); 71 $sth->execute; 72 return (undef,$sth->errstr) if $sth->err; 73 while (my @data = $sth->fetchrow_array) { 74 push @citylist, $data[0]; 75 if ($data[1] eq 'y') { 76 push @poplist, $data[0]; 77 } 78 } 79 80 # Master block list 81 $sth = $dbh->prepare("select * from masterblocks order by cidr"); 82 $sth->execute; 83 for (my $i=0; my @data = $sth->fetchrow_array(); $i++) { 84 $masterblocks[$i] = new NetAddr::IP $data[0]; 85 $allocated{"$masterblocks[$i]"} = 0; 86 $free{"$masterblocks[$i]"} = 0; 87 $bigfree{"$masterblocks[$i]"} = 128; # Larger number means smaller block. 88 # Set to 128 to prepare for IPv6 89 $routed{"$masterblocks[$i]"} = 0; 90 } 91 return (undef,$sth->errstr) if $sth->err; 92 93 return (1,"OK"); 94 } # end initIPDBGlobals 95 96 97 ## IPDB::connectDB() 29 98 # Creates connection to IPDB. 30 # Default is a PostgreSQL db; could be any DBMS with the 31 # right changes. MySQL in comments. Note that some DBMS's don't 32 # support transactions, this is a Bad Thing! 99 # Requires the database name, username, and password. 33 100 # Returns a handle to the db. 101 # Set up for a PostgreSQL db; could be any transactional DBMS with the 102 # right changes. 103 # This definition should be sub connectDB($$$) to be technically correct, 104 # but this breaks. GRR. 34 105 sub connectDB { 106 my ($dbname,$user,$pass) = @_; 35 107 my $dbh; 36 my $DSN = "DBI:Pg:dbname= ipdb";37 my $user = 'ipdb';38 my $pw = 'ipdbpwd';108 my $DSN = "DBI:Pg:dbname=$dbname"; 109 # my $user = 'ipdb'; 110 # my $pw = 'ipdbpwd'; 39 111 40 112 # Note that we want to autocommit by default, and we will turn it off locally as necessary. 41 $dbh = DBI->connect($DSN, $user, $pw, { AutoCommit => 1 } ) 42 or return undef if(!$dbh); 43 44 return $dbh; 113 # We may not want to print gobbledygook errors; YMMV. Have to ponder that further. 114 $dbh = DBI->connect($DSN, $user, $pass, { 115 AutoCommit => 1, 116 PrintError => 0 117 }) 118 or return (undef, $DBI::errstr) if(!$dbh); 119 120 # Return here if we can't select. Note that this indicates a 121 # problem executing the select. 122 my $sth = $dbh->prepare('select cidr from masterblocks'); 123 $sth->execute(); 124 return (undef,$DBI::errstr) if ($sth->err); 125 126 # See if the select returned anything (or null data). This should 127 # succeed if the select executed, but... 128 $sth->fetchrow(); 129 return (undef,$DBI::errstr) if ($sth->err); 130 131 # If we get here, we should be OK. 132 return ($dbh,"DB connection OK"); 45 133 } # end connectDB 46 134 135 136 ## IPDB::finish() 137 # Cleans up after database handles and so on. 138 # Requires a database handle 139 sub finish { 140 my $dbh = $_[0]; 141 $dbh->disconnect; 142 } # end finish 143 144 145 ## IPDB::checkDBSanity() 47 146 # Quick check to see if the db is responding. A full integrity 48 147 # check will have to be a separate tool to walk the IP allocation trees. 49 148 sub checkDBSanity { 50 my $dbh = connectDB();149 my ($dbh) = $_[0]; 51 150 52 151 if (!$dbh) { 53 print "Cannot connect to the database!"; 152 print "No database handle, or connection has been closed."; 153 return -1; 54 154 } else { 55 155 # it connects, try a stmt. … … 62 162 } else { 63 163 print "Connected to the database, but could not execute test statement. ".$sth->errstr(); 164 return -1; 64 165 } 65 166 } 66 167 # Clean up after ourselves. 67 $dbh->disconnect;168 # $dbh->disconnect; 68 169 } # end checkDBSanity 69 170 70 171 71 # 172 ## IPDB::allocateBlock() 72 173 # Does all of the magic of actually allocating a netblock 73 sub allocateBlock($) { 74 } 75 76 77 # mailNotify() 174 # Requires database handle, block to allocate, custid, type, city, 175 # description, notes, circuit ID, block to allocate from, 176 # Returns a success code and optional error message. 177 sub allocateBlock { 178 my ($dbh,undef,undef,$custid,$type,$city,$desc,$notes,$circid) = @_; 179 180 my $cidr = new NetAddr::IP $_[1]; 181 my $alloc_from = new NetAddr::IP $_[2]; 182 my $sth; 183 184 # To contain the error message, if any. 185 my $msg = "Unknown error allocating $cidr as '$type'"; 186 187 # Enable transactions and error handling 188 local $dbh->{AutoCommit} = 0; # These need to be local so we don't 189 local $dbh->{RaiseError} = 1; # step on our toes by accident. 190 191 if ($type =~ /^[cdsmw]i$/) { 192 $msg = "Unable to assign static IP $cidr to $custid"; 193 eval { 194 # We'll just have to put up with the oddities caused by SQL (un)sort order 195 $sth = $dbh->prepare("select * from poolips where pool='$alloc_from'". 196 " and available='y' order by ip"); 197 $sth->execute; 198 199 # update poolips set custid='$custid',city='$city',available='n', 200 # description='$desc',notes='$notes',circuitid='$circid' 201 # where ip=(select ip from poolips where pool='$alloc_from' 202 # and available='y' order by ip limit 1); 203 ##err Need better handling here; what if there's no free IPs when this sub gets called? 204 my @data = $sth->fetchrow_array; 205 my $cidr = $data[1]; 206 207 $sth = $dbh->prepare("update poolips set custid='$custid',". 208 "city='$city',available='n',description='$desc',notes='$notes',". 209 "circuitid='$circid'". 210 " where ip='$cidr'"); 211 $sth->execute; 212 $dbh->commit; 213 }; 214 if ($@) { 215 $msg .= ": '".$sth->errstr."'"; 216 eval { $dbh->rollback; }; 217 return ('FAIL',$msg); 218 } else { 219 return ('OK',"$cidr"); 220 } 221 222 } else { # end IP-from-pool allocation 223 224 if ($cidr == $alloc_from) { 225 # Easiest case- insert in one table, delete in the other, and go home. More or less. 226 # insert into allocations values (cidr,custid,type,city,desc) and 227 # delete from freeblocks where cidr='cidr' 228 # For data safety on non-transaction DBs, we delete first. 229 230 eval { 231 $msg = "Unable to allocate $cidr as '$disp_alloctypes{$type}'"; 232 if ($type eq 'rr') { 233 $sth = $dbh->prepare("update freeblocks set routed='y',city='$city'". 234 " where cidr='$cidr'"); 235 $sth->execute; 236 $sth = $dbh->prepare("insert into routed values ('$cidr',". 237 $cidr->masklen.",'$city')"); 238 $sth->execute; 239 } else { 240 # common stuff for end-use, dialup, dynDSL, pools, etc, etc. 241 $sth = $dbh->prepare("delete from freeblocks where cidr='$cidr'"); 242 $sth->execute; 243 244 $sth = $dbh->prepare("insert into allocations values ('$cidr',". 245 "'$custid','$type','$city','$desc','$notes',". 246 $cidr->masklen.",'$circid')"); 247 $sth->execute; 248 249 # And initialize the pool, if necessary 250 if ($type =~ /^.p$/) { 251 $msg = "Could not initialize IPs in new $disp_alloctypes{$type} pool $cidr"; 252 initPool($dbh,$cidr,$type,$city,($type eq 'dp' ? "all" : "normal")); 253 } 254 255 } # routing vs non-routing netblock 256 257 $dbh->commit; 258 }; # end of eval 259 if ($@) { 260 $msg = $@; 261 eval { $dbh->rollback; }; 262 return ('FAIL',$@); 263 } else { 264 return ('OK',"OK"); 265 } 266 267 } else { # cidr != alloc_from 268 269 # Hard case. Allocation is smaller than free block. 270 my $wantmaskbits = $cidr->masklen; 271 my $maskbits = $alloc_from->masklen; 272 273 my @newfreeblocks; # Holds free blocks generated from splitting the source freeblock. 274 275 # This determines which blocks will be left "free" after allocation. We take the 276 # block we're allocating from, and split it in half. We see which half the wanted 277 # block is in, and repeat until the wanted block is equal to one of the halves. 278 my $i=0; 279 my $tmp_from = $alloc_from; # So we don't munge $alloc_from 280 while ($maskbits++ < $wantmaskbits) { 281 my @subblocks = $tmp_from->split($maskbits); 282 $newfreeblocks[$i++] = (($cidr->within($subblocks[0])) ? $subblocks[1] : $subblocks[0]); 283 $tmp_from = ( ($cidr->within($subblocks[0])) ? $subblocks[0] : $subblocks[1] ); 284 } # while 285 286 # Begin SQL transaction block 287 eval { 288 $msg = "Unable to allocate $cidr as '$disp_alloctypes{$type}'"; 289 290 # Delete old freeblocks entry 291 $sth = $dbh->prepare("delete from freeblocks where cidr='$alloc_from'"); 292 $sth->execute(); 293 294 # now we have to do some magic for routing blocks 295 if ($type eq 'rr') { 296 297 # Insert the new freeblocks entries 298 # Note that non-routed blocks are assigned to <NULL> 299 $sth = $dbh->prepare("insert into freeblocks values (?, ?, '<NULL>','n')"); 300 foreach my $block (@newfreeblocks) { 301 $sth->execute("$block", $block->masklen); 302 } 303 304 # Insert the entry in the routed table 305 $sth = $dbh->prepare("insert into routed values ('$cidr',". 306 $cidr->masklen.",'$city')"); 307 $sth->execute; 308 # Insert the (almost) same entry in the freeblocks table 309 $sth = $dbh->prepare("insert into freeblocks values ('$cidr',". 310 $cidr->masklen.",'$city','y')"); 311 $sth->execute; 312 313 } else { # done with alloctype == rr 314 315 # Insert the new freeblocks entries 316 $sth = $dbh->prepare("insert into freeblocks values (?, ?, ". 317 "(select city from routed where cidr >>= '$cidr'),'y')"); 318 foreach my $block (@newfreeblocks) { 319 $sth->execute("$block", $block->masklen); 320 } 321 322 # Insert the allocations entry 323 $sth = $dbh->prepare("insert into allocations values ('$cidr',". 324 "'$custid','$type','$city','$desc','$notes',".$cidr->masklen. 325 ",'$circid')"); 326 $sth->execute; 327 328 # And initialize the pool, if necessary 329 if ($type =~ /^.p$/) { 330 $msg = "Could not initialize IPs in new $disp_alloctypes{$type} $cidr"; 331 initPool($dbh,$cidr,$type,$city,($type eq 'dp' ? "all" : "normal")); 332 } 333 334 } # done with netblock alloctype != rr 335 336 $dbh->commit; 337 }; # end eval 338 if ($@) { 339 eval { $dbh->rollback; }; 340 return ('FAIL',$msg); 341 } else { 342 return ('OK',"OK"); 343 } 344 345 } # end fullcidr != alloc_from 346 347 } # end static-IP vs netblock allocation 348 349 } # end allocateBlock() 350 351 352 ## IPDB::initPool() 353 # Initializes a pool 354 # Requires a database handle, the pool CIDR, type, city, and a parameter 355 # indicating whether the pool should allow allocation of literally every 356 # IP, or if it should reserve network/gateway/broadcast IPs 357 # Note that this is NOT done in a transaction, that's why it's a private 358 # function and should ONLY EVER get called from allocateBlock() 359 sub initPool { 360 my ($dbh,undef,$type,$city,$class) = @_; 361 my $pool = new NetAddr::IP $_[1]; 362 363 my ($pooltype) = ($type =~ /^(.)p$/); 364 my $sth; 365 366 # have to insert all pool IPs into poolips table as "unallocated". 367 $sth = $dbh->prepare("insert into poolips values ('$pool',". 368 " ?, '6750400', '$city', '$pooltype', 'y', '', '', '')"); 369 my @poolip_list = $pool->hostenum; 370 if ($class eq 'all') { # (DSL-ish block - *all* IPs available 371 $sth->execute($pool->addr); 372 for (my $i=0; $i<=$#poolip_list; $i++) { 373 $sth->execute($poolip_list[$i]->addr); 374 } 375 $pool--; 376 $sth->execute($pool->addr); 377 } else { # (real netblock) 378 for (my $i=1; $i<=$#poolip_list; $i++) { 379 $sth->execute($poolip_list[$i]->addr); 380 } 381 } 382 } # end initPool() 383 384 385 ## IPDB::deleteBlock() 386 # Removes an allocation from the database, including deleting IPs 387 # from poolips and recombining entries in freeblocks if possible 388 # Also handles "deleting" a static IP allocation, and removal of a master 389 # Requires a database handle, the block to delete, and the type of block 390 sub deleteBlock { 391 my ($dbh,undef,$type) = @_; 392 my $cidr = new NetAddr::IP $_[1]; 393 394 my $sth; 395 396 # To contain the error message, if any. 397 my $msg = "Unknown error deallocating $type $cidr"; 398 # Enable transactions and exception-on-errors... but only for this sub 399 local $dbh->{AutoCommit} = 0; 400 local $dbh->{RaiseError} = 1; 401 402 # First case. The "block" is a static IP 403 # Note that we still need some additional code in the odd case 404 # of a netblock-aligned contiguous group of static IPs 405 if ($type =~ /^.i$/) { 406 407 eval { 408 $msg = "Unable to deallocate $type $cidr"; 409 $sth = $dbh->prepare("update poolips set custid='6750400',available='y',". 410 "city=(select city from allocations where cidr >>= '$cidr'),". 411 "description='',notes='',circuitid='' where ip='$cidr'"); 412 $sth->execute; 413 $dbh->commit; 414 }; 415 if ($@) { 416 eval { $dbh->rollback; }; 417 return ('FAIL',$msg); 418 } else { 419 return ('OK',"OK"); 420 } 421 422 } elsif ($type eq 'mm') { # end alloctype =~ /.i/ 423 424 $msg = "Unable to delete master block $cidr"; 425 eval { 426 $sth = $dbh->prepare("delete from masterblocks where cidr='$cidr'"); 427 $sth->execute; 428 $sth = $dbh->prepare("delete from freeblocks where cidr='$cidr'"); 429 $sth->execute; 430 $dbh->commit; 431 }; 432 if ($@) { 433 eval { $dbh->rollback; }; 434 return ('FAIL', $msg); 435 } else { 436 return ('OK',"OK"); 437 } 438 439 } else { # end alloctype master block case 440 441 ## This is a big block; but it HAS to be done in a chunk. Any removal 442 ## of a netblock allocation may result in a larger chunk of free 443 ## contiguous IP space - which may in turn be combined into a single 444 ## netblock rather than a number of smaller netblocks. 445 446 eval { 447 448 if ($type eq 'rr') { 449 $msg = "Unable to remove routing allocation $cidr"; 450 $sth = $dbh->prepare("delete from routed where cidr='$cidr'"); 451 $sth->execute; 452 # Make sure block getting deleted is properly accounted for. 453 $sth = $dbh->prepare("update freeblocks set routed='n',city='<NULL>'". 454 " where cidr='$cidr'"); 455 $sth->execute; 456 # Set up query to start compacting free blocks. 457 $sth = $dbh->prepare("select * from freeblocks where ". 458 "maskbits<=".$cidr->masklen." and routed='n' order by maskbits desc"); 459 460 } else { # end alloctype routing case 461 462 $sth = $dbh->prepare("delete from allocations where cidr='$cidr'"); 463 $sth->execute; 464 # Special case - delete pool IPs 465 if ($type =~ /^.p$/) { 466 # We have to delete the IPs from the pool listing. 467 $sth = $dbh->prepare("delete from poolips where pool='$cidr'"); 468 $sth->execute; 469 } 470 471 # Set up query for compacting free blocks. 472 $sth = $dbh->prepare("select * from freeblocks where cidr <<= ". 473 "(select cidr from routed where cidr >>= '$cidr') ". 474 " and maskbits<=".$cidr->masklen." and routed='y' order by maskbits desc"); 475 476 } # end alloctype general case 477 478 # Now we look for larger-or-equal-sized free blocks in the same master (routed) 479 # (super)block. If there aren't any, we can't combine blocks anyway. If there 480 # are, we check to see if we can combine blocks. 481 # Execute the statement prepared in the if-else above. 482 483 $sth->execute; 484 485 # NetAddr::IP->compact() attempts to produce the smallest inclusive block 486 # from the caller and the passed terms. 487 # EG: if you call $cidr->compact($ip1,$ip2,$ip3) when $cidr, $ip1, $ip2, 488 # and $ip3 are consecutive /27's starting on .0 (.0-.31, .32-.63, 489 # .64-.95, and .96-.128), you will get an array containing a single 490 # /25 as element 0 (.0-.127). Order is not important; you could have 491 # $cidr=.32/27, $ip1=.96/27, $ip2=.0/27, and $ip3=.64/27. 492 493 my (@together, @combinelist); 494 my $i=0; 495 while (my @data = $sth->fetchrow_array) { 496 my $testIP = new NetAddr::IP $data[0]; 497 @together = $testIP->compact($cidr); 498 my $num = @together; 499 if ($num == 1) { 500 $cidr = $together[0]; 501 $combinelist[$i++] = $testIP; 502 } 503 } 504 505 # Clear old freeblocks entries - if any. $i==0 if not. 506 if ($i>0) { 507 $sth = $dbh->prepare("delete from freeblocks where cidr=?"); 508 foreach my $block (@combinelist) { 509 $sth->execute("$block"); 510 } 511 } 512 513 # insert "new" freeblocks entry 514 if ($type eq 'rr') { 515 $sth = $dbh->prepare("insert into freeblocks values ('$cidr',".$cidr->masklen. 516 ",'<NULL>','n')"); 517 } else { 518 $sth = $dbh->prepare("insert into freeblocks values ('$cidr',".$cidr->masklen. 519 ",(select city from routed where cidr >>= '$cidr'),'y')"); 520 } 521 $sth->execute; 522 523 # If we got here, we've succeeded. Whew! 524 $dbh->commit; 525 }; # end eval 526 if ($@) { 527 eval { $dbh->rollback; }; 528 return ('FAIL', $msg); 529 } else { 530 return ('OK',"OK"); 531 } 532 533 } # end alloctype != netblock 534 535 } # end deleteBlock() 536 537 538 ## IPDB::mailNotify() 78 539 # Sends notification mail to recipients regarding an IPDB operation 79 540 sub mailNotify ($$$) { … … 84 545 $mailer->to($recip); 85 546 $mailer->data("From: \"IP Database\" <ipdb\@example.com>\n", 86 "To: $recip\n",87 547 "Date: ".strftime("%a, %d %b %Y %H:%M:%S %z",localtime)."\n", 88 548 "Subject: {IPDB} $subj\n", -
branches/stable/cgi-bin/consistency-check.pl
r64 r125 10 10 11 11 use DBI; 12 use IPDB qw(:ALL);12 use IPDB 2.0 qw(:ALL); 13 13 use NetAddr::IP; 14 14 15 $dbh = connectDB;15 ($dbh,$errstr) = connectDB("ipdb", "ipdb", "ipdbpwd"); 16 16 17 17 # Schlep up the masters -
branches/stable/cgi-bin/freespace.pl
r117 r125 8 8 # Last update by $Author$ 9 9 ### 10 # Copyright (C) 2004 - Kris Deugau 10 11 11 12 use DBI; 12 use IPDB qw(:ALL);13 use IPDB 2.0 qw(:ALL); 13 14 use NetAddr::IP; 14 15 15 $dbh = connectDB;16 ($dbh,errstr) = connectDB("ipdb", "ipdb", "ipdbpwd"); 16 17 17 18 print "Content-type: text/plain\n\n"; -
branches/stable/cgi-bin/main.cgi
r124 r125 14 14 use DBI; 15 15 use CommonWeb qw(:ALL); 16 use IPDB qw(:ALL);16 use IPDB 2.0 qw(:ALL); 17 17 use CustIDCK; 18 18 use POSIX qw(ceil); … … 33 33 syslog "debug", "$authuser active"; 34 34 35 checkDBSanity(); 35 # Why not a global DB handle? (And a global statement handle, as well...) 36 # Use the connectDB function, otherwise we end up confusing ourselves 37 my $ip_dbh; 38 my $sth; 39 my $errstr; 40 ($ip_dbh,$errstr) = connectDB("ipdb", "ipdb", "ipdbpwd"); 41 if (!$ip_dbh) { 42 printAndExit("Failed to connect to database: $errstr\n"); 43 } 44 checkDBSanity($ip_dbh); 45 initIPDBGlobals($ip_dbh); 36 46 37 47 #prototypes … … 48 58 49 59 # Stuff that gets loaded from the database 50 my @masterblocks; 51 my @citylist; 52 my @poplist; 53 my %disp_alloctypes; 54 my %list_alloctypes; 55 my %allocated; # Count for allocated blocks in a master block 56 my %free; # Count for free blocks (routed and unrouted) in a master block 57 my %bigfree; # Tracking largest free block in a master block 58 my %routed; # Number of routed blocks in a master block 59 60 # Why not a global DB handle? (And a global statement handle, as well...) 61 # We already know the DB is happy, (checkDBSanity) otherwise we wouldn't be here. 62 # Use the connectDB function, otherwise we end up confusing ourselves 63 my $ip_dbh = connectDB; 64 my $sth; 60 #my @citylist; 61 #my @poplist; 62 #my %allocated; # Count for allocated blocks in a master block 63 #my %free; # Count for free blocks (routed and unrouted) in a master block 64 #my %bigfree; # Tracking largest free block in a master block 65 #my %routed; # Number of routed blocks in a master block 65 66 66 67 # Slurp up the master block list - we need this several places 67 68 # While we're at it, initialize the related hashes. 68 $sth = $ip_dbh->prepare("select * from masterblocks order by cidr"); 69 $sth->execute; 70 for (my $i=0; my @data = $sth->fetchrow_array(); $i++) { 71 $masterblocks[$i] = new NetAddr::IP $data[0]; 72 $allocated{"$masterblocks[$i]"} = 0; 73 $free{"$masterblocks[$i]"} = 0; 74 $bigfree{"$masterblocks[$i]"} = 128; # Larger number means smaller block. 75 # Set to 128 to prepare for IPv6 76 $routed{"$masterblocks[$i]"} = 0; 77 } 78 79 # Initialize the city and poplist arrays 80 $sth = $ip_dbh->prepare("select * from cities order by city"); 81 $sth->execute; 82 my $i = 0; 83 my $j = 0; 84 while (my @data = $sth->fetchrow_array) { 85 $citylist[$i++] = $data[0]; 86 if ($data[1] eq 'y') { 87 $poplist[$j++] = $data[0]; 88 } 89 } 90 91 # Initialize alloctypes hashes 92 $sth = $ip_dbh->prepare("select * from alloctypes order by listorder"); 93 $sth->execute; 94 while (my @data = $sth->fetchrow_array) { 95 $disp_alloctypes{$data[0]} = $data[2]; 96 if ($data[3] < 900) { 97 $list_alloctypes{$data[0]} = $data[1]; 98 } 99 } 69 #$sth = $ip_dbh->prepare("select * from masterblocks order by cidr"); 70 #$sth->execute; 71 #for (my $i=0; my @data = $sth->fetchrow_array(); $i++) { 72 # $masterblocks[$i] = new NetAddr::IP $data[0]; 73 # $allocated{"$masterblocks[$i]"} = 0; 74 # $free{"$masterblocks[$i]"} = 0; 75 # $bigfree{"$masterblocks[$i]"} = 128; # Larger number means smaller block. 76 # # Set to 128 to prepare for IPv6 77 # $routed{"$masterblocks[$i]"} = 0; 78 #} 79 100 80 101 81 … … 114 94 my $cidr = new NetAddr::IP $webvar{cidr}; 115 95 116 print "<div type=heading align=center>Adding $cidr as master block.... \n";96 print "<div type=heading align=center>Adding $cidr as master block....</div>\n"; 117 97 118 98 # Allow transactions, and raise an exception on errors so we can catch it later. … … 142 122 eval { $ip_dbh->rollback; }; 143 123 syslog "err", "Could not add master block '$webvar{cidr}' to database: '$@'"; 144 print AndExit("Could not add master block $webvar{cidr} to database: $@");145 } 146 147 print "Success!</div>\n";148 149 printFooter; 124 printError("Could not add master block $webvar{cidr} to database: $@"); 125 } else { 126 print "<div type=heading align=center>Success!</div>\n"; 127 syslog "info", "$authuser added master block $webvar{cidr}"; 128 } 129 150 130 } # end add new master 151 131 … … 169 149 viewBy($webvar{searchfor}, $webvar{input}); 170 150 } 171 printFooter();172 151 } 173 152 … … 208 187 printAndExit("Error $boing: ".$excuses[$rnd/30.0]); 209 188 } 210 211 212 #end main() 213 214 # Shut up error log warning about not disconnecting. Maybe. 215 $ip_dbh->disconnect; 216 # Just in case something waaaayyy down isn't in place properly... 217 exit 0; 189 ## Finally! Done with that NASTY "case" emulation! 190 191 192 193 # Clean up IPDB globals, DB handle, etc. 194 finish($ip_dbh); 195 # We print the footer here, so we don't have to do it elsewhere. 196 printFooter; 197 # Just in case something waaaayyy down isn't in place 198 # properly... we exit explicitly. 199 exit; 200 218 201 219 202 … … 314 297 } else { 315 298 # This shouldn't happen, but if it does, whoever gets it deserves what they get... 316 print AndExit("Invalid query.");299 printError("Invalid query."); 317 300 } 318 301 } else { 319 302 # This shouldn't happen, but if it does, whoever gets it deserves what they get... 320 print AndExit("Invalid searchfor.");303 printError("Invalid searchfor."); 321 304 } 322 305 } # viewBy … … 425 408 426 409 # Initial display: Show master blocks with total allocated subnets, total free subnets 427 sub showSummary 428 { 410 sub showSummary { 411 # this is horrible-ugly-bad and will Go Away real soon now(TM) 429 412 print "Content-type: text/html\n\n"; 430 413 … … 432 415 'Free netblocks', 'Largest free block'); 433 416 434 # Snag the allocations. 435 # I think it's too confusing to leave out internal allocations. 436 $sth = $ip_dbh->prepare("select * from allocations"); 437 $sth->execute(); 438 while (my @data = $sth->fetchrow_array()) { 439 # cidr,custid,type,city,description 440 # We only need the cidr 441 my $cidr = new NetAddr::IP $data[0]; 442 foreach my $master (@masterblocks) { 443 if ($master->contains($cidr)) { 444 $allocated{"$master"}++; 445 } 446 } 447 } 448 449 # Snag routed blocks 450 $sth = $ip_dbh->prepare("select * from routed"); 451 $sth->execute(); 452 while (my @data = $sth->fetchrow_array()) { 453 # cidr,maskbits,city 454 # We only need the cidr 455 my $cidr = new NetAddr::IP $data[0]; 456 foreach my $master (@masterblocks) { 457 if ($master->contains($cidr)) { 458 $routed{"$master"}++; 459 } 460 } 461 } 462 463 # Snag the free blocks. 464 $sth = $ip_dbh->prepare("select * from freeblocks"); 465 $sth->execute(); 466 while (my @data = $sth->fetchrow_array()) { 467 # cidr,maskbits,city 468 # We only need the cidr 469 my $cidr = new NetAddr::IP $data[0]; 470 foreach my $master (@masterblocks) { 471 if ($master->contains($cidr)) { 472 $free{"$master"}++; 473 if ($cidr->masklen < $bigfree{"$master"}) { $bigfree{"$master"} = $cidr->masklen; } 474 } 475 } 476 } 477 478 # Print the data. 417 my %allocated; 418 my %free; 419 my %routed; 420 my %bigfree; 421 422 # Count the allocations. 423 $sth = $ip_dbh->prepare("select count(*) from allocations where cidr <<= ?"); 424 foreach my $master (@masterblocks) { 425 $sth->execute("$master"); 426 $sth->bind_columns(\$allocated{"$master"}); 427 $sth->fetch(); 428 } 429 430 # Count routed blocks 431 $sth = $ip_dbh->prepare("select count(*) from routed where cidr <<= ?"); 432 foreach my $master (@masterblocks) { 433 $sth->execute("$master"); 434 $sth->bind_columns(\$routed{"$master"}); 435 $sth->fetch(); 436 } 437 438 # Count the free blocks. 439 $sth = $ip_dbh->prepare("select count(*) from freeblocks where cidr <<= ?"); 440 foreach my $master (@masterblocks) { 441 $sth->execute("$master"); 442 $sth->bind_columns(\$free{"$master"}); 443 $sth->fetch(); 444 } 445 446 # Find the largest free block in each master 447 $sth = $ip_dbh->prepare("select maskbits from freeblocks where cidr <<= ? order by maskbits limit 1"); 448 foreach my $master (@masterblocks) { 449 $sth->execute("$master"); 450 $sth->bind_columns(\$bigfree{"$master"}); 451 $sth->fetch(); 452 } 453 454 # Print the data. 479 455 my $count=0; 480 456 foreach my $master (@masterblocks) { … … 492 468 print "Note: Free blocks noted here include both routed and unrouted blocks.\n"; 493 469 494 # Because of the way this sub gets called, we don't need to print the footer here.495 # (index.shtml makes an SSI #include call to cgi-bin/main.cgi?action=index)496 # If we do, the footer comes in twice...497 #printFooter;498 470 } # showSummary 499 471 … … 510 482 qq($webvar{block}:</div></center><br>\n); 511 483 484 my %allocated; 485 my %free; 486 my %routed; 487 my %bigfree; 488 512 489 my $master = new NetAddr::IP $webvar{block}; 513 490 my @localmasters; 514 491 515 $sth = $ip_dbh->prepare("select * from routed order by cidr"); 492 # Fetch only the blocks relevant to this master 493 $sth = $ip_dbh->prepare("select * from routed where cidr <<= '$master' order by cidr"); 516 494 $sth->execute(); 517 495 … … 519 497 while (my @data = $sth->fetchrow_array()) { 520 498 my $cidr = new NetAddr::IP $data[0]; 521 if ($master->contains($cidr)) {522 $localmasters[$i++] = $cidr;523 $free{"$cidr"} = 0;524 $allocated{"$cidr"} = 0;499 $localmasters[$i++] = $cidr; 500 $free{"$cidr"} = 0; 501 $allocated{"$cidr"} = 0; 502 $bigfree{"$cidr"} = 128; 525 503 # Retain the routing destination 526 $routed{"$cidr"} = $data[2]; 527 } 528 } 529 530 # Check if there were actually any blocks routed from this master 504 $routed{"$cidr"} = $data[2]; 505 } 506 507 # Check if there were actually any blocks routed from this master 531 508 if ($i > 0) { 532 509 startTable('Routed block','Routed to','Allocated blocks', 533 510 'Free blocks','Largest free block'); 534 511 535 # Count the allocations 536 $sth = $ip_dbh->prepare("select * from allocations"); 537 $sth->execute(); 538 while (my @data = $sth->fetchrow_array()) { 539 # cidr,custid,type,city,description 540 # We only need the cidr 541 my $cidr = new NetAddr::IP $data[0]; 542 foreach my $master (@localmasters) { 543 if ($master->contains($cidr)) { 544 $allocated{"$master"}++; 545 } 546 } 547 } 548 549 # initialize bigfree base points 550 foreach my $lmaster (@localmasters) { 551 $bigfree{"$lmaster"} = 128; 552 } 553 554 # Snag the free blocks. 555 $sth = $ip_dbh->prepare("select * from freeblocks"); 556 $sth->execute(); 557 while (my @data = $sth->fetchrow_array()) { 558 # cidr,maskbits,city 559 # We only need the cidr 560 my $cidr = new NetAddr::IP $data[0]; 561 foreach my $lmaster (@localmasters) { 562 if ($lmaster->contains($cidr)) { 563 $free{"$lmaster"}++; 564 if ($cidr->masklen < $bigfree{"$lmaster"}) { 565 $bigfree{"$lmaster"} = $cidr->masklen; 566 } 567 } 568 # check for largest free block 569 } 512 # Count the allocations 513 $sth = $ip_dbh->prepare("select count(*) from allocations where cidr <<= ?"); 514 foreach my $master (@localmasters) { 515 $sth->execute("$master"); 516 $sth->bind_columns(\$allocated{"$master"}); 517 $sth->fetch(); 518 } 519 520 # Count the free blocks. 521 $sth = $ip_dbh->prepare("select count(*) from freeblocks where cidr <<= ?"); 522 foreach my $master (@localmasters) { 523 $sth->execute("$master"); 524 $sth->bind_columns(\$free{"$master"}); 525 $sth->fetch(); 526 } 527 528 # Get the size of the largest free block 529 $sth = $ip_dbh->prepare("select maskbits from freeblocks where cidr <<= ? order by maskbits limit 1"); 530 foreach my $master (@localmasters) { 531 $sth->execute("$master"); 532 $sth->bind_columns(\$bigfree{"$master"}); 533 $sth->fetch(); 570 534 } 571 535 … … 603 567 # Snag the free blocks. 604 568 my $count = 0; 605 $sth = $ip_dbh->prepare("select * from freeblocks where routed='n' order by cidr"); 569 $sth = $ip_dbh->prepare("select cidr from freeblocks where cidr <<='$master' and ". 570 "routed='n' order by cidr"); 606 571 $sth->execute(); 607 572 while (my @data = $sth->fetchrow_array()) { 608 # cidr,maskbits,city609 # We only need the cidr610 573 my $cidr = new NetAddr::IP $data[0]; 611 if ($master->contains($cidr)) { 612 my @row = ("$cidr", $cidr->range); 613 printRow(\@row, 'color1' ) if($count%2==0); 614 printRow(\@row, 'color2' ) if($count%2!=0); 615 $count++; 616 } 574 my @row = ("$cidr", $cidr->range); 575 printRow(\@row, 'color1' ) if($count%2==0); 576 printRow(\@row, 'color2' ) if($count%2!=0); 577 $count++; 617 578 } 618 579 619 580 print "</table>\n"; 620 printFooter;621 581 } # showMaster 622 582 … … 641 601 qq($master ($data[2]):</div></center><br>\n); 642 602 643 $sth = $ip_dbh->prepare("select * from allocations order by cidr"); 603 startTable('CIDR allocation','Customer Location','Type','CustID','Description/Name'); 604 605 # Snag the allocations for this block 606 $sth = $ip_dbh->prepare("select * from allocations where cidr <<= '$master' order by cidr"); 644 607 $sth->execute(); 645 646 startTable('CIDR allocation','Customer Location','Type','CustID','Description/Name');647 608 648 609 my $count=0; 649 610 while (my @data = $sth->fetchrow_array()) { 650 # cidr,custid,type,city,description,notes,maskbits 611 # cidr,custid,type,city,description,notes,maskbits,circuitid 651 612 my $cidr = new NetAddr::IP $data[0]; 652 if (!$master->contains($cidr)) { next; }653 613 654 614 # Clean up extra spaces that are borking things. … … 691 651 # unrouted free blocks, but it's better to let the database do the work if we can. 692 652 $count = 0; 693 $sth = $ip_dbh->prepare("select * from freeblocks where routed='y' order by cidr");653 $sth = $ip_dbh->prepare("select * from freeblocks where routed='y' and cidr <<= '$master' order by cidr"); 694 654 $sth->execute(); 695 655 while (my @data = $sth->fetchrow_array()) { 696 656 # cidr,maskbits,city 697 657 my $cidr = new NetAddr::IP $data[0]; 698 if ($master->contains($cidr)) { 699 my @row = ("<a href=\"/ip/cgi-bin/main.cgi?action=assign&block=$cidr\">$cidr</a>", 658 my @row = ("<a href=\"/ip/cgi-bin/main.cgi?action=assign&block=$cidr\">$cidr</a>", 700 659 $cidr->range); 701 printRow(\@row, 'color1') if ($count%2 == 0); 702 printRow(\@row, 'color2') if ($count%2 != 0); 703 $count++; 704 } 660 printRow(\@row, 'color1') if ($count%2 == 0); 661 printRow(\@row, 'color2') if ($count%2 != 0); 662 $count++; 705 663 } 706 664 707 665 print "</table>\n"; 708 printFooter;709 666 } # showRBlock 710 667 … … 762 719 print "</table>\n"; 763 720 764 printFooter;765 721 } # end listPool 766 722 767 723 768 # Should this maybe just be a full static page? It just spews out some predefined HTML. 724 # Show "Add new allocation" page. Note that the actual page may 725 # be one of two templates, and the lists come from the database. 769 726 sub assignBlock { 770 727 printHeader(''); … … 824 781 print $html; 825 782 826 printFooter();827 783 } # assignBlock 828 784 … … 837 793 # Going to manually validate some items. 838 794 # custid and city are automagic. 839 validateInput(); 840 841 # This isn't always useful. 842 # if (!$webvar{maskbits}) { 843 # printAndExit("Please enter a CIDR block length."); 844 # } 795 return if !validateInput(); 845 796 846 797 # Several different cases here. … … 860 811 " ptype='$base' and (city='Sudbury' or city='North Bay')"; 861 812 } else { 862 ## $city doesn't seem to get defined here.863 my $city; # Shut up Perl's "strict" scoping/usage check.864 813 $sql = "select * from poolips where available='y' and". 865 814 " ptype='$base' and city='$webvar{pop}'"; … … 891 840 892 841 if (!$webvar{maskbits}) { 893 printAndExit("Please specify a CIDR mask length."); 842 printError("Please specify a CIDR mask length."); 843 return; 894 844 } 895 845 my $sql; … … 908 858 " a set of smaller netblocks or a single smaller netblock."; 909 859 } else { 860 ##fixme 861 # This section needs serious Pondering. 910 862 if ($webvar{alloctype} =~ /^[cdsmw]p$/) { 911 863 if (($webvar{city} !~ /^(Sudbury|North Bay)$/) && ($webvar{alloctype} eq 'dp')) { 912 printAndExit("You must chose Sudbury or North Bay for DSL pools."); } 864 printError("You must chose Sudbury or North Bay for DSL pools."); 865 return; 866 } 913 867 $city = $webvar{city}; 914 868 $failmsg = "No suitable free block found.<br>\nYou will have to route another". 915 " superblock <br>\nfrom one of themaster blocks in Sudbury or chose a smaller".869 " superblock from one of the<br>\nmaster blocks in Sudbury or chose a smaller". 916 870 " block size for the pool."; 917 871 } else { … … 933 887 my @data = $sth->fetchrow_array(); 934 888 if ($data[0] eq "") { 935 printAndExit($failmsg); 889 printError($failmsg); 890 return; 936 891 } 937 892 $cidr = new NetAddr::IP $data[0]; … … 982 937 print $html; 983 938 984 printFooter;985 939 } # end confirmAssign 986 940 … … 990 944 # Some things are done more than once. 991 945 printHeader(''); 992 validateInput(); 993 994 # Set some things that may be needed 995 # Don't set $cidr here as it may not even be a valid IP address. 996 my $alloc_from = new NetAddr::IP $webvar{alloc_from}; 997 998 # dynDSL (dy), sIP DSL(dp), and server pools (sp) are nominally allocated to Sudbury 999 # no matter what else happens. 1000 # if ($webvar{alloctype} =~ /^([sd]p|dy)$/) { $webvar{city} = "Sudbury"; } 1001 # OOPS. forgot about North Bay DSL. 1002 #### Gotta make this cleaner and more accurate 1003 # if ($webvar{alloctype} eq "sp") { $webvar{city} = "Sudbury"; } 1004 1005 # Same ordering as confirmation page 1006 1007 if ($webvar{alloctype} =~ /^[cdsmw]i$/) { 1008 my ($base,$tmp) = split //, $webvar{alloctype}; # split into individual chars 1009 1010 # We'll just have to put up with the oddities caused by SQL (un)sort order 1011 $sth = $ip_dbh->prepare("select * from poolips where pool='$webvar{alloc_from}'". 1012 " and available='y' order by ip"); 1013 $sth->execute; 1014 1015 my @data = $sth->fetchrow_array; 1016 my $cidr = $data[1]; 1017 1018 $sth = $ip_dbh->prepare("update poolips set custid='$webvar{custid}',". 1019 "city='$webvar{city}',available='n',description='$webvar{desc}',". 1020 "circuitid='$webvar{circid}'". 1021 " where ip='$cidr'"); 1022 $sth->execute; 1023 if ($sth->err) { 1024 syslog "err", "Allocation of $cidr to $webvar{custid} by $authuser failed: ". 1025 "'".$sth->errstr."'"; 1026 printAndExit("Allocation of $cidr to $webvar{custid} failed: '".$sth->errstr."'"); 1027 } 1028 print qq(<div class="center"><div class="heading">The IP $cidr has been allocated to customer $webvar{custid}</div></div>); 1029 syslog "notice", "$authuser allocated $cidr to $webvar{custid}"; 1030 # Notify tech@example.com 1031 mailNotify('tech@example.com',"$disp_alloctypes{$webvar{alloctype}} allocation", 1032 "$disp_alloctypes{$webvar{alloctype}} $cidr allocated to customer $webvar{custid}\n". 1033 "Description: $webvar{desc}\n\nAllocated by: $authuser\n"); 1034 1035 } else { # end IP-from-pool allocation 1036 1037 # Set $cidr here as it may not be a valid IP address elsewhere. 1038 my $cidr = new NetAddr::IP $webvar{fullcidr}; 1039 1040 # Allow transactions, and make errors much easier to catch. 1041 # Much as I would like to error-track specifically on each ->execute, 1042 # that's a LOT of code, and some SQL blocks MUST be atomic at a 1043 # multi-statement level. :/ 1044 local $ip_dbh->{AutoCommit} = 0; # These need to be local so we don't 1045 local $ip_dbh->{RaiseError} = 1; # step on our toes by accident. 1046 1047 if ($webvar{fullcidr} eq $webvar{alloc_from}) { 1048 # Easiest case- insert in one table, delete in the other, and go home. More or less. 1049 # insert into allocations values (cidr,custid,type,city,desc) and 1050 # delete from freeblocks where cidr='cidr' 1051 # For data safety on non-transaction DBs, we delete first. 1052 1053 eval { 1054 if ($webvar{alloctype} eq 'rr') { 1055 $sth = $ip_dbh->prepare("update freeblocks set routed='y',city='$webvar{city}'". 1056 " where cidr='$webvar{fullcidr}'"); 1057 $sth->execute; 1058 $sth = $ip_dbh->prepare("insert into routed values ('$webvar{fullcidr}',". 1059 $cidr->masklen.",'$webvar{city}')"); 1060 $sth->execute; 1061 } else { 1062 # common stuff for end-use, dialup, dynDSL, pools, etc, etc. 1063 1064 # city has to be reset for DSL/server pools; nominally to Sudbury. 1065 ## Gotta rethink this; DSL pools can be in North Bay as well. :/ 1066 #if ($webvar{alloctype} =~ /^[sd]p$/) { $webvar{city} = 'Sudbury'; } 1067 1068 $sth = $ip_dbh->prepare("delete from freeblocks where cidr='$webvar{fullcidr}'"); 1069 $sth->execute; 1070 1071 $sth = $ip_dbh->prepare("insert into allocations values ('$webvar{fullcidr}',". 1072 "'$webvar{custid}','$webvar{alloctype}','$webvar{city}','$webvar{desc}',". 1073 "'$webvar{notes}',".$cidr->masklen.",'$webvar{circid}')"); 1074 $sth->execute; 1075 } # routing vs non-routing netblock 1076 $ip_dbh->commit; 1077 }; # end of eval 1078 if ($@) { 1079 carp "Transaction aborted because $@"; 1080 eval { $ip_dbh->rollback; }; 1081 syslog "err", "Allocation of '$webvar{fullcidr}' to '$webvar{custid}' as ". 1082 "'$webvar{alloctype}' by $authuser failed: '$@'"; 1083 printAndExit("Allocation of $cidr as $disp_alloctypes{$webvar{alloctype}} failed.\n"); 1084 } 1085 1086 # If we get here, the DB transaction has succeeded. 1087 syslog "notice", "$authuser allocated '$webvar{fullcidr}' to '$webvar{custid}' as '$webvar{alloctype}'"; 1088 1089 # How to log SQL without munging too many error-checking wrappers in? 1090 # syslog "info", " 1091 # We don't. GRRR. 1092 1093 } else { # webvar{fullcidr} != webvar{alloc_from} 1094 # Hard case. Allocation is smaller than free block. 1095 my $wantmaskbits = $cidr->masklen; 1096 my $maskbits = $alloc_from->masklen; 1097 1098 my @newfreeblocks; # Holds free blocks generated from splitting the source freeblock. 1099 1100 my $i=0; 1101 while ($maskbits++ < $wantmaskbits) { 1102 my @subblocks = $alloc_from->split($maskbits); 1103 $newfreeblocks[$i++] = $subblocks[1]; 1104 } # while 1105 1106 # Begin SQL transaction block 1107 eval { 1108 # Delete old freeblocks entry 1109 $sth = $ip_dbh->prepare("delete from freeblocks where cidr='$webvar{alloc_from}'"); 1110 $sth->execute(); 1111 1112 # now we have to do some magic for routing blocks 1113 if ($webvar{alloctype} eq 'rr') { 1114 # Insert the new freeblocks entries 1115 # Note that non-routed blocks are assigned to <NULL> 1116 $sth = $ip_dbh->prepare("insert into freeblocks values (?, ?, '<NULL>','n')"); 1117 foreach my $block (@newfreeblocks) { 1118 $sth->execute("$block", $block->masklen); 1119 } 1120 # Insert the entry in the routed table 1121 $sth = $ip_dbh->prepare("insert into routed values ('$cidr',". 1122 $cidr->masklen.",'$webvar{city}')"); 1123 $sth->execute; 1124 # Insert the (almost) same entry in the freeblocks table 1125 $sth = $ip_dbh->prepare("insert into freeblocks values ('$cidr',". 1126 $cidr->masklen.",'$webvar{city}','y')"); 1127 $sth->execute; 1128 1129 } else { # done with alloctype == rr 1130 1131 # Insert the new freeblocks entries 1132 $sth = $ip_dbh->prepare("insert into freeblocks values (?, ?, (select city from routed where cidr >> '$cidr'),'y')"); 1133 foreach my $block (@newfreeblocks) { 1134 $sth->execute("$block", $block->masklen); 1135 } 1136 # Insert the allocations entry 1137 $sth = $ip_dbh->prepare("insert into allocations values ('$webvar{fullcidr}',". 1138 "'$webvar{custid}','$webvar{alloctype}','$webvar{city}',". 1139 "'$webvar{desc}','$webvar{notes}',".$cidr->masklen.",'$webvar{circid}')"); 1140 $sth->execute; 1141 } # done with netblock alloctype != rr 1142 $ip_dbh->commit; 1143 }; # end eval 1144 if ($@) { 1145 carp "Transaction aborted because $@"; 1146 eval { $ip_dbh->rollback; }; 1147 syslog "err", "Allocation of '$webvar{fullcidr}' to '$webvar{custid}' as ". 1148 "'$webvar{alloctype}' by $authuser failed: '$@'"; 1149 printAndExit("Allocation of $cidr as $disp_alloctypes{$webvar{alloctype}} failed.\n"); 1150 } 1151 syslog "notice", "$authuser allocated '$webvar{fullcidr}' to '$webvar{custid}' as '$webvar{alloctype}'"; 1152 1153 } # end fullcidr != alloc_from 1154 1155 # Begin SQL transaction block 1156 eval { 1157 # special extra handling for pools. 1158 # Note that this must be done for ANY pool allocation! 1159 if ( my ($pooltype) = ($webvar{alloctype} =~ /^([cdsmw])p$/) ) { 1160 # have to insert all pool IPs into poolips table as "unallocated". 1161 $sth = $ip_dbh->prepare("insert into poolips values ('$webvar{fullcidr}',". 1162 " ?, '6750400', '$webvar{city}', '$pooltype', 'y', '', '', '')"); 1163 my @poolip_list = $cidr->hostenum; 1164 for (my $i=1; $i<=$#poolip_list; $i++) { 1165 $sth->execute($poolip_list[$i]->addr); 1166 } 1167 } # end pool special 1168 $ip_dbh->commit; 1169 }; # end eval 1170 if ($@) { 1171 carp "Transaction aborted because $@"; 1172 eval { $ip_dbh->rollback; }; 1173 syslog "err", "Initialization of pool '$webvar{fullcidr}' by $authuser failed: '$@'"; 1174 printAndExit("$disp_alloctypes{$webvar{alloctype}} $webvar{fullcidr} not completely initialized."); 1175 } 1176 syslog "notice", "$disp_alloctypes{$webvar{alloctype}} '$webvar{fullcidr}' successfully initialized by $authuser"; 1177 1178 print qq(<div class="center"><div class="heading">The block $webvar{fullcidr} was sucessfully added as type '$webvar{alloctype}' ($disp_alloctypes{$webvar{alloctype}})</div></div>); 1179 1180 if ($webvar{alloctype} eq 'cn') { 946 return if !validateInput(); 947 948 # $code is "success" vs "failure", $msg contains OK for a 949 # successful netblock allocation, the IP allocated for static 950 # IP, or the error message if an error occurred. 951 my ($code,$msg) = allocateBlock($ip_dbh, $webvar{fullcidr}, $webvar{alloc_from}, 952 $webvar{custid}, $webvar{alloctype}, $webvar{city}, $webvar{desc}, $webvar{notes}, 953 $webvar{circid}); 954 955 if ($code eq 'OK') { 956 if ($webvar{alloctype} =~ /^.i$/) { 957 print qq(<div class="center"><div class="heading">The IP $msg has been allocated to customer $webvar{custid}</div></div>); 1181 958 # Notify tech@example.com 1182 959 mailNotify('tech@example.com',"$disp_alloctypes{$webvar{alloctype}} allocation", 1183 "$disp_alloctypes{$webvar{alloctype}} $ cidrallocated to customer $webvar{custid}\n".960 "$disp_alloctypes{$webvar{alloctype}} $msg allocated to customer $webvar{custid}\n". 1184 961 "Description: $webvar{desc}\n\nAllocated by: $authuser\n"); 1185 } 1186 1187 } # end static-IP vs netblock allocation 1188 1189 printFooter(); 962 } else { 963 print qq(<div class="center"><div class="heading">The block $webvar{fullcidr} was ). 964 "sucessfully added as type '$webvar{alloctype}' ". 965 "($disp_alloctypes{$webvar{alloctype}})</div></div>"; 966 } 967 syslog "notice", "$authuser allocated '$webvar{fullcidr}' to '$webvar{custid}' as ". 968 "'$webvar{alloctype}'"; 969 } else { 970 syslog "err", "Allocation of '$webvar{fullcidr}' to '$webvar{custid}' as ". 971 "'$webvar{alloctype}' by $authuser failed: '$msg'"; 972 printError("Allocation of $webvar{fullcidr} as $disp_alloctypes{$webvar{alloctype}}". 973 " failed: $msg\n"); 974 } 975 1190 976 } # end insertAssign() 1191 977 … … 1196 982 sub validateInput { 1197 983 if ($webvar{city} eq '-') { 1198 printAndExit("Please choose a city."); 984 printError("Please choose a city."); 985 return; 1199 986 } 1200 987 chomp $webvar{alloctype}; … … 1202 989 if ($webvar{alloctype} =~ /^(ci|di|cn|mi|wi)$/) { 1203 990 if (!$webvar{custid}) { 1204 printAndExit("Please enter a customer ID."); 991 printError("Please enter a customer ID."); 992 return; 1205 993 } 1206 994 if ($webvar{custid} !~ /^(?:\d{10}|\d{7}|STAFF)(?:-\d\d?)?$/) { … … 1209 997 # Crosscheck with ... er... something. 1210 998 my $status = CustIDCK->custid_exist($webvar{custid}); 1211 printAndExit("Error verifying customer ID: ".$CustIDCK::ErrMsg) 1212 if $CustIDCK::Error; 1213 printAndExit("Customer ID not valid. Make sure the Customer ID ". 1214 "is correct.<br>\nUse STAFF for staff static IPs, and 6750400 for any other ". 1215 "non-customer assignments.") 1216 if !$status; 999 if ($CustIDCK::Error) { 1000 printError("Error verifying customer ID: ".$CustIDCK::ErrMsg); 1001 return; 1002 } 1003 if (!$status) { 1004 printError("Customer ID not valid. Make sure the Customer ID ". 1005 "is correct.<br>\nUse STAFF for staff static IPs, and 6750400 for any other ". 1006 "non-customer assignments."); 1007 return; 1008 } 1217 1009 #"Please enter a valid customer ID- this must be a 7- or 10-digit number, or STAFF for 1218 1010 #static IPs for staff."); 1219 1011 } 1220 1012 # print "<!-- [ In validateInput(). Insert customer ID cross-check here. ] -->\n"; 1221 } elsif ($webvar{alloctype} =~ /^([cdsmw]p|si|dn|dy|dc|ee|rr|i i)$/){1013 } elsif ($webvar{alloctype} =~ /^([cdsmw]p|si|dn|dy|dc|ee|rr|in)$/){ 1222 1014 # All non-customer allocations MUST be entered with "our" customer ID. 1223 1015 # I have Defined this as 6750400 for consistency. … … 1226 1018 $webvar{custid} = "6750400"; 1227 1019 } 1228 if ($webvar{alloctype} eq 'rr') {1229 my $flag;1230 foreach (@poplist) {1231 if (/^$webvar{city}$/) {1232 $flag = 'y'; last;1233 }1234 }1235 if (!$flag) {1236 printAndExit("Please choose a valid POP location for a routed netblock. Valid ".1237 "POP locations are currently:<br>\n".join (" - ", @poplist));1238 }1239 }1240 1020 } else { 1241 1021 # Danger! Danger! alloctype should ALWAYS be set by a dropdown. Anyone 1242 1022 # managing to call things in such a way as to cause this deserves a cryptic error. 1243 printAndExit("Invalid alloctype"); 1244 } 1245 return 0; 1023 printError("Invalid alloctype"); 1024 return; 1025 } 1026 1027 # Check POP location 1028 my $flag; 1029 if ($webvar{alloctype} eq 'rr') { 1030 $flag = 'for a routed netblock'; 1031 foreach (@poplist) { 1032 if (/^$webvar{city}$/) { 1033 $flag = 'n'; 1034 last; 1035 } 1036 } 1037 } else { 1038 $flag = 'n'; 1039 if ($webvar{pop} =~ /^-$/) { 1040 $flag = 'to route the block from/through'; 1041 } 1042 } 1043 if ($flag ne 'n') { 1044 printError("Please choose a valid POP location $flag. Valid ". 1045 "POP locations are currently:<br>\n".join (" - ", @poplist)); 1046 return; 1047 } 1048 1049 return 'OK'; 1246 1050 } # end validateInput 1247 1051 … … 1318 1122 print $html; 1319 1123 1320 printFooter();1321 1124 } # edit() 1322 1125 … … 1352 1155 eval { $ip_dbh->rollback; }; 1353 1156 syslog "err", "$authuser could not update block/IP '$webvar{block}': '$@'"; 1354 printAndExit("Could not update block/IP $webvar{block}: $@"); 1157 printError("Could not update block/IP $webvar{block}: $@"); 1158 return; 1355 1159 } 1356 1160 … … 1358 1162 syslog "notice", "$authuser updated $webvar{block}"; 1359 1163 open (HTML, "../updated.html") 1360 1164 or croak "Could not open updated.html :$!"; 1361 1165 my $html = join('', <HTML>); 1362 1166 … … 1376 1180 print $html; 1377 1181 1378 printFooter;1379 1182 } # update() 1380 1183 1381 1184 1382 1185 # Delete an allocation. 1383 sub remove 1384 { 1186 sub remove { 1385 1187 printHeader(''); 1386 1188 #show confirm screen. … … 1392 1194 # Serves'em right for getting here... 1393 1195 if (!defined($webvar{block})) { 1394 printAndExit("Error 332"); 1196 printError("Error 332"); 1197 return; 1395 1198 } 1396 1199 … … 1466 1269 1467 1270 print $html; 1468 printFooter;1469 1271 } # end edit() 1470 1272 … … 1477 1279 printHeader(''); 1478 1280 1479 # Enable transactions and exception-on-errors... but only for this sub 1480 local $ip_dbh->{AutoCommit} = 0; 1481 local $ip_dbh->{RaiseError} = 1; 1482 1483 if ($webvar{alloctype} =~ /^[cdsmw]i$/) { 1484 1485 eval { 1486 $sth = $ip_dbh->prepare("select * from poolips where ip='$webvar{block}'"); 1487 $sth->execute; 1488 my @data = $sth->fetchrow_array; 1489 $sth = $ip_dbh->prepare("select city from allocations where cidr='$data[0]'"); 1490 $sth->execute; 1491 @data = $sth->fetchrow_array; 1492 $sth = $ip_dbh->prepare("update poolips set custid='6750400', available='y',". 1493 " city='$data[0]', description='', notes='', circuitid='' where ip='$webvar{block}'"); 1494 $sth->execute; 1495 $ip_dbh->commit; 1496 }; 1497 if ($@) { 1498 carp "Transaction aborted because $@"; 1499 eval { $ip_dbh->rollback; }; 1500 syslog "err", "$authuser could not deallocate static IP '$webvar{block}': '$@'"; 1501 printAndExit("Could not deallocate static IP $webvar{block}: $@"); 1502 } 1281 my ($code,$msg) = deleteBlock($ip_dbh, $webvar{block}, $webvar{alloctype}); 1282 1283 if ($code eq 'OK') { 1503 1284 print "<div class=heading align=center>Success! $webvar{block} deallocated.</div>\n"; 1504 syslog "notice", "$authuser deallocated static IP $webvar{block}";1505 1506 } elsif ($webvar{alloctype} eq 'mm') { # end alloctype = [cdsmw]i1507 1508 eval {1509 $sth = $ip_dbh->prepare("delete from masterblocks where cidr='$webvar{block}'");1510 $sth->execute;1511 $sth = $ip_dbh->prepare("delete from freeblocks where cidr='$webvar{block}'");1512 $sth->execute;1513 $ip_dbh->commit;1514 };1515 if ($@) {1516 carp "Transaction aborted because $@";1517 eval { $ip_dbh->rollback; };1518 syslog "err", "$authuser could not remove master block '$webvar{block}': '$@'";1519 printAndExit("Could not remove master block $webvar{block}: $@");1520 }1521 print "<div class=heading align=center>Success! Master $webvar{block} removed.</div>\n";1522 syslog "notice", "$authuser removed master block $webvar{block}";1523 1524 } else { # end alloctype master block case1525 1526 ## This is a big block; but it HAS to be done in a chunk. Any removal1527 ## of a netblock allocation may result in a larger chunk of free1528 ## contiguous IP space - which may in turn be combined into a single1529 ## netblock rather than a number of smaller netblocks.1530 1531 eval {1532 1533 my $cidr = new NetAddr::IP $webvar{block};1534 if ($webvar{alloctype} eq 'rr') {1535 1536 $sth = $ip_dbh->prepare("delete from routed where cidr='$webvar{block}'");1537 $sth->execute;1538 # Make sure block getting deleted is properly accounted for.1539 $sth = $ip_dbh->prepare("update freeblocks set routed='n',city='<NULL>'".1540 " where cidr='$webvar{block}'");1541 $sth->execute;1542 # Set up query to start compacting free blocks.1543 $sth = $ip_dbh->prepare("select * from freeblocks where ".1544 "maskbits<=".$cidr->masklen." and routed='n' order by maskbits desc");1545 1546 } else { # end alloctype routing case1547 1548 $sth = $ip_dbh->prepare("delete from allocations where cidr='$webvar{block}'");1549 $sth->execute;1550 # Special case - delete pool IPs1551 if ($webvar{alloctype} =~ /^[cdsmw]p$/) {1552 # We have to delete the IPs from the pool listing.1553 $sth = $ip_dbh->prepare("delete from poolips where pool='$webvar{block}'");1554 $sth->execute;1555 }1556 1557 # Set up query for compacting free blocks.1558 $sth = $ip_dbh->prepare("select * from freeblocks where cidr << ".1559 "(select cidr from routed where cidr >> '$cidr') ".1560 " and maskbits<=".$cidr->masklen." and routed='y' order by maskbits desc");1561 1562 } # end alloctype general case1563 1564 ##TEMP1565 ## Temporary wrapper to "properly" deallocate sIP PPPoE/DSL "netblocks" in 209.91.185.0/241566 my $staticpool = new NetAddr::IP "209.91.185.0/24";1567 ##TEMP1568 if ($cidr->within($staticpool)) {1569 ##TEMP1570 # We've already deleted the block, now we have to stuff its IPs into the pool.1571 $sth = $ip_dbh->prepare("insert into poolips values ('209.91.185.0/24',?,'6750400','Sudbury','d','y','','','')");1572 $sth->execute($cidr->addr);1573 foreach my $ip ($cidr->hostenum) {1574 $sth->execute("$ip");1575 }1576 $cidr--;1577 $sth->execute($cidr->addr);1578 1579 ##TEMP1580 } else {1581 ##TEMP1582 1583 # Now we look for larger-or-equal-sized free blocks in the same master (routed)1584 # (super)block. If there aren't any, we can't combine blocks anyway. If there1585 # are, we check to see if we can combine blocks.1586 # Execute the statement prepared in the if-else above.1587 1588 $sth->execute;1589 1590 # NetAddr::IP->compact() attempts to produce the smallest inclusive block1591 # from the caller and the passed terms.1592 # EG: if you call $cidr->compact($ip1,$ip2,$ip3) when $cidr, $ip1, $ip2,1593 # and $ip3 are consecutive /27's starting on .0 (.0-.31, .32-.63,1594 # .64-.95, and .96-.128), you will get an array containing a single1595 # /25 as element 0 (.0-.127). Order is not important; you could have1596 # $cidr=.32/27, $ip1=.96/27, $ip2=.0/27, and $ip3=.64/27.1597 1598 my (@together, @combinelist);1599 my $i=0;1600 while (my @data = $sth->fetchrow_array) {1601 my $testIP = new NetAddr::IP $data[0];1602 @together = $testIP->compact($cidr);1603 my $num = @together;1604 if ($num == 1) {1605 $cidr = $together[0];1606 $combinelist[$i++] = $testIP;1607 }1608 }1609 1610 # Clear old freeblocks entries - if any. $i==0 if not.1611 if ($i>0) {1612 $sth = $ip_dbh->prepare("delete from freeblocks where cidr=?");1613 foreach my $block (@combinelist) {1614 $sth->execute("$block");1615 }1616 }1617 1618 # insert "new" freeblocks entry1619 if ($webvar{alloctype} eq 'rr') {1620 $sth = $ip_dbh->prepare("insert into freeblocks values ('$cidr',".$cidr->masklen.1621 ",'<NULL>','n')");1622 } else {1623 $sth = $ip_dbh->prepare("insert into freeblocks values ('$cidr',".$cidr->masklen.1624 ",(select city from routed where cidr >>= '$cidr'),'y')");1625 }1626 $sth->execute;1627 1628 ##TEMP1629 }1630 ##TEMP1631 1632 # If we got here, we've succeeded. Whew!1633 $ip_dbh->commit;1634 }; # end eval1635 if ($@) {1636 carp "Transaction aborted because $@";1637 eval { $ip_dbh->rollback; };1638 syslog "err", "$authuser could not deallocate netblock '$webvar{block}': '$@'";1639 printAndExit("Could not deallocate netblock $webvar{block}: $@");1640 }1641 print "<div class=heading align=center>Success! $webvar{block} deleted.</div>\n";1642 1285 syslog "notice", "$authuser deallocated '$webvar{alloctype}'-type netblock $webvar{block}"; 1643 1644 } # end alloctype != netblock 1645 1646 printFooter; 1286 } else { 1287 if ($webvar{alloctype} =~ /^.i$/) { 1288 syslog "err", "$authuser could not deallocate static IP '$webvar{block}': '$msg'"; 1289 printError("Could not deallocate static IP $webvar{block}: $msg"); 1290 } else { 1291 syslog "err", "$authuser could not deallocate netblock '$webvar{block}': '$msg'"; 1292 printError("Could not deallocate netblock $webvar{block}: $msg"); 1293 } 1294 } 1295 1647 1296 } # finalDelete 1648 1297 -
branches/stable/index.shtml
r4 r125 1 1 <!--#include file="header.inc"--> 2 2 <!--#include virtual="/ip/cgi-bin/main.cgi?action=index" --> 3 <!--#include file="footer.inc"-->
Note:
See TracChangeset
for help on using the changeset viewer.