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