source: branches/sql-cleanup/cgi-bin/main.cgi@ 155

Last change on this file since 155 was 155, checked in by Kris Deugau, 19 years ago

/branches/sql-cleanup

Fixed (most) of the last of the semi-"legacy" checks on
pool/static-ip types to allow simple addition of new types via
the alloctypes table rather than having to modify code. Two
legacy checks remain, which add 'i' to poolips.ptype values and
which should never trigger with the updated arrangment for the
poolips table.

  • Property svn:executable set to *
  • Property svn:keywords set to Date Rev Author
File size: 42.5 KB
Line 
1#!/usr/bin/perl
2# ipdb/cgi-bin/main.cgi
3# Started munging from noc.vianet's old IPDB 04/22/2004
4###
5# SVN revision info
6# $Date: 2005-02-04 22:35:56 +0000 (Fri, 04 Feb 2005) $
7# SVN revision $Rev: 155 $
8# Last update by $Author: kdeugau $
9###
10
11use strict;
12use warnings;
13use CGI::Carp qw(fatalsToBrowser);
14use DBI;
15use CommonWeb qw(:ALL);
16use MyIPDB;
17use POSIX qw(ceil);
18use NetAddr::IP;
19
20use Sys::Syslog;
21
22openlog "IPDB","pid","local2";
23
24# Collect the username from HTTP auth. If undefined, we're in a test environment.
25my $authuser;
26if (!defined($ENV{'REMOTE_USER'})) {
27 $authuser = '__temptest';
28} else {
29 $authuser = $ENV{'REMOTE_USER'};
30}
31
32syslog "debug", "$authuser active";
33
34# Why not a global DB handle? (And a global statement handle, as well...)
35# Use the connectDB function, otherwise we end up confusing ourselves
36my $ip_dbh;
37my $sth;
38my $errstr;
39($ip_dbh,$errstr) = connectDB_My;
40if (!$ip_dbh) {
41 printAndExit("Failed to connect to database: $errstr\n");
42}
43checkDBSanity($ip_dbh);
44initIPDBGlobals($ip_dbh);
45
46#prototypes
47sub viewBy($$); # feed it the category and query
48sub queryResults($$$); # args is the sql, the page# and the rowCount
49# Needs rewrite/rename
50sub countRows($); # returns first element of first row of passed SQL
51 # Only usage passes "select count(*) ..."
52
53# Global variables
54my $RESULTS_PER_PAGE = 50;
55my %webvar = parse_post();
56cleanInput(\%webvar);
57
58
59#main()
60
61if(!defined($webvar{action})) {
62 $webvar{action} = "<NULL>"; #shuts up the warnings.
63}
64
65if($webvar{action} eq 'index') {
66 showSummary();
67} elsif ($webvar{action} eq 'newmaster') {
68 printHeader('');
69
70 my $cidr = new NetAddr::IP $webvar{cidr};
71
72 print "<div type=heading align=center>Adding $cidr as master block....</div>\n";
73
74 # Allow transactions, and raise an exception on errors so we can catch it later.
75 # Use local to make sure these get "reset" properly on exiting this block
76 local $ip_dbh->{AutoCommit} = 0;
77 local $ip_dbh->{RaiseError} = 1;
78
79 # Wrap the SQL in a transaction
80 eval {
81 $sth = $ip_dbh->prepare("insert into masterblocks values ('$webvar{cidr}')");
82 $sth->execute;
83
84# Unrouted blocks aren't associated with a city (yet). We don't rely on this
85# elsewhere though; legacy data may have traps and pitfalls in it to break this.
86# Thus the "routed" flag.
87
88 $sth = $ip_dbh->prepare("insert into freeblocks (cidr,maskbits,city,routed)".
89 " values ('$webvar{cidr}',".$cidr->masklen.",'<NULL>','n')");
90 $sth->execute;
91
92 # If we get here, everything is happy. Commit changes.
93 $ip_dbh->commit;
94 }; # end eval
95
96 if ($@) {
97 carp "Transaction aborted because $@";
98 eval { $ip_dbh->rollback; };
99 syslog "err", "Could not add master block '$webvar{cidr}' to database: '$@'";
100 printError("Could not add master block $webvar{cidr} to database: $@");
101 } else {
102 print "<div type=heading align=center>Success!</div>\n";
103 syslog "info", "$authuser added master block $webvar{cidr}";
104 }
105
106} # end add new master
107
108elsif($webvar{action} eq 'showmaster') {
109 showMaster();
110}
111elsif($webvar{action} eq 'showrouted') {
112 showRBlock();
113}
114elsif($webvar{action} eq 'listpool') {
115 listPool();
116}
117elsif($webvar{action} eq 'search') {
118 printHeader('');
119 if (!$webvar{input}) {
120 # No search term. Display everything.
121 viewBy('all', '');
122 } else {
123 # Search term entered. Display matches.
124 # We should really sanitize $webvar{input}, no?
125 viewBy($webvar{searchfor}, $webvar{input});
126 }
127}
128
129# Not modified or added; just shuffled
130elsif($webvar{action} eq 'assign') {
131 assignBlock();
132}
133elsif($webvar{action} eq 'confirm') {
134 confirmAssign();
135}
136elsif($webvar{action} eq 'insert') {
137 insertAssign();
138}
139elsif($webvar{action} eq 'edit') {
140 edit();
141}
142elsif($webvar{action} eq 'update') {
143 update();
144}
145elsif($webvar{action} eq 'delete') {
146 remove();
147}
148elsif($webvar{action} eq 'finaldelete') {
149 finalDelete();
150}
151
152# Default is an error. It shouldn't be possible to easily get here.
153# The only way I can think of offhand is to just call main.cgi bare-
154# which is not in any way guaranteed to provide anything useful.
155else {
156 printHeader('');
157 my $rnd = rand 500;
158 my $boing = sprintf("%.2f", rand 500);
159 my @excuses = ("Aether cloudy. Ask again later.","The gods are unhappy with your sacrifice.",
160 "Because one of it's legs are both the same", "*wibble*",
161 "Hey! Stop pushing my buttons!", "I ain't done nuttin'", "9",
162 "8", "9", "10", "11", "12", "13", "14", "15", "16", "17");
163 printAndExit("Error $boing: ".$excuses[$rnd/30.0]);
164}
165## Finally! Done with that NASTY "case" emulation!
166
167
168
169# Clean up IPDB globals, DB handle, etc.
170finish($ip_dbh);
171# We print the footer here, so we don't have to do it elsewhere.
172printFooter;
173# Just in case something waaaayyy down isn't in place
174# properly... we exit explicitly.
175exit;
176
177
178
179sub viewBy($$) {
180 my ($category,$query) = @_;
181
182 # Local variables
183 my $sql;
184
185#print "<pre>\n";
186
187#print "start querysub: query '$query'\n";
188# this may happen with more than one subcategory. Unlikely, but possible.
189
190 # Calculate start point for LIMIT clause
191 my $offset = ($webvar{page}-1)*$RESULTS_PER_PAGE;
192
193# Possible cases:
194# 1) Partial IP/subnet. Treated as "first-three-octets-match" in old IPDB,
195# I should be able to handle it similarly here.
196# 2a) CIDR subnet. Treated more or less as such in old IPDB.
197# 2b) CIDR netmask. Not sure how it's treated.
198# 3) Customer ID. Not handled in old IPDB
199# 4) Description.
200# 5) Invalid data which might be interpretable as an IP or something, but
201# which probably shouldn't be for reasons of sanity.
202
203 if ($category eq 'all') {
204
205 print qq(<div class="heading">Showing all netblock and static-IP allocations</div><br>\n);
206 $sql = "select * from searchme";
207 my $count = countRows("select count(*) from ($sql) foo");
208 $sql .= " order by cidr limit $RESULTS_PER_PAGE offset $offset";
209 queryResults($sql, $webvar{page}, $count);
210
211 } elsif ($category eq 'cust') {
212
213 print qq(<div class="heading">Searching for Customer IDs containing '$query'</div><br>\n);
214
215 # Query for a customer ID. Note that we can't restrict to "numeric-only"
216 # as we have non-numeric custIDs in the legacy data. :/
217 $sql = "select * from searchme where custid ilike '%$query%'";
218 my $count = countRows("select count(*) from ($sql) foo");
219 $sql .= " order by cidr limit $RESULTS_PER_PAGE offset $offset";
220 queryResults($sql, $webvar{page}, $count);
221
222 } elsif ($category eq 'desc') {
223
224 print qq(<div class="heading">Searching for descriptions containing '$query'</div><br>\n);
225 # Query based on description (includes "name" from old DB).
226 $sql = "select * from searchme where description ilike '%$query%'";
227 my $count = countRows("select count(*) from ($sql) foo");
228 $sql .= " order by cidr limit $RESULTS_PER_PAGE offset $offset";
229 queryResults($sql, $webvar{page}, $count);
230
231 } elsif ($category =~ /ipblock/) {
232
233 # Query is for a partial IP, a CIDR block in some form, or a flat IP.
234 print qq(<div class="heading">Searching for IP-based matches on '$query'</div><br>\n);
235
236 $query =~ s/\s+//g;
237 if ($query =~ /\//) {
238 # 209.91.179/26 should show all /26 subnets in 209.91.179
239 my ($net,$maskbits) = split /\//, $query;
240 if ($query =~ /^(\d{1,3}\.){3}\d{1,3}\/\d{2}$/) {
241 # /0->/9 are silly to worry about right now. I don't think
242 # we'll be getting a class A anytime soon. <g>
243 $sql = "select * from searchme where cidr='$query'";
244 queryResults($sql, $webvar{page}, 1);
245 } else {
246 print "Finding all blocks with netmask /$maskbits, leading octet(s) $net<br>\n";
247 # Partial match; beginning of subnet and maskbits are provided
248 $sql = "select * from searchme where text(cidr) like '$net%' and ".
249 "text(cidr) like '%$maskbits'";
250 my $count = countRows("select count(*) from ($sql) foo");
251 $sql .= " order by cidr limit $RESULTS_PER_PAGE offset $offset";
252 queryResults($sql, $webvar{page}, $count);
253 }
254 } elsif ($query =~ /^(\d{1,3}\.){3}\d{1,3}$/) {
255 # Specific IP address match
256 print "4-octet pattern found; finding netblock containing IP $query<br>\n";
257 my ($net,$ip) = ($query =~ /(\d{1,3}\.\d{1,3}\.\d{1,3}\.)(\d{1,3})/);
258 my $sfor = new NetAddr::IP $query;
259 $sth = $ip_dbh->prepare("select * from searchme where text(cidr) like '$net%'");
260 $sth->execute;
261 while (my @data = $sth->fetchrow_array()) {
262 my $cidr = new NetAddr::IP $data[0];
263 if ($cidr->contains($sfor)) {
264 queryResults("select * from searchme where cidr='$cidr'", $webvar{page}, 1);
265 }
266 }
267 } elsif ($query =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.?$/) {
268 print "Finding matches where the first three octets are $query<br>\n";
269 $sql = "select * from searchme where text(cidr) like '$query%'";
270 my $count = countRows("select count(*) from ($sql) foo");
271 $sql .= " order by cidr limit $RESULTS_PER_PAGE offset $offset";
272 queryResults($sql, $webvar{page}, $count);
273 } else {
274 # This shouldn't happen, but if it does, whoever gets it deserves what they get...
275 printError("Invalid query.");
276 }
277 } else {
278 # This shouldn't happen, but if it does, whoever gets it deserves what they get...
279 printError("Invalid searchfor.");
280 }
281} # viewBy
282
283
284# args are: a reference to an array with the row to be printed and the
285# class(stylesheet) to use for formatting.
286# if ommitting the class - call the sub as &printRow(\@array)
287sub printRow {
288 my ($rowRef,$class) = @_;
289
290 if (!$class) {
291 print "<tr>\n";
292 } else {
293 print "<tr class=\"$class\">\n";
294 }
295
296ELEMENT: foreach my $element (@$rowRef) {
297 if (!defined($element)) {
298 print "<td></td>\n";
299 next ELEMENT;
300 }
301 $element =~ s|\n|</br>|g;
302 print "<td>$element</td>\n";
303 }
304 print "</tr>";
305} # printRow
306
307
308# Display certain types of search query. Note that this can't be
309# cleanly reused much of anywhere else as the data isn't neatly tabulated.
310# This is tied to the search sub tightly enough I may just gut it and provide
311# more appropriate tables directly as needed.
312sub queryResults($$$) {
313 my ($sql, $pageNo, $rowCount) = @_;
314 my $offset = 0;
315 $offset = $1 if($sql =~ m/.*limit\s+(.*),.*/);
316
317 my $sth = $ip_dbh->prepare($sql);
318 $sth->execute();
319
320 startTable('Allocation','CustID','Type','City','Description/Name');
321 my $count = 0;
322
323 while (my @data = $sth->fetchrow_array) {
324 # cidr,custid,type,city,description,notes
325 # Fix up types from pools (which are single-char)
326 # Fixing the database would be... painful. :(
327##fixme LEGACY CODE
328 if ($data[2] =~ /^[cdsmw]$/) {
329 $data[2] .= 'i';
330 }
331 my @row = (qq(<a href="/ip/cgi-bin/main.cgi?action=edit&block=$data[0]">$data[0]</a>),
332 $data[1], $disp_alloctypes{$data[2]}, $data[3], $data[4]);
333 # Allow listing of pool if desired/required.
334 if ($data[2] =~ /^.[pd]$/) {
335 $row[0] .= ' &nbsp; <a href="/ip/cgi-bin/main.cgi?action=listpool'.
336 "&pool=$data[0]\">List IPs</a>";
337 }
338 printRow(\@row, 'color1', 1) if ($count%2==0);
339 printRow(\@row, 'color2', 1) if ($count%2!=0);
340 $count++;
341 }
342
343 # Have to think on this call, it's primarily to clean up unfetched rows from a select.
344 # In this context it's probably a good idea.
345 $sth->finish();
346
347 my $upper = $offset+$count;
348 print "<tr><td colspan=10 bgcolor=white class=regular>Records found: $rowCount<br><i>Displaying: $offset - $upper</i></td></tr>\n";
349 print "</table></center>\n";
350
351 # print the page thing..
352 if ($rowCount > $RESULTS_PER_PAGE) {
353 my $pages = ceil($rowCount/$RESULTS_PER_PAGE);
354 print qq(<div class="center"> Page: );
355 for (my $i = 1; $i <= $pages; $i++) {
356 if ($i == $pageNo) {
357 print "<b>$i&nbsp;</b>\n";
358 } else {
359 print qq(<a href="/ip/cgi-bin/main.cgi?page=$i&input=$webvar{input}&action=search&searchfor=$webvar{searchfor}">$i</a>&nbsp;\n);
360 }
361 }
362 print "</div>";
363 }
364} # queryResults
365
366
367# Prints table headings. Accepts any number of arguments;
368# each argument is a table heading.
369sub startTable {
370 print qq(<center><table width="98%" cellspacing="0" class="center"><tr>);
371
372 foreach(@_) {
373 print qq(<td class="heading">$_</td>);
374 }
375 print "</tr>\n";
376} # startTable
377
378
379# Return first element of passed SQL query
380sub countRows($) {
381 my $sth = $ip_dbh->prepare($_[0]);
382 $sth->execute();
383 my @a = $sth->fetchrow_array();
384 $sth->finish();
385 return $a[0];
386}
387
388
389# Initial display: Show master blocks with total allocated subnets, total free subnets
390sub showSummary {
391 # this is horrible-ugly-bad and will Go Away real soon now(TM)
392 print "Content-type: text/html\n\n";
393
394 startTable('Master netblock', 'Routed netblocks', 'Allocated netblocks',
395 'Free netblocks', 'Largest free block');
396
397 my %allocated;
398 my %free;
399 my %routed;
400 my %bigfree;
401
402 # Count the allocations.
403 $sth = $ip_dbh->prepare("select count(*) from allocations where cidr <<= ?");
404 foreach my $master (@masterblocks) {
405 $sth->execute("$master");
406 $sth->bind_columns(\$allocated{"$master"});
407 $sth->fetch();
408 }
409
410 # Count routed blocks
411 $sth = $ip_dbh->prepare("select count(*) from routed where cidr <<= ?");
412 foreach my $master (@masterblocks) {
413 $sth->execute("$master");
414 $sth->bind_columns(\$routed{"$master"});
415 $sth->fetch();
416 }
417
418 # Count the free blocks.
419 $sth = $ip_dbh->prepare("select count(*) from freeblocks where cidr <<= ?");
420 foreach my $master (@masterblocks) {
421 $sth->execute("$master");
422 $sth->bind_columns(\$free{"$master"});
423 $sth->fetch();
424 }
425
426 # Find the largest free block in each master
427 $sth = $ip_dbh->prepare("select maskbits from freeblocks where cidr <<= ? order by maskbits limit 1");
428 foreach my $master (@masterblocks) {
429 $sth->execute("$master");
430 $sth->bind_columns(\$bigfree{"$master"});
431 $sth->fetch();
432 }
433
434 # Print the data.
435 my $count=0;
436 foreach my $master (@masterblocks) {
437 my @row = ("<a href=\"/ip/cgi-bin/main.cgi?action=showmaster&block=$master\">$master</a>",
438 $routed{"$master"}, $allocated{"$master"}, $free{"$master"},
439 ( ($bigfree{"$master"} eq 128) ? ("&lt;NONE&gt;") : ("/".$bigfree{"$master"}) )
440 );
441
442 printRow(\@row, 'color1' ) if($count%2==0);
443 printRow(\@row, 'color2' ) if($count%2!=0);
444 $count++;
445 }
446 print "</table>\n";
447 print qq(<a href="/ip/addmaster.shtml">Add new master block</a><br><br>\n);
448 print "Note: Free blocks noted here include both routed and unrouted blocks.\n";
449
450} # showSummary
451
452
453# Display detail on master
454# Alrighty then! We're showing routed blocks within a single master this time.
455# We should be able to steal code from showSummary(), and if I'm really smart
456# I'll figger a way to munge the two together. (Once I've done that, everything
457# else should follow. YMMV.)
458sub showMaster {
459 printHeader('');
460
461 print qq(<center><div class="heading">Summarizing routed blocks for ).
462 qq($webvar{block}:</div></center><br>\n);
463
464 my %allocated;
465 my %free;
466 my %routed;
467 my %bigfree;
468
469 my $master = new NetAddr::IP $webvar{block};
470 my @localmasters;
471
472 # Fetch only the blocks relevant to this master
473 $sth = $ip_dbh->prepare("select cidr,city from routed where cidr <<= '$master' order by cidr");
474 $sth->execute();
475
476 my $i=0;
477 while (my @data = $sth->fetchrow_array()) {
478 my $cidr = new NetAddr::IP $data[0];
479 $localmasters[$i++] = $cidr;
480 $free{"$cidr"} = 0;
481 $allocated{"$cidr"} = 0;
482 $bigfree{"$cidr"} = 128;
483 # Retain the routing destination
484 $routed{"$cidr"} = $data[1];
485 }
486
487 # Check if there were actually any blocks routed from this master
488 if ($i > 0) {
489 startTable('Routed block','Routed to','Allocated blocks',
490 'Free blocks','Largest free block');
491
492 # Count the allocations
493 $sth = $ip_dbh->prepare("select count(*) from allocations where cidr <<= ?");
494 foreach my $master (@localmasters) {
495 $sth->execute("$master");
496 $sth->bind_columns(\$allocated{"$master"});
497 $sth->fetch();
498 }
499
500 # Count the free blocks.
501 $sth = $ip_dbh->prepare("select count(*) from freeblocks where cidr <<= ?");
502 foreach my $master (@localmasters) {
503 $sth->execute("$master");
504 $sth->bind_columns(\$free{"$master"});
505 $sth->fetch();
506 }
507
508 # Get the size of the largest free block
509 $sth = $ip_dbh->prepare("select maskbits from freeblocks where cidr <<= ? order by maskbits limit 1");
510 foreach my $master (@localmasters) {
511 $sth->execute("$master");
512 $sth->bind_columns(\$bigfree{"$master"});
513 $sth->fetch();
514 }
515
516 # Print the data.
517 my $count=0;
518 foreach my $master (@localmasters) {
519 my @row = ("<a href=\"/ip/cgi-bin/main.cgi?action=showrouted&block=$master\">$master</a>",
520 $routed{"$master"}, $allocated{"$master"},
521 $free{"$master"},
522 ( ($bigfree{"$master"} eq 128) ? ("&lt;NONE&gt;") : ("/".$bigfree{"$master"}) )
523 );
524 printRow(\@row, 'color1' ) if($count%2==0);
525 printRow(\@row, 'color2' ) if($count%2!=0);
526 $count++;
527 }
528 } else {
529 # If a master block has no routed blocks, then by definition it has no
530 # allocations, and can be deleted.
531 print qq(<hr width="60%"><center><div class="heading">No allocations in ).
532 qq($master.</div>\n).
533 qq(<form action="/ip/cgi-bin/main.cgi" method=POST>\n).
534 qq(<input type=hidden name=action value="delete">\n).
535 qq(<input type=hidden name=block value="$master">\n).
536 qq(<input type=hidden name=alloctype value="mm">\n).
537 qq(<input type=submit value=" Remove this master ">\n).
538 qq(</form></center>\n);
539
540 } # end check for existence of routed blocks in master
541
542 print qq(</table>\n<hr width="60%">\n).
543 qq(<center><div class="heading">Unrouted blocks in $master:</div></center><br>\n);
544
545 startTable('Netblock','Range');
546
547 # Snag the free blocks.
548 my $count = 0;
549 $sth = $ip_dbh->prepare("select cidr from freeblocks where cidr <<='$master' and ".
550 "routed='n' order by cidr");
551 $sth->execute();
552 while (my @data = $sth->fetchrow_array()) {
553 my $cidr = new NetAddr::IP $data[0];
554 my @row = ("$cidr", $cidr->range);
555 printRow(\@row, 'color1' ) if($count%2==0);
556 printRow(\@row, 'color2' ) if($count%2!=0);
557 $count++;
558 }
559
560 print "</table>\n";
561} # showMaster
562
563
564# Display details of a routed block
565# Alrighty then! We're showing allocations within a routed block this time.
566# We should be able to steal code from showSummary() and showMaster(), and if
567# I'm really smart I'll figger a way to munge all three together. (Once I've
568# done that, everything else should follow. YMMV.
569# This time, we check the database before spewing, because we may
570# not have anything useful to spew.
571sub showRBlock {
572 printHeader('');
573
574 my $master = new NetAddr::IP $webvar{block};
575
576 $sth = $ip_dbh->prepare("select city from routed where cidr='$master'");
577 $sth->execute;
578 my @data = $sth->fetchrow_array;
579
580 print qq(<center><div class="heading">Summarizing allocated blocks for ).
581 qq($master ($data[0]):</div></center><br>\n);
582
583 startTable('CIDR allocation','Customer Location','Type','CustID','Description/Name');
584
585 # Snag the allocations for this block
586 $sth = $ip_dbh->prepare("select cidr,city,type,custid,description".
587 " from allocations where cidr <<= '$master' order by cidr");
588 $sth->execute();
589
590 my $count=0;
591 while (my @data = $sth->fetchrow_array()) {
592 # cidr,city,type,custid,description, as per the SELECT
593 my $cidr = new NetAddr::IP $data[0];
594
595 # Clean up extra spaces that are borking things.
596# $data[2] =~ s/\s+//g;
597
598 my @row = ("<a href=\"/ip/cgi-bin/main.cgi?action=edit&block=$data[0]\">$data[0]</a>",
599 $data[1], $disp_alloctypes{$data[2]}, $data[3], $data[4]);
600 # If the allocation is a pool, allow listing of the IPs in the pool.
601 if ($data[2] =~ /^.[pd]$/) {
602 $row[0] .= ' &nbsp; <a href="/ip/cgi-bin/main.cgi?action=listpool'.
603 "&pool=$data[0]\">List IPs</a>";
604 }
605
606 printRow(\@row, 'color1') if ($count%2 == 0);
607 printRow(\@row, 'color2') if ($count%2 != 0);
608 $count++;
609 }
610
611 print "</table>\n";
612
613 # If the routed block has no allocations, by definition it only has
614 # one free block, and therefore may be deleted.
615 if ($count == 0) {
616 print qq(<hr width="60%"><center><div class="heading">No allocations in ).
617 qq($master.</div></center>\n).
618 qq(<form action="/ip/cgi-bin/main.cgi" method=POST>\n).
619 qq(<input type=hidden name=action value="delete">\n).
620 qq(<input type=hidden name=block value="$master">\n).
621 qq(<input type=hidden name=alloctype value="rr">\n).
622 qq(<input type=submit value=" Remove this block ">\n).
623 qq(</form>\n);
624 }
625
626 print qq(<hr width="60%">\n<center><div class="heading">Free blocks within routed ).
627 qq(submaster $master</div></center>\n);
628
629 startTable('CIDR block','Range');
630
631 # Snag the free blocks. We don't really *need* to be pedantic about avoiding
632 # unrouted free blocks, but it's better to let the database do the work if we can.
633 $count = 0;
634 $sth = $ip_dbh->prepare("select cidr from freeblocks where routed='y' and cidr <<= '$master' order by cidr");
635 $sth->execute();
636 while (my @data = $sth->fetchrow_array()) {
637 # cidr,maskbits,city
638 my $cidr = new NetAddr::IP $data[0];
639 my @row = ("<a href=\"/ip/cgi-bin/main.cgi?action=assign&block=$cidr\">$cidr</a>",
640 $cidr->range);
641 printRow(\@row, 'color1') if ($count%2 == 0);
642 printRow(\@row, 'color2') if ($count%2 != 0);
643 $count++;
644 }
645
646 print "</table>\n";
647} # showRBlock
648
649
650# List the IPs used in a pool
651sub listPool {
652 printHeader('');
653
654 my $cidr = new NetAddr::IP $webvar{pool};
655
656 my ($pooltype,$poolcity);
657
658 # Snag pool info for heading
659 $sth = $ip_dbh->prepare("select type,city from allocations where cidr='$cidr'");
660 $sth->execute;
661 $sth->bind_columns(\$pooltype, \$poolcity);
662 $sth->fetch() || carp $sth->errstr;
663
664 print qq(<center><div class="heading">Listing pool IPs for $cidr<br>\n).
665 qq(($disp_alloctypes{$pooltype} in $poolcity)</div></center><br>\n);
666 # Only display net/gw/bcast if it's a "real" netblock and not a PPP(oE) lunacy
667 if ($pooltype =~ /^.d$/) {
668 print qq(<div class="indent"><b>Reserved IPs:</b><br>\n);
669 print qq(<div class="indent"><table><tr class=color1><td>Network IP:</td><td>).
670 $cidr->addr."</td></tr>\n";
671 $cidr++;
672 print "<tr class=color2><td>Gateway:</td><td>".$cidr->addr."</td></tr>\n";
673 $cidr--; $cidr--;
674 print "<tr class=color1><td>Broadcast:</td><td>".$cidr->addr."</td></tr>\n".
675 "<tr><td>Netmask:</td><td>".$cidr->mask."</td></tr>\n".
676 "</table></div></div>\n";
677 }
678
679# probably have to add an "edit IP allocation" link here somewhere.
680
681 startTable('IP','Customer ID','Available?','Description','');
682 $sth = $ip_dbh->prepare("select ip,custid,available,description,type".
683 " from poolips where pool='$webvar{pool}' order by ip");
684 $sth->execute;
685 my $count = 0;
686 while (my @data = $sth->fetchrow_array) {
687 # pool,ip,custid,city,ptype,available,notes,description,circuitid
688 # ip,custid,available,description,type
689 # If desc is "null", make it not null. <g>
690 if ($data[3] eq '') {
691 $data[3] = '&nbsp;';
692 }
693 # Some nice hairy Perl to decide whether to allow unassigning each IP
694 # -> if $data[2] (aka poolips.available) == 'n' then we print the unassign link
695 # else we print a blank space
696 my @row = ( qq(<a href="/ip/cgi-bin/main.cgi?action=edit&block=$data[0]">$data[0]</a>),
697 $data[1],$data[2],$data[3],
698 ( ($data[2] eq 'n') ?
699 ("<a href=\"/ip/cgi-bin/main.cgi?action=delete&block=$data[0]&".
700 "alloctype=$data[4]\">Unassign this IP</a>") :
701 ("&nbsp;") )
702 );
703 printRow(\@row, 'color1') if($count%2==0);
704 printRow(\@row, 'color2') if($count%2!=0);
705 $count++;
706 }
707 print "</table>\n";
708
709} # end listPool
710
711
712# Show "Add new allocation" page. Note that the actual page may
713# be one of two templates, and the lists come from the database.
714sub assignBlock {
715 printHeader('');
716
717 my $html;
718
719 # New special case- block to assign is specified
720 if ($webvar{block} ne '') {
721 open HTML, "../fb-assign.html"
722 or croak "Could not open fb-assign.html: $!";
723 $html = join('',<HTML>);
724 close HTML;
725 my $block = new NetAddr::IP $webvar{block};
726 $html =~ s|\$\$BLOCK\$\$|$block|g;
727 $html =~ s|\$\$MASKBITS\$\$|$block->masklen|;
728 my $typelist = '';
729 $sth = $ip_dbh->prepare("select type,listname from alloctypes where listorder < 500 and type not like '_i' order by listorder");
730 $sth->execute;
731 my @data = $sth->fetchrow_array;
732 $typelist .= "<option value='$data[0]' selected>$data[1]</option>\n";
733 while (my @data = $sth->fetchrow_array) {
734 $typelist .= "<option value='$data[0]'>$data[1]</option>\n";
735 }
736 $html =~ s|\$\$TYPELIST\$\$|$typelist|g;
737 } else {
738 open HTML, "../assign.html"
739 or croak "Could not open assign.html: $!";
740 $html = join('',<HTML>);
741 close HTML;
742 my $masterlist = "<select name=allocfrom><option selected>-</option>\n";
743 foreach my $master (@masterblocks) {
744 $masterlist .= "<option>$master</option>\n";
745 }
746 $masterlist .= "</select>\n";
747 $html =~ s|\$\$MASTERLIST\$\$|$masterlist|g;
748 my $pops = '';
749 foreach my $pop (@poplist) {
750 $pops .= "<option>$pop</option>\n";
751 }
752 $html =~ s|\$\$POPLIST\$\$|$pops|g;
753 my $typelist = '';
754 $sth = $ip_dbh->prepare("select type,listname from alloctypes where listorder < 900 order by listorder");
755 $sth->execute;
756 my @data = $sth->fetchrow_array;
757 $typelist .= "<option value='$data[0]' selected>$data[1]</option>\n";
758 while (my @data = $sth->fetchrow_array) {
759 $typelist .= "<option value='$data[0]'>$data[1]</option>\n";
760 }
761 $html =~ s|\$\$TYPELIST\$\$|$typelist|g;
762 }
763 my $cities = '';
764 foreach my $city (@citylist) {
765 $cities .= "<option>$city</option>\n";
766 }
767 $html =~ s|\$\$ALLCITIES\$\$|$cities|g;
768
769 print $html;
770
771} # assignBlock
772
773
774# Take info on requested IP assignment and see what we can provide.
775sub confirmAssign {
776 printHeader('');
777
778 my $cidr;
779 my $alloc_from;
780
781 # Going to manually validate some items.
782 # custid and city are automagic.
783 return if !validateInput();
784
785# Several different cases here.
786# Static IP vs netblock
787# + Different flavours of static IP
788# + Different flavours of netblock
789
790 if ($webvar{alloctype} =~ /^.i$/) {
791 my ($base,undef) = split //, $webvar{alloctype}; # split into individual chars
792 my $sql;
793 # Check for pools in Subury or North Bay if DSL or server pool. Anywhere else is
794 # invalid and shouldn't be in the db in the first place.
795 # ... aside from #^%#$%#@#^%^^!!!! legacy data. GRRR.
796 # Note that we want to retain the requested city to relate to customer info.
797##fixme This needs thought.
798##SELECT DISTINCT pool, Count(*) FROM poolips where available='y' GROUP BY pool;
799 if ($base =~ /^[ds]$/) {
800 $sql = "select * from poolips where available='y' and".
801 " ptype='$base' and (city='Sudbury' or city='North Bay')";
802 } else {
803 $sql = "select * from poolips where available='y' and".
804 " ptype='$base' and city='$webvar{pop}'";
805 }
806
807 # Now that we know where we're looking, we can list the pools with free IPs.
808 $sth = $ip_dbh->prepare($sql);
809 $sth->execute;
810 my %ipcount;
811 my $optionlist;
812 while (my @data = $sth->fetchrow_array) {
813 $ipcount{$data[0]}++;
814 }
815 $sth = $ip_dbh->prepare("select city from allocations where cidr=?");
816 foreach my $key (keys %ipcount) {
817 $sth->execute($key);
818 my @data = $sth->fetchrow_array;
819 $optionlist .= "<option value='$key'>$key [$ipcount{$key} free IP(s)] in $data[0]</option>\n";
820 }
821 $cidr = "Single static IP";
822 $alloc_from = "<select name=alloc_from>".$optionlist."</select>\n";
823
824 } else { # end show pool options
825
826 if ($webvar{fbassign} eq 'y') {
827 $cidr = new NetAddr::IP $webvar{block};
828 $webvar{maskbits} = $cidr->masklen;
829 } else { # done with direct freeblocks assignment
830
831 if (!$webvar{maskbits}) {
832 printError("Please specify a CIDR mask length.");
833 return;
834 }
835 my $sql;
836 my $city;
837 my $failmsg;
838 if ($webvar{alloctype} eq 'rr') {
839 if ($webvar{allocfrom} ne '-') {
840 $sql = "select * from freeblocks where maskbits<=$webvar{maskbits} and routed='n'".
841 " and cidr <<= '$webvar{allocfrom}' order by maskbits desc";
842 } else {
843 $sql = "select * from freeblocks where maskbits<=$webvar{maskbits} and routed='n'".
844 " order by maskbits desc";
845 }
846 $failmsg = "No suitable free block found.<br>\nWe do not have a free".
847 " routeable block of that size.<br>\nYou will have to either route".
848 " a set of smaller netblocks or a single smaller netblock.";
849 } else {
850##fixme
851# This section needs serious Pondering.
852 if ($webvar{alloctype} =~ /^.[pd]$/) {
853 if (($webvar{city} !~ /^(Sudbury|North Bay)$/) && ($webvar{alloctype} eq 'dp')) {
854 printError("You must chose Sudbury or North Bay for DSL pools.");
855 return;
856 }
857 $city = $webvar{city};
858 $failmsg = "No suitable free block found.<br>\nYou will have to route another".
859 " superblock from one of the<br>\nmaster blocks in Sudbury or chose a smaller".
860 " block size for the pool.";
861 } else {
862 $city = $webvar{pop};
863 $failmsg = "No suitable free block found.<br>\nYou will have to route another".
864 " superblock to $webvar{pop}<br>\nfrom one of the master blocks in Sudbury or".
865 " chose a smaller blocksize.";
866 }
867 if ($webvar{allocfrom} ne '-') {
868 $sql = "select cidr from freeblocks where city='$city' and maskbits<=$webvar{maskbits}".
869 " and cidr <<= '$webvar{allocfrom}' and routed='y' order by cidr,maskbits desc";
870 } else {
871 $sql = "select cidr from freeblocks where city='$city' and maskbits<=$webvar{maskbits}".
872 " and routed='y' order by cidr,maskbits desc";
873 }
874 }
875 $sth = $ip_dbh->prepare($sql);
876 $sth->execute;
877 my @data = $sth->fetchrow_array();
878 if ($data[0] eq "") {
879 printError($failmsg);
880 return;
881 }
882 $cidr = new NetAddr::IP $data[0];
883 } # check for freeblocks assignment or IPDB-controlled assignment
884
885 $alloc_from = qq($cidr<input type=hidden name=alloc_from value="$cidr">);
886
887 # If the block to be allocated is smaller than the one we found,
888 # figure out the "real" block to be allocated.
889 if ($cidr->masklen() ne $webvar{maskbits}) {
890 my $maskbits = $cidr->masklen();
891 my @subblocks;
892 while ($maskbits++ < $webvar{maskbits}) {
893 @subblocks = $cidr->split($maskbits);
894 }
895 $cidr = $subblocks[0];
896 }
897 } # if ($webvar{alloctype} =~ /^.i$/)
898
899 open HTML, "../confirm.html"
900 or croak "Could not open confirm.html: $!";
901 my $html = join '', <HTML>;
902 close HTML;
903
904### gotta fix this in final
905 # Stick in customer info as necessary - if it's blank, it just ends
906 # up as blank lines ignored in the rendering of the page
907 my $custbits;
908 $html =~ s|\$\$CUSTBITS\$\$|$custbits|g;
909###
910
911 # Stick in the allocation data
912 $html =~ s|\$\$ALLOC_TYPE\$\$|$webvar{alloctype}|g;
913 $html =~ s|\$\$TYPEFULL\$\$|$disp_alloctypes{$webvar{alloctype}}|g;
914 $html =~ s|\$\$ALLOC_FROM\$\$|$alloc_from|g;
915 $html =~ s|\$\$CIDR\$\$|$cidr|g;
916 $webvar{city} = desanitize($webvar{city});
917 $html =~ s|\$\$CITY\$\$|$webvar{city}|g;
918 $html =~ s|\$\$CUSTID\$\$|$webvar{custid}|g;
919 $webvar{circid} = desanitize($webvar{circid});
920 $html =~ s|\$\$CIRCID\$\$|$webvar{circid}|g;
921 $webvar{desc} = desanitize($webvar{desc});
922 $html =~ s|\$\$DESC\$\$|$webvar{desc}|g;
923 $webvar{notes} = desanitize($webvar{notes});
924 $html =~ s|\$\$NOTES\$\$|$webvar{notes}|g;
925 $html =~ s|\$\$ACTION\$\$|insert|g;
926
927 print $html;
928
929} # end confirmAssign
930
931
932# Do the work of actually inserting a block in the database.
933sub insertAssign {
934 # Some things are done more than once.
935 printHeader('');
936 return if !validateInput();
937
938 # $code is "success" vs "failure", $msg contains OK for a
939 # successful netblock allocation, the IP allocated for static
940 # IP, or the error message if an error occurred.
941 my ($code,$msg) = allocateBlock($ip_dbh, $webvar{fullcidr}, $webvar{alloc_from},
942 $webvar{custid}, $webvar{alloctype}, $webvar{city}, $webvar{desc}, $webvar{notes},
943 $webvar{circid});
944
945 if ($code eq 'OK') {
946 if ($webvar{alloctype} =~ /^.i$/) {
947 print qq(<div class="center"><div class="heading">The IP $msg has been allocated to customer $webvar{custid}</div></div>);
948 # Notify tech@example.com
949 mailNotify('tech@example.com',"$disp_alloctypes{$webvar{alloctype}} allocation",
950 "$disp_alloctypes{$webvar{alloctype}} $msg allocated to customer $webvar{custid}\n".
951 "Description: $webvar{desc}\n\nAllocated by: $authuser\n");
952 } else {
953 print qq(<div class="center"><div class="heading">The block $webvar{fullcidr} was ).
954 "sucessfully added as type '$webvar{alloctype}' ".
955 "($disp_alloctypes{$webvar{alloctype}})</div></div>";
956 }
957 syslog "notice", "$authuser allocated '$webvar{fullcidr}' to '$webvar{custid}' as ".
958 "'$webvar{alloctype}'";
959 } else {
960 syslog "err", "Allocation of '$webvar{fullcidr}' to '$webvar{custid}' as ".
961 "'$webvar{alloctype}' by $authuser failed: '$msg'";
962 printError("Allocation of $webvar{fullcidr} as $disp_alloctypes{$webvar{alloctype}}".
963 " failed:<br>\n$msg\n");
964 }
965
966} # end insertAssign()
967
968
969# Does some basic checks on common input data to make sure nothing
970# *really* weird gets in to the database through this script.
971# Does NOT do complete input validation!!!
972sub validateInput {
973 if ($webvar{city} eq '-') {
974 printError("Please choose a city.");
975 return;
976 }
977
978 # Alloctype check.
979 chomp $webvar{alloctype};
980 if (!grep /$webvar{alloctype}/, keys %disp_alloctypes) {
981 # Danger! Danger! alloctype should ALWAYS be set by a dropdown. Anyone
982 # managing to call things in such a way as to cause this deserves a cryptic error.
983 printError("Invalid alloctype");
984 return;
985 }
986
987 # CustID check
988 # We have different handling for customer allocations and "internal" or "our" allocations
989 if ($webvar{alloctype} =~ /^(cn|.i)$/) {
990 if (!$webvar{custid}) {
991 printError("Please enter a customer ID.");
992 return;
993 }
994 if ($webvar{custid} !~ /^(?:\d{10}|\d{7}|STAFF|TEMP)(?:-\d\d?)?$/) {
995 printError("Please enter a valid customer ID- this must be a 7- or 10-digit number, or STAFF for static IPs for staff.");
996 return;
997 }
998 print "<!-- [ In validateInput(). Insert customer ID cross-check here. ] -->\n";
999 } else {
1000 # All non-customer allocations MUST be entered with "our" customer ID.
1001 # I have Defined this as 6750400 for consistency.
1002 $webvar{custid} = "6750400";
1003 }
1004
1005 # Check POP location
1006 my $flag;
1007 if ($webvar{alloctype} eq 'rr') {
1008 $flag = 'for a routed netblock';
1009 foreach (@poplist) {
1010 if (/^$webvar{city}$/) {
1011 $flag = 'n';
1012 last;
1013 }
1014 }
1015 } else {
1016 $flag = 'n';
1017 if ($webvar{pop} =~ /^-$/) {
1018 $flag = 'to route the block from/through';
1019 }
1020 }
1021 if ($flag ne 'n') {
1022 printError("Please choose a valid POP location $flag. Valid ".
1023 "POP locations are currently:<br>\n".join (" - ", @poplist));
1024 return;
1025 }
1026
1027 return 'OK';
1028} # end validateInput
1029
1030
1031# Displays details of a specific allocation in a form
1032# Allows update/delete
1033# action=edit
1034sub edit {
1035 printHeader('');
1036
1037 my $sql;
1038
1039 # Two cases: block is a netblock, or block is a static IP from a pool
1040 # because I'm lazy, we'll try to make the SELECT's bring out identical)ish) data
1041 if ($webvar{block} =~ /\/32$/) {
1042 $sql = "select ip,custid,ptype,city,circuitid,description,notes from poolips where ip='$webvar{block}'";
1043 } else {
1044 $sql = "select cidr,custid,type,city,circuitid,description,notes from allocations where cidr='$webvar{block}'"
1045 }
1046
1047 # gotta snag block info from db
1048 $sth = $ip_dbh->prepare($sql);
1049 $sth->execute;
1050 my @data = $sth->fetchrow_array;
1051
1052 # Clean up extra whitespace on alloc type
1053 $data[2] =~ s/\s//;
1054
1055##fixme LEGACY CODE
1056 # Postfix "i" on pool IP types
1057 if ($data[2] =~ /^[cdsmw]$/) {
1058 $data[2] .= "i";
1059 }
1060
1061 open (HTML, "../editDisplay.html")
1062 or croak "Could not open editDisplay.html :$!";
1063 my $html = join('', <HTML>);
1064
1065 # We can't let the city be changed here; this block is a part of
1066 # a larger routed allocation and therefore by definition can't be moved.
1067 # block and city are static.
1068##fixme
1069# Needs thinking. Have to allow changes to city to correct errors, no?
1070 $html =~ s/\$\$BLOCK\$\$/$webvar{block}/g;
1071 $html =~ s/\$\$CITY\$\$/$data[3]/g;
1072
1073# Screw it. Changing allocation types gets very ugly VERY quickly- especially
1074# with the much longer list of allocation types.
1075# We'll just show what type of block it is.
1076
1077# this has now been Requested, so here goes.
1078
1079 if ($data[2] =~ /^d[nyc]|cn|ee|in$/) {
1080 # Block that can be changed
1081 my $blockoptions = "<select name=alloctype><option".
1082 (($data[2] eq 'dn') ? ' selected' : '') ." value='dn'>Dialup netblock</option>\n<option".
1083 (($data[2] eq 'dy') ? ' selected' : '') ." value='dy'>Dynamic DSL netblock</option>\n<option".
1084 (($data[2] eq 'dc') ? ' selected' : '') ." value='dc'>Dynamic cable netblock</option>\n<option".
1085 (($data[2] eq 'cn') ? ' selected' : '') ." value='cn'>Customer netblock</option>\n<option".
1086 (($data[2] eq 'ee') ? ' selected' : '') ." value='ee'>End-use netblock</option>\n<option".
1087 (($data[2] eq 'in') ? ' selected' : '') ." value='in'>Internal netblock</option>\n".
1088 "</select>\n";
1089 $html =~ s/\$\$TYPESELECT\$\$/$blockoptions/g;
1090 } else {
1091 $html =~ s/\$\$TYPESELECT\$\$/$disp_alloctypes{$data[2]}<input type=hidden name=alloctype value="$data[2]">/g;
1092 }
1093
1094 # These can be modified, although CustID changes may get ignored.
1095 $html =~ s/\$\$CUSTID\$\$/$data[1]/g;
1096 $html =~ s/\$\$TYPE\$\$/$data[2]/g;
1097 $html =~ s/\$\$CIRCID\$\$/$data[4]/g;
1098 $html =~ s/\$\$DESC\$\$/$data[5]/g;
1099 $html =~ s/\$\$NOTES\$\$/$data[6]/g;
1100
1101 print $html;
1102
1103} # edit()
1104
1105
1106# Stuff new info about a block into the db
1107# action=update
1108sub update {
1109 printHeader('');
1110
1111 # Make sure incoming data is in correct format - custID among other things.
1112 validateInput;
1113
1114 # SQL transaction wrapper
1115 eval {
1116 # Relatively simple SQL transaction here.
1117 my $sql;
1118 if (my $pooltype = ($webvar{alloctype} =~ /^(.)i$/) ) {
1119 # Note the hack ( available='n' ) to work around "update" additions
1120 # to static IP space. Eww.
1121 $sql = "update poolips set custid='$webvar{custid}',notes='$webvar{notes}',".
1122 "circuitid='$webvar{circid}',description='$webvar{desc}',available='n' ".
1123 "where ip='$webvar{block}'";
1124 } else {
1125 $sql = "update allocations set custid='$webvar{custid}',".
1126 "description='$webvar{desc}',notes='$webvar{notes}',city='$webvar{city}',".
1127 "type='$webvar{alloctype}',circuitid='$webvar{circid}' where cidr='$webvar{block}'";
1128 }
1129 # Log the details of the change.
1130 syslog "debug", $sql;
1131 $sth = $ip_dbh->prepare($sql);
1132 $sth->execute;
1133 $ip_dbh->commit;
1134 };
1135 if ($@) {
1136 carp "Transaction aborted because $@";
1137 eval { $ip_dbh->rollback; };
1138 syslog "err", "$authuser could not update block/IP '$webvar{block}': '$@'";
1139 printError("Could not update block/IP $webvar{block}: $@");
1140 return;
1141 }
1142
1143 # If we get here, the operation succeeded.
1144 syslog "notice", "$authuser updated $webvar{block}";
1145 open (HTML, "../updated.html")
1146 or croak "Could not open updated.html :$!";
1147 my $html = join('', <HTML>);
1148
1149 $html =~ s/\$\$BLOCK\$\$/$webvar{block}/g;
1150 $webvar{city} = desanitize($webvar{city});
1151 $html =~ s/\$\$CITY\$\$/$webvar{city}/g;
1152 $html =~ s/\$\$ALLOCTYPE\$\$/$webvar{alloctype}/g;
1153 $html =~ s/\$\$TYPEFULL\$\$/$disp_alloctypes{$webvar{alloctype}}/g;
1154 $html =~ s/\$\$CUSTID\$\$/$webvar{custid}/g;
1155 $webvar{circid} = desanitize($webvar{circid});
1156 $html =~ s/\$\$CIRCID\$\$/$webvar{circid}/g;
1157 $webvar{desc} = desanitize($webvar{desc});
1158 $html =~ s/\$\$DESC\$\$/$webvar{desc}/g;
1159 $webvar{notes} = desanitize($webvar{notes});
1160 $html =~ s/\$\$NOTES\$\$/$webvar{notes}/g;
1161
1162 print $html;
1163
1164} # update()
1165
1166
1167# Delete an allocation.
1168sub remove {
1169 printHeader('');
1170 #show confirm screen.
1171 open HTML, "../confirmRemove.html"
1172 or croak "Could not open confirmRemove.html :$!";
1173 my $html = join('', <HTML>);
1174 close HTML;
1175
1176 # Serves'em right for getting here...
1177 if (!defined($webvar{block})) {
1178 printError("Error 332");
1179 return;
1180 }
1181
1182 my ($cidr, $custid, $type, $city, $circid, $desc, $notes, $alloctype);
1183
1184 if ($webvar{alloctype} eq 'rr') {
1185 $sth = $ip_dbh->prepare("select cidr,city from routed where cidr='$webvar{block}'");
1186 $sth->execute();
1187
1188# This feels... extreme.
1189 croak $sth->errstr() if($sth->errstr());
1190
1191 $sth->bind_columns(\$cidr,\$city);
1192 $sth->execute();
1193 $sth->fetch || croak $sth->errstr();
1194 $custid = "N/A";
1195 $alloctype = $webvar{alloctype};
1196 $circid = "N/A";
1197 $desc = "N/A";
1198 $notes = "N/A";
1199
1200 } elsif ($webvar{alloctype} eq 'mm') {
1201 $cidr = $webvar{block};
1202 $city = "N/A";
1203 $custid = "N/A";
1204 $alloctype = $webvar{alloctype};
1205 $circid = "N/A";
1206 $desc = "N/A";
1207 $notes = "N/A";
1208 } elsif ($webvar{alloctype} =~ /^.i$/) { # done with alloctype=rr
1209
1210 # Unassigning a static IP
1211 my $sth = $ip_dbh->prepare("select ip,custid,city,ptype,notes,circuitid from poolips".
1212 " where ip='$webvar{block}'");
1213 $sth->execute();
1214# croak $sth->errstr() if($sth->errstr());
1215
1216 $sth->bind_columns(\$cidr, \$custid, \$city, \$alloctype, \$notes, \$circid);
1217 $sth->fetch() || croak $sth->errstr;
1218
1219 $alloctype .="i";
1220
1221 } else { # done with alloctype=~ /^.i$/
1222
1223 my $sth = $ip_dbh->prepare("select cidr,custid,type,city,circuitid,description,notes from ".
1224 "allocations where cidr='$webvar{block}'");
1225 $sth->execute();
1226# croak $sth->errstr() if($sth->errstr());
1227
1228 $sth->bind_columns(\$cidr, \$custid, \$alloctype, \$city, \$circid, \$desc, \$notes);
1229 $sth->fetch() || carp $sth->errstr;
1230 } # end cases for different alloctypes
1231
1232 # Munge everything into HTML
1233 $html =~ s|Please confirm|Please confirm <b>removal</b> of|;
1234 $html =~ s|\$\$BLOCK\$\$|$cidr|g;
1235 $html =~ s|\$\$TYPEFULL\$\$|$disp_alloctypes{$alloctype}|g;
1236 $html =~ s|\$\$ALLOCTYPE\$\$|$alloctype|g;
1237 $html =~ s|\$\$CITY\$\$|$city|g;
1238 $html =~ s|\$\$CUSTID\$\$|$custid|g;
1239 $html =~ s|\$\$CIRCID\$\$|$circid|g;
1240 $html =~ s|\$\$DESC\$\$|$desc|g;
1241 $html =~ s|\$\$NOTES\$\$|$notes|g;
1242
1243 $html =~ s|\$\$ACTION\$\$|finaldelete|g;
1244
1245 # Set the warning text.
1246 if ($alloctype =~ /^.[pd]$/) {
1247 $html =~ s|<!--warn-->|<tr bgcolor="black"><td colspan="2"><div class="red">Warning: clicking confirm will remove this record entirely.<br>Any IPs allocated from this pool will also be removed!</div></td></tr>|;
1248 } else {
1249 $html =~ s|<!--warn-->|<tr bgcolor="black"><td colspan="2"><div class="red">Warning: clicking confirm will remove this record entirely.</div></td></tr>|;
1250 }
1251
1252 print $html;
1253} # end edit()
1254
1255
1256# Delete an allocation. Return it to the freeblocks table; munge
1257# data as necessary to keep as few records as possible in freeblocks
1258# to prevent weirdness when allocating blocks later.
1259# Remove IPs from pool listing if necessary
1260sub finalDelete {
1261 printHeader('');
1262
1263 my ($code,$msg) = deleteBlock($ip_dbh, $webvar{block}, $webvar{alloctype});
1264
1265 if ($code eq 'OK') {
1266 print "<div class=heading align=center>Success! $webvar{block} deallocated.</div>\n";
1267 syslog "notice", "$authuser deallocated '$webvar{alloctype}'-type netblock $webvar{block}";
1268 } else {
1269 if ($webvar{alloctype} =~ /^.i$/) {
1270 syslog "err", "$authuser could not deallocate static IP '$webvar{block}': '$msg'";
1271 printError("Could not deallocate static IP $webvar{block}: $msg");
1272 } else {
1273 syslog "err", "$authuser could not deallocate netblock '$webvar{block}': '$msg'";
1274 printError("Could not deallocate netblock $webvar{block}: $msg");
1275 }
1276 }
1277
1278} # finalDelete
1279
1280
1281# Just in case we manage to get here.
1282exit 0;
Note: See TracBrowser for help on using the repository browser.