Ignore:
Timestamp:
05/15/13 16:17:00 (12 years ago)
Author:
Kris Deugau
Message:

/branches/stable

Merge SQL changes and other miscellaneous fixes from /trunk through r553.

Location:
branches/stable
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • branches/stable

  • branches/stable/cgi-bin/CustIDCK.pm

    r593 r594  
    3434  my $custid = shift;
    3535
    36   return 1 if $custid =~ /^STAFF$/;
    37   return 1 if $custid =~ /^5554242$/;  # just in case some later change might block this
    38   return 1 if $custid =~ /^\d{7}$/;
    39   return 1 if $custid =~ /^\d{10}$/;
     36  # hardcoded "OK" custids.
     37  return 1 if $custid =~ /^STAFF(?:-\d\d?)?$/;
     38  return 1 if $custid =~ /^5554242(?:-\d\d?)?$/;  # just in case some later change might block this
     39  return 1 if $custid =~ /^\d{7}(?:-\d\d?)?$/;
     40  return 1 if $custid =~ /^\d{10}(?:-\d\d?)?$/;
     41
     42  # Force uppercase for now...
     43  $custid =~ tr/a-z/A-Z/;
    4044
    4145# some example code for a database check
     
    6670
    6771  # We should have a valid DB connection by now.
    68   my $sth = $dbh->prepare("SELECT custid FROM custid WHERE custid = '$custid'");
    69   $sth->execute;
     72 
     73  my $hr = $dbh->selectrow_hashref("SELECT custid FROM custid WHERE custid = ?", undef, ($custid) );
     74  my $status = 0;
    7075  if ($dbh->err) {
    7176    $CustIDCK::Error = 1;
    7277    $CustIDCK::ErrMsg = $dbh->errstr();
    73     $sth->finish;
    74     $dbh->disconnect;
    75     return 0;
     78  } else {
     79    $status = 1 if ( $hr->{custid} );
    7680  }
    77   my $hr = $sth->fetchrow_hashref();
    78   my $status = 0;
    79   $status = 1 if ( $hr->{custid} );
    80   $sth->finish;
    8181  $dbh->disconnect;
    8282  return $status;
  • branches/stable/cgi-bin/IPDB.pm

    r593 r594  
    2323@ISA            = qw(Exporter);
    2424@EXPORT_OK    = qw(
    25         %disp_alloctypes %list_alloctypes %def_custids @citylist @poplist @masterblocks
    26         %allocated %free %routed %bigfree %IPDBacl %aclmsg
    27         &initIPDBGlobals &connectDB &finish &checkDBSanity &allocateBlock &addMaster
    28         &deleteBlock &getBlockData &mailNotify
     25        %disp_alloctypes %list_alloctypes %def_custids @citylist @poplist
     26        %IPDBacl %aclmsg
     27        &initIPDBGlobals &connectDB &finish &checkDBSanity
     28        &addMaster &touchMaster
     29        &listSummary &listMaster &listRBlock &listFree &listPool
     30        &getMasterList &getTypeList &getPoolSelect &findAllocateFrom
     31        &ipParent &subParent &blockParent &getRoutedCity
     32        &allocateBlock &updateBlock &deleteBlock &getBlockData
     33        &getNodeList &getNodeName &getNodeInfo
     34        &mailNotify
    2935        );
    3036
     
    3238%EXPORT_TAGS    = ( ALL => [qw(
    3339                %disp_alloctypes %list_alloctypes %def_custids @citylist @poplist
    34                 @masterblocks %allocated %free %routed %bigfree %IPDBacl %aclmsg
    35                 &initIPDBGlobals &connectDB &finish &checkDBSanity &allocateBlock
    36                 &addMaster &deleteBlock &getBlockData &mailNotify
     40                %IPDBacl %aclmsg
     41                &initIPDBGlobals &connectDB &finish &checkDBSanity
     42                &addMaster &touchMaster
     43                &listSummary &listMaster &listRBlock &listFree &listPool
     44                &getMasterList &getTypeList &getPoolSelect &findAllocateFrom
     45                &ipParent &subParent &blockParent &getRoutedCity
     46                &allocateBlock &updateBlock &deleteBlock &getBlockData
     47                &getNodeList &getNodeName &getNodeInfo
     48                &mailNotify
    3749                )]
    3850        );
     
    4658our @citylist;
    4759our @poplist;
    48 our @masterblocks;
    49 our %allocated;
    50 our %free;
    51 our %routed;
    52 our %bigfree;
    5360our %IPDBacl;
    5461
     
    113120  }
    114121
    115   # Master block list
    116   $sth = $dbh->prepare("select cidr from masterblocks order by cidr");
    117   $sth->execute;
    118   return (undef,$sth->errstr) if $sth->err;
    119   for (my $i=0; my @data = $sth->fetchrow_array(); $i++) {
    120     $masterblocks[$i] = new NetAddr::IP $data[0];
    121     $allocated{"$masterblocks[$i]"} = 0;
    122     $free{"$masterblocks[$i]"} = 0;
    123     $bigfree{"$masterblocks[$i]"} = 128; # Larger number means smaller block.
    124                                         # Set to 128 to prepare for IPv6
    125     $routed{"$masterblocks[$i]"} = 0;
    126   }
    127 
    128122  # Load ACL data.  Specific username checks are done at a different level.
    129123  $sth = $dbh->prepare("select username,acl from users");
     
    232226  # Wrap all the SQL in a transaction
    233227  eval {
    234     my $sth = $dbh->prepare("select count(*) from masterblocks where cidr <<= '$cidr'");
    235     $sth->execute;
    236     my @data = $sth->fetchrow_array;
    237 
    238     if ($data[0] eq 0) {
     228    my ($mexist) = $dbh->selectrow_array("SELECT cidr FROM masterblocks WHERE cidr <<= ?", undef, ($cidr) );
     229
     230    if (!$mexist) {
    239231      # First case - master is brand-spanking-new.
    240232##fixme: rwhois should be globally-flagable somewhere, much like a number of other things
    241233## maybe a db table called "config"?
    242       $sth = $dbh->prepare("insert into masterblocks (cidr,rwhois) values ('$cidr','y')");
    243       $sth->execute;
     234      $dbh->do("INSERT INTO masterblocks (cidr,rwhois) VALUES (?,?)", undef, ($cidr,'y') );
    244235
    245236# Unrouted blocks aren't associated with a city (yet).  We don't rely on this
    246237# elsewhere though;  legacy data may have traps and pitfalls in it to break this.
    247238# Thus the "routed" flag.
    248 
    249       $sth = $dbh->prepare("insert into freeblocks (cidr,maskbits,city,routed)".
    250         " values ('$cidr',".$cidr->masklen.",'<NULL>','n')");
    251       $sth->execute;
     239      $dbh->do("INSERT INTO freeblocks (cidr,maskbits,city,routed) VALUES (?,?,?,?)", undef,
     240        ($cidr, $cidr->masklen, '<NULL>', 'n') );
    252241
    253242      # If we get here, everything is happy.  Commit changes.
    254243      $dbh->commit;
    255244
    256     } # new master does not contain existing master(s)
     245    } # done new master does not contain existing master(s)
    257246    else {
    258247
    259248      # collect the master(s) we're going to absorb, and snag the longest netmask while we're at it.
    260249      my $smallmask = $cidr->masklen;
    261       $sth = $dbh->prepare("select cidr as mask from masterblocks where cidr <<= '$cidr'");
    262       $sth->execute;
     250      my $sth = $dbh->prepare("SELECT cidr FROM masterblocks WHERE cidr <<= ?");
     251      $sth->execute($cidr);
    263252      my @cmasters;
    264253      while (my @data = $sth->fetchrow_array) {
     
    279268
    280269      # collect the unrouted free blocks within the new master
    281       $sth = $dbh->prepare("select cidr from freeblocks where ".
    282                 "maskbits>=$smallmask and cidr <<= '$cidr' and routed='n'");
    283       $sth->execute;
     270      $sth = $dbh->prepare("SELECT cidr FROM freeblocks WHERE maskbits <= ? AND cidr <<= ? AND routed = 'n'");
     271      $sth->execute($smallmask, $cidr);
    284272      while (my @data = $sth->fetchrow_array) {
    285273        my $freeblock = new NetAddr::IP $data[0];
     
    293281
    294282      # freeblocks
    295       $sth = $dbh->prepare("delete from freeblocks where cidr <<= ?");
    296       my $sth2 = $dbh->prepare("insert into freeblocks (cidr,maskbits,city,routed) values (?,?,'<NULL>','n')");
     283      $sth = $dbh->prepare("DELETE FROM freeblocks WHERE cidr <<= ?");
     284      my $sth2 = $dbh->prepare("INSERT INTO freeblocks (cidr,maskbits,city,routed) VALUES (?,?,'<NULL>','n')");
    297285      foreach my $newblock (@blocklist) {
    298         $sth->execute("$newblock");
    299         $sth2->execute("$newblock", $newblock->masklen);
     286        $sth->execute($newblock);
     287        $sth2->execute($newblock, $newblock->masklen);
    300288      }
    301289
    302290      # master
    303       $sth = $dbh->prepare("delete from masterblocks where cidr <<= '$cidr'");
    304       $sth->execute;
    305       $sth = $dbh->prepare("insert into masterblocks (cidr,rwhois) values ('$cidr','y')");
    306       $sth->execute;
     291      $dbh->do("DELETE FROM masterblocks WHERE cidr <<= ?", undef, ($cidr) );
     292      $dbh->do("INSERT INTO masterblocks (cidr,rwhois) VALUES (?,?)", undef, ($cidr, 'y') );
    307293
    308294      # *whew*  If we got here, we likely suceeded.
     
    319305  }
    320306} # end addMaster
     307
     308
     309## IPDB::touchMaster()
     310# Update last-changed timestamp on a master block.
     311sub touchMaster {
     312  my $dbh = shift;
     313  my $master = shift;
     314
     315  local $dbh->{AutoCommit} = 0;
     316  local $dbh->{RaiseError} = 1;
     317
     318  eval {
     319    $dbh->do("UPDATE masterblocks SET mtime=now() WHERE cidr = ?", undef, ($master));
     320    $dbh->commit;
     321  };
     322
     323  if ($@) {
     324    my $msg = $@;
     325    eval { $dbh->rollback; };
     326    return ('FAIL',$msg);
     327  }
     328  return ('OK','OK');
     329} # end touchMaster()
     330
     331
     332## IPDB::listSummary()
     333# Get summary list of all master blocks
     334# Returns an arrayref to a list of hashrefs containing the master block, routed count,
     335# allocated count, free count, and largest free block masklength
     336sub listSummary {
     337  my $dbh = shift;
     338
     339  my $mlist = $dbh->selectall_arrayref("SELECT cidr AS master FROM masterblocks ORDER BY cidr", { Slice => {} });
     340
     341  foreach (@{$mlist}) {
     342    my ($rcnt) = $dbh->selectrow_array("SELECT count(*) FROM routed WHERE cidr <<= ?", undef, ($$_{master}));
     343    $$_{routed} = $rcnt;
     344    my ($acnt) = $dbh->selectrow_array("SELECT count(*) FROM allocations WHERE cidr <<= ?", undef, ($$_{master}));
     345    $$_{allocated} = $acnt;
     346    my ($fcnt) = $dbh->selectrow_array("SELECT count(*) FROM freeblocks WHERE cidr <<= ?".
     347        " AND (routed='y' OR routed='n')", undef, ($$_{master}));
     348    $$_{free} = $fcnt;
     349    my ($bigfree) = $dbh->selectrow_array("SELECT maskbits FROM freeblocks WHERE cidr <<= ?".
     350        " AND (routed='y' OR routed='n') ORDER BY maskbits LIMIT 1", undef, ($$_{master}));
     351##fixme:  should find a way to do this without having to HTMLize the <>
     352    $bigfree = "/$bigfree" if $bigfree;
     353    $bigfree = '<NONE>' if !$bigfree;
     354    $$_{bigfree} = $bigfree;
     355  }
     356  return $mlist;
     357} # end listSummary()
     358
     359
     360## IPDB::listMaster()
     361# Get list of routed blocks in the requested master
     362# Returns an arrayref to a list of hashrefs containing the routed block, POP/city the block is routed to,
     363# allocated count, free count, and largest free block masklength
     364sub listMaster {
     365  my $dbh = shift;
     366  my $master = shift;
     367
     368  my $rlist = $dbh->selectall_arrayref("SELECT cidr AS block,city FROM routed WHERE cidr <<= ? ORDER BY cidr",
     369        { Slice => {} }, ($master) );
     370
     371  foreach (@{$rlist}) {
     372    my ($acnt) = $dbh->selectrow_array("SELECT count(*) FROM allocations WHERE cidr <<= ?", undef, ($$_{block}));
     373    $$_{nsubs} = $acnt;
     374    my ($fcnt) = $dbh->selectrow_array("SELECT count(*) FROM freeblocks WHERE cidr <<= ?".
     375        " AND (routed='y' OR routed='n')", undef, ($$_{block}));
     376    $$_{nfree} = $fcnt;
     377    my ($bigfree) = $dbh->selectrow_array("SELECT maskbits FROM freeblocks WHERE cidr <<= ?".
     378        " AND (routed='y' OR routed='n') ORDER BY maskbits LIMIT 1", undef, ($$_{block}));
     379##fixme:  should find a way to do this without having to HTMLize the <>
     380    $bigfree = "/$bigfree" if $bigfree;
     381    $bigfree = '<NONE>' if !$bigfree;
     382    $$_{lfree} = $bigfree;
     383  }
     384  return $rlist;
     385} # end listMaster()
     386
     387
     388## IPDB::listRBlock()
     389# Gets a list of free blocks in the requested parent/master in both CIDR and range notation
     390# Takes a parent/master and an optional flag to look at routed or unrouted blocks, depending
     391# on whether the master is a direct master or a routed block
     392# Returns an arrayref to a list of hashrefs containing the CIDR and range-notation blocks
     393sub listRBlock {
     394  my $dbh = shift;
     395  my $routed = shift;
     396
     397  # Snag the allocations for this block
     398  my $sth = $dbh->prepare("SELECT cidr,city,type,custid,swip,description".
     399        " FROM allocations WHERE cidr <<= ? ORDER BY cidr");
     400  $sth->execute($routed);
     401
     402  # hack hack hack
     403  # set up to flag swip=y records if they don't actually have supporting data in the customers table
     404  my $custsth = $dbh->prepare("SELECT count(*) FROM customers WHERE custid = ?");
     405
     406  my @blocklist;
     407  while (my ($cidr,$city,$type,$custid,$swip,$desc) = $sth->fetchrow_array()) {
     408    $custsth->execute($custid);
     409    my ($ncust) = $custsth->fetchrow_array();
     410    my %row = (
     411        block => $cidr,
     412        city => $city,
     413        type => $disp_alloctypes{$type},
     414        custid => $custid,
     415        swip => ($swip eq 'y' ? 'Yes' : 'No'),
     416        partswip => ($swip eq 'y' && $ncust == 0 ? 1 : 0),
     417        desc => $desc
     418        );
     419    $row{subblock} = ($type =~ /^.r$/);         # hmf.  wonder why these won't work in the hash declaration...
     420    $row{listpool} = ($type =~ /^.[pd]$/);
     421    push (@blocklist, \%row);
     422  }
     423  return \@blocklist;
     424} # end listRBlock()
     425
     426
     427## IPDB::listFree()
     428# Gets a list of free blocks in the requested parent/master in both CIDR and range notation
     429# Takes a parent/master and an optional "routed or unrouted" flag that defaults to unrouted.
     430# Returns an arrayref to a list of hashrefs containing the CIDR and range-notation blocks
     431# Returns some extra flags in the hashrefs for routed blocks, since those can have several subtypes
     432sub listFree {
     433  my $dbh = shift;
     434  my $master = shift;
     435  my $routed = shift || 'n';
     436
     437  # do it this way so we can waste a little less time iterating
     438  my $sth = $dbh->prepare("SELECT cidr,routed FROM freeblocks WHERE cidr <<= ? AND ".
     439        ($routed eq 'n' ? '' : 'NOT')." routed = 'n' ORDER BY cidr");
     440  $sth->execute($master);
     441  my @flist;
     442  while (my ($cidr,$rtype) = $sth->fetchrow_array()) {
     443    $cidr = new NetAddr::IP $cidr;
     444    my %row = (
     445        fblock => "$cidr",
     446        frange => $cidr->range,
     447        );
     448    if ($routed eq 'y') {
     449      $row{subblock} = ($rtype ne 'y' && $rtype ne 'n');
     450      $row{fbtype} = $rtype;
     451    }
     452    push @flist, \%row;
     453  }
     454  return \@flist;
     455} # end listFree()
     456
     457
     458## IPDB::listPool()
     459#
     460sub listPool {
     461  my $dbh = shift;
     462  my $pool = shift;
     463
     464  my $sth = $dbh->prepare("SELECT ip,custid,available,description,type".
     465        " FROM poolips WHERE pool = ? ORDER BY ip");
     466  $sth->execute($pool);
     467  my @poolips;
     468  while (my ($ip,$custid,$available,$desc,$type) = $sth->fetchrow_array) {
     469    my %row = (
     470        ip => $ip,
     471        custid => $custid,
     472        available => $available,
     473        desc => $desc,
     474        delme => $available eq 'n'
     475        );
     476    push @poolips, \%row;
     477  }
     478  return \@poolips;
     479} # end listPool()
     480
     481
     482## IPDB::getMasterList()
     483# Get a list of master blocks, optionally including last-modified timestamps
     484# Takes an optional flag to indicate whether to include timestamps;
     485#  'm' includes ctime, all others (suggest 'c') do not.
     486# Returns an arrayref to a list of hashrefs
     487sub getMasterList {
     488  my $dbh = shift;
     489  my $stampme = shift || 'm';   # optional but should be set by caller for clarity
     490
     491  my $mlist = $dbh->selectall_arrayref("SELECT cidr AS master".($stampme eq 'm' ? ',mtime' : '').
     492        " FROM masterblocks ORDER BY cidr", { Slice => {} });
     493  return $mlist;
     494} # end getMasterList()
     495
     496
     497## IPDB::getTypeList()
     498# Get an alloctype/description pair list suitable for dropdowns
     499# Takes a flag to determine which general groups of types are returned
     500# Returns an reference to an array of hashrefs
     501sub getTypeList {
     502  my $dbh = shift;
     503  my $tgroup = shift || 'a';    # technically optional, like this, but should
     504                                # really be specified in the call for clarity
     505  my $tlist;
     506  if ($tgroup eq 'p') {
     507    # grouping 'p' - primary allocation types.  These include static IP pools (_d and _p),
     508    # dynamic-allocation ranges (_e), containers (_c), and the "miscellaneous" cn, in, and en types.
     509    $tlist = $dbh->selectall_arrayref("SELECT type,listname FROM alloctypes WHERE listorder < 500 ".
     510        "AND type NOT LIKE '_i' AND type NOT LIKE '_r' ORDER BY listorder", { Slice => {} });
     511  } elsif ($tgroup eq 'c') {
     512    # grouping 'c' - contained types.  These include all static IPs and all _r types.
     513    $tlist = $dbh->selectall_arrayref("SELECT type,listname FROM alloctypes WHERE listorder <= 500 ".
     514        " AND (type LIKE '_i' OR type LIKE '_r') ORDER BY listorder", { Slice => {} });
     515  } else {
     516    # grouping 'a' - all standard allocation types.  This includes everything
     517    # but mm (present only as a formality).  Make this the default.
     518    $tlist = $dbh->selectall_arrayref("SELECT type,listname FROM alloctypes WHERE listorder <= 500 ".
     519        " ORDER BY listorder", { Slice => {} });
     520  }
     521  return $tlist;
     522}
     523
     524
     525## IPDB::getPoolSelect()
     526# Get a list of pools matching the passed city and type that have 1 or more free IPs
     527# Returns an arrayref to a list of hashrefs
     528sub getPoolSelect {
     529  my $dbh = shift;
     530  my $iptype = shift;
     531  my $pcity = shift;
     532
     533  my ($ptype) = ($iptype =~ /^(.)i$/);
     534  return if !$ptype;
     535  $ptype .= '_';
     536
     537  my $plist = $dbh->selectall_arrayref(
     538        "SELECT (SELECT city FROM allocations WHERE cidr=poolips.pool) AS poolcit, ".
     539        "poolips.pool AS poolblock, COUNT(*) AS poolfree FROM poolips,allocations ".
     540        "WHERE poolips.available='y' AND poolips.pool=allocations.cidr ".
     541        "AND allocations.city = ? AND poolips.type LIKE ? ".
     542        "GROUP BY pool", { Slice => {} }, ($pcity, $ptype) );
     543  return $plist;
     544} # end getPoolSelect()
     545
     546
     547## IPDB::findAllocateFrom()
     548# Find free block to add a new allocation from.  (CIDR block version of pool select above, more or less)
     549# Takes
     550#  - mask length
     551#  - allocation type
     552#  - POP city "parent"
     553#  - optional master-block restriction
     554#  - optional flag to allow automatic pick-from-private-network-ranges
     555# Returns a string with the first CIDR block matching the criteria, if any
     556sub findAllocateFrom {
     557  my $dbh = shift;
     558  my $maskbits = shift;
     559  my $type = shift;
     560  my $city = shift;
     561  my $pop = shift;
     562  my %optargs = @_;
     563
     564  my $failmsg = "No suitable free block found\n";
     565
     566## Set up the SQL to find out what freeblock we can (probably) use for an allocation.
     567## Very large systems will require development of a reserve system (possibly an extension
     568## of the reserve-for-expansion concept in https://secure.deepnet.cx/trac/ipdb/ticket/24?)
     569## Also populate a value list for the DBI call.
     570
     571  my @vallist = ($maskbits, ($type eq 'rm' ? 'n' : ($type =~ /^(.)r$/ ? "$1" : 'y')) );
     572  my $sql = "SELECT cidr FROM freeblocks WHERE maskbits <= ? AND routed = ?";
     573
     574  # for PPP(oE) and container types, the POP city is the one attached to the pool.
     575  # individual allocations get listed with the customer city site.
     576  ##fixme:  chain cities to align roughly with a full layer-2 node graph
     577  $city = $pop if $type !~ /^.[pc]$/;
     578  if ($type ne 'rm' && $city) {
     579    $sql .= " AND city = ?";
     580    push @vallist, $city;
     581  }
     582  # Allow specifying an arbitrary full block, instead of a master
     583  if ($optargs{gimme}) {
     584    $sql .= " AND cidr >>= ?";
     585    push @vallist, $optargs{gimme};
     586  }
     587  # if a specific master was requested, allow the requestor to self->shoot(foot)
     588  if ($optargs{master} && $optargs{master} ne '-') {
     589    $sql .= " AND cidr <<= ?" if $optargs{master} ne '-';
     590    push @vallist, $optargs{master};
     591  } else {
     592    # if a specific master was NOT requested, filter out the RFC 1918 private networks
     593    if (!$optargs{allowpriv}) {
     594      $sql .= " AND NOT (cidr <<= '192.168.0.0/16' OR cidr <<= '10.0.0.0/8' OR cidr <<= '172.16.0.0/12')";
     595    }
     596  }
     597  # Sorting and limiting, since we don't (currently) care to provide a selection of
     598  # blocks to carve up.  This preserves something resembling optimal usage of the IP
     599  # space by forcing contiguous allocations and free blocks as much as possible.
     600  $sql .= " ORDER BY maskbits DESC,cidr LIMIT 1";
     601
     602  my ($fbfound) = $dbh->selectrow_array($sql, undef, @vallist);
     603  return $fbfound;
     604} # end findAllocateFrom()
     605
     606
     607## IPDB::ipParent()
     608# Get an IP's parent pool's details
     609# Takes a database handle and IP
     610# Returns a hashref to the parent pool block, if any
     611sub ipParent {
     612  my $dbh = shift;
     613  my $block = shift;
     614
     615  my $pinfo = $dbh->selectrow_hashref("SELECT cidr,custid,type,city,description FROM allocations".
     616        " WHERE cidr >>= ?", undef, ($block) );
     617  return $pinfo;
     618} # end ipParent()
     619
     620
     621## IPDB::subParent()
     622# Get a block's parent's details
     623# Takes a database handle and CIDR block
     624# Returns a hashref to the parent container block, if any
     625sub subParent {
     626  my $dbh = shift;
     627  my $block = shift;
     628
     629  my $pinfo = $dbh->selectrow_hashref("SELECT cidr,custid,type,city,description FROM allocations".
     630        " WHERE cidr >>= ?", undef, ($block) );
     631  return $pinfo;
     632} # end subParent()
     633
     634
     635## IPDB::blockParent()
     636# Get a block's parent's details
     637# Takes a database handle and CIDR block
     638# Returns a hashref to the parent container block, if any
     639sub blockParent {
     640  my $dbh = shift;
     641  my $block = shift;
     642
     643  my $pinfo = $dbh->selectrow_hashref("SELECT cidr,city FROM routed".
     644        " WHERE cidr >>= ?", undef, ($block) );
     645  return $pinfo;
     646} # end blockParent()
     647
     648
     649## IPDB::getRoutedCity()
     650# Get the city for a routed block.
     651sub getRoutedCity {
     652  my $dbh = shift;
     653  my $block = shift;
     654
     655  my ($rcity) = $dbh->selectrow_array("SELECT city FROM routed WHERE cidr = ?", undef, ($block) );
     656  return $rcity;
     657} # end getRoutedCity()
    321658
    322659
     
    362699#       and available='y' order by ip limit 1);
    363700
    364 # If no specific IP was requested, pick the next available one from the pool.
    365       if (!$cidr) {
    366         $sth = $dbh->prepare("select ip from poolips where pool='$alloc_from'".
    367           " and available='y' order by ip");
    368         $sth->execute;
    369 
    370         my @data = $sth->fetchrow_array;
    371         $cidr = $data[0];  # $cidr is already declared when we get here!
    372       }
    373 
    374       $sth = $dbh->prepare("update poolips set custid=?,city=?,".
    375         "available='n',description=?,notes=?,circuitid=?,privdata=?".
    376         " where ip=?");
    377       $sth->execute($custid, $city, $desc, $notes, $circid, $privdata, "$cidr");
     701      if ($cidr) {
     702        my ($isavail) = $dbh->selectrow_array("SELECT available FROM poolips WHERE ip=?", undef, ($cidr) );
     703        if ($isavail eq 'n') {
     704          die "IP already allocated.  Deallocate and reallocate, or update the entry\n";
     705        }
     706        if (!$isavail) {
     707          die "IP is not in an IP pool.\n";
     708        }
     709      } else {
     710        ($cidr) = $dbh->selectrow_array("SELECT ip FROM poolips WHERE pool=? AND available='y' ORDER BY ip",
     711                undef, ($alloc_from) );
     712      }
     713      $dbh->do("UPDATE poolips SET custid=?,city=?,available='n',description=?,notes=?,circuitid=?,privdata=? ".
     714        "WHERE ip=?", undef, ($custid, $city, $desc, $notes, $circid, $privdata, $cidr) );
     715
    378716# node hack
    379717      if ($nodeid && $nodeid ne '') {
     
    382720      }
    383721# end node hack
     722
    384723      $dbh->commit;
    385724    };
    386725    if ($@) {
    387       $msg .= ": '".$sth->errstr."'";
     726      $msg .= ": $@";
    388727      eval { $dbh->rollback; };
    389728      return ('FAIL',$msg);
     
    634973
    635974
     975## IPDB::updateBlock()
     976# Update an allocation
     977# Takes all allocation fields in a hash
     978sub updateBlock {
     979  my $dbh = shift;
     980  my %args = @_;
     981
     982  return ('FAIL', 'Missing block to update') if !$args{block};
     983
     984  # do it all in a transaction
     985  local $dbh->{AutoCommit} = 0;
     986  local $dbh->{RaiseError} = 1;
     987
     988  my @fieldlist;
     989  my @vallist;
     990  foreach ('custid', 'city', 'description', 'notes', 'circuitid', 'privdata') {
     991    if ($args{$_}) {
     992      push @fieldlist, $_;
     993      push @vallist, $args{$_};
     994    }
     995  }
     996
     997  my $updtable = 'allocations';
     998  my $keyfield = 'cidr';
     999  if ($args{type} =~ /^(.)i$/) {
     1000    $updtable = 'poolips';
     1001    $keyfield = 'ip';
     1002  } else {
     1003## fixme:  there's got to be a better way...
     1004    if ($args{swip}) {
     1005      if ($args{swip} eq 'on' || $args{swip} eq '1' || $args{swip} eq 'y') {
     1006        $args{swip} = 'y';
     1007      } else {
     1008        $args{swip} = 'n';
     1009      }
     1010    }
     1011    foreach ('type', 'swip') {
     1012      if ($args{$_}) {
     1013        push @fieldlist, $_;
     1014        push @vallist, $args{$_};
     1015      }
     1016    }
     1017  }
     1018
     1019  return ('FAIL', 'No fields to update') if !@fieldlist;
     1020
     1021  push @vallist, $args{block};
     1022  my $sql = "UPDATE $updtable SET ";
     1023  $sql .= join " = ?, ", @fieldlist;
     1024  $sql .= " = ? WHERE $keyfield = ?";
     1025
     1026  eval {
     1027    # do the update
     1028    $dbh->do($sql, undef, @vallist);
     1029
     1030    if ($args{node}) {
     1031      # done with delete/insert so we don't have to worry about funkyness updating a node ref that isn't there
     1032      $dbh->do("DELETE FROM noderef WHERE block = ?", undef, ($args{block}) );
     1033      $dbh->do("INSERT INTO noderef (block,node_id) VALUES (?,?)", undef, ($args{block}, $args{node}) );
     1034    }
     1035
     1036    $dbh->commit;
     1037  };
     1038  if ($@) {
     1039    my $msg = $@;
     1040    $dbh->rollback;
     1041    return ('FAIL', $msg);
     1042  }
     1043  return 0;
     1044} # end updateBlock()
     1045
     1046
    6361047## IPDB::deleteBlock()
    6371048# Removes an allocation from the database, including deleting IPs
     
    8431254
    8441255## IPDB::getBlockData()
    845 # Return custid, type, city, and description for a block
     1256# Get CIDR or IP, custid, type, city, circuit ID, description, notes, modification time, private/restricted
     1257# data, for a CIDR block or pool IP
     1258# Also returns SWIP status flag for CIDR blocks
     1259# Takes the block/IP to look up
     1260# Returns an arrayref to a list of hashrefs
    8461261sub getBlockData {
    8471262  my $dbh = shift;
    8481263  my $block = shift;
    8491264
    850   my $sth = $dbh->prepare("select cidr,custid,type,city,description from searchme".
    851         " where cidr='$block'");
    852   $sth->execute();
    853   return $sth->fetchrow_array();
     1265  my $cidr = new NetAddr::IP $block;
     1266
     1267  my $keycol = 'cidr';
     1268  my $blocktable = 'allocations';
     1269  my $poolip = 0;
     1270
     1271  # Pool IP and IPv6 check all in one!  Still needs to be tightened
     1272  # up a little for the as-yet-unhandled case of IPv6 IP pools
     1273  if ($cidr->bits == 32 && $cidr->masklen == 32) {
     1274    $poolip = 1;
     1275    $keycol = 'ip';
     1276    $blocktable = 'poolips';
     1277  }
     1278  my $binfo = $dbh->selectrow_hashref("SELECT $keycol AS block, custid, type, city, circuitid, description,".
     1279        " notes, modifystamp AS lastmod, privdata".($poolip ? '' : ', swip')." FROM $blocktable".
     1280        " WHERE $keycol = ?", undef, ($block) );
     1281  return $binfo;
    8541282} # end getBlockData()
     1283
     1284
     1285## IPDB::getNodeList()
     1286# Gets a list of node ID+name pairs as an arrayref to a list of hashrefs
     1287sub getNodeList {
     1288  my $dbh = shift;
     1289 
     1290  my $ret = $dbh->selectall_arrayref("SELECT node_id, node_name FROM nodes ORDER BY node_type,node_id",
     1291        { Slice => {} });
     1292  return $ret;
     1293} # end getNodeList()
     1294
     1295
     1296## IPDB::getNodeName()
     1297# Get node name from the ID
     1298sub getNodeName {
     1299  my $dbh = shift;
     1300  my $nid = shift;
     1301
     1302  my ($nname) = $dbh->selectrow_array("SELECT node_name FROM nodes WHERE node_id = ?", undef, ($nid) );
     1303  return $nname;
     1304} # end getNodeName()
     1305
     1306
     1307## IPDB::getNodeInfo()
     1308# Get node name and ID associated with a block
     1309sub getNodeInfo {
     1310  my $dbh = shift;
     1311  my $block = shift;
     1312
     1313  my ($nid, $nname) = $dbh->selectrow_array("SELECT nodes.node_id,node_name FROM nodes INNER JOIN noderef".
     1314        " ON nodes.node_id=noderef.node_id WHERE noderef.block = ?", undef, ($block) );
     1315  return ($nid, $nname);
     1316} # end getNodeInfo()
    8551317
    8561318
  • branches/stable/cgi-bin/admin.cgi

    r593 r594  
    6969}
    7070
     71if(!defined($webvar{action})) {
     72  $webvar{action} = "main";   #shuts up the warnings.
     73}
     74
    7175# handle DB error output
    7276if ($webvar{action} eq 'dberr') {
     
    8892my $header = HTML::Template->new(filename => "admin/header.tmpl");
    8993
    90 if(!defined($webvar{action})) {
    91   $webvar{action} = "main";   #shuts up the warnings.
    92 }
    93 
    9494my $page;
    9595if (-e "$ENV{HTML_TEMPLATE_ROOT}/admin/$webvar{action}.tmpl") {
     
    103103  $header->param(mainpage => 1);
    104104
    105   $sth = $ip_dbh->prepare("select type,listname from alloctypes where listorder < 900 order by listorder");
    106   $sth->execute;
    107 
    108   my @typelist;
    109   my $count = 0;
    110   while (my ($type,$listname) = $sth->fetchrow_array) {
    111     my %row = (
    112         selected => $count++,
    113         type => $type,
    114         dispname => $listname
    115         );
    116     push @typelist, \%row;
    117   }
    118   $page->param(typelist => \@typelist);
    119 
    120   my @masterlist;
    121   $sth = $ip_dbh->prepare("select cidr,mtime from masterblocks order by cidr");
    122   $sth->execute;
    123   while (my ($cidr,$mtime) = $sth->fetchrow_array) {
    124     my %row = (
    125         master => $cidr,
    126         masterdate => $mtime
    127         );
    128     push @masterlist, \%row;
    129   }
    130   $page->param(masterlist => \@masterlist);
    131 
     105  my $tlist = getTypeList($ip_dbh, 'a');
     106  $tlist->[0]->{sel} = 1;
     107  $page->param(typelist => $tlist);
     108
     109  my $mlist = getMasterList($ip_dbh, 'm');
     110  $page->param(masterlist => $mlist);
    132111}
    133112
     
    136115elsif ($webvar{action} eq 'alloc') {
    137116
    138   if ($webvar{cidr} !~ /^\s*(\d{1,3}\.){3}\d{1,3}(\/\d{2})?\s*$/) {
     117  my $cidr = new NetAddr::IP $webvar{cidr};
     118  if (!$cidr || "$cidr" =~ /^0/) {
    139119    $page->param(errmsg => "Can't allocate something that's not a netblock/ip");
    140120    goto ERRJUMP;
    141121  }
    142122
    143   $sth = $ip_dbh->prepare("select def_custid from alloctypes where type='$webvar{alloctype}'");
    144   $sth->execute;
    145   my @data = $sth->fetchrow_array;
    146   my $custid = $data[0];
     123  my $custid = $def_custids{$webvar{alloctype}};
    147124  if ($custid eq '') {
    148     if ($webvar{custid} !~ /^(?:\d{10}|\d{7}|STAFF)(?:-\d\d?)?$/) {
    149       # Force uppercase for now...
    150       $webvar{custid} =~ tr/a-z/A-Z/;
    151       # Crosscheck with billing.
    152       my $status = CustIDCK->custid_exist($webvar{custid});
    153       if ($CustIDCK::Error) {
    154         $page->param(errmsg => "Error verifying customer ID: ".$CustIDCK::ErrMsg);
    155         goto ERRJUMP;
    156       }
    157       if (!$status) {
    158         $page->param(errmsg => "Customer ID not valid.  Make sure the Customer ID ".
    159           "is correct.<br>\nUse STAFF for staff static IPs, and $IPDB::defcustid for any other ".
    160           "non-customer assignments.");
    161         goto ERRJUMP;
    162       }
     125    # Crosscheck with billing.
     126    my $status = CustIDCK->custid_exist($webvar{custid});
     127    if ($CustIDCK::Error) {
     128      $page->param(errmsg => "Error verifying customer ID: ".$CustIDCK::ErrMsg);
     129      goto ERRJUMP;
     130    }
     131    if (!$status) {
     132      $page->param(errmsg => "Customer ID not valid.  Make sure the Customer ID ".
     133        "is correct.<br>\nUse STAFF for staff static IPs, and $IPDB::defcustid for any other ".
     134        "non-customer assignments.");
     135      goto ERRJUMP;
    163136    }
    164137    # Type that doesn't have a default custid
     
    166139  }
    167140
    168   my $cidr = new NetAddr::IP $webvar{cidr};
    169   my @data;
     141  my $maskbits = $cidr->masklen;
     142  my $fbtmp = findAllocateFrom($ip_dbh, $maskbits, $webvar{alloctype}, '','',
     143        (gimme => "$cidr", allowpriv => 1));
     144
    170145  if ($webvar{alloctype} eq 'rm') {
    171     $sth = $ip_dbh->prepare("select cidr from freeblocks where cidr >>='$cidr' and routed='n'");
    172     $sth->execute;
    173     @data = $sth->fetchrow_array;
    174 # User deserves errors if user can't be bothered to find the free block first.
    175     if (!$data[0]) {
     146    if (!$fbtmp) {
    176147      $page->param(errmsg => "Can't allocate from outside a free block!!");
    177148      goto ERRJUMP;
    178149    }
    179150  } elsif ($webvar{alloctype} =~ /^(.)i$/) {
    180     $sth = $ip_dbh->prepare("select cidr from allocations where cidr >>='$cidr' and (type like '_d' or type like '_p')");
    181     $sth->execute;
    182     @data = $sth->fetchrow_array;
    183 # User deserves errors if user can't be bothered to find the pool and a free IP first.
    184     if (!$data[0]) {
     151    my $iptype = $1;
     152    my $ptmp = ipParent($ip_dbh, "$cidr");
     153    if ($ptmp->{type} =~ /^(.)[dp]$/) {
     154      my $newiptype = "$1i";
     155      $fbtmp = $ptmp->{cidr};
     156      if ($ptmp->{type} !~ /^$iptype./) {
     157        $page->param(warnmsg => "Warning:  Allocating IP as '".$disp_alloctypes{$newiptype}."' instead of '".
     158                $disp_alloctypes{$webvar{alloctype}}."' to match pool $fbtmp\n");
     159        $webvar{alloctype} = $newiptype;
     160      }
     161    }
     162    if (!$fbtmp) {
    185163      $page->param(errmsg => "Can't allocate static IP from outside a pool!!");
    186164      goto ERRJUMP;
    187165    }
    188166  } else {
    189     $sth = $ip_dbh->prepare("select cidr from freeblocks where cidr >>='$cidr' and not (routed='n')");
    190     $sth->execute;
    191     @data = $sth->fetchrow_array;
    192 # User deserves errors if user can't be bothered to find the free block first.
    193     if (!$data[0]) {
     167    if (!$fbtmp) {
    194168      $page->param(errmsg => "Can't allocate from outside a routed block!!");
    195169      goto ERRJUMP;
     
    197171  }
    198172
    199   my $alloc_from = new NetAddr::IP $data[0];
    200   $sth->finish;
     173  my $alloc_from = new NetAddr::IP $fbtmp;
    201174
    202175  my @cities;
     
    226199    $page->param(locerr => "Invalid customer location!  Go back and select customer's location.");
    227200    goto ERRJUMP;
    228   } else {
    229     if ($webvar{alloctype} =~ /^.i$/) {
    230       $sth = $ip_dbh->prepare("update poolips set available='n', custid='$webvar{custid}', ".
    231         "city='$webvar{city}', description='$webvar{desc}', notes='$webvar{notes}' ".
    232         "where ip='$webvar{cidr}'");
    233       $sth->execute;
    234       if ($sth->err) {
    235         $page->param(errmsg => $sth->errstr);
    236         syslog "err", "($authuser) Allocation of '$webvar{cidr}' to '$webvar{custid}' as ".
    237                 "'$webvar{alloctype}' failed: '".$sth->errstr."'";
    238       } else {
    239         syslog "notice", "$authuser allocated '$webvar{cidr}' to '$webvar{custid}' as ".
    240                 "'$webvar{alloctype}'";
    241         mailNotify($ip_dbh, "a$webvar{alloctype}", "ADDED: $disp_alloctypes{$webvar{alloctype}} allocation",
    242           "$disp_alloctypes{$webvar{alloctype}} $webvar{cidr} allocated to customer $webvar{custid}\n".
    243           "Description: $webvar{desc}\n\nAllocated by: $authuser\n");
    244       }
    245     } else {
    246       my ($retcode,$msg) = allocateBlock($ip_dbh, $webvar{cidr}, $webvar{alloc_from},
     201  }
     202
     203  my ($retcode,$msg) = allocateBlock($ip_dbh, $webvar{cidr}, $webvar{alloc_from},
    247204        $webvar{custid}, $webvar{alloctype}, $webvar{city}, $webvar{desc}, $webvar{notes},
    248205        $webvar{circid});
    249       if ($retcode eq 'OK') {
    250         syslog "notice", "$authuser allocated '$webvar{cidr}' to '$webvar{custid}' as ".
    251                 "'$webvar{alloctype}'";
    252       } else {
    253         $page->param(errmsg => $msg);
    254         syslog "err", "($authuser) Allocation of '$webvar{cidr}' to '$webvar{custid}' as ".
    255                 "'$webvar{alloctype}' failed: '$msg'";
    256       }
    257     } # static IP vs netblock
    258 
    259   } # done city check
     206  if ($retcode eq 'OK') {
     207    syslog "notice", "$authuser allocated '$webvar{cidr}' to '$webvar{custid}' as ".
     208        "'$webvar{alloctype}'";
     209    if ($webvar{alloctype} =~ /^.i$/) {
     210      mailNotify($ip_dbh, "a$webvar{alloctype}", "ADDED: $disp_alloctypes{$webvar{alloctype}} allocation",
     211        "$disp_alloctypes{$webvar{alloctype}} $webvar{cidr} allocated to customer $webvar{custid}\n".
     212        "Description: $webvar{desc}\n\nAllocated by: $authuser\n");
     213    }
     214  } else {
     215    $page->param(errmsg => $msg);
     216    syslog "err", "($authuser) Allocation of '$webvar{cidr}' to '$webvar{custid}' as ".
     217        "'$webvar{alloctype}' failed: '$msg'";
     218  }
    260219
    261220} elsif ($webvar{action} eq 'alloctweak') {
     
    270229} elsif ($webvar{action} eq 'touch') {
    271230
    272   $page->param(master => $webvar{whichmaster});
    273   $sth = $ip_dbh->prepare("update masterblocks set mtime=now() where cidr='$webvar{whichmaster}'");
    274   $sth->execute;
    275   if ($sth->err) {
    276     $page->param(errmsg => $sth->errstr);
    277   }
     231  my ($code,$msg) = touchMaster($ip_dbh, $webvar{whichmaster});
     232  $page->param(errmsg => $msg) if $code eq 'FAIL';
    278233
    279234} elsif ($webvar{action} eq 'listcust') {
     
    612567# List all IPs in a pool, and allow arbitrary admin changes to each
    613568# Allow changes to ALL fields
    614 sub showPool($) {
     569sub showPool {
    615570  my $pool = new NetAddr::IP $_[0];
    616571
     
    627582  $page->param(typelist => \@typelist);
    628583
    629   $sth = $ip_dbh->prepare("select ip,custid,city,type,available,description,notes from poolips where pool='$pool' order by ip");
    630   $sth->execute;
     584  $sth = $ip_dbh->prepare("SELECT ip,custid,city,type,available,description,notes from poolips".
     585        " WHERE pool=? ORDER BY ip");
     586  $sth->execute($pool);
    631587  my @iplist;
    632588  while (my ($ip,$custid,$city,$type,$avail,$desc,$notes) = $sth->fetchrow_array) {
  • branches/stable/cgi-bin/main.cgi

    r593 r594  
    6060# Use the connectDB function, otherwise we end up confusing ourselves
    6161my $ip_dbh;
    62 my $sth;
    6362my $errstr;
    6463($ip_dbh,$errstr) = connectDB_My;
     
    9089my $page;
    9190if (-e "$ENV{HTML_TEMPLATE_ROOT}/$webvar{action}.tmpl") {
    92   $page = HTML::Template->new(filename => "$webvar{action}.tmpl");
     91  $page = HTML::Template->new(filename => "$webvar{action}.tmpl", loop_context_vars => 1, global_vars => 1);
    9392} else {
    9493  $page = HTML::Template->new(filename => "dunno.tmpl");
     
    129128}
    130129elsif($webvar{action} eq 'listpool') {
    131   listPool();
     130  showPool();
    132131}
    133132
     
    155154}
    156155elsif ($webvar{action} eq 'nodesearch') {
    157   $sth = $ip_dbh->prepare("SELECT node_id, node_name FROM nodes ORDER BY node_type,node_id");
    158   $sth->execute() or $page->param(errmsg => $sth->errstr);
    159   my @nodelist;
    160   while (my ($nid,$nname) = $sth->fetchrow_array()) {
    161     my %row = (nodeid => $nid, nodename => $nname);
    162     push @nodelist, \%row;
    163   }
    164   $page->param(nodelist => \@nodelist);
     156  my $nodelist = getNodeList($ip_dbh);
     157  $page->param(nodelist => $nodelist);
    165158}
    166159
     
    201194}
    202195
    203 
    204196# Clean up IPDB globals, DB handle, etc.
    205197finish($ip_dbh);
     
    224216# Initial display:  Show master blocks with total allocated subnets, total free subnets
    225217sub showSummary {
    226   my %allocated;
    227   my %free;
    228   my %routed;
    229   my %bigfree;
    230 
    231   # Count the allocations.
    232   $sth = $ip_dbh->prepare("select count(*) from allocations where cidr <<= ?");
    233   foreach my $master (@masterblocks) {
    234     $sth->execute("$master");
    235     $sth->bind_columns(\$allocated{"$master"});
    236     $sth->fetch();
    237   }
    238 
    239   # Count routed blocks
    240   $sth = $ip_dbh->prepare("select count(*) from routed where cidr <<= ?");
    241   foreach my $master (@masterblocks) {
    242     $sth->execute("$master");
    243     $sth->bind_columns(\$routed{"$master"});
    244     $sth->fetch();
    245   }
    246 
    247   # Count the free blocks.
    248   $sth = $ip_dbh->prepare("select count(*) from freeblocks where cidr <<= ? and ".
    249         "(routed='y' or routed='n')");
    250   foreach my $master (@masterblocks) {
    251     $sth->execute("$master");
    252     $sth->bind_columns(\$free{"$master"});
    253     $sth->fetch();
    254   }
    255 
    256   # Find the largest free block in each master
    257   $sth = $ip_dbh->prepare("select maskbits from freeblocks where cidr <<= ? and ".
    258         "(routed='y' or routed='n') order by maskbits limit 1");
    259   foreach my $master (@masterblocks) {
    260     $sth->execute("$master");
    261     $sth->bind_columns(\$bigfree{"$master"});
    262     $sth->fetch();
    263   }
    264 
    265   # Assemble the data to stuff into the template.
    266   my @masterlist;
    267   my $rowclass=0;
    268   foreach my $master (@masterblocks) {
    269     my %row = (
    270         rowclass => $rowclass++ % 2,
    271         master => "$master",
    272         routed => $routed{"$master"},
    273         allocated => $allocated{"$master"},
    274         free => $free{"$master"},
    275         bigfree => ( ($bigfree{"$master"} eq '') ? ("&lt;NONE&gt;") : ("/".$bigfree{"$master"}) )
    276         );
    277     push (@masterlist, \%row);
    278   }
    279   $page->param(masterlist => \@masterlist);
     218  my $masterlist = listSummary($ip_dbh);
     219  $page->param(masterlist => $masterlist);
    280220
    281221  $page->param(addmaster => ($IPDBacl{$authuser} =~ /a/) );
    282 
    283222} # showSummary
    284223
     
    292231
    293232  $page->param(master => $webvar{block});
    294 
    295   my %allocated;
    296   my %free;
    297   my %cities;
    298   my %bigfree;
    299 
    300   my $master = new NetAddr::IP $webvar{block};
    301   my @localmasters;
    302 
    303   # Fetch only the blocks relevant to this master
    304   $sth = $ip_dbh->prepare("select cidr,city from routed where cidr <<= '$master' order by cidr");
    305   $sth->execute();
    306 
    307   my $i=0;
    308   while (my @data = $sth->fetchrow_array()) {
    309     my $cidr = new NetAddr::IP $data[0];
    310     $localmasters[$i++] = $cidr;
    311     $free{"$cidr"} = 0;
    312     $allocated{"$cidr"} = 0;
    313     $bigfree{"$cidr"} = 128;
    314     # Retain the routing destination
    315     $cities{"$cidr"} = $data[1];
    316   }
    317 
    318   # Check if there were actually any blocks routed from this master
    319   if ($i > 0) {
    320 
    321     # Count the allocations
    322     $sth = $ip_dbh->prepare("select count(*) from allocations where cidr <<= ?");
    323     foreach my $master (@localmasters) {
    324       $sth->execute("$master");
    325       $sth->bind_columns(\$allocated{"$master"});
    326       $sth->fetch();
    327     }
    328 
    329     # Count the free blocks.
    330     $sth = $ip_dbh->prepare("select count(*) from freeblocks where cidr <<= ? and ".
    331         "(routed='y' or routed='n')");
    332     foreach my $master (@localmasters) {
    333       $sth->execute("$master");
    334       $sth->bind_columns(\$free{"$master"});
    335       $sth->fetch();
    336     }
    337 
    338     # Get the size of the largest free block
    339     $sth = $ip_dbh->prepare("select maskbits from freeblocks where cidr <<= ? and ".
    340         "(routed='y' or routed='n') order by maskbits limit 1");
    341     foreach my $master (@localmasters) {
    342       $sth->execute("$master");
    343       $sth->bind_columns(\$bigfree{"$master"});
    344       $sth->fetch();
    345     }
    346 
    347     my @routed;
    348     my $rowclass = 0;
    349     foreach my $master (@localmasters) {
    350       my %row = (
    351         rowclass => $rowclass++ % 2,
    352         block => "$master",
    353         city => $cities{"$master"},
    354         nsubs => $allocated{"$master"},
    355         nfree => $free{"$master"},
    356         lfree => ( ($bigfree{"$master"} eq 128) ? ("&lt;NONE&gt;") : ("/".$bigfree{"$master"}) )
    357         );
    358       push @routed, \%row;
    359     }
    360     $page->param(routedlist => \@routed);
    361 
    362   } # end check for existence of routed blocks in master
    363 
    364233  $page->param(delmaster => ($IPDBacl{$authuser} =~ /d/));
    365234
    366   # Snag the free blocks.
    367   my $count = 0;
    368   $sth = $ip_dbh->prepare("select cidr from freeblocks where cidr <<='$master' and ".
    369         "routed='n' order by cidr");
    370   $sth->execute();
    371   my @unrouted;
    372   my $rowclass = 0;
    373   while (my @data = $sth->fetchrow_array()) {
    374     my $cidr = new NetAddr::IP $data[0];
    375     my %row = (
    376         rowclass => $rowclass++ % 2,
    377         fblock => "$cidr",
    378         frange => $cidr->range
    379         );
    380     push @unrouted, \%row;
    381   }
    382   $page->param(unrouted => \@unrouted);
    383 
     235  my $rlist = listMaster($ip_dbh, $webvar{block});
     236  $page->param(routedlist => $rlist);
     237
     238  my $flist = listFree($ip_dbh, $webvar{block});
     239  $page->param(unrouted => $flist);
    384240} # showMaster
    385241
     
    394250sub showRBlock {
    395251
    396   my $master = new NetAddr::IP $webvar{block};
    397 
    398   $sth = $ip_dbh->prepare("select city from routed where cidr='$master'");
    399   $sth->execute;
    400   my ($rcity) = $sth->fetchrow_array;
    401 
    402   $page->param(master => "$master");
     252  $page->param(master => $webvar{block});
     253  $page->param(delrouted => $IPDBacl{$authuser} =~ /d/);
     254
     255  my $rcity = getRoutedCity($ip_dbh, $webvar{block});
    403256  $page->param(rcity => $rcity);
    404257
    405   # Snag the allocations for this block
    406   $sth = $ip_dbh->prepare("select cidr,city,type,custid,swip,description".
    407         " from allocations where cidr <<= '$master' order by cidr");
    408   $sth->execute();
    409 
    410   # hack hack hack
    411   # set up to flag swip=y records if they don't actually have supporting data in the customers table
    412   my $custsth = $ip_dbh->prepare("select count(*) from customers where custid=?");
    413 
    414   my $rowclass = 0;
    415   my @blocklist;
    416   while (my ($cidr,$city,$type,$custid,$swip,$desc) = $sth->fetchrow_array()) {
    417     $custsth->execute($custid);
    418     my ($ncust) = $custsth->fetchrow_array();
    419 
    420     my %row = (
    421         rowclass => $rowclass++ % 2,
    422         block => $cidr,
    423         city => $city,
    424         type => $disp_alloctypes{$type},
    425         custid => $custid,
    426         swip => ($swip eq 'y' ? ($ncust == 0 ? 'Yes<small>*</small>' : 'Yes') : 'No'),
    427         desc => $desc
    428         );
    429     $row{subblock} = ($type =~ /^.r$/);         # hmf.  wonder why these won't work in the hash declaration...
    430     $row{listpool} = ($type =~ /^.[pd]$/);
    431     push (@blocklist, \%row);
    432   }
    433   $page->param(blocklist => \@blocklist);
    434 
    435   $page->param(delrouted => $IPDBacl{$authuser} =~ /d/);
    436 
    437   # Snag the free blocks.  We don't really *need* to be pedantic about avoiding
    438   # unrouted free blocks, but it's better to let the database do the work if we can.
    439   $rowclass = 0;
    440   my @unassigned;
    441   $sth = $ip_dbh->prepare("select cidr,routed from freeblocks where cidr <<= '$master'".
    442         " order by cidr");
    443   $sth->execute();
    444   while (my ($cidr_db,$routed) = $sth->fetchrow_array()) {
    445     my $cidr = new NetAddr::IP $cidr_db;
    446 
    447     my %row = (
    448         rowclass => $rowclass++ % 2,
    449         subblock => ($routed ne 'y' && $routed ne 'n'),
    450         fblock => $cidr_db,
    451         fbtype => $routed,
    452         frange => $cidr->range,
    453         );
    454     push @unassigned, \%row;
    455   }
    456   $page->param(unassigned => \@unassigned);
    457 
     258  my $blist = listRBlock($ip_dbh, $webvar{block});
     259  $page->param(blocklist => $blist);
     260
     261  my $flist = listFree($ip_dbh, $webvar{block}, 'y');
     262  $page->param(unassigned => $flist);
    458263} # showRBlock
    459264
    460265
    461266# List the IPs used in a pool
    462 sub listPool {
     267sub showPool {
    463268
    464269  my $cidr = new NetAddr::IP $webvar{pool};
     
    473278
    474279  # Snag pool info for heading
    475   $sth = $ip_dbh->prepare("select type,city from allocations where cidr=?");
    476   $sth->execute($webvar{pool});
    477   my ($pooltype, $poolcity) = $sth->fetchrow_array;
    478 
    479   $page->param(disptype => $disp_alloctypes{$pooltype});
    480   $page->param(city => $poolcity);
     280  my $poolinfo = getBlockData($ip_dbh, $webvar{pool});
     281
     282  $page->param(disptype => $disp_alloctypes{$poolinfo->{type}});
     283  $page->param(city => $poolinfo->{city});
    481284
    482285  # Only display net/gw/bcast if it's a "real" netblock and not a PPP(oE) lunacy
    483   $page->param(realblock => $pooltype =~ /^.d$/);
     286  $page->param(realblock => $poolinfo->{type} =~ /^.d$/);
    484287
    485288# probably have to add an "edit IP allocation" link here somewhere.
    486289
    487   $sth = $ip_dbh->prepare("select ip,custid,available,description,type".
    488         " from poolips where pool='$webvar{pool}' order by ip");
    489   $sth->execute;
    490   my @poolips;
    491   my $rowclass = 0;
    492   while (my ($ip,$custid,$available,$desc,$type) = $sth->fetchrow_array) {
    493     my %row = (
    494         rowclass => $rowclass++ % 2,
    495         ip => $ip,
    496         custid => $custid,
    497         available => $available,
    498         desc => $desc,
    499         maydel => $IPDBacl{$authuser} =~ /d/,
    500         delme => $available eq 'n'
    501         );
    502     push @poolips, \%row;
    503   }
    504   $page->param(poolips => \@poolips);
    505 
    506 } # end listPool
     290  my $plist = listPool($ip_dbh, $webvar{pool});
     291  # technically slightly more efficient to check the ACL in an if () once outside the foreach
     292  foreach (@{$plist}) {
     293    $$_{maydel} = $IPDBacl{$authuser} =~ /d/;
     294  }
     295  $page->param(poolips => $plist);
     296} # end showPool
    507297
    508298
     
    535325    if ($webvar{fbtype} ne 'y') {
    536326      # Snag the type of the container block from the database.
    537       $sth = $ip_dbh->prepare("select type from allocations where cidr >>='$block'");
    538       $sth->execute;
    539       my @data = $sth->fetchrow_array;
    540       $data[0] =~ s/c$/r/;      # Munge the type into the correct form
    541       $page->param(fbdisptype => $list_alloctypes{$data[0]});
    542       $page->param(type => $data[0]);
     327## hmm.  need a flag for parent class/type, sort of?
     328      my $pblock = subParent($ip_dbh, $webvar{block});
     329      my $ptype = $pblock->{type};
     330      $ptype =~ s/c$/r/;
     331      $page->param(fbdisptype => $list_alloctypes{$ptype});
     332      $page->param(type => $ptype);
    543333    } else {
    544       $sth = $ip_dbh->prepare("select type,listname from alloctypes where listorder < 500 ".
    545         "and type not like '_i' order by listorder");
    546       $sth->execute;
    547       my @typelist;
    548       my $selflag = 0;
    549       while (my @data = $sth->fetchrow_array) {
    550         my %row = (tval => $data[0],
    551                 type => $data[1],
    552                 sel => ($selflag == 0 ? ' selected' : '')
    553                 );
    554         push (@typelist, \%row);
    555         $selflag++;
    556       }
    557       $page->param(typelist => \@typelist);
     334      # get "primary" alloctypes, since these are all that can correctly be assigned if we're in this branch
     335      my $tlist = getTypeList($ip_dbh, 'p');
     336      $tlist->[0]->{sel} = 1;
     337      $page->param(typelist => $tlist);
    558338    }
    559339  } else {
    560     my @masterlist;
    561     foreach my $master (@masterblocks) {
    562       my %row = (master => "$master");
    563       push (@masterlist, \%row);
    564     }
    565     $page->param(masterlist => \@masterlist);
     340    my $mlist = getMasterList($ip_dbh, 'c');
     341    $page->param(masterlist => $mlist);
    566342
    567343    my @pops;
     
    572348    $page->param(pops => \@pops);
    573349
    574     # could arguably include routing (500) in the list, but ATM it doesn't
    575     # make sense, and in any case that shouldn't be structurally possible here.
    576     $sth = $ip_dbh->prepare("select type,listname from alloctypes where listorder <= 500 order by listorder");
    577     $sth->execute;
    578     my @typelist;
    579     my $selflag = 0;
    580     while (my @data = $sth->fetchrow_array) {
    581       my %row = (tval => $data[0],
    582         type => $data[1],
    583         sel => ($selflag == 0 ? ' selected' : '')
    584         );
    585       push (@typelist, \%row);
    586       $selflag++;
    587     }
    588     $page->param(typelist => \@typelist);
     350    # get all standard alloctypes
     351    my $tlist = getTypeList($ip_dbh, 'a');
     352    $tlist->[0]->{sel} = 1;
     353    $page->param(typelist => $tlist);
    589354  }
    590355
     
    597362
    598363## node hack
    599   $sth = $ip_dbh->prepare("SELECT node_id, node_name FROM nodes ORDER BY node_type,node_id");
    600   $sth->execute() or print "DEBUG: failed retrieval from nodes: ".$sth->errstr,"<br>\n";
    601   my @nodes;
    602   while (my ($nid,$nname) = $sth->fetchrow_array()) {
    603     my %row = (nid => $nid, nname => $nname);
    604     push (@nodes, \%row);
    605   }
    606   $page->param(nodelist => \@nodes);
     364  my $nlist = getNodeList($ip_dbh);
     365  $page->param(nodelist => $nlist);
    607366## end node hack
    608367
     
    632391
    633392  if ($webvar{alloctype} =~ /^.i$/ && $webvar{fbassign} ne 'y') {
    634     my ($base,undef) = split //, $webvar{alloctype};    # split into individual chars
    635 
    636 # Ewww.  But it works.
    637     $sth = $ip_dbh->prepare("SELECT (SELECT city FROM allocations WHERE cidr=poolips.pool), ".
    638         "poolips.pool, COUNT(*) FROM poolips,allocations WHERE poolips.available='y' AND ".
    639         "poolips.pool=allocations.cidr AND allocations.city='$webvar{pop}' AND poolips.type LIKE '".$base."_' ".
    640         "GROUP BY pool");
    641     $sth->execute;
    642     my $optionlist;
    643 
    644     my @poollist;
    645     while (my ($poolcit,$poolblock,$poolfree) = $sth->fetchrow_array) {
    646       # city,pool cidr,free IP count
    647       if ($poolfree > 0) {
    648         my %row = (poolcit => $poolcit, poolblock => $poolblock, poolfree => $poolfree);
    649         push (@poollist, \%row);
    650       }
    651     }
     393    my $plist = getPoolSelect($ip_dbh, $webvar{alloctype}, $webvar{pop});
    652394    $page->param(staticip => 1);
    653     $page->param(poollist => \@poollist);
     395    $page->param(poollist => $plist) if $plist;
    654396    $cidr = "Single static IP";
    655397##fixme:  need to handle "no available pools"
     
    657399  } else { # end show pool options
    658400
    659     if ($webvar{fbassign} eq 'y') {
     401    if ($webvar{fbassign} && $webvar{fbassign} eq 'y') {
    660402      $alloc_from = new NetAddr::IP $webvar{allocfrom};
    661403## possibly messy behaviour:  force the _from and block to be the network addr?
     
    669411        return;
    670412      }
    671       my $sql;
    672       my $city;
    673       my $failmsg;
    674       my $extracond = '';
    675       if ($webvar{allocfrom} eq '-') {
    676         $extracond = ($webvar{allowpriv} eq 'on' ? '' :
    677                 " and not (cidr <<= '192.168.0.0/16'".
    678                         " or cidr <<= '10.0.0.0/8'".
    679                         " or cidr <<= '172.16.0.0/12')");
    680       }
    681       my $sortorder;
     413
     414##fixme ick, ew, bleh.  gotta handle the failure message generation better.  push it into findAllocateFrom()?
     415      my $failmsg = "No suitable free block found.<br>\n";
    682416      if ($webvar{alloctype} eq 'rm') {
    683         if ($webvar{allocfrom} ne '-') {
    684           $sql = "select * from freeblocks where maskbits<=$webvar{maskbits} and routed='n'".
    685                 " and cidr <<= '$webvar{allocfrom}'";
    686           $sortorder = "maskbits desc";
    687         } else {
    688           $sql = "select * from freeblocks where maskbits<=$webvar{maskbits} and routed='n'";
    689           $sortorder = "maskbits desc";
    690         }
    691         $failmsg = "No suitable free block found.<br>\nWe do not have a free".
    692           " routeable block of that size.<br>\nYou will have to either route".
    693           " a set of smaller netblocks or a single smaller netblock.";
     417        $failmsg .= "We do not have a free routeable block of that size.<br>\n".
     418                "You will have to either route a set of smaller netblocks or a single smaller netblock.";
    694419      } else {
    695 ##fixme
    696 # This section needs serious Pondering.
    697         # Pools of most types get assigned to the POP they're "routed from"
    698         # This includes WAN blocks and other netblock "containers"
    699         # This does NOT include cable pools.
    700420        if ($webvar{alloctype} =~ /^.[pc]$/) {
    701           $city = $webvar{city};
    702           $failmsg = "No suitable free block found.<br>\nYou will have to route another".
    703             " superblock from one of the<br>\nmaster blocks or chose a smaller".
    704             " block size for the pool.";
     421          $failmsg .= "You will have to route another superblock from one of the<br>\n".
     422                "master blocks or chose a smaller block size for the pool.";
    705423        } else {
    706424          if (!$webvar{pop}) {
     
    708426            return;
    709427          }
    710           $city = $webvar{pop};
    711           $failmsg = "No suitable free block found.<br>\nYou will have to route another".
    712             " superblock to $webvar{pop}<br>\nfrom one of the master blocks or".
    713             " chose a smaller blocksize.";
    714         }
    715         if (defined $webvar{allocfrom} && $webvar{allocfrom} ne '-') {
    716           $sql = "select cidr from freeblocks where city='$city' and maskbits<=$webvar{maskbits}".
    717                 " and cidr <<= '$webvar{allocfrom}' and routed='".
    718                 (($webvar{alloctype} =~ /^(.)r$/) ? "$1" : 'y')."'";
    719           $sortorder = "maskbits desc,cidr";
    720         } else {
    721           $sql = "select cidr from freeblocks where city='$city' and maskbits<=$webvar{maskbits}".
    722                 " and routed='".(($webvar{alloctype} =~ /^(.)r$/) ? "$1" : 'y')."'";
    723           $sortorder = "maskbits desc,cidr";
     428          $failmsg .= "You will have to route another superblock to $webvar{pop}<br>\n".
     429                "from one of the master blocks or chose a smaller blocksize.";
    724430        }
    725431      }
    726       $sql = $sql.$extracond." order by ".$sortorder;
    727       $sth = $ip_dbh->prepare($sql);
    728       $sth->execute;
    729       my @data = $sth->fetchrow_array();
    730       if ($data[0] eq "") {
     432
     433      $cidr = findAllocateFrom($ip_dbh, $webvar{maskbits}, $webvar{alloctype}, $webvar{city}, $webvar{pop},
     434        (master => $webvar{allocfrom}, allowpriv => $webvar{allowpriv}) );
     435      if (!$cidr) {
    731436        $page->param(err => $failmsg);
    732437        return;
    733438      }
    734       $cidr = new NetAddr::IP $data[0];
     439      $cidr = new NetAddr::IP $cidr;
    735440
    736441# this chunk now specific to "guided" allocation;  freeblock-select can now slice-n-dice on its own.
     
    754459## node hack
    755460  if ($webvar{node} && $webvar{node} ne '-') {
    756     $sth = $ip_dbh->prepare("SELECT node_name FROM nodes WHERE node_id=?");
    757     $sth->execute($webvar{node});
    758     my ($nodename) = $sth->fetchrow_array();
     461    my $nodename = getNodeName($ip_dbh, $webvar{node});
    759462    $page->param(nodename => $nodename);
    760463    $page->param(nodeid => $webvar{node});
     
    875578      return;
    876579    }
    877     if ($webvar{custid} !~ /^(?:\d{10}|\d{7}|STAFF)(?:-\d\d?)?$/) {
    878       # Force uppercase for now...
    879       $webvar{custid} =~ tr/a-z/A-Z/;
    880       # Crosscheck with billing.
    881       my $status = CustIDCK->custid_exist($webvar{custid});
    882       if ($CustIDCK::Error) {
    883         $page->param(err => "Error verifying customer ID: ".$CustIDCK::ErrMsg);
    884         return;
    885       }
    886       if (!$status) {
    887         $page->param(err => "Customer ID not valid.  Make sure the Customer ID ".
    888           "is correct.<br>\nUse STAFF for staff static IPs, and $IPDB::defcustid for any other ".
    889           "non-customer assignments.");
    890         return;
    891       }
     580    # Crosscheck with billing.
     581    my $status = CustIDCK->custid_exist($webvar{custid});
     582    if ($CustIDCK::Error) {
     583      $page->param(err => "Error verifying customer ID: ".$CustIDCK::ErrMsg);
     584      return;
     585    }
     586    if (!$status) {
     587      $page->param(err => "Customer ID not valid.  Make sure the Customer ID ".
     588        "is correct.<br>\nUse STAFF for staff static IPs, and $IPDB::defcustid for any other ".
     589        "non-customer assignments.");
     590      return;
    892591    }
    893592#    print "<!-- [ In validateInput().  Insert customer ID cross-check here. ] -->\n";
     
    913612##fixme:  hook to force-set POP or city on certain alloctypes
    914613# if ($webvar{alloctype =~ /foo,bar,bz/ { $webvar{pop} = 'blah'; }
    915     if ($webvar{pop} =~ /^-$/) {
     614    if ($webvar{pop} && $webvar{pop} =~ /^-$/) {
    916615      $flag = 'to route the block from/through';
    917616    }
     
    935634sub edit {
    936635
    937   my $sql;
    938 
    939   # Two cases:  block is a netblock, or block is a static IP from a pool
    940   # because I'm lazy, we'll try to make the SELECT's bring out identical)ish) data
    941 ##fixme:  allow "SWIP" (publication to rWHOIS) of static IP data
    942   if ($webvar{block} =~ /\/32$/) {
    943     $sql = "select ip,custid,type,city,circuitid,description,notes,modifystamp,privdata from poolips where ip='$webvar{block}'";
    944   } else {
    945     $sql = "select cidr,custid,type,city,circuitid,description,notes,modifystamp,privdata,swip from allocations where cidr='$webvar{block}'"
    946   }
    947 
    948   # gotta snag block info from db
    949   $sth = $ip_dbh->prepare($sql);
    950   $sth->execute;
    951   my @data = $sth->fetchrow_array;
    952 
    953   # Clean up extra whitespace on alloc type
    954   $data[2] =~ s/\s//;
    955 
    956   # We can't let the city be changed here;  this block is a part of
    957   # a larger routed allocation and therefore by definition can't be moved.
    958   # block and city are static.
    959 ##fixme
    960 # Needs thinking.  Have to allow changes to city to correct errors, no?
    961 # Also have areas where a routed block at a POP serves "many" cities/towns/named crossroads
    962 
    963 # @data: cidr,custid,type,city,circuitid,description,notes,modifystamp,privdata,swip
     636  # snag block info from db
     637  my $blockinfo = getBlockData($ip_dbh, $webvar{block});
     638
     639  # Clean up extra whitespace on alloc type.  Mainly a legacy-data cleanup.
     640  $blockinfo->{type} =~ s/\s//;
    964641
    965642  $page->param(block => $webvar{block});
    966643
    967   $page->param(custid => $data[1]);
    968   $page->param(city => $data[3]);
    969   $page->param(circid => $data[4]);
    970   $page->param(desc => $data[5]);
    971   $page->param(notes => $data[6]);
     644  $page->param(custid   => $blockinfo->{custid});
     645  $page->param(city     => $blockinfo->{city});
     646  $page->param(circid   => $blockinfo->{circuitid});
     647  $page->param(desc     => $blockinfo->{description});
     648  $page->param(notes    => $blockinfo->{notes});
    972649
    973650##fixme The check here should be built from the database
    974651# Need to expand to support pool types too
    975   if ($data[2] =~ /^.[ne]$/ && $IPDBacl{$authuser} =~ /c/) {
     652  if ($blockinfo->{type} =~ /^.[ne]$/ && $IPDBacl{$authuser} =~ /c/) {
    976653    $page->param(changetype => 1);
    977654    $page->param(alloctype => [
    978                 { selme => ($data[2] eq 'me'), type => "me", disptype => "Dialup netblock" },
    979                 { selme => ($data[2] eq 'de'), type => "de", disptype => "Dynamic DSL netblock" },
    980                 { selme => ($data[2] eq 'ce'), type => "ce", disptype => "Dynamic cable netblock" },
    981                 { selme => ($data[2] eq 'we'), type => "we", disptype => "Dynamic wireless netblock" },
    982                 { selme => ($data[2] eq 'cn'), type => "cn", disptype => "Customer netblock" },
    983                 { selme => ($data[2] eq 'en'), type => "en", disptype => "End-use netblock" },
    984                 { selme => ($data[2] eq 'in'), type => "in", disptype => "Internal netblock" },
     655                { selme => ($blockinfo->{type} eq 'me'), type => "me", disptype => "Dialup netblock" },
     656                { selme => ($blockinfo->{type} eq 'de'), type => "de", disptype => "Dynamic DSL netblock" },
     657                { selme => ($blockinfo->{type} eq 'ce'), type => "ce", disptype => "Dynamic cable netblock" },
     658                { selme => ($blockinfo->{type} eq 'we'), type => "we", disptype => "Dynamic wireless netblock" },
     659                { selme => ($blockinfo->{type} eq 'cn'), type => "cn", disptype => "Customer netblock" },
     660                { selme => ($blockinfo->{type} eq 'en'), type => "en", disptype => "End-use netblock" },
     661                { selme => ($blockinfo->{type} eq 'in'), type => "in", disptype => "Internal netblock" },
    985662                ]
    986663        );
    987664  } else {
    988     $page->param(disptype => $disp_alloctypes{$data[2]});
    989     $page->param(type => $data[2]);
     665    $page->param(disptype => $disp_alloctypes{$blockinfo->{type}});
     666    $page->param(type => $blockinfo->{type});
    990667  }
    991668
    992669## node hack
    993   $sth = $ip_dbh->prepare("SELECT nodes.node_id,node_name FROM nodes INNER JOIN noderef".
    994         " ON nodes.node_id=noderef.node_id WHERE noderef.block='$webvar{block}'");
    995   $sth->execute;
    996   my ($nodeid,$nodename) = $sth->fetchrow_array();
     670  my ($nodeid,$nodename) = getNodeInfo($ip_dbh, $webvar{block});
    997671  $page->param(havenodeid => $nodeid);
    998672
    999   if ($data[2] eq 'fr' || $data[2] eq 'bi') {
     673  if ($blockinfo->{type} eq 'fr' || $blockinfo->{type} eq 'bi') {
    1000674    $page->param(typesupportsnodes => 1);
    1001675    $page->param(nodename => $nodename);
     
    1006680#  (currently) have a nodeid set in the first place.
    1007681    if ($IPDBacl{$authuser} =~ /c/) {
    1008       $sth = $ip_dbh->prepare("SELECT node_id, node_name FROM nodes ORDER BY node_type,node_id");
    1009       $sth->execute;
    1010       my @nodelist;
    1011       while (my ($nid,$nname) = $sth->fetchrow_array()) {
    1012         my %row = (
    1013                 selme => ($nodeid == $nid),
    1014                 nodeid => $nid,
    1015                 nodename => $nname,
    1016                 );
    1017         push (@nodelist, \%row);
     682      my $nlist = getNodeList($ip_dbh);
     683      foreach (@{$nlist}) {
     684        $$_{selme} = ($$_{node_id} == $nodeid);
    1018685      }
    1019       $page->param(nodelist => \@nodelist);
     686      $page->param(nodelist => $nlist);
    1020687    }
    1021688  }
    1022689## end node hack
    1023690
    1024   my ($lastmod,undef) = split /\s+/, $data[7];
     691  my ($lastmod,undef) = split /\s+/, $blockinfo->{lastmod};
    1025692  $page->param(lastmod => $lastmod);
    1026693
    1027694  # not happy with the upside-down logic, but...
    1028   $page->param(swipable => $data[2] !~ /.i/);
    1029   $page->param(swip => $data[10] ne 'n');
     695  $page->param(swipable => $blockinfo->{type} !~ /.i/);
     696  $page->param(swip => $blockinfo->{swip} ne 'n') if $blockinfo->{swip};
    1030697
    1031698  # Check to see if we can display sensitive data
    1032699  $page->param(nocling => $IPDBacl{$authuser} =~ /s/);
    1033   $page->param(privdata => $data[8]);
     700  $page->param(privdata => $blockinfo->{privdata});
    1034701
    1035702  # ACL trickery - these two template booleans control the presence of all form/input tags
     
    1048715  }
    1049716
    1050   # Check to see if we can update restricted data
    1051   my $privdata = '';
    1052   if ($IPDBacl{$authuser} =~ /s/) {
    1053     $privdata = ",privdata='$webvar{privdata}'";
    1054   }
    1055 
    1056717  # Make sure incoming data is in correct format - custID among other things.
    1057718  return if !validateInput;
    1058719
    1059   # SQL transaction wrapper
    1060   eval {
    1061     # Relatively simple SQL transaction here.
    1062     my $sql;
    1063     if (my $pooltype = ($webvar{alloctype} =~ /^(.)i$/) ) {
    1064       $sql = "UPDATE poolips SET custid='$webvar{custid}',".
    1065         "city=?,description=?,notes=?,".
    1066         "circuitid='$webvar{circid}',".
    1067         "$privdata where ip='$webvar{block}'";
    1068     } else {
    1069       $sql = "UPDATE allocations SET custid='$webvar{custid}',".
    1070         "city=?,description=?,notes=?,".
    1071         "circuitid='$webvar{circid}'$privdata,".
    1072         "type='$webvar{alloctype}',".
    1073         "swip='".($webvar{swip} eq 'on' ? 'y' : 'n')."' ".
    1074         "where cidr='$webvar{block}'";
    1075     }
    1076     # Log the details of the change.
    1077     syslog "debug", $sql;
    1078     $sth = $ip_dbh->prepare($sql);
    1079     $sth->execute($webvar{city}, $webvar{desc}, $webvar{notes});
    1080 ## node hack
    1081     if ($webvar{node}) {
    1082       # done with delete/insert so we don't have to worry about funkyness updating a node ref that isn't there
    1083       $ip_dbh->do("DELETE FROM noderef WHERE block='$webvar{block}'");
    1084       $sth = $ip_dbh->prepare("INSERT INTO noderef (block,node_id) VALUES (?,?)");
    1085       $sth->execute($webvar{block},$webvar{node});
    1086     }
    1087 ## end node hack
    1088     $ip_dbh->commit;
    1089   };
    1090   if ($@) {
    1091     my $msg = $@;
    1092     eval { $ip_dbh->rollback; };
     720  $webvar{swip} = 'n' if !$webvar{swip};
     721
     722  my %updargs = (
     723        custid          => $webvar{custid},
     724        city            => $webvar{city},
     725        description     => $webvar{desc},
     726        notes           => $webvar{notes},
     727        circuitid       => $webvar{circid},
     728        block           => $webvar{block},
     729        type            => $webvar{alloctype},
     730        swip            => $webvar{swip},
     731        );
     732
     733  # Semioptional values
     734  $updargs{privdata} = $webvar{privdata} if $IPDBacl{$authuser} =~ /s/;
     735  $updargs{node} = $webvar{node} if $webvar{node};
     736
     737  my ($code,$msg) = updateBlock($ip_dbh, %updargs);
     738
     739  if ($code eq 'FAIL') {
    1093740    syslog "err", "$authuser could not update block/IP '$webvar{block}': '$msg'";
    1094741    $page->param(err => "Could not update block/IP $webvar{block}: $msg");
     
    1098745  # If we get here, the operation succeeded.
    1099746  syslog "notice", "$authuser updated $webvar{block}";
     747##fixme:  log details of the change?  old way is in the .debug stream anyway.
    1100748##fixme:  need to wedge something in to allow "update:field" notifications
    1101749## hmm.  how to tell what changed?  O_o
     
    1105753## node hack
    1106754  if ($webvar{node} && $webvar{node} ne '-') {
    1107     $sth = $ip_dbh->prepare("SELECT node_name FROM nodes WHERE node_id=?");
    1108     $sth->execute($webvar{node});
    1109     my ($nodename) = $sth->fetchrow_array();
     755    my $nodename = getNodeName($ip_dbh, $webvar{node});
    1110756    $page->param(nodename => $nodename);
    1111757  }
     
    1113759
    1114760  # Link back to browse-routed or list-pool page on "Update complete" page.
    1115   my $cblock;   # to contain the CIDR of the container block we're retrieving.
    1116   my $sql;
     761  my $cblock;
    1117762  if (my $pooltype = ($webvar{alloctype} =~ /^(.)i$/) ) {
    1118763    $page->param(backpool => 1);
    1119     $sql = "select pool from poolips where ip='$webvar{block}'";
     764    $cblock = ipParent($ip_dbh, $webvar{block});
    1120765  } else {
    1121     $sql = "select cidr from routed where cidr >>= '$webvar{block}'";
    1122   }
    1123   # I define there to be no errors on this operation...  so we don't need to check for them.
    1124   $sth = $ip_dbh->prepare($sql);
    1125   $sth->execute;
    1126   $sth->bind_columns(\$cblock);
    1127   $sth->fetch();
    1128   $sth->finish;
    1129   $page->param(backblock => $cblock);
     766    $cblock = blockParent($ip_dbh, $webvar{block});
     767  }
     768  $page->param(backblock => $cblock->{cidr});
     769
     770  # Do some HTML fiddling here instead of using ESCAPE=HTML in the template,
     771  # because otherwise we can't convert \n to <br>.  *sigh*
     772  $webvar{notes} = $q->escapeHTML($webvar{notes});      # escape first...
     773  $webvar{notes} =~ s/\n/<br>\n/;                       # ... then convert newlines
     774  $webvar{privdata} = ($webvar{privdata} ? $q->escapeHTML($webvar{privdata}) : "&nbsp;");
     775  $webvar{privdata} =~ s/\n/<br>\n/;
    1130776
    1131777  $page->param(cidr => $webvar{block});
     
    1134780  $page->param(custid => $webvar{custid});
    1135781  $page->param(swip => $webvar{swip} eq 'on' ? 'Yes' : 'No');
    1136   $page->param(circid => $q->escapeHTML($webvar{circid}));
    1137   $page->param(desc => $q->escapeHTML($webvar{desc}));
    1138   $page->param(notes => $q->escapeHTML($webvar{notes}));
    1139   $webvar{privdata} = ($webvar{privdata} ? $q->escapeHTML($webvar{privdata}) : "&nbsp;");
     782  $page->param(circid => $webvar{circid});
     783  $page->param(desc => $webvar{desc});
     784  $page->param(notes => $webvar{notes});
    1140785  $page->param(privdata => $webvar{privdata})
    1141786        if $IPDBacl{$authuser} =~ /s/;
     
    1157802  }
    1158803
    1159   my ($cidr, $custid, $type, $city, $circid, $desc, $notes, $alloctype, $privdata);
     804  my $blockdata;
    1160805
    1161806  if ($webvar{alloctype} eq 'rm') {
    1162     $sth = $ip_dbh->prepare("select cidr,city from routed where cidr='$webvar{block}'");
    1163     $sth->execute();
    1164 
    1165 # This feels...  extreme.
    1166     croak $sth->errstr() if($sth->errstr());
    1167 
    1168     $sth->bind_columns(\$cidr,\$city);
    1169     $sth->execute();
    1170     $sth->fetch || croak $sth->errstr();
    1171     $custid = "N/A";
    1172     $alloctype = $webvar{alloctype};
    1173     $circid = "N/A";
    1174     $desc = "N/A";
    1175     $notes = "N/A";
    1176     $privdata = "N/A";
     807
     808    $blockdata->{block} = $webvar{block};
     809    $blockdata->{city} = getRoutedCity($ip_dbh, $webvar{block});
     810    $blockdata->{custid} = "N/A";
     811    $blockdata->{type} = $webvar{alloctype};
     812    $blockdata->{circuitid} = "N/A";
     813    $blockdata->{description} = "N/A";
     814    $blockdata->{notes} = "N/A";
     815    $blockdata->{privdata} = "N/A";
    1177816
    1178817  } elsif ($webvar{alloctype} eq 'mm') {
    1179818
    1180     $cidr = $webvar{block};
    1181     $city = "N/A";
    1182     $custid = "N/A";
    1183     $alloctype = $webvar{alloctype};
    1184     $circid = "N/A";
    1185     $desc = "N/A";
    1186     $notes = "N/A";
    1187     $privdata = "N/A";
    1188 
    1189   } elsif ($webvar{alloctype} =~ /^.i$/) { # done with alloctype=[rm]m
    1190 
    1191     # Unassigning a static IP
    1192     my $sth = $ip_dbh->prepare("select ip,custid,city,type,notes,circuitid,privdata".
    1193         " from poolips where ip='$webvar{block}'");
    1194     $sth->execute();
    1195 #  croak $sth->errstr() if($sth->errstr());
    1196 
    1197     $sth->bind_columns(\$cidr, \$custid, \$city, \$alloctype, \$notes, \$circid,
    1198         \$privdata);
    1199     $sth->fetch() || croak $sth->errstr;
    1200 
    1201   } else { # done with alloctype=~ /^.i$/
    1202 
    1203     my $sth = $ip_dbh->prepare("select cidr,custid,type,city,circuitid,description,notes,privdata".
    1204         " from allocations where cidr='$webvar{block}'");
    1205     $sth->execute();
    1206 #       croak $sth->errstr() if($sth->errstr());
    1207 
    1208     $sth->bind_columns(\$cidr, \$custid, \$alloctype, \$city, \$circid, \$desc,
    1209         \$notes, \$privdata);
    1210     $sth->fetch() || carp $sth->errstr;
     819    $blockdata->{block} = $webvar{block};
     820    $blockdata->{city} = "N/A";
     821    $blockdata->{custid} = "N/A";
     822    $blockdata->{type} = $webvar{alloctype};
     823    $blockdata->{circuitid} = "N/A";
     824    $blockdata->{description} = "N/A";
     825    $blockdata->{notes} = "N/A";
     826    $blockdata->{privdata} = "N/A";
     827
     828  } else {
     829
     830    $blockdata = getBlockData($ip_dbh, $webvar{block})
     831
    1211832  } # end cases for different alloctypes
    1212833
    1213   $page->param(block => $cidr);
    1214   $page->param(disptype => $disp_alloctypes{$alloctype});
    1215   $page->param(type => $alloctype);
    1216   $page->param(city => $city);
    1217   $page->param(custid => $custid);
    1218   $page->param(circid => $circid);
    1219   $page->param(desc => $desc);
    1220   $page->param(notes => $notes);
    1221   $privdata = '&nbsp;' if $privdata eq '';
    1222   $page->param(privdata => $privdata) if $IPDBacl{$authuser} =~ /s/;
    1223   $page->param(delpool => $alloctype =~ /^.[pd]$/);
     834  $page->param(block => $blockdata->{block});
     835  $page->param(disptype => $disp_alloctypes{$blockdata->{type}});
     836  $page->param(type => $blockdata->{type});
     837  $page->param(city => $blockdata->{city});
     838  $page->param(custid => $blockdata->{custid});
     839  $page->param(circid => $blockdata->{circuitid});
     840  $page->param(desc => $blockdata->{description});
     841  $blockdata->{notes} = $q->escapeHTML($blockdata->{notes});
     842  $blockdata->{notes} =~ s/\n/<br>\n/;
     843  $page->param(notes => $blockdata->{notes});
     844  $blockdata->{privdata} = $q->escapeHTML($blockdata->{privdata});
     845  $blockdata->{privdata} = '&nbsp;' if !$blockdata->{privdata};
     846  $blockdata->{privdata} =~ s/\n/<br>\n/;
     847  $page->param(privdata => $blockdata->{privdata}) if $IPDBacl{$authuser} =~ /s/;
     848  $page->param(delpool => $blockdata->{type} =~ /^.[pd]$/);
    1224849
    1225850} # end remove()
     
    1237862
    1238863  # need to retrieve block data before deleting so we can notify on that
    1239   my ($cidr,$custid,$type,$city,$description) = getBlockData($ip_dbh, $webvar{block});
     864  my $blockinfo = getBlockData($ip_dbh, $webvar{block});
    1240865
    1241866  my ($code,$msg) = deleteBlock($ip_dbh, $webvar{block}, $webvar{alloctype});
     
    1243868  $page->param(block => $webvar{block});
    1244869  if ($code eq 'OK') {
    1245     syslog "notice", "$authuser deallocated '$webvar{alloctype}'-type netblock $webvar{block}".
    1246         " $custid, $city, desc='$description'";
     870    syslog "notice", "$authuser deallocated '$webvar{alloctype}'-type netblock $webvar{block} ".
     871        $blockinfo->{custid}.", ".$blockinfo->{city}.", desc='".$blockinfo->{description}."'";
    1247872    mailNotify($ip_dbh, 'da', "REMOVED: $disp_alloctypes{$webvar{alloctype}} $webvar{block}",
    1248873        "$disp_alloctypes{$webvar{alloctype}} $webvar{block} deallocated by $authuser\n".
    1249         "CustID: $custid\nCity: $city\nDescription: $description\n");
     874        "CustID: ".$blockinfo->{custid}."\nCity: ".$blockinfo->{city}.
     875        "\nDescription: ".$blockinfo->{description}."\n");
    1250876  } else {
    1251877    $page->param(failmsg => $msg);
  • branches/stable/cgi-bin/search.cgi

    r593 r594  
    146146  my $cols = "cidr,custid,type,city,description";
    147147
     148  # hack fix for undefined variables
     149  $webvar{custid} = '' if !$webvar{custid};
     150  $webvar{desc}   = '' if !$webvar{desc};
     151  $webvar{notes}  = '' if !$webvar{notes};
     152  $webvar{custexclude}  = '' if !$webvar{custexclude};
     153  $webvar{descexclude}  = '' if !$webvar{descexclude};
     154  $webvar{notesexclude} = '' if !$webvar{notesexclude};
     155
    148156  # First chunk of SQL.  Filter on custid, description, and notes as necessary.
    149   my $sql = "(select $cols from searchme where".
    150         " $webvar{custexclude} (custid ilike '%$webvar{custid}%'".
    151         " $sqlconcat (select $cols from searchme where $webvar{descexclude} description ilike '%$webvar{desc}%')".
    152         " $sqlconcat (select $cols from searchme where $webvar{notesexclude} notes ilike '%$webvar{notes}%')";
     157  my $sql = qq(SELECT $cols FROM searchme\n);
     158  $sql .= " WHERE $webvar{custexclude} (custid ~ '$webvar{custid}')\n";
     159  $sql .= " $sqlconcat (select $cols from searchme where $webvar{descexclude} description ~ '$webvar{desc}')\n";
     160  $sql .= " $sqlconcat (select $cols from searchme where $webvar{notesexclude} notes ~ '$webvar{notes}')";
    153161
    154162  # If we're not supposed to search for all types, search for the selected types.
     163  $webvar{alltypes} = '' if !$webvar{alltypes};
     164  $webvar{typeexclude} = '' if !$webvar{typeexclude};
    155165  if ($webvar{alltypes} ne 'on') {
    156166    $sql .= " $sqlconcat (select $cols from searchme where $webvar{typeexclude} type in (";
     
    164174  # If we're not supposed to search for all cities, search for the selected cities.
    165175  # This could be vastly improved with proper foreign keys in the database.
     176  $webvar{allcities} = '' if !$webvar{allcities};
     177  $webvar{cityexclude} = '' if !$webvar{cityexclude};
    166178  if ($webvar{allcities} ne 'on') {
    167179    $sql .= " $sqlconcat (select $cols from searchme where $webvar{cityexclude} city in (";
     
    315327# Creates appropriate SQL to run the search and display the results
    316328# with queryResults()
    317 sub viewBy($$) {
     329sub viewBy {
    318330  my ($category,$query) = @_;
    319331
     
    445457# Display search queries based on the passed SQL.
    446458# Takes SQL, page number (for multipage search results), and a total count.
    447 sub queryResults($$$) {
     459sub queryResults {
    448460  my ($sql, $pageNo, $rowCount) = @_;
    449461  my $offset = 0;
     
    529541# Return count of rows to be returned in a "real" query
    530542# with the passed SQL statement
    531 sub countRows($) {
     543sub countRows {
    532544  # Note that the "as foo" is required
    533545  my $sth = $ip_dbh->prepare("select count(*) from ($_[0]) as foo");
Note: See TracChangeset for help on using the changeset viewer.