source: trunk/cgi-bin/main-alpha2.cgi@ 6

Last change on this file since 6 was 6, checked in by Kris Deugau, 20 years ago

Add intermediate development files for posterity

  • Property svn:executable set to *
File size: 52.2 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# Current version 05/18/2004 kdeugau@vianet
5
6#use strict;
7use warnings;
8use CGI::Carp qw/fatalsToBrowser/;
9use DBI;
10use CommonWeb qw/:ALL/;
11use POSIX qw/ceil/;
12use NetAddr::IP;
13
14checkDBSanity();
15
16#prototypes
17sub viewBy($$); # feed it the category and query
18sub queryResults($$$); # args is the sql, the page# and the rowCount
19# Needs rewrite/rename
20sub countRows($); # returns first element of first row of passed SQL
21 # Only usage passes "select count(*) ..."
22# Not sure if this is needed any more.
23sub parseInput($);
24
25my $RESULTS_PER_PAGE = 50;
26my %webvar = parse_post();
27cleanInput(\%webvar);
28
29my %full_alloc_types = (
30 "ci","Cable pool IP",
31 "di","DSL pool IP",
32 "si","Server pool IP",
33 "cp","Cable pool",
34 "dp","DSL pool",
35 "sp","Server pool",
36 "dn","Dialup netblock",
37 "dy","Dynamic DSL netblock",
38 "dc","Dynamic cable netblock",
39 "cn","Customer netblock",
40 "e","End-use netblock",
41 "r","Routed netblock",
42 "i","Internal netblock",
43 "m","Master block"
44);
45
46
47# Start new code: 04/22/2004
48###
49
50# Initial display: Show master blocks with total allocated subnets, total free subnets
51# foreach block (allocations[type=cust])
52# check which master it's in
53# increment appropriate counter
54# foreach block (freeblocks)
55# check which master it's in
56# increment appropriate counter
57
58# Some things we will need to do every time.
59
60# Why not a global DB handle?
61# We already know the DB is happy, (checkDBSanity) otherwise we wouldn't be here.
62$ip_dbh = DBI->connect("dbi:mysql:ipdb", "root", "");
63
64# Slurp up the master block list - we need this several places
65$sth = $ip_dbh->prepare("select * from masterblocks;");
66$sth->execute;
67$i=0;
68for ($i=0; @data = $sth->fetchrow_array(); $i++) {
69 $masterblocks[$i] = new NetAddr::IP $data[0];
70 $allocated{"$masterblocks[$i]"} = 0;
71 $free{"$masterblocks[$i]"} = 0;
72 $bigfree{"$masterblocks[$i]"} = 128; # Larger number means smaller block.
73 # Set to 128 to prepare for IPv6
74 $routed{"$masterblocks[$i]"} = 0;
75}
76
77
78
79
80#main()
81
82if(!defined($webvar{action})) {
83 $webvar{action} = "<NULL>"; #shuts up the warnings.
84}
85
86if($webvar{action} eq 'index') {
87 showSummary();
88} elsif ($webvar{action} eq 'newmaster') {
89 printHeader('');
90
91 $cidr = new NetAddr::IP $webvar{cidr};
92
93 print "<div type=heading align=center>Adding $cidr as master block....\n";
94 $sth = $ip_dbh->prepare("insert into masterblocks values ('$webvar{cidr}')");
95 $sth->execute;
96 die $sth->errstr if ($sth->errstr());
97
98# Unrouted blocks aren't associated with a city (yet). We don't rely on this
99# elsewhere though; legacy data may have traps and pitfalls in it to break this.
100# Thus the "routed" flag.
101
102 $sth = $ip_dbh->prepare("insert into freeblocks values ('$webvar{cidr}',".
103 $cidr->masklen.",'<NULL>','n')");
104 $sth->execute;
105 die $sth->errstr if ($sth->errstr());
106
107 print "Success!</div>\n";
108
109 printFooter;
110} elsif($webvar{action} eq 'showmaster') {
111 showMaster();
112} elsif($webvar{action} eq 'showrouted') {
113 showRBlock();
114} elsif($webvar{action} eq 'listpool') {
115 listPool();
116} elsif($webvar{action} eq 'search') {
117 printHeader('');
118 if (!$webvar{input}) {
119 # No search term. Display everything.
120 viewBy('all', '');
121 } else {
122 # Search term entered. Display matches.
123 # We should really sanitize $webvar{input}, no?
124 viewBy($webvar{searchfor}, $webvar{input});
125 }
126 printFooter();
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 'edit') {
137 edit();
138}
139elsif($webvar{action} eq 'update') {
140 update();
141}
142elsif($webvar{action} eq 'delete') {
143 remove();
144}
145elsif($webvar{action} eq 'finaldelete') {
146 finalDelete();
147}
148
149
150
151elsif($webvar{action} eq 'free')
152{
153 showFree();
154}
155elsif($webvar{action} eq 'free2')
156{
157 showFreeDetail();
158}
159elsif($webvar{action} eq 'insert')
160{
161 insertAssign();
162}
163elsif($webvar{action} eq 'showedit')
164{
165 showEdit();
166}
167elsif($webvar{action} eq 'view')
168{
169 view();
170}
171# Eeeewwww.. The default case should be an error, really. Added "search" check.
172else #handle the search part.
173{
174 printHeader('');
175 if(!$webvar{input})
176 {
177 viewBy('all', '');
178 }
179 else
180 {
181 viewBy(parseInput($webvar{input}), $webvar{input});
182 }
183 printFooter();
184 exit(0);
185}
186
187
188#end main()
189
190# Just in case something waaaayyy down isn't in place properly...
191exit 0;
192
193sub viewBy($$) {
194 my ($category,$query) = @_;
195
196print "<pre>\n";
197
198print "start querysub: query '$query'\n";
199# this may happen with more than one subcategory. Unlikely, but possible.
200 my $offset = ($webvar{page}-1)*$RESULTS_PER_PAGE;
201
202# Possible cases:
203# 1) Partial IP/subnet. Treated as "first-three-octets-match" in old IPDB,
204# I should be able to handle it similarly here.
205# 2a) CIDR subnet. Treated more or less as such in old IPDB.
206# 2b) CIDR netmask. Not sure how it's treated.
207# 3) Customer ID. Not handled in old IPDB
208# 4) Customer "name". If doing customer search, and we have non-numerics,
209# search on customer name.
210# 5) Invalid data which might be interpretable as an IP or something, but
211# which probably shouldn't be for reasons of sanity.
212
213 if ($category =~ /all/) {
214 print "Showing all allocations\n";
215 my $count = countRows('select count(*) from allocations');
216 $sql = "select * from allocations order by cidr limit $offset,$RESULTS_PER_PAGE";
217 queryResults($sql, $webvar{page}, $count);
218 } elsif ($category =~ /cust/) {
219 # Query for a customer ID.
220 if ($query =~ /^\s*[0-9]+\s*$/) {
221 # All numeric. Search on customer ID.
222 $sql = "select * from allocations where custid like '%$query%'";
223 queryResults($sql, $webvar{page}, $count);
224 } else {
225 print "Searching for a customer based on (partial) name....\n";
226 $sth = $ip_dbh->prepare("select * from customers where name like '%$query%'");
227 $sth->execute;
228
229# sth->rows may not work properly- it's not guaranteed to be accurate until
230# ALL rows have actually been fetch...()'ed
231 if ($sth->rows eq 1) {
232 @data = $sth->fetchrow_array;
233 # Only 1 cust matched.
234print "Found 1 cust. Displaying...\n";
235 $sql = "select * from allocations where custid like '%$data[0]%'";
236 queryResults($sql, $webvar{page}, $count);
237 } elsif ($sth->rows == 0) {
238 # D'Oh! Nothing found!
239 printAndExit("No customers found. Try searching on a smaller string.");
240 } else {
241 # More than one found. List'em and let the searcher decide.
242 print "Found more than one. Click the customer ID you want to show allocations for:\n";
243 startTable('custid','name','city','phone','abuse contact','description');
244 $count = 0;
245 while (@data = $sth->fetchrow_array) {
246 # custid,name,street,street2,city,province,pocode,phone,abuse,def_rdns,description
247 @row = ("<a href=\"/ip/cgi-bin/main.cgi?action=search&input=$data[0]&searchfor=cust\">$data[0]</a>",
248 $data[1],$data[4],$data[7],$data[8],$data[10]);
249 printRow(\@row, 'color1' ) if($count%2==0);
250 printRow(\@row, 'color2' ) if($count%2!=0);
251 }
252 print "</table>\n";
253 } # end if sth->rows
254 } # query pattern if
255 } elsif ($category =~ /ipblock/) {
256 # Query is for a partial IP, a CIDR block in some form, or a flat IP.
257 $query =~ s/\s+//g;
258print "Looking for IP-based matches on '$query':<br>\n";
259 if ($query =~ /\//) {
260print "CIDR query. Results may vary.\n";
261 # 209.91.179/26 should show all /26 subnets in 209.91.179
262 ($net,$maskbits) = split /\//, $query;
263 if ($query =~ /^(\d{1,3}\.){3}\d{1,3}\/\d{2}$/) {
264 # /0->/9 are silly to worry about right now. :/
265 print "Exact subnet search...\n";
266 $sth = $ip_dbh->prepare("select * from allocations where cidr='$query'");
267 $sth->execute;
268 if ($sth->rows == 0) {
269 print "No matches\n";
270 } elsif ($sth->rows == 1) {
271 @data = $sth->fetchrow_array;
272 print "Found $data[0]\n";
273 } else {
274 print "Too many matches (".$sth->rows.", should be 1). Database is b0rked.\n";
275 }
276 } else {
277 # select * from allocations where cidr like '$net%' and cidr like '%$maskbits'
278 }
279 } elsif ($query =~ /^(\d{1,3}\.){3}\d{1,3}$/) {
280 ($net,$ip) = ($query =~ /(\d{1,3}\.\d{1,3}\.\d{1,3})\.(\d{1,3})/);
281 print "Trying to find based on net '$net' and ip '$ip'...";
282 $sfor = new NetAddr::IP $query;
283 $sth = $ip_dbh->prepare("select * from allocations where cidr like '$net%'");
284 $sth->execute;
285 while (@data = $sth->fetchrow_array()) {
286 $cidr = new NetAddr::IP $data[0];
287 if ($cidr->contains($sfor)) {
288 print "Found '$cidr'!\n";
289 }
290 }
291 } elsif ($query =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.?$/) {
292 print "3-octet block pattern.";
293 $sql = "select * from allocations where cidr like '$query%'";
294 queryResults($sql, $webvar{page}, $count);
295 } else {
296 # This shouldn't happen, but if it does, whoever gets it deserves what they get...
297 printAndExit("Invalid query.");
298 }
299 } else {
300 # This shouldn't happen, but if it does, whoever gets it deserves what they get...
301 printAndExit("Invalid searchfor.");
302 }
303} # viewBy
304
305# args are: a reference to an array with the row to be printedthe
306# class(stylesheet) to use for formatting. and the class - optional.
307# if ommitting the class - call the sub as &printRow(\@array)
308sub printRow {
309 my ($rowRef,$class) = @_;
310
311 $class = '' if (!$class);
312
313 print "<tr class=\"$class\">\n";
314 foreach my $element (@$rowRef) {
315 print "<td></td>" if (!defined($element));
316 $element =~ s|\n|</br>|g;
317 print "<td>$element</td>\n";
318 }
319 print "</tr>";
320} # printRow
321
322# Display certain types of search query. Note that this can't be
323# cleanly reused much of anywhere else as the data isn't neatly tabulated.
324sub queryResults($$$) {
325 my ($sql, $pageNo, $rowCount) = @_;
326 my $offset = 0;
327 $offset = $1 if($sql =~ m/.*limit\s+(.*),.*/);
328 my $sth = $ip_dbh->prepare($sql);
329 $sth->execute();
330# Need some error checking...
331print "About to start showing allocations: ".$ip_dbh->errstr;
332 startTable('Allocation','CustID','Type','City','Description/Name');
333 my $count = 0;
334 while(my @data = ($sth->fetchrow_array())) {
335 # cidr,custid,type,city,description,notes
336# We need to munge row[0] here. We may also need to extract additional data.
337 @row = (qq(<a href="/ip/cgi-bin/main.cgi?action=edit&block=$data[0]">$data[0]</a>),
338 $data[1], $full_alloc_types{$data[2]}, $data[3], $data[4]);
339 printRow(\@row, 'color1', 1) if ($count%2==0);
340 printRow(\@row, 'color2', 1) if ($count%2!=0);
341 $count++;
342 }
343
344# Have to think on this call, it's primarily to clean up unfetched rows from a select.
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}">$i&nbsp</a>\n);
360 }
361 }
362 print "</div>";
363 }
364} # queryResults
365
366# Prints table headings. Accepts any number of arguments;
367# each argument is a table heading.
368sub startTable {
369 print qq(<center><table width="98%" cellspacing="0" class="center"><tr>);
370
371 foreach(@_) {
372 print qq(<td class="heading">$_</td>);
373 }
374 print "</tr>\n";
375} # startTable
376
377# parseInput() unused?
378###
379# given the input as a param, it returns the type of input:
380# either ipclass, name etc...
381#
382sub parseInput($)
383{
384 my $input = $_[0];
385
386 return 'ipclass' if($input =~ m/^\s*\d{1,3}\.\d{1,3}\.\d{1,3}\.?$/);
387 return 'ipclass' if($input =~ m/^\s*\d{1,3}\.\d{1,3}\.\d{1,3}\.0$/);
388 return 'ip' if($input =~ m/^\s*\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/);
389 return 'ipc_nm' if($input =~ m/^\s*\d{1,3}\.\d{1,3}\.\d{1,3}\s*\/\d{2}$/);
390 return 'ipc_nm' if($input =~ m/^\s*\d{1,3}\.\d{1,3}\.\d{1,3}\.0\s*\/\d{2}$/ );
391 return 'nm' if($input =~ m/^\s*\/\d{2}$/);
392 return 'name' if($input =~ m/^[\s\w\-]+$/);
393
394 return 'unknown';
395}
396
397sub countRows($)
398{
399 my $ip_dbh = connectDB();
400 my $sth = $ip_dbh->prepare($_[0]);
401 $sth->execute();
402 my @a = $sth->fetchrow_array();
403 $sth->finish();
404 $ip_dbh->disconnect();
405 return $a[0];
406}
407
408# Initial display: Show master blocks with total allocated subnets, total free subnets
409sub showSummary
410{
411 print "Content-type: text/html\n\n";
412
413 startTable('Master netblock', 'Routed netblocks', 'Allocated netblocks',
414 'Free netblocks', 'Largest free block');
415
416# Snag the allocations.
417# I think it's too confusing to leave out internal allocations.
418 my $sth = $ip_dbh->prepare("select * from allocations");
419 $sth->execute();
420 while (@data = $sth->fetchrow_array()) {
421 # cidr,custid,type,city,description
422 # We only need the cidr
423 my $cidr = new NetAddr::IP $data[0];
424 foreach $master (@masterblocks) {
425 if ($master->contains($cidr)) {
426 $allocated{"$master"}++;
427 }
428 }
429 }
430
431# Snag routed blocks
432 my $sth = $ip_dbh->prepare("select * from routed");
433 $sth->execute();
434 while (@data = $sth->fetchrow_array()) {
435 # cidr,maskbits,city
436 # We only need the cidr
437 my $cidr = new NetAddr::IP $data[0];
438 foreach $master (@masterblocks) {
439 if ($master->contains($cidr)) {
440 $routed{"$master"}++;
441 }
442 }
443 }
444
445# Snag the free blocks.
446 my $sth = $ip_dbh->prepare("select * from freeblocks");
447 $sth->execute();
448 while (@data = $sth->fetchrow_array()) {
449 # cidr,maskbits,city
450 # We only need the cidr
451 my $cidr = new NetAddr::IP $data[0];
452 foreach $master (@masterblocks) {
453 if ($master->contains($cidr)) {
454 $free{"$master"}++;
455 if ($cidr->masklen < $bigfree{"$master"}) { $bigfree{"$master"} = $cidr->masklen; }
456 }
457 }
458 }
459
460# Print the data.
461 $count=0;
462 foreach $master (@masterblocks) {
463 @row = ("<a href=\"/ip/cgi-bin/main.cgi?action=showmaster&block=$master\">$master</a>",
464 $routed{"$master"}, $allocated{"$master"}, $free{"$master"},
465 ( ($bigfree{"$master"} eq 128) ? ("&lt;NONE&gt;") : ("/".$bigfree{"$master"}) )
466 );
467
468 printRow(\@row, 'color1' ) if($count%2==0);
469 printRow(\@row, 'color2' ) if($count%2!=0);
470 $count++;
471 }
472 print "</table>\n";
473 print qq(<a href="/ip/addmaster.shtml">Add new master block</a><br><br>\n);
474 print "Note: Free blocks noted here include both routed and unrouted blocks.\n";
475# For some *very* strange reason, we don't have to call printFooter here.
476# If we do, the footer comes in twice...
477# printFooter;
478} # showSummary
479
480# Display detail on master
481# Alrighty then! We're showing routed blocks within a single master this time.
482# We should be able to steal code from showSummary(), and if I'm really smart
483# I'll figger a way to munge the two together. (Once I've done that, everything
484# else should follow. YMMV.)
485sub showMaster {
486 printHeader('');
487
488 print qq(<center><div class="heading">Summarizing routed blocks for ).
489 qq($webvar{block}:</div></center><br>\n);
490
491 my $master = new NetAddr::IP $webvar{block};
492
493 my $sth = $ip_dbh->prepare("select * from routed");
494 $sth->execute();
495
496 $i=0;
497 while (@data = $sth->fetchrow_array()) {
498 my $cidr = new NetAddr::IP $data[0];
499 if ($master->contains($cidr)) {
500 $localmasters[$i++] = $cidr;
501 $free{"$cidr"} = 0;
502 $allocated{"$cidr"} = 0;
503 # Retain the routing destination
504 $routed{"$cidr"} = $data[2];
505 }
506 }
507
508# Check if there were actually any blocks routed from this master
509 if ($i > 0) {
510 startTable('Routed block','Routed to','Allocated blocks',
511 'Free blocks','Largest free block');
512
513 # Count the allocations
514 $sth = $ip_dbh->prepare("select * from allocations");
515 $sth->execute();
516 while (@data = $sth->fetchrow_array()) {
517 # cidr,custid,type,city,description
518 # We only need the cidr
519 my $cidr = new NetAddr::IP $data[0];
520 foreach $master (@localmasters) {
521 if ($master->contains($cidr)) {
522 $allocated{"$master"}++;
523 }
524 }
525 }
526
527 # Snag the free blocks.
528 $sth = $ip_dbh->prepare("select * from freeblocks");
529 $sth->execute();
530 while (@data = $sth->fetchrow_array()) {
531 # cidr,maskbits,city
532 # We only need the cidr
533 my $cidr = new NetAddr::IP $data[0];
534 my $mask = 128;
535 foreach $master (@localmasters) {
536 if ($master->contains($cidr)) {
537 $free{"$master"}++;
538 if ($cidr->masklen < $mask) {
539 $bigfree{"$master"} = $cidr;
540 $mask = $cidr->masklen;
541 }
542 }
543 # check for largest free block
544 }
545 }
546
547 # Print the data.
548 $count=0;
549 foreach $master (@localmasters) {
550 @row = ("<a href=\"/ip/cgi-bin/main.cgi?action=showrouted&block=$master\">$master</a>",
551 $routed{"$master"}, $allocated{"$master"},
552 $free{"$master"}, $bigfree{"$master"});
553 printRow(\@row, 'color1' ) if($count%2==0);
554 printRow(\@row, 'color2' ) if($count%2!=0);
555 $count++;
556 }
557 } else {
558 print qq(<center>No routed blocks found for $master</center><br>\n);
559 } # end check for existence of routed blocks in master
560
561 print qq(</table>\n<hr width="60%">\n).
562 qq(<center><div class="heading">Unrouted blocks in $master:</div></center><br>\n);
563
564 startTable('Netblock','Range');
565
566 # Snag the free blocks.
567 $count = 0;
568 $sth = $ip_dbh->prepare("select * from freeblocks where routed='n'");
569 $sth->execute();
570 while (@data = $sth->fetchrow_array()) {
571 # cidr,maskbits,city
572 # We only need the cidr
573 my $cidr = new NetAddr::IP $data[0];
574 if ($master->contains($cidr)) {
575 @row = ("$cidr", $cidr->range);
576 printRow(\@row, 'color1' ) if($count%2==0);
577 printRow(\@row, 'color2' ) if($count%2!=0);
578 $count++;
579 }
580 }
581
582 print "</table>\n";
583 printFooter;
584} # showMaster
585
586# Display details of a routed block
587# Alrighty then! We're showing allocations within a routed block this time.
588# We should be able to steal code from showSummary() and showMaster(), and if
589# I'm really smart I'll figger a way to munge all three together. (Once I've
590# done that, everything else should follow. YMMV.
591# This time, we check the database before spewing, because we may
592# not have anything useful to spew.
593sub showRBlock {
594 printHeader('');
595
596 my $master = new NetAddr::IP $webvar{block};
597
598 print qq(<center><div class="heading">Summarizing allocated blocks for ).
599 qq($master:</div></center><br>\n);
600
601 my $sth = $ip_dbh->prepare("select * from allocations");
602 $sth->execute();
603
604 startTable('CIDR allocation','Type','CustID','Description/Name');
605
606 $count=0;
607 while (@data = $sth->fetchrow_array()) {
608 # cidr,custid,type,city,description
609 my $cidr = new NetAddr::IP $data[0];
610 if (!$master->contains($cidr)) { next; }
611
612 @row = ("<a href=\"/ip/cgi-bin/main.cgi?action=edit&block=$data[0]\">$data[0]</a>",
613 $full_alloc_types{$data[2]}, $data[1], $data[4]);
614
615 # If the allocation is a pool, allow listing of the IPs in the pool.
616 if ($data[2] =~ /^[sdc]p$/) {
617 $row[0] .= ' &nbsp; <a href="/ip/cgi-bin/main.cgi?action=listpool'.
618 "&pool=$data[0]\">List IPs</a>";
619 }
620
621 printRow(\@row, 'color1') if ($count%2 == 0);
622 printRow(\@row, 'color2') if ($count%2 != 0);
623 $count++;
624 }
625
626 print "</table>\n";
627
628 # If the routed block has no allocations, by definition it only has
629 # one free block, and therefore may be deleted.
630 if ($count == 0) {
631 print qq(<hr width="60%"><center><div class="heading">No allocations in ).
632 qq($master.</div></center>\n).
633 qq(<form action="/ip/cgi-bin/main.cgi" method=POST>\n).
634 qq(<input type=hidden name=action value="delete">\n).
635 qq(<input type=hidden name=block value="$master">\n).
636 qq(<input type=hidden name=alloctype value="r">\n).
637 qq(<input type=submit value=" Remove this block ">\n).
638 qq(</form>\n);
639 }
640
641 print qq(<hr width="60%">\n<center><div class="heading">Free blocks within routed ).
642 qq(submaster $master</div></center>\n);
643
644 startTable('');
645
646 # Snag the free blocks. We don't really *need* to be pedantic about avoiding
647 # unrouted free blocks, but it's better to let the database do the work if we can.
648 $count = 0;
649 $sth = $ip_dbh->prepare("select * from freeblocks where routed='y'");
650 $sth->execute();
651 while (@data = $sth->fetchrow_array()) {
652 # cidr,maskbits,city
653 my $cidr = new NetAddr::IP $data[0];
654 if ($master->contains($cidr)) {
655 @row = ($data[0]);
656 printRow(\@row, 'color1') if ($count%2 == 0);
657 printRow(\@row, 'color2') if ($count%2 != 0);
658 $count++;
659 }
660 }
661
662 print "</table>\n";
663 printFooter;
664} # showRBlock
665
666# List the IPs used in a pool
667sub listPool {
668 printHeader('');
669
670 my $cidr = new NetAddr::IP $webvar{pool};
671
672 # Snag pool info for heading
673 $sth = $ip_dbh->prepare("select * from allocations where cidr='$cidr'");
674 $sth->execute;
675 my @data = $sth->fetchrow_array;
676 my $type = $data[2]; # We'll need this later.
677
678 print qq(<center><div class="heading">Listing pool IPs for $cidr<br>\n).
679 qq(($full_alloc_types{$type} in $data[3])</div></center><br>\n);
680 print qq(<div class="indent"><b>Reserved IPs:</b><br>\n);
681 print qq(<div class="indent"><table><tr class=color1><td>Network IP:</td><td>).
682 $cidr->addr."</td></tr>\n";
683 $cidr++;
684 print "<tr class=color2><td>Gateway:</td><td>".$cidr->addr."</td></tr>\n";
685 $cidr--; $cidr--;
686 print "<tr class=color1><td>Broadcast:</td><td>".$cidr->addr."</td></tr>\n".
687 "<tr><td>Netmask:</td><td>".$cidr->mask."</td></tr>\n".
688 "</table></div></div>\n";
689
690# probably have to add an "edit IP allocation" link here somewhere.
691
692 startTable('IP','Customer ID','Available?','');
693 $sth = $ip_dbh->prepare("select * from poolips where pool='$webvar{pool}'");
694 $sth->execute;
695 $count = 0;
696 while (@data = $sth->fetchrow_array) {
697 # pool,ip,custid,city,ptype,available
698 # Some nice hairy Perl to decide whether to allow unassigning each IP
699 @row = ($data[1],$data[2],$data[5],
700 ( ($data[5] eq 'n') ?
701 ("<a href=\"/ip/cgi-bin/main.cgi?action=delete&block=$data[1]&".
702 "alloctype=$data[4]i\">Unassign this IP</a>") :
703 ("&nbsp;") )
704 );
705 printRow(\@row, 'color1') if($count%2==0);
706 printRow(\@row, 'color2') if($count%2!=0);
707 $count++;
708 }
709 print "</table>\n";
710
711 printFooter;
712} # end listPool
713
714# Should this maybe just be a full static page?
715sub assignBlock
716{
717 printHeader('');
718
719 open HTML, "../assign.html"
720 or die "Could not open assign.html: $!";
721 my $html = join('',<HTML>);
722 close(HTML);
723
724 print $html;
725
726 printFooter();
727} # assignBlock
728
729# Take info on requested IP assignment and see what we can provide.
730sub confirmAssign
731{
732 printHeader('');
733
734 # Going to manually validate some items.
735 # custid and city are automagic.
736 validateInput();
737
738# This isn't always useful.
739# if (!$webvar{maskbits}) {
740# printAndExit("Please enter a CIDR block length.");
741# }
742
743# Several different cases here.
744# Static IP vs netblock
745# + Different flavours of static IP
746# + Different flavours of netblock
747
748 if ($webvar{alloctype} =~ /^[cds]i$/) {
749 ($base,$tmp) = split //, $webvar{alloctype}; # split into individual chars
750 # Check for pools in Subury or North Bay if DSL or server pool. Anywhere else is
751 # invalid and shouldn't be in the db in the first place.
752 # Note that we want to retain the requested city to relate to customer info.
753 if ($base =~ /^[ds]$/) {
754 $sql = "select * from poolips where available='y' and".
755 " ptype='$base' and city='Sudbury' or city='North Bay'";
756 } else {
757 $sql = "select * from poolips where available='y' and".
758 " ptype='$base' and city='$city'";
759 }
760
761 # Now that we know where we're looking, we can list the pools with free IPs.
762 $sth = $ip_dbh->prepare($sql);
763 $sth->execute;
764 while (@data = $sth->fetchrow_array) {
765 $ipcount{$data[0]}++;
766 }
767 foreach $key (keys %ipcount) {
768 $optionlist .= "<option value='$key'>$key [$ipcount{$key} free IP(s)]</option>\n";
769 }
770 $cidr = "Single static IP";
771 $alloc_from = "<select name=alloc_from>".$optionlist."</select>\n";
772
773 } else { # end show pool options
774
775 if ($webvar{alloctype} eq 'r') {
776 $sql = "select * from freeblocks where maskbits<=$webvar{maskbits} and routed='n'".
777 " order by maskbits desc";
778 $failmsg = "No suitable free block found.<br>\nWe do not have a free".
779 " routeable block of that size.<br>\nYou will have to either route".
780 " a set of smaller netblocks or a single smaller netblock.";
781 } else {
782 if ($webvar{alloctype} =~ /^[sd]p$/) {
783 if (($webvar{city} !~ /^(Sudbury|North Bay)$/) && ($webvar{alloctype} eq 'dp')) {
784 printAndExit("You must chose Sudbury or North Bay for DSL pools."); }
785 if ($webvar{alloctype} eq 'sp') { $city = "Sudbury"; } else { $city = $webvar{city}; }
786 $failmsg = "No suitable free block found.<br>\nYou will have to route another".
787 " superblock <br>\nfrom one of the master blocks in Sudbury or chose a smaller".
788 " block size for the pool.";
789 } else {
790 $city = $webvar{city};
791 $failmsg = "No suitable free block found.<br>\nYou will have to route another".
792 " superblock to $webvar{city}<br>\nfrom one of the master blocks in Sudbury or".
793 " chose a smaller blocksize.";
794 }
795 $sql = "select * from freeblocks where city='$city' and maskbits<=$webvar{maskbits}".
796 " and routed='y' order by maskbits desc";
797 }
798 $sth = $ip_dbh->prepare($sql);
799 $sth->execute;
800 @data = $sth->fetchrow_array();
801 if ($data[0] eq "") {
802 printAndExit($failmsg);
803 }
804
805 $cidr = new NetAddr::IP $data[0];
806 $alloc_from = qq($cidr<input type=hidden name=alloc_from value="$cidr">);
807
808 # If the block to be allocated is smaller than the one we found,
809 # figure out the "real" block to be allocated.
810 if ($cidr->masklen() ne $webvar{maskbits}) {
811 $maskbits = $cidr->masklen();
812 while ($maskbits++ < $webvar{maskbits}) {
813 @subblocks = $cidr->split($maskbits);
814 }
815 $cidr = $subblocks[0];
816 }
817 } # if ($webvar{alloctype} =~ /^[cds]i$/) {
818
819 open HTML, "../confirm.html"
820 or die "Could not open confirm.html: $!";
821 my $html = join '', <HTML>;
822 close HTML;
823
824### gotta fix this in final
825 # Stick in customer info as necessary - if it's blank, it just ends
826 # up as blank lines ignored in the rendering of the page
827 $html =~ s|\$\$CUSTBITS\$\$|$custbits|g;
828###
829
830 # Stick in the allocation data
831 $html =~ s|\$\$ALLOC_TYPE\$\$|$webvar{alloctype}|g;
832 $html =~ s|\$\$TYPEFULL\$\$|$full_alloc_types{$webvar{alloctype}}|g;
833 $html =~ s|\$\$ALLOC_FROM\$\$|$alloc_from|g;
834 $html =~ s|\$\$CIDR\$\$|$cidr|g;
835 $html =~ s|\$\$CITY\$\$|$webvar{city}|g;
836 $html =~ s|\$\$CUSTID\$\$|$webvar{custid}|g;
837 $webvar{desc} = desanitize($webvar{desc});
838 $webvar{notes} = desanitize($webvar{notes});
839 $html =~ s|\$\$DESC\$\$|$webvar{desc}|g;
840 $html =~ s|\$\$NOTES\$\$|$webvar{notes}|g;
841 $html =~ s|\$\$ACTION\$\$|insert|g;
842
843 print $html;
844
845 printFooter;
846
847 return 0;
848
849#####
850### OLD CODE BELOW (this sub only)
851#####
852
853# Hokay, pools break my original setup a little. 4? basic classes of allocation:
854# -> Routing allocation. Taken from unrouted free blocks. Semi-geographic.
855# types: r (routing)
856# -> Pool. Taken from routed free block. Semi-geographic.
857# types: p (pool)
858# -> Static IP from pool. Taken from a customer or server pool. Semi-geographic.
859# types: ci (customer static IP)
860# s (server static IP)
861# -> End-use netblock. Taken from routed free blocks. Geographic.
862# types: cn (customer netblock)
863# di (dialup)
864# dy (dynamic cable/DSL)
865# e (end-use) -> Misc stuff, sort of a catch-all.
866
867# Snag the list of free blocks that are big enough for the requested allocation.
868# Not yet sure what to do other than break if there's nothing. <g>
869# Not entirely sure how to detect that, either. :(
870
871 if ($webvar{alloctype} eq 'r') {
872 $sql = "select * from freeblocks where maskbits<=$webvar{maskbits}".
873 " and routed='n' order by maskbits desc";
874 $failmsg = "No suitable free block found.<br>\nWe do not have a free".
875 " routeable block of that size.<br>\nYou will have to either route".
876 " a set of smaller netblocks or a single smaller netblock.";
877 } elsif ($webvar{alloctype} eq 'p') {
878# Pools are allocated the same way netblocks are, except that the "city" is Sudbury.
879 # allocate a netblock from a routed superblock.
880 $sql = "select * from freeblocks where city='Sudbury'".
881 " and maskbits<=$webvar{maskbits} and routed='y' order by maskbits desc";
882 $failmsg = "No suitable free block found.<br>\nYou will have to route another".
883 " superblock <br>\nfrom one of the master blocks in Sudbury or chose a smaller".
884 " block size for the pool.";
885 } elsif ($webvar{alloctype} =~ /^(ci|s)$/) {
886 # Special case number 3; allocate an IP from a pool.
887 # Logic will be a bit different for this case.
888 $sql = "select * from allocations where type='p'";
889 $failmsg = "No pools available.<br>\nYou will have to allocate a subnet as an IP pool.";
890 print "Trying to allocate IP from a pool.\n";
891 } else {
892 # General case, allocate a netblock from a routed superblock.
893 $sql = "select * from freeblocks where city='$webvar{city}'".
894 " and maskbits<=$webvar{maskbits} and routed='y' order by maskbits desc";
895 $failmsg = "No suitable free block found.<br>\nYou will have to route another".
896 " superblock to $webvar{city}<br>\nfrom one of the master blocks in Sudbury or".
897 " chose a smaller blocksize.";
898 }
899
900# OK. We need to find out if anything comes back from execution of this select. However...
901# For some stupid reason, we're not supposed to trust $sth->rows until we've retrieved all
902# of the data. GRRRR.
903
904#$sth = $ip_dbh->prepare("select count(*) from '$sql'");
905# $sth->execute;
906#print "exec err code: '".$sth->err."'<br> exec err str: '".$sth->errstr."'";
907
908 $sth = $ip_dbh->prepare("$sql");
909
910 $sth->execute;
911
912#print "exec err code: '".$sth->err."'<br> exec err str: '".$sth->errstr."'";
913# @data = $sth->fetchrow_array();
914#$num = @data;
915#print "<br>1st data element: '$data[0]'<br>";
916#print "rows in select: ".$sth->rows." (maybe)<br>";
917#print "number of elements: '$num'<br>";
918#print "fetch err code: '".$sth->err."'<br> fetch err str: '".$sth->errstr."'";
919#while (@data = $sth->fetchrow_array) {
920# print "<br>data[0]: $data[0]\n";
921#}
922#printFooter;
923#exit 0;
924
925# Gotta rethink this; may have use for more than the first match.
926 @data = $sth->fetchrow_array();
927 if ($data[0] eq "") {
928 printAndExit($failmsg);
929 }
930
931 # cidr,maskbits,city
932 # We only need the cidr
933 my $cidr = new NetAddr::IP $data[0];
934
935print "Found one!<br>\n";
936# foreach $master (@masterblocks) {
937# if ($master->contains($cidr)) {
938# $free{"$master"}++;
939# }
940# }
941
942print "$cidr to be allocated as type $webvar{alloctype} (".
943 $full_alloc_types{$webvar{alloctype}}.")";
944
945
946
947exit 0;
948
949### REALLY old code below here.
950
951
952# Cases for actual allocation:
953# Routing: Allocate from unrouted free blocks
954# Static IP: Allocate from pool
955# Pool, end-use, dynIP cable/DSL, dialup: Allocate from routed free block
956
957# Special case: Static IP allocation
958 if ($webvar{alloctype} =~ /^(ci|s)$/) {
959 # while (
960 } else {
961
962 $alloc_from = $cidr;
963
964 if ($cidr->masklen() == $webvar{maskbits}) {
965 print "OK: Allocating $cidr to $webvar{custid}<br>\n";
966 } else {
967 print "err case: need to allocate subblock of free block $cidr<br>\n";
968
969 print "<pre>\n";
970
971 print "Need a /$webvar{maskbits} from $cidr:<br>\n";
972 $maskbits = $cidr->masklen();
973 while ($maskbits++ < $webvar{maskbits}) {
974 @subblocks = $cidr->split($maskbits);
975 print "$subblocks[0]\t$subblocks[1]\n";
976 } # while
977 $cidr = $subblocks[0];
978
979 print "</pre>\n";
980
981 }
982
983
984 # Check for new customer iff we're doing a customer allocation
985 my $custbits = "";
986 if ($webvar{alloctype} eq 'cn') {
987
988 # This check to validate off fargo (?) instead
989 # $sth = $ip_dbh->prepare("select * from customers where custid='$webvar{custid}'");
990 # $sth->execute;
991print "Insert check for customer validity here\n";
992
993# if ($sth->rows ne 1) {
994# open CUSTHTML, "../newcust.html"
995# or die "Could not open newcust.html: $!";
996# $custbits = join '', <CUSTHTML>;
997# close CUSTHTML;
998# $custbits =~ s|\$\$CUSTID\$\$|$webvar{custid}|g;
999# $custbits =~ s|\$\$CUSTCITY\$\$|$webvar{city}|g;
1000# }
1001
1002 } # Customer netblock if
1003
1004 open HTML, "../confirm.html"
1005 or die "Could not open confirm.html: $!";
1006 my $html = join '', <HTML>;
1007 close HTML;
1008
1009 # Stick in customer info as necessary - if it's blank, it just ends
1010 # up as blank lines ignored in the rendering of the page
1011 $html =~ s|\$\$CUSTBITS\$\$|$custbits|g;
1012
1013 # Stick in the allocation data
1014 $html =~ s|\$\$ALLOC_TYPE\$\$|$webvar{alloctype}|g;
1015 $html =~ s|\$\$ALLOC_FROM\$\$|$alloc_from|g;
1016 $html =~ s|\$\$CIDR\$\$|$cidr|g;
1017 $html =~ s|\$\$CITY\$\$|$webvar{city}|g;
1018 $html =~ s|\$\$CUSTID\$\$|$webvar{custid}|g;
1019 $webvar{desc} = desanitize($webvar{desc});
1020 $html =~ s|\$\$DESC\$\$|$webvar{desc}|g;
1021 $html =~ s|\$\$NOTES\$\$|$webvar{notes}|g;
1022 $html =~ s|\$\$ACTION\$\$|insert|g;
1023
1024 print $html;
1025 } # [else] special case alloctype =~ ci|s
1026
1027 printFooter();
1028}
1029
1030sub insertAssign
1031{
1032 # Some things are done more than once.
1033 printHeader('');
1034 validateInput();
1035
1036# here we do the donkeywork of actually adding a block.
1037# Check cidr and alloc_from to see how bad it's going to be.
1038
1039# MySQL doesn't enforce referential integrity, but Postgres can.
1040# So we insert the customer data (if any) before the allocation.
1041# Note that city may be DIFFERENT than the city used for allocation!
1042#if ($webvar{newcust} eq 'y') {
1043# $sth = $ip_dbh->prepare("insert into customers values ('$webvar{custid}', ".
1044# "'$webvar{custname}', '$webvar{custaddr1}', '$webvar{custaddr2}', ".
1045# "'$webvar{custcity}', '$webvar{custprov}', '$webvar{custpocode}', ".
1046# "'$webvar{custphone}', '$webvar{custabuse}', '$webvar{custrdns}', ".
1047# "'$webvar{custdesc}')");
1048# $sth->execute;
1049# print "customers: '".$sth->errstr."'\n";
1050#}
1051
1052# Set some things that may be needed
1053# Don't set $cidr here as it may not even be a valid IP address.
1054 $alloc_from = new NetAddr::IP $webvar{alloc_from};
1055
1056# dynDSL (dy), sIP DSL(dp), and server pools (sp) are nominally allocated to Sudbury
1057# no matter what else happens.
1058# if ($webvar{alloctype} =~ /^([sd]p|dy)$/) { $webvar{city} = "Sudbury"; }
1059# OOPS. forgot about North Bay DSL.
1060# if ($webvar{alloctype} eq "sp") { $webvar{city} = "Sudbury"; }
1061
1062# Same ordering as confirmation page
1063
1064 if ($webvar{alloctype} =~ /^[cds]i$/) {
1065 ($base,$tmp) = split //, $webvar{alloctype}; # split into individual chars
1066
1067 # We'll just have to put up with the oddities caused by SQL (un)sort order
1068 $sth = $ip_dbh->prepare("select * from poolips where pool='$webvar{alloc_from}'".
1069 " and available='y'");
1070 $sth->execute;
1071
1072print "db err?: ".$sth->errstr."<br>\n";
1073@data = $sth->fetchrow_array;
1074 $cidr = $data[1];
1075
1076print "$cidr selected as IP";
1077
1078 $sth = $ip_dbh->prepare("update poolips set custid='$webvar{custid}',available='n'".
1079 " where ip='$cidr'");
1080 $sth->execute;
1081 print qq(<div class="center"><div class="heading">The IP $cidr has been allocated to customer $webvar{custid}</div></div>);
1082
1083###
1084
1085 } else { # end IP-from-pool allocation
1086 # Set $cidr here as it may not be a valid IP address elsewhere.
1087 $cidr = new NetAddr::IP $webvar{fullcidr};
1088
1089 if ($webvar{fullcidr} eq $webvar{alloc_from}) {
1090 # Easiest case- insert in one table, delete in the other, and go home. More or less.
1091 # insert into allocations values (cidr,custid,type,city,desc) and
1092 # delete from freeblocks where cidr='cidr'
1093 # For data safety on non-transaction DBs, we delete first.
1094
1095 if ($webvar{alloctype} eq 'r') {
1096 $sth = $ip_dbh->prepare("update freeblocks set routed='y',city='$webvar{city}'".
1097 " where cidr='$webvar{fullcidr}'");
1098 $sth->execute;
1099 $sth = $ip_dbh->prepare("insert into routed values ('$webvar{fullcidr}',".
1100 $cidr->masklen.",'$webvar{city}')");
1101 $sth->execute;
1102 } else {
1103 # common stuff for end-use, dialup, dynDSL, pools, etc, etc.
1104
1105 # city has to be reset for DSL/server pools; nominally to Sudbury.
1106 if ($webvar{alloctype} =~ /^[sd]p$/) { $webvar{city} = 'Sudbury'; }
1107
1108 $sth = $ip_dbh->prepare("delete from freeblocks where cidr='$webvar{fullcidr}'");
1109 $sth->execute;
1110
1111 $sth = $ip_dbh->prepare("insert into allocations values ('$webvar{fullcidr}',".
1112 "'$webvar{custid}','$webvar{alloctype}','$webvar{city}','$webvar{desc}',".
1113 "'$webvar{notes}')");
1114 $sth->execute;
1115 } # routing vs non-routing netblock
1116
1117 } else { # webvar{fullcidr} != webvar{alloc_from}
1118 # Hard case. Allocation is smaller than free block.
1119
1120print "Into the hard case<br>\n";
1121
1122 $wantmaskbits = $cidr->masklen;
1123
1124 $maskbits = $alloc_from->masklen();
1125 my $i=0;
1126 while ($maskbits++ < $wantmaskbits) {
1127 @subblocks = $alloc_from->split($maskbits);
1128 $newfreeblocks[$i++] = $subblocks[1];
1129 } # while
1130
1131 # Delete old freeblocks entry
1132 $sth = $ip_dbh->prepare("delete from freeblocks where cidr='$webvar{alloc_from}'");
1133 $sth->execute();
1134
1135print "Delete from freeblocks: '".$ip_dbh->errstr."'<br>\n";
1136print "$subblocks[0] to be allocated<br>\n";
1137foreach $block (@newfreeblocks) {
1138 print "$block still free<br>\n";
1139}
1140
1141 # now we have to do some magic for routing blocks
1142 if ($webvar{alloctype} eq 'r') {
1143 # Insert the new freeblocks entries
1144 # Note that non-routed blocks are assigned to <NULL>
1145 $sth = $ip_dbh->prepare("insert into freeblocks values (?, ?, '<NULL>','n')");
1146 foreach $block (@newfreeblocks) {
1147 $sth->execute("$block", $block->masklen);
1148 }
1149 # Insert the entry in the routed table
1150 $sth = $ip_dbh->prepare("insert into routed values ('$cidr',".
1151 $cidr->masklen.",'$webvar{city}')");
1152 $sth->execute;
1153 # Insert the (almost) same entry in the freeblocks table
1154 $sth = $ip_dbh->prepare("insert into freeblocks values ('$cidr',".
1155 $cidr->masklen.",'$webvar{city}','y')");
1156 $sth->execute;
1157 } else { # done with alloctype == r
1158print "supposed to inserting type $webvar{alloctype}<br>\n";
1159 # Insert the new freeblocks entries
1160 $sth = $ip_dbh->prepare("insert into freeblocks values (?, ?, ?,'y')");
1161 foreach $block (@newfreeblocks) {
1162 $sth->execute("$block", $block->masklen, $webvar{city});
1163 }
1164 # Insert the allocations entry
1165 $sth = $ip_dbh->prepare("insert into allocations values ('$webvar{fullcidr}',".
1166 "'$webvar{custid}','$webvar{alloctype}','$webvar{city}',".
1167 "'$webvar{desc}','$webvar{notes}')");
1168 $sth->execute;
1169print "'".$sth->errstr."'";
1170 } # done with alloctype != r
1171
1172## section ends
1173 } # end fullcidr != alloc_from
1174
1175 # special extra handling for pools.
1176 # Note that this must be done for ANY pool allocation!
1177 if ( my ($pooltype) = ($webvar{alloctype} =~ /^([sdc])p$/) ) {
1178 # have to insert all pool IPs into poolips table as "unallocated".
1179 # sql: insert into poolips values (fullcidr,$ip,'6750400',alloctype,'n')
1180 $sth = $ip_dbh->prepare("insert into poolips values ('$webvar{fullcidr}',".
1181 " ?, '6750400', '$webvar{city}', '$pooltype', 'y', '')");
1182 $cidr = new NetAddr::IP $webvar{fullcidr};
1183 @poolip_list = $cidr->hostenum;
1184 for (my $i=1; $i<=$#poolip_list; $i++) {
1185 $sth->execute($poolip_list[$i]->addr);
1186 }
1187 } # end pool special
1188
1189 print qq(<div class="center"><div class="heading">The block $webvar{fullcidr} was sucessfully added as type '$webvar{alloctype}' ($full_alloc_types{$webvar{alloctype}})</div></div>);
1190
1191 } # end static-IP vs netblock allocation
1192
1193 printFooter();
1194
1195return 0;
1196
1197
1198
1199#####
1200### Old code for this sub below.
1201#####
1202
1203 if ($webvar{fullcidr} eq $webvar{alloc_from}) {
1204 # Easiest case- insert in one table, delete in the other, and go home.
1205 # insert into allocations values (cidr,custid,type,city,desc) and
1206 # delete from freeblocks where cidr='cidr'
1207 # For data safety on non-transaction DBs, we delete first.
1208
1209# new logic: is it a routing allocation?
1210 if ($webvar{alloctype} eq 'r') {
1211# easiest case in the set. Just update the table to indicate where
1212# the block is routed, and that it's available for further breakdown.
1213 $sth = $ip_dbh->prepare("update freeblocks set routed='y',city='$webvar{city}'".
1214 " where cidr='$webvar{fullcidr}'");
1215 $sth->execute;
1216 $sth = $ip_dbh->prepare("insert into routed values ('$webvar{fullcidr}',".
1217 $cidr->masklen.",'$webvar{city}')");
1218 $sth->execute;
1219 } else {
1220# Gotta clean the data for db transactions before actually doing this.
1221 $sth = $ip_dbh->prepare("delete from freeblocks where cidr='$webvar{fullcidr}'");
1222 $sth->execute;
1223 $sth = $ip_dbh->prepare("insert into allocations values ('$webvar{fullcidr}',".
1224 "'$webvar{custid}','$webvar{alloctype}','$webvar{city}','$webvar{desc}',".
1225 "'$webvar{notes}')");
1226 $sth->execute;
1227# Gotta check for errors too.
1228 }
1229 } else {
1230 # OK, this isn't so easy. How bad is it going to get?
1231 # i=0
1232 # while ( )
1233 # newfree[i++] = current->split(newalloc->maskbits)[1]
1234
1235 $wantmaskbits = $cidr->masklen;
1236
1237 $maskbits = $alloc_from->masklen();
1238$i=0;
1239 while ($maskbits++ < $wantmaskbits) {
1240 @subblocks = $alloc_from->split($maskbits);
1241 $newfreeblocks[$i++] = $subblocks[1];
1242 } # while
1243# We should now have a collection of the block(s) to be added to freeblocks in @newfreeblocks
1244# The next block of execution should be in a transaction on the db.
1245# However, transactions aside, this should fail in the safest way possible.
1246 # Delete old freeblocks entry
1247 $sth = $ip_dbh->prepare("delete from freeblocks where cidr='$webvar{alloc_from}'");
1248 $sth->execute();
1249print "Delete from freeblocks: '".$ip_dbh->errstr."'<br>\n";
1250# now we have to do some magic for routing blocks
1251 if ($webvar{alloctype} eq 'r') {
1252 # Insert the new freeblocks entries
1253 # Note that non-routed blocks are assigned to Sudbury by default
1254# --> that should be changed to a definite null entry of some kind.
1255 $sth = $ip_dbh->prepare("insert into freeblocks values (?, ?, 'Sudbury','n')");
1256 foreach $block (@newfreeblocks) {
1257 $sth->execute("$block", $block->masklen);
1258print "Adding free block $block: '".$ip_dbh->errstr."'<br>\n";
1259 }
1260 # Insert the entry in the routed table
1261 $sth = $ip_dbh->prepare("insert into routed values ('$cidr',".
1262 $cidr->masklen.",'$webvar{city}')");
1263 $sth->execute;
1264print "Adding routing entry: '".$ip_dbh->errstr."'<br>\n";
1265 # Insert the (almost) same entry in the freeblocks table
1266 $sth = $ip_dbh->prepare("insert into freeblocks values ('$cidr',".
1267 $cidr->masklen.",'$webvar{city}','y')");
1268 $sth->execute;
1269print "Adding freeblocks entry: '".$ip_dbh->errstr."'<br>\n";
1270 } else {
1271 # Insert the new freeblocks entries
1272 $sth = $ip_dbh->prepare("insert into freeblocks values (?, ?, ?,'y')");
1273 foreach $block (@newfreeblocks) {
1274 $sth->execute("$block", $block->masklen, $webvar{city});
1275 }
1276 # Insert the allocations entry
1277 $sth = $ip_dbh->prepare("insert into allocations values ('$webvar{fullcidr}',".
1278 "'$webvar{custid}','$webvar{alloctype}','$webvar{city}','$webvar{desc}')");
1279 $sth->execute;
1280 }
1281 }
1282
1283 print qq(<div class="center"><div class="heading">The information was sucessfully added</div></div>);
1284 printFooter();
1285
1286} # end insertAssign()
1287
1288# Does some basic checks on common input data to make sure nothing
1289# *really* weird gets in to the database through this script.
1290# Does NOT do complete input validation!!!
1291sub validateInput {
1292 if ($webvar{city} eq '-') {
1293 printAndExit("Please choose a city.");
1294 }
1295 if ($webvar{alloctype} =~ /^(ci|di|cn)$/) {
1296 if (!$webvar{custid}) {
1297 printAndExit("Please enter a customer ID.");
1298 }
1299 print "[ In validateInput(). Insert customer ID cross-check here. ]<br>\n";
1300 } elsif ($webvar{alloctype} =~ /^([sdc]p|si|e|dn|dy|dc|e|r|i)$/){
1301 # All non-customer allocations MUST be entered with "our" customer ID.
1302 # I have Defined this as 6750400 for consistency.
1303 $webvar{custid} = "6750400";
1304 } else {
1305 # Danger! Danger! alloctype should ALWAYS be set by a dropdown. Anyone
1306 # managing to call things in such a way as to cause this deserves a cryptic error.
1307 printAndExit("Invalid alloctype");
1308 }
1309 return 0;
1310}
1311
1312
1313# Displays details of a specific allocation in a form
1314# Allows update/delete
1315# action=edit
1316sub edit
1317{
1318 printHeader('');
1319
1320 # gotta snag block info from db
1321 $sth = $ip_dbh->prepare("select * from allocations where cidr='$webvar{block}'");
1322 $sth->execute;
1323 @data = $sth->fetchrow_array;
1324
1325 open (HTML, "../editDisplay.html") || die "Could not open editDisplay.html :$!";
1326 my $html = join('', <HTML>);
1327
1328 # We can't let the city be changed here; this block is a part of
1329 # a larger routed allocation and therefore by definition can't be moved.
1330 # block and city are static.
1331 $html =~ s/\$\$BLOCK\$\$/$webvar{block}/g;
1332 $html =~ s/\$\$CITY\$\$/$data[3]/g;
1333
1334# Screw it. Changing allocation types gets very ugly VERY quickly- especially
1335# with the much longer list of allocation types.
1336# We'll just show what type of block it is.
1337
1338 $html =~ s/\$\$TYPE\$\$/$data[2]/g;
1339 $html =~ s/\$\$FULLTYPE\$\$/$full_alloc_types{$data[2]}/g;
1340
1341 # These can be modified, although CustID changes may get ignored.
1342 $html =~ s/\$\$CUSTID\$\$/$data[1]/g;
1343 $html =~ s/\$\$DESC\$\$/$data[4]/g;
1344 $html =~ s/\$\$NOTES\$\$/$data[5]/g;
1345
1346 print $html;
1347
1348 printFooter();
1349} # edit()
1350
1351# Stuff new info about a block into the db
1352# action=update
1353sub update {
1354 printHeader('');
1355print "<pre>\n";
1356
1357print " block: $webvar{block}\n";
1358print " type: $webvar{alloctype} ($full_alloc_types{$webvar{alloctype}})\n";
1359print "custid: $webvar{custid}\n";
1360print " desc: $webvar{desc}\n";
1361print " notes: $webvar{notes}\n";
1362
1363# -> Always update desc and notes
1364# better yet, just update the customer id every time, based on allocation type...
1365
1366if ($webvar{alloctype} eq 'c') {
1367 print "Updating customer alloc:\n ";
1368 $sth = $ip_dbh->prepare("update allocations set type='$webvar{alloctype}',".
1369 "custid='$webvar{custid}',description='$webvar{desc}',notes='$webvar{notes}' ".
1370 "where cidr='$webvar{block}'");
1371} else {
1372 print "Updating non-customer alloc:\n ";
1373 $sth = $ip_dbh->prepare("update allocations set type='$webvar{alloctype}',".
1374 "custid='6750400',description='$webvar{desc}',notes='$webvar{notes}' ".
1375 "where cidr='$webvar{block}'");
1376}
1377$sth->execute;
1378
1379if($sth->errstr()) {
1380 print $sth->errstr()
1381} else {
1382 print "Update successful.\n";
1383}
1384
1385print "</pre>\n";
1386 printFooter;
1387} # update()
1388
1389# Delete an allocation.
1390sub remove
1391{
1392 printHeader('');
1393print "Trying to delete...<br>\n";
1394 #show confirm screen.
1395 open HTML, "../confirmRemove.html"
1396 or die "Could not open confirmRemove.html :$!";
1397 my $html = join('', <HTML>);
1398 close HTML;
1399
1400# Serves'em right for getting here...
1401 if (!defined($webvar{block})) {
1402 printAndExit("Error 332");
1403 }
1404
1405 my ($cidr, $custid, $type, $city, $desc, $notes);
1406
1407
1408if ($webvar{alloctype} eq 'r') {
1409 $sth = $ip_dbh->prepare("select cidr,city from routed where cidr='$webvar{block}'");
1410 $sth->execute();
1411
1412 die $sth->errstr() if($sth->errstr());
1413
1414 $sth->bind_columns(\$cidr,\$city);
1415 $sth->execute();
1416 $sth->fetch || die $sth->errstr();
1417 $custid = "N/A";
1418 $alloctype = $webvar{alloctype};
1419 $desc = "N/A";
1420 $notes = "N/A";
1421} elsif ($webvar{alloctype} =~ /^[sdc]i$/) {
1422 # Unassigning a static IP
1423 print "Unassigning static IP $webvar{block}...";
1424
1425 my $sth = $ip_dbh->prepare("select ip,custid,city,ptype,notes from poolips".
1426 " where ip='$webvar{block}'");
1427 $sth->execute();
1428# die $sth->errstr() if($sth->errstr());
1429
1430 $sth->bind_columns(\$cidr, \$custid, \$city, \$alloctype, \$notes);
1431 $sth->fetch() || die;
1432
1433 $alloctype .="i";
1434} else {
1435
1436 my $sth = $ip_dbh->prepare("select * from allocations where cidr='$webvar{block}'");
1437 $sth->execute();
1438# die $sth->errstr() if($sth->errstr());
1439
1440 $sth->bind_columns(\$cidr, \$custid, \$alloctype, \$city, \$desc, \$notes);
1441 $sth->fetch() || die;
1442}
1443
1444print "Type: '$full_alloc_types{$alloctype}' alloctype: '$alloctype'";
1445 $html =~ s|Please confirm|Please confirm <b>removal</b> of|;
1446 $html =~ s|\$\$BLOCK\$\$|$cidr|g;
1447 $html =~ s|\$\$TYPEFULL\$\$|$full_alloc_types{$alloctype}|g;
1448 $html =~ s|\$\$ALLOCTYPE\$\$|$alloctype|g;
1449 $html =~ s|\$\$CITY\$\$|$city|g;
1450 $html =~ s|\$\$CUSTID\$\$|$custid|g;
1451 $html =~ s|\$\$DESC\$\$|$desc|g;
1452 $html =~ s|\$\$NOTES\$\$|$notes|g;
1453
1454 $html =~ s|\$\$ACTION\$\$|finaldelete|g;
1455
1456if ($alloctype =~ /^[sdc]p$/) {
1457 $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>|;
1458} else {
1459 $html =~ s|<!--warn-->|<tr bgcolor="black"><td colspan="2"><div class="red">Warning: clicking confirm will remove this record entirely.</div></td></tr>|;
1460}
1461
1462 print $html;
1463 printFooter;
1464} # end edit()
1465
1466###
1467#
1468# given a netmask of the form /24 it will return the number of IPs
1469# e.g.: nm2number('/24') = 256
1470# Note: no checking.... if the caller does not provide a valid netmask,
1471# the passed value is returned untouched.
1472#
1473sub nm2number
1474{
1475 my $netmask = $_[0];
1476
1477 if( $netmask =~ m|.*/24.*|){
1478 $netmask = 256;}
1479 elsif( $netmask =~ m|.*/25.*|){
1480 $netmask = 128;}
1481 elsif( $netmask =~ m|.*/26.*|){
1482 $netmask = 64;}
1483 elsif( $netmask =~ m|.*/27.*|){
1484 $netmask = 32;}
1485 elsif( $netmask =~ m|.*/28.*|){
1486 $netmask = 16;}
1487 elsif( $netmask =~ m|.*/29.*|){
1488 $netmask = 8;}
1489 elsif( $netmask =~ m|.*/30.*|){
1490 $netmask = 4;}
1491 elsif( $netmask =~ m|.*/31.*|){
1492 $netmask = 2;}
1493 elsif( $netmask =~ m|.*/32.*|){
1494 $netmask = 1;}
1495
1496 return $netmask;
1497}
1498
1499# Delete an allocation. Return it to the freeblocks table; munge
1500# data as necessary to keep as few records as possible in freeblocks
1501# to prevent weirdness when allocating blocks later.
1502# Remove IPs from pool listing if necessary
1503sub finalDelete
1504{
1505 printHeader('');
1506
1507 if ($webvar{alloctype} =~ /^[sdc]i$/) {
1508 print "Preparing to deallocate $webvar{block}...";
1509
1510 $sth = $ip_dbh->prepare("select * from poolips where ip='$webvar{block}'");
1511 $sth->execute;
1512 @data = $sth->fetchrow_array;
1513 $sth = $ip_dbh->prepare("select city from allocations where cidr='$data[0]'");
1514 $sth->execute;
1515 @data = $sth->fetchrow_array;
1516 $sth = $ip_dbh->prepare("update poolips set custid='6750400', available='y',".
1517 " city='$data[0]' where ip='$webvar{block}'");
1518 $sth->execute;
1519 print "<div class=heading align=center>Success! $webvar{block} deallocated.</div>\n";
1520
1521 } else { # end alloctype = [sdc]i
1522
1523 $cidr = new NetAddr::IP $webvar{block};
1524 if ($webvar{alloctype} eq 'r') {
1525 $sth = $ip_dbh->prepare("delete from routed where cidr='$webvar{block}'");
1526 $sth->execute;
1527
1528 # Make sure block getting deleted is properly accounted for.
1529 $sth = $ip_dbh->prepare("update freeblocks set routed='n',city='<NULL>'".
1530 " where cidr='$webvar{block}'");
1531 $sth->execute;
1532
1533 $sth = $ip_dbh->prepare("select * from freeblocks where ".
1534 "maskbits<=".$cidr->masklen." and routed='n' order by maskbits desc");
1535 } else { # end alloctype routing case
1536 $sth = $ip_dbh->prepare("delete from allocations where cidr='$webvar{block}'");
1537 $sth->execute;
1538
1539 # Special case - delete pool IPs
1540 if ($webvar{alloctype} =~ /^[sdc]p$/) {
1541 # We have to delete the IPs from the pool listing.
1542 $sth = $ip_dbh->prepare("delete * from poolips where pool='$webvar{block}'");
1543 $sth->execute;
1544 }
1545
1546 # Set up query for compacting free blocks.
1547 $sth = $ip_dbh->prepare("select * from freeblocks where city='$webvar{city}'".
1548 " and maskbits<=".$cidr->masklen." and routed='y' order by maskbits desc");
1549 } # end alloctype general case
1550
1551 # Now we look for larger-or-equal-sized free blocks in the same master (routed)
1552 # (super)block. If there aren't any, we can't combine blocks anyway. If there
1553 # are, we check to see if we can combine blocks.
1554 # Execute the statement prepared in the if-else above.
1555
1556 $sth->execute;
1557
1558# NetAddr::IP->compact() attempts to produce the smallest inclusive block
1559# from the caller and the passed terms.
1560# EG: if you call $cidr->compact($ip1,$ip2,$ip3) when $cidr, $ip1, $ip2,
1561# and $ip3 are consecutive /27's starting on .0 (.0-.31, .32-.63,
1562# .64-.95, and .96-.128), you will get an array containing a single
1563# /25 as element 0 (.0-.127). Order is not important; you could have
1564# $cidr=.32/27, $ip1=.96/27, $ip2=.0/27, and $ip3=.64/27.
1565
1566 $i=0;
1567 while (@data = $sth->fetchrow_array) {
1568 my $testIP = new NetAddr::IP $data[0];
1569 @together = $testIP->compact($cidr);
1570 $num = @together;
1571 if ($num == 1) {
1572 $cidr = $together[0];
1573 $combinelist[$i++] = $testIP;
1574 }
1575 }
1576
1577 # Clear old freeblocks entries - if any. $i==0 if not.
1578 if ($i>0) {
1579 $sth = $ip_dbh->prepare("delete from freeblocks where cidr=?");
1580 foreach $block (@combinelist) {
1581 $sth->execute($block);
1582 }
1583 }
1584
1585 # insert "new" freeblocks entry
1586 if ($webvar{alloctype} eq 'r') {
1587 $sth = $ip_dbh->prepare("insert into freeblocks values ('$cidr',".$cidr->masklen.
1588 ",'<NULL>','n')");
1589 } else {
1590 $sth = $ip_dbh->prepare("insert into freeblocks values ('$cidr',".$cidr->masklen.
1591 ",'$webvar{city}','y')");
1592 }
1593 $sth->execute;
1594print $sth->errstr;
1595 print "<div class=heading align=center>Success! $webvar{block} deleted.</div>\n";
1596
1597 } # end alloctype != netblock
1598
1599 printFooter;
1600} # finalDelete
1601
1602# Just in case we manage to get here.
1603exit 0;
Note: See TracBrowser for help on using the repository browser.