- Timestamp:
- 10/20/22 17:46:32 (2 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/cgi-bin/search.cgi
r906 r930 9 9 # Last update by $Author$ 10 10 ### 11 # Copyright 2005-2010,2012,2015 ,2016 - Kris Deugau11 # Copyright 2005-2010,2012,2015-2017,2022 - Kris Deugau <kdeugau@deepnet.cx> 12 12 13 13 use strict; … … 101 101 # in each (sub)select 102 102 my $cols = "s.cidr, s.custid, s.type, s.city, s.description, s.id, s.parent_id, s.available, a.vrf"; 103 # Common base select. JOIN provides the VRF which may not be noted on individual allocations 104 my $sqlbase = "SELECT $cols FROM searchme s JOIN allocations a ON s.master_id=a.id"; 103 105 104 106 # Handle the DB error first … … 125 127 # IP addresses should only have numbers, digits, and maybe a slash+netmask 126 128 $searchfor = "ipblock"; 129 } elsif ($webvar{input} =~ /(?:^\d{6}\-|[A-Z][A-Z]\d\d\d)/) { 130 # Looks like part of a circuit ID 131 $searchfor = "circuitid"; 127 132 } else { 128 133 # Anything else. … … 167 172 168 173 # First chunk of SQL. Filter on custid, description, and notes as necessary. 169 my $sql = qq(SELECT $cols FROM searchme s JOIN allocations a ON s.master_id=a.id\n); 170 $sql .= " WHERE $webvar{custexclude} (s.custid ~ '$webvar{custid}')\n" if $webvar{custid}; 171 $sql .= " $sqlconcat (SELECT $cols FROM searchme s JOIN allocations a ON s.master_id=a.id WHERE $webvar{descexclude} s.description ~ '$webvar{desc}')\n" if $webvar{desc}; 172 $sql .= " $sqlconcat (SELECT $cols FROM searchme s JOIN allocations a ON s.master_id=a.id WHERE $webvar{notesexclude} s.notes ~ '$webvar{notes}')" if $webvar{notes}; 174 # Putting newlines in the SQL so that any SQL logging is somewhat more readable 175 # than a gigantic long line of conditions. 176 my $sql = "$sqlbase\n"; 177 my @bindargs; 178 if ($webvar{custid}) { 179 $sql .= " WHERE $webvar{custexclude} (s.custid ~ ?)\n"; 180 push @bindargs, $webvar{custid}; 181 } 182 if ($webvar{desc}) { 183 $sql .= " $sqlconcat ($sqlbase WHERE $webvar{descexclude} s.description ~* ?)\n"; 184 push @bindargs, $webvar{desc}; 185 } 186 if ($webvar{notes}) { 187 $sql .= " $sqlconcat ($sqlbase WHERE $webvar{notesexclude} s.notes ~ ?)"; 188 push @bindargs, $webvar{notes}; 189 } 173 190 174 191 # If we're not supposed to search for all types, search for the selected types. … … 176 193 $webvar{typeexclude} = '' if !$webvar{typeexclude}; 177 194 if ($webvar{alltypes} ne 'on') { 178 $sql .= " $sqlconcat ( SELECT $cols FROM searchme s JOIN allocations a ON s.master_id=a.idWHERE $webvar{typeexclude} s.type IN (";195 $sql .= " $sqlconcat ($sqlbase WHERE $webvar{typeexclude} s.type IN ("; 179 196 foreach my $key (keys %webvar) { 180 $sql .= "'$1'," if $key =~ /type\[( ..)\]/;197 $sql .= "'$1'," if $key =~ /type\[(\w\w)\]/; 181 198 } 182 199 chop $sql; … … 189 206 $webvar{cityexclude} = '' if !$webvar{cityexclude}; 190 207 if ($webvar{allcities} ne 'on') { 191 $sql .= " $sqlconcat ( SELECT $cols FROM searchme s JOIN allocations a ON s.master_id=a.idWHERE $webvar{cityexclude} s.city IN (";208 $sql .= " $sqlconcat ($sqlbase WHERE $webvar{cityexclude} s.city IN ("; 192 209 $sth = $ip_dbh->prepare("SELECT city FROM cities WHERE id=?"); 193 210 foreach my $key (keys %webvar) { … … 214 231 # /0->/9 are silly to worry about right now. I don't think 215 232 # we'll be getting a class A anytime soon. <g> 216 $sql .= " $sqlconcat ( SELECT $cols FROM searchme s JOIN allocations a ON s.master_id=a.id WHERE ".217 "$webvar{cidrexclude} s.cidr<<='$webvar{cidr}')";233 $sql .= " $sqlconcat ($sqlbase WHERE $webvar{cidrexclude} s.cidr <<= ?)"; 234 push @bindargs, $webvar{cidr}; 218 235 } else { 219 236 # Partial match; beginning of subnet and maskbits are provided 220 237 # Show any blocks with the leading octet(s) and that masklength 221 238 # Need some more magic for bare /nn searches: 222 my $condition = ($net eq '' ? 223 "masklen(s.cidr)=$maskbits" : "text(s.cidr) like '$net%' and masklen(s.cidr)=$maskbits"); 224 $sql .= " $sqlconcat (select $cols from searchme s JOIN allocations a ON s.master_id=a.id where $webvar{cidrexclude} ". 225 "($condition))"; 239 $sql .= " $sqlconcat ($sqlbase WHERE $webvar{cidrexclude} (masklen(s.cidr) = ?"; 240 push @bindargs, $maskbits; 241 if ($net ne '') { 242 $sql .= " AND text(s.cidr) LIKE ?"; 243 push @bindargs, $net; 244 } 245 $sql .= "))"; 226 246 } 227 247 } elsif ($webvar{cidr} =~ /^(\d{1,3}\.){3}\d{1,3}$/) { 228 248 # Specific IP address match. Will show either a single netblock, 229 249 # or a static pool plus an IP. 230 $sql .= " $sqlconcat ( select $cols from searchme s JOIN allocations a ON s.master_id=a.id where $webvar{cidrexclude} ".231 "s.cidr >>= '$webvar{cidr}')";250 $sql .= " $sqlconcat ($sqlbase WHERE $webvar{cidrexclude} s.cidr >>= ?)"; 251 push @bindargs, $webvar{cidr}; 232 252 } elsif ($webvar{cidr} =~ /^\d{1,3}(\.(\d{1,3}(\.(\d{1,3}\.?)?)?)?)?$/) { 233 253 # Leading octets in CIDR 234 $sql .= " $sqlconcat ( select $cols from searchme s JOIN allocations a ON s.master_id=a.id where $webvar{cidrexclude} ".235 "text(s.cidr) like '$webvar{cidr}%')";254 $sql .= " $sqlconcat ($sqlbase WHERE $webvar{cidrexclude} text(s.cidr) LIKE ?)"; 255 push @bindargs, "$webvar{cidr}%"; 236 256 } else { 237 257 # do nothing. … … 243 263 244 264 # Find out how many rows the "core" query will return. 245 my $count = countRows($sql); 246 247 # join against yourself! only master blocks are really guaranteed to have a VRF set - especially in legacy data 248 #$sql .= " JOIN allocations mv ON 265 my $count = countRows($sql, @bindargs); 249 266 250 267 if ($count == 0) { … … 253 270 } else { 254 271 # Add the limit/offset clauses 255 $sql .= " order bycidr";256 $sql .= " limit $RESULTS_PER_PAGE offset$offset" if $RESULTS_PER_PAGE != 0;272 $sql .= " ORDER BY s.cidr"; 273 $sql .= " LIMIT $RESULTS_PER_PAGE OFFSET $offset" if $RESULTS_PER_PAGE != 0; 257 274 # And tell the user. 258 275 print "<div class=heading>Searching...............</div>\n"; 259 queryResults($sql, $webvar{page}, $count );276 queryResults($sql, $webvar{page}, $count, @bindargs); 260 277 } 261 278 … … 263 280 # Node search. 264 281 265 my $sql = "SELECT $cols FROM searchme". 266 " WHERE cidr IN (SELECT block FROM noderef WHERE node_id=$webvar{node})"; 282 my $sql = "$sqlbase JOIN noderef nr ON nr.block=s.cidr WHERE nr.node_id = ?"; 267 283 268 284 # Find the offset for multipage results … … 270 286 271 287 # Find out how many rows the "core" query will return. 272 my $count = countRows($sql); 288 my $count = countRows($sql, $webvar{node}); 289 290 my $nodename = getNodeName($ip_dbh, $webvar{node}); 273 291 274 292 if ($count == 0) { 275 $page->param(errmsg => "No customers currently listed as connected through this node.");293 $page->param(errmsg => "No customers currently listed as connected through $nodename."); 276 294 ##fixme: still get the results table header 277 295 } else { 278 296 # Add the limit/offset clauses 279 $sql .= " order bycidr";280 $sql .= " limit $RESULTS_PER_PAGE offset$offset" if $RESULTS_PER_PAGE != 0;297 $sql .= " ORDER BY cidr"; 298 $sql .= " LIMIT $RESULTS_PER_PAGE OFFSET $offset" if $RESULTS_PER_PAGE != 0; 281 299 # And tell the user. 282 print "<div class=heading>Searching ...............</div>\n";283 queryResults($sql, $webvar{page}, $count );300 print "<div class=heading>Searching for assignments terminating on $nodename...</div>\n"; 301 queryResults($sql, $webvar{page}, $count, $webvar{node}); 284 302 } 285 303 … … 350 368 # Calculate start point for LIMIT clause 351 369 my $offset = ($webvar{page}-1)*$RESULTS_PER_PAGE; 352 353 # Possible cases: 354 # 1) Partial IP/subnet. Treated as "octet-prefix". 355 # 2a) CIDR subnet. Exact match. 356 # 2b) CIDR netmask. YMMV but it should be octet-prefix-with-netmask 357 # (ie, all matches with the octet prefix *AND* that netmask) 358 # 3) Customer ID. "Match-any-segment" 359 # 4) Description. "Match-any-segment" 360 # 5) Invalid data which might be interpretable as an IP or something, but 361 # which probably shouldn't be for reasons of sanity. 370 ##fixme: squeeze ORDER BY etc out into somewhere common, or at least an 371 # includeable bit instead of hardcoding in each block 362 372 363 373 if ($category eq 'all') { 364 374 365 $sql = "select $cols from searchme s JOIN allocations a ON s.master_id=a.id"; 375 # Sort of pointless, just horks up everything. 376 $sql = "$sqlbase"; 366 377 my $count = countRows($sql); 367 $sql .= " order by s.cidr limit $RESULTS_PER_PAGE offset$offset";378 $sql .= " ORDER BY s.cidr LIMIT $RESULTS_PER_PAGE OFFSET $offset"; 368 379 queryResults($sql, $webvar{page}, $count); 369 380 … … 375 386 # Query for a customer ID. Note that we can't restrict to "numeric-only" 376 387 # as we have non-numeric custIDs in the legacy data. :/ 377 $sql = " select $cols from searchme s JOIN allocations a ON s.master_id=a.id where s.custid ilike '%$query%' or s.description like '%$query%'";378 my $count = countRows($sql );379 $sql .= " order by s.cidr limit $RESULTS_PER_PAGE offset$offset";380 queryResults($sql, $webvar{page}, $count );388 $sql = "$sqlbase WHERE s.custid ~* ? OR s.description ~* ?"; 389 my $count = countRows($sql, $query, $query); 390 $sql .= " ORDER BY s.cidr LIMIT $RESULTS_PER_PAGE OFFSET $offset"; 391 queryResults($sql, $webvar{page}, $count, $query, $query); 381 392 382 393 } elsif ($category eq 'desc') { 383 394 384 print qq(<div class="heading">Searching for description s containing '$query'</div><br>\n);395 print qq(<div class="heading">Searching for description, customer ID, or circuit ID matching '$query'</div><br>\n); 385 396 # Query based on description (includes "name" from old DB). 386 $sql = "select $cols from searchme s JOIN allocations a ON s.master_id=a.id where s.description ilike '%$query%'". 387 " or s.custid ilike '%$query%'"; 388 my $count = countRows($sql); 389 $sql .= " order by s.cidr limit $RESULTS_PER_PAGE offset $offset"; 390 queryResults($sql, $webvar{page}, $count); 397 $sql = "$sqlbase WHERE s.description ~* ? OR s.custid ~* ? OR s.circuitid ~* ?"; 398 my $count = countRows($sql, $query, $query, $query); 399 $sql .= " ORDER BY s.cidr LIMIT $RESULTS_PER_PAGE OFFSET $offset"; 400 queryResults($sql, $webvar{page}, $count, $query, $query, $query); 401 402 } elsif ($category eq 'circuitid') { 403 404 print qq(<div class="heading">Searching for allocations with circuit ID matching '$query'</div><br>\n); 405 # Pretty similar to description and cust searches above, but focus on circuit ID 406 # JOIN needed for VRF field 407 $sql = "$sqlbase WHERE s.circuitid ~* ? OR s.description ~* ?"; 408 my $count = countRows($sql, $query, $query); 409 $sql .= " ORDER BY s.cidr LIMIT $RESULTS_PER_PAGE OFFSET $offset"; 410 queryResults($sql, $webvar{page}, $count, $query, $query); 391 411 392 412 } elsif ($category =~ /ipblock/) { … … 402 422 # /0->/9 are silly to worry about right now. I don't think 403 423 # we'll be getting a class A anytime soon. <g> 404 $sql = " select $cols from searchme s JOIN allocations a ON s.master_id=a.id where s.cidr='$query'";405 queryResults($sql, $webvar{page}, 1 );424 $sql = "$sqlbase WHERE s.cidr = ?"; 425 queryResults($sql, $webvar{page}, 1, $query); 406 426 } else { 407 427 #print "Finding all blocks with netmask /$maskbits, leading octet(s) $net<br>\n"; 408 428 # Partial match; beginning of subnet and maskbits are provided 409 $sql = "select $cols from searchme s JOIN allocations a ON s.master_id=a.id". 410 " where text(s.cidr) like '$net%' and text(s.cidr) like '%$maskbits'"; 411 my $count = countRows($sql); 412 $sql .= " order by s.cidr limit $RESULTS_PER_PAGE offset $offset"; 413 queryResults($sql, $webvar{page}, $count); 429 $sql = "$sqlbase WHERE text(s.cidr) LIKE ? AND text(s.cidr) LIKE ?"; 430 my $count = countRows($sql, "$net%", "%$maskbits"); 431 $sql .= " ORDER BY s.cidr LIMIT $RESULTS_PER_PAGE OFFSET $offset"; 432 queryResults($sql, $webvar{page}, $count, "$net%", "%$maskbits"); 414 433 } 434 415 435 } elsif ($query =~ /^(\d{1,3}\.){3}\d{1,3}$/) { 416 436 # Specific IP address match … … 418 438 my ($net,$ip) = ($query =~ /(\d{1,3}\.\d{1,3}\.\d{1,3}\.)(\d{1,3})/); 419 439 my $sfor = new NetAddr::IP $query; 420 # $sth = $ip_dbh->prepare("select $cols from searchme s JOIN allocations a ON s.master_id=a.id where text(s.cidr) like '$net%'"); 421 #print "select $cols from searchme s JOIN allocations a ON s.master_id=a.id where text(s.cidr) like '$net%'"; 422 423 # $sth->execute; 424 # while (my @data = $sth->fetchrow_array()) { 425 # my $cidr = new NetAddr::IP $data[0]; 426 # if ($cidr->contains($sfor) || $cidr == $sfor) { 427 #print "cidr: $data[0]\n"; 428 #print "<br>select $cols from searchme s JOIN allocations a ON s.master_id=a.id where s.cidr='$cidr' and s.type <> 'mm'"; 429 queryResults( 430 #"select $cols from searchme s JOIN allocations a ON s.master_id=a.id where s.cidr='$cidr' and s.type <> 'mm'", 431 "select $cols from searchme s JOIN allocations a ON s.master_id=a.id where s.cidr >>= '$sfor' and s.type <> 'mm' order by masklen(s.cidr) desc", 432 $webvar{page}, 1); 433 #print $page->output; 434 # } 435 # } 440 $sql = "$sqlbase WHERE s.cidr >>= ? AND s.type <> 'mm'"; 441 my $count = countRows($sql, $sfor); 442 $sql .= " ORDER BY masklen(s.cidr) DESC"; 443 queryResults($sql, $webvar{page}, $count, $sfor); 444 436 445 } elsif ($query =~ /^(\d{1,3}\.){1,3}\d{1,3}\.?$/) { 437 446 #print "Finding matches with leading octet(s) $query<br>\n"; 438 $sql = "SELECT $cols FROM searchme s JOIN allocations a ON s.master_id=a.id". 439 " WHERE text(s.cidr) LIKE '$query%'"; 440 my $count = countRows($sql); 441 $sql .= " order by s.cidr limit $RESULTS_PER_PAGE offset $offset"; 442 queryResults($sql, $webvar{page}, $count); 447 $sql = "$sqlbase WHERE text(s.cidr) LIKE ?"; 448 my $count = countRows($sql, "$query%"); 449 $sql .= " ORDER BY s.cidr LIMIT $RESULTS_PER_PAGE OFFSET $offset"; 450 queryResults($sql, $webvar{page}, $count, "$query%"); 443 451 } else { 444 452 # This shouldn't happen, but if it does, whoever gets it deserves what they get... … … 457 465 # Takes SQL, page number (for multipage search results), and a total count. 458 466 sub queryResults { 459 my ($sql, $pageNo, $rowCount) = @_; 467 my $sql = shift; 468 my $pageNo = shift; 469 my $rowCount = shift; 470 my @bindargs = @_; 471 460 472 my $offset = 0; 461 $offset = $1 if($sql =~ m/.* limit\s+(.*),.*/);473 $offset = $1 if($sql =~ m/.*LIMIT\s+(.*),.*/); 462 474 463 475 my $sth = $ip_dbh->prepare($sql); 464 $sth->execute( );476 $sth->execute(@bindargs); 465 477 466 478 $page->param(searchtitle => "Showing all netblock and static-IP allocations"); … … 535 547 # with the passed SQL statement 536 548 sub countRows { 549 my $sql = shift; 550 537 551 # Note that the "as foo" is required 538 my $sth = $ip_dbh->prepare("select count(*) from ($_[0]) as foo"); 539 $sth->execute(); 540 my @a = $sth->fetchrow_array(); 541 $sth->finish(); 552 my @a = $ip_dbh->selectrow_array("SELECT count(*) FROM ($sql) AS foo", undef, @_); 542 553 return $a[0]; 543 554 }
Note:
See TracChangeset
for help on using the changeset viewer.