Changeset 756 for branches/stable/DNSDB.pm
- Timestamp:
- 06/13/17 13:58:57 (7 years ago)
- Location:
- branches/stable
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/stable
- Property svn:mergeinfo changed
/trunk merged: 722-724,727-749
- Property svn:mergeinfo changed
-
branches/stable/DNSDB.pm
r725 r756 3 3 ## 4 4 # $Id$ 5 # Copyright 2008-201 3Kris Deugau <kdeugau@deepnet.cx>5 # Copyright 2008-2016 Kris Deugau <kdeugau@deepnet.cx> 6 6 # 7 7 # This program is free software: you can redistribute it and/or modify … … 36 36 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); 37 37 38 $VERSION = "1. 2.5p2"; ##VERSION##38 $VERSION = "1.4.0"; ##VERSION## 39 39 @ISA = qw(Exporter); 40 40 @EXPORT_OK = qw( … … 146 146 domain => 'domain_id', 147 147 revzone => 'rdns_id', 148 record => 'record_id' 148 record => 'record_id', 149 149 ); 150 150 my %par_col = ( … … 456 456 # group_id, log entry 457 457 # and optionally one or more of: 458 # domain_id, rdns_id 458 # domain_id, rdns_id, logparent 459 459 # The %userdata hash provides the user ID, username, and fullname 460 # Returns the log entry ID, mainly for use in bulk operations to allow a "parent" log entry 461 # and a set of child entries (eg, domain add and the individual default-record-copy entries) 460 462 sub _log { 461 463 my $self = shift; … … 466 468 $args{rdns_id} = 0 if !$args{rdns_id}; 467 469 $args{domain_id} = 0 if !$args{domain_id}; 470 $args{logparent} = 0 if !$args{logparent}; 468 471 469 472 ##fixme: farm out the actual logging to different subs for file, syslog, internal, etc based on config 470 473 # if ($self->{log_channel} eq 'sql') { 471 $dbh->do("INSERT INTO log (domain_id,rdns_id,group_id,entry,user_id,email,name) VALUES (?,?,?,?,?,?,?)", 474 $dbh->do("INSERT INTO log (domain_id,rdns_id,group_id,logparent,entry,user_id,email,name) ". 475 "VALUES (?,?,?,?,?,?,?,?)", 472 476 undef, 473 ($args{domain_id}, $args{rdns_id}, $args{group_id}, $args{ entry},477 ($args{domain_id}, $args{rdns_id}, $args{group_id}, $args{logparent}, $args{entry}, 474 478 $self->{loguserid}, $self->{logusername}, $self->{logfullname}) ); 479 480 my ($log_id) = $dbh->selectrow_array("SELECT currval('log_log_id_seq')"); 481 return $log_id; 482 475 483 # } elsif ($self->{log_channel} eq 'file') { 476 484 # } elsif ($self->{log_channel} eq 'syslog') { … … 1655 1663 my ($c) = ($$tmpl =~ /(\%-?c)/); my $nld = ''; my $cld = ''; 1656 1664 $c = '' if !$c; 1665 my ($cn) = ($$tmpl =~ /(\%x)/); 1657 1666 my $skipgw = ($c =~ /\%-c/ ? 0 : 1); 1658 1667 my $ipkill = 0; 1668 1669 if ($cn) { 1670 # "natural n'th IP in the block" pattern 1671 $$tmpl =~ s/$cn/$ipindex+1/e; 1672 } 1659 1673 1660 1674 ##fixme: still have one edge case not handled well: … … 2368 2382 undef, ($domain, $defloc)); 2369 2383 2370 $self->_log(domain_id => $dom_id, group_id => $group,2384 my $logparent = $self->_log(domain_id => $dom_id, group_id => $group, 2371 2385 entry => "Added ".($state ? 'active' : 'inactive')." domain $domain"); 2372 2386 … … 2384 2398 my @tmp1 = split /:/, $host; 2385 2399 my @tmp2 = split /:/, $val; 2386 $self->_log(domain_id => $dom_id, group_id => $group, 2400 $self->_log(domain_id => $dom_id, group_id => $group, logparent => $logparent, 2387 2401 entry => "[new $domain] Added SOA record [contact $tmp1[0]] [master $tmp1[1]] ". 2388 2402 "[refresh $tmp2[0]] [retry $tmp2[1]] [expire $tmp2[2]] [minttl $tmp2[3]], TTL $ttl"); … … 2391 2405 $logentry .= " [distance $dist]" if $typemap{$type} eq 'MX'; 2392 2406 $logentry .= " [priority $dist] [weight $weight] [port $port]" if $typemap{$type} eq 'SRV'; 2393 $self->_log(domain_id => $dom_id, group_id => $group, 2407 $self->_log(domain_id => $dom_id, group_id => $group, logparent => $logparent, 2394 2408 entry => $logentry." $val', TTL $ttl"); 2395 2409 } … … 3439 3453 "WHERE group_id IN ($args{curgroup}".($args{childlist} ? ",$args{childlist}" : '').")". 3440 3454 ($args{startwith} ? " AND username ~* ?" : ''). 3441 ($args{filter} ? " AND username ~* ?" : ''); 3455 ($args{filter} ? " AND username ~* ?" : ''). 3456 " AND NOT type = 'R' "; 3442 3457 my ($count) = $dbh->selectrow_array($sql, undef, (@filterargs) ); 3443 3458 $errstr = $dbh->errstr if !$count; … … 3645 3660 $errstr = $DBI::errstr if !$uname; 3646 3661 3662 no warnings qw (uninitialized); 3647 3663 $fullformat =~ s/\%u/$uname/g; 3648 3664 $fullformat =~ s/\%f/$fname/g; … … 4810 4826 # Get a count of log entries 4811 4827 # Takes a database handle and a hash containing at least: 4812 # - Entity IDand entity type as the primary log "slice"4828 # - Entity identifier and entity type as the primary log "slice" 4813 4829 sub getLogCount { 4814 4830 my $self = shift; 4815 my $dbh = $self->{dbh}; 4816 4817 my %args = @_; 4818 4819 my @filterargs; 4820 ##fixme: which fields do we want to filter on? 4821 # push @filterargs, 4822 4823 $errstr = 'Missing primary parent ID and/or type'; 4824 # fail early if we don't have a "prime" ID to look for log entries for 4825 return if !$args{id}; 4826 4827 # or if the prime id type is missing or invalid 4828 return if !$args{logtype}; 4829 $args{logtype} = 'revzone' if $args{logtype} eq 'rdns'; # hack pthui 4830 $args{logtype} = 'domain' if $args{logtype} eq 'dom'; # hack pthui 4831 return if !grep /^$args{logtype}$/, ('group', 'domain', 'revzone', 'user'); 4832 4833 my $sql = "SELECT count(*) FROM log ". 4834 "WHERE $id_col{$args{logtype}}=?". 4835 ($args{filter} ? " AND entry ~* ?" : ''); 4836 my ($count) = $dbh->selectrow_array($sql, undef, ($args{id}, @filterargs) ); 4837 $errstr = $dbh->errstr if !$count; 4838 return $count; 4831 return $self->getLogEntries(@_, count => 1); 4839 4832 } # end getLogCount() 4840 4833 … … 4843 4836 # Get a list of log entries 4844 4837 # Takes arguments as with getLogCount() above, plus optional: 4838 # - "count" flag 4839 # OR 4845 4840 # - sort field 4846 4841 # - sort order … … 4854 4849 my @filterargs; 4855 4850 4856 # fail early if we don't have a "prime" ID to look for log entries for 4857 return if !$args{id}; 4858 4859 # or if the prime id type is missing or invalid 4851 # fail if the prime id type is missing or invalid 4852 $errstr = "Missing primary log slice type"; 4860 4853 return if !$args{logtype}; 4861 4854 $args{logtype} = 'revzone' if $args{logtype} eq 'rdns'; # hack pthui 4862 4855 $args{logtype} = 'domain' if $args{logtype} eq 'dom'; # hack pthui 4856 $errstr = "Invalid primary log slice type"; 4863 4857 return if !grep /^$args{logtype}$/, ('group', 'domain', 'revzone', 'user'); 4858 4859 # fail if we don't have a prime ID to look for log entries for 4860 $errstr = "Missing ID for primary log slice"; 4861 return if !($args{id} || $args{fname}); 4864 4862 4865 4863 # Sorting defaults … … 4868 4866 $args{offset} = 0 if !$args{offset} || $args{offset} !~ /^(?:all|\d+)$/; 4869 4867 4870 my %sortmap = (fname => 'name', username => 'email', entry => 'entry', stamp => 'stamp'); 4868 my %sortmap = (fname => 'name', username => 'email', entry => 'entry', stamp => 'stamp', 4869 revzone => 'revnet', domain => 'domain'); 4871 4870 $args{sortby} = $sortmap{$args{sortby}}; 4872 4871 4873 my $sql = "SELECT user_id AS userid, email AS useremail, name AS userfname, entry AS logentry, ". 4874 "date_trunc('second',stamp) AS logtime ". 4875 "FROM log ". 4876 "WHERE $id_col{$args{logtype}}=?". 4877 ($args{filter} ? " AND entry ~* ?" : ''). 4878 " ORDER BY $args{sortby} $args{sortorder}, log_id $args{sortorder}". 4872 push @filterargs, $args{filter} if $args{filter}; 4873 my $sql; 4874 if ($args{count}) { 4875 $sql = "SELECT count(*) FROM log l "; 4876 } else { 4877 $sql = "SELECT l.log_id AS logparent, l.user_id AS userid, l.name AS userfname, d.domain, l.domain_id, ". 4878 "r.revnet AS revzone, ". 4879 "l.rdns_id, l.entry AS logentry, date_trunc('second',l.stamp) AS logtime ". 4880 "FROM log l ". 4881 "LEFT JOIN domains d ON l.domain_id = d.domain_id ". 4882 "LEFT JOIN revzones r ON l.rdns_id = r.rdns_id "; 4883 } 4884 4885 # decide which ID argument to use. Only use the "full name" if no normal ID is present 4886 my $idarg; 4887 if ($args{id}) { 4888 $sql .= "WHERE l.$id_col{$args{logtype}} = ? "; 4889 $idarg = $args{id}; 4890 } else { 4891 $sql .= "WHERE l.name = ? "; 4892 $idarg = $args{fname}; 4893 } 4894 4895 # trim log "subentries" - we'll figure out where to stash these later 4896 $sql .= " AND logparent = 0"; 4897 4898 # add the entry filter, if any 4899 $sql .= ($args{filter} ? " AND entry ~* ?" : ''); 4900 4901 # Limit scope based on group. Mainly useful for ltype==user, so subgroup 4902 # users can see what the deities in parent groups have done to their domains. 4903 if ($args{group} != 1) { 4904 my @grouplist; 4905 $self->getChildren($args{group}, \@grouplist); 4906 my $groupset = join(',', $args{group}, @grouplist); 4907 $sql .= " AND l.group_id IN ($groupset)"; 4908 } 4909 4910 if ($args{count}) { 4911 my ($count) = $dbh->selectrow_array($sql, undef, ($idarg, @filterargs) ); 4912 $errstr = $dbh->errstr if !$count; 4913 return $count; 4914 } else { 4915 $sql .= " ORDER BY $args{sortby} $args{sortorder}, log_id $args{sortorder}". 4879 4916 ($args{offset} eq 'all' ? '' : " LIMIT $self->{perpage} OFFSET ".$args{offset}*$self->{perpage}); 4880 my $loglist = $dbh->selectall_arrayref($sql, { Slice => {} }, ($args{id}, @filterargs) ); 4881 $errstr = $dbh->errstr if !$loglist; 4882 return $loglist; 4917 my @loglist; 4918 my $sth = $dbh->prepare($sql); 4919 my $logchild = $dbh->prepare("SELECT entry FROM log WHERE logparent = ? ORDER BY log_id"); 4920 $sth->execute($idarg, @filterargs); 4921 while (my $row = $sth->fetchrow_hashref) { 4922 $logchild->execute($row->{logparent}); 4923 my $childlist = $logchild->fetchall_arrayref({}); 4924 $row->{childentries} = $childlist; 4925 push @loglist, $row; 4926 } 4927 return \@loglist; 4928 } 4929 4930 # Your llama is on fire 4931 4883 4932 } # end getLogEntries() 4933 4934 4935 # a collection of joins for the record search 4936 our $recsearchsqlbase = q( 4937 FROM records r 4938 LEFT JOIN domains d ON r.domain_id = d.domain_id 4939 LEFT JOIN groups g1 ON d.group_id = g1.group_id 4940 LEFT JOIN revzones z ON r.rdns_id = z.rdns_id 4941 LEFT JOIN groups g2 on z.group_id = g2.group_id 4942 JOIN rectypes t ON r.type = t.val 4943 LEFT JOIN locations l ON r.location = l.location 4944 WHERE r.type <> 6 AND (r.host ~* ? OR r.val ~* ?) 4945 ); 4946 4947 4948 ## DNSDB::recSearchCount() 4949 # Get a total count for a global record search 4950 # Takes a hash with the search string and the login group of the user 4951 sub recSearchCount { 4952 my $self = shift; 4953 my $dbh = $self->{dbh}; 4954 my %args = @_; 4955 4956 my $sql = "SELECT count(*)".$recsearchsqlbase; 4957 4958 # Limit scope based on group 4959 if ($args{group} != 1) { 4960 my @grouplist; 4961 $self->getChildren($args{group}, \@grouplist); 4962 my $groupset = join(',', $args{group}, @grouplist); 4963 # oh my aching HEAD. there has to be a better way to do conditions on joined tables... 4964 $sql .= "AND ( 4965 (g1.group_id IN ($groupset) AND g2.group_id IN ($groupset)) OR 4966 (g1.group_id IN ($groupset) AND g2.group_id IS NULL) OR 4967 (g1.group_id IS NULL AND g2.group_id IN ($groupset)) 4968 ) 4969 "; 4970 } 4971 4972 my $count = $dbh->selectrow_array($sql, undef, $args{searchfor}, $args{searchfor}); 4973 $errstr = $dbh->errstr if !$count; 4974 return $count; 4975 4976 } # end recSearchCount() 4977 4978 4979 ## DNSDB::recSearch() 4980 # Find records matching the search string 4981 # Takes a hash with the search string, login group of the user, pagination offset, sort field, 4982 # and sort direction 4983 # Returns a reference to a list of hashrefs 4984 sub recSearch { 4985 my $self = shift; 4986 my $dbh = $self->{dbh}; 4987 my %args = @_; 4988 4989 my $sql = q(SELECT 4990 r.domain_id, d.domain, g1.group_name AS domgroup, 4991 r.rdns_id, z.revnet AS revzone, g2.group_name AS revgroup, 4992 r.host, t.name AS rectype, r.val, l.description AS location, r.record_id). 4993 $recsearchsqlbase; 4994 4995 # Limit scope based on group 4996 if ($args{group} != 1) { 4997 my @grouplist; 4998 $self->getChildren($args{group}, \@grouplist); 4999 my $groupset = join(',', $args{group}, @grouplist); 5000 # oh my aching HEAD. there has to be a better way to do conditions on joined tables... 5001 $sql .= "AND ( 5002 (g1.group_id IN ($groupset) AND g2.group_id IN ($groupset)) OR 5003 (g1.group_id IN ($groupset) AND g2.group_id IS NULL) OR 5004 (g1.group_id IS NULL AND g2.group_id IN ($groupset)) 5005 ) 5006 "; 5007 } 5008 5009 # mixed tables means this isn't a simple prefix like the regular record list filter. :/ 5010 my %sortmap = ( 5011 domain => 'd.domain', 5012 revzone => 'z.revnet', 5013 host => 'r.host', 5014 type => 't.name', 5015 val => 'inetlazy(r.val)', 5016 location => 'r.location', 5017 ); 5018 5019 # Sorting defaults 5020 $args{sortorder} = 'ASC' if !$args{sortorder} || !grep /^$args{sortorder}$/, ('ASC','DESC'); 5021 $args{sortby} = 'r.host' if !$args{sortby} || $args{sortby} !~ /^[\w_.]+$/; 5022 $args{offset} = 0 if !$args{offset} || $args{offset} !~ /^(?:all|\d+)$/; 5023 5024 $args{sortby} = $sortmap{$args{sortby}} if $args{sortby} !~ /\./; 5025 5026 # Add sort and offset to SQL 5027 $sql .= "ORDER BY $args{sortby} $args{sortorder},record_id ASC\n"; 5028 $sql .= ($args{offset} eq 'all' ? '' : "LIMIT $self->{perpage} OFFSET ".$args{offset}*$self->{perpage}); 5029 5030 ##fixme: should probably sent the warning somewhere else 5031 my $ret = $dbh->selectall_arrayref($sql, { Slice => {} }, $args{searchfor}, $args{searchfor}) 5032 or warn $dbh->errstr; 5033 return $ret; 5034 5035 } # end recSearch() 4884 5036 4885 5037 … … 5379 5531 eval { 5380 5532 5533 my $logparent; 5534 5381 5535 if ($rev eq 'n') { 5382 5536 ##fixme: serial … … 5386 5540 ($zone_id) = $dbh->selectrow_array("SELECT currval('domains_domain_id_seq')"); 5387 5541 $domain_id = $zone_id; 5388 $ self->_log(group_id => $group, domain_id => $domain_id,5542 $logparent = $self->_log(group_id => $group, domain_id => $domain_id, 5389 5543 entry => "[Added ".($args{status} ? 'active' : 'inactive')." domain $zone via AXFR]"); 5390 5544 } else { … … 5395 5549 ($zone_id) = $dbh->selectrow_array("SELECT currval('revzones_rdns_id_seq')"); 5396 5550 $rdns_id = $zone_id; 5397 $ self->_log(group_id => $group, rdns_id => $rdns_id,5551 $logparent = $self->_log(group_id => $group, rdns_id => $rdns_id, 5398 5552 entry => "[Added ".($args{status} ? 'active' : 'inactive')." reverse zone $cidr via AXFR]"); 5399 5553 } … … 5647 5801 $logentry .= " ".($rev eq 'y' ? $host : $val)."', TTL $ttl"; 5648 5802 } 5649 $self->_log(group_id => $group, domain_id => $domain_id, rdns_id => $rdns_id, entry => $logentry); 5803 $self->_log(group_id => $group, domain_id => $domain_id, rdns_id => $rdns_id, 5804 logparent => $logparent, entry => $logentry); 5650 5805 5651 5806 } # while axfr_next
Note:
See TracChangeset
for help on using the changeset viewer.