261 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
			
		
		
	
	
			261 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
| package App::Netdisco::DB::ResultSet::NodeIp;
 | |
| use base 'App::Netdisco::DB::ResultSet';
 | |
| 
 | |
| use strict;
 | |
| use warnings;
 | |
| 
 | |
| __PACKAGE__->load_components(qw/
 | |
|   +App::Netdisco::DB::ExplicitLocking
 | |
| /);
 | |
| 
 | |
| my $order_by_time_last_and_join_oui = {
 | |
|     order_by => {'-desc' => 'time_last'},
 | |
|     '+columns' => [
 | |
|       'oui.company',
 | |
|       'oui.abbrev',
 | |
|       { time_first_stamp => \"to_char(time_first, 'YYYY-MM-DD HH24:MI')" },
 | |
|       { time_last_stamp =>  \"to_char(time_last, 'YYYY-MM-DD HH24:MI')" },
 | |
|     ],
 | |
|     join => 'oui'
 | |
| };
 | |
| 
 | |
| =head1 with_times
 | |
| 
 | |
| This is a modifier for any C<search()> (including the helpers below) which
 | |
| will add the following additional synthesized columns to the result set:
 | |
| 
 | |
| =over 4
 | |
| 
 | |
| =item time_first_stamp
 | |
| 
 | |
| =item time_last_stamp
 | |
| 
 | |
| =back
 | |
| 
 | |
| =cut
 | |
| 
 | |
| sub with_times {
 | |
|   my ($rs, $cond, $attrs) = @_;
 | |
| 
 | |
|   return $rs
 | |
|     ->search_rs({}, $order_by_time_last_and_join_oui)
 | |
|     ->search($cond, $attrs);
 | |
| }
 | |
| 
 | |
| =head1 search_by_ip( \%cond, \%attrs? )
 | |
| 
 | |
|  my $set = $rs->search_by_ip({ip => '192.0.2.1', active => 1});
 | |
| 
 | |
| Like C<search()>, this returns a ResultSet of matching rows from the
 | |
| NodeIp table.
 | |
| 
 | |
| =over 4
 | |
| 
 | |
| =item *
 | |
| 
 | |
| The C<cond> parameter must be a hashref containing a key C<ip> with the value
 | |
| to search for. Value can either be a simple string of IPv4 or IPv6, or a
 | |
| L<NetAddr::IP::Lite> object in which case all results within the CIDR/Prefix
 | |
| will be retrieved.
 | |
| 
 | |
| =item *
 | |
| 
 | |
| Results are ordered by time last seen.
 | |
| 
 | |
| =item *
 | |
| 
 | |
| Additional columns C<time_first_stamp> and C<time_last_stamp> provide
 | |
| preformatted timestamps of the C<time_first> and C<time_last> fields.
 | |
| 
 | |
| =item *
 | |
| 
 | |
| A JOIN is performed on the OUI table and the OUI C<company> column prefetched.
 | |
| 
 | |
| =back
 | |
| 
 | |
| To limit results only to active IPs, set C<< {active => 1} >> in C<cond>.
 | |
| 
 | |
| =cut
 | |
| 
 | |
| sub search_by_ip {
 | |
|     my ($rs, $cond, $attrs) = @_;
 | |
| 
 | |
|     die "ip address required for search_by_ip\n"
 | |
|       if ref {} ne ref $cond or !exists $cond->{ip};
 | |
| 
 | |
|     # handle either plain text IP or NetAddr::IP (/32 or CIDR)
 | |
|     my ($op, $ip) = ('=', delete $cond->{ip});
 | |
| 
 | |
|     if ('NetAddr::IP::Lite' eq ref $ip and $ip->num > 1) {
 | |
|         $op = '<<=';
 | |
|         $ip = $ip->cidr;
 | |
|     }
 | |
|     $cond->{ip} = { $op => $ip };
 | |
| 
 | |
|     return $rs
 | |
|       ->search_rs({}, $order_by_time_last_and_join_oui)
 | |
|       ->search($cond, $attrs);
 | |
| }
 | |
| 
 | |
| =head1 search_by_dns( \%cond, \%attrs? )
 | |
| 
 | |
|  my $set = $rs->search_by_dns({
 | |
|    dns => 'foo.example.com',
 | |
|    suffix => qr/(?:\.example\..com|\.local)$/,
 | |
|    active => 1
 | |
|  });
 | |
| 
 | |
| Like C<search()>, this returns a ResultSet of matching rows from the
 | |
| NodeIp table.
 | |
| 
 | |
| =over 4
 | |
| 
 | |
| =item *
 | |
| 
 | |
| The NodeIp table must have a C<dns> column for this search to work. Typically
 | |
| this column is the IP's DNS PTR record, cached at the time of Netdisco Arpnip.
 | |
| 
 | |
| =item *
 | |
| 
 | |
| The C<cond> parameter must be a hashref containing a key C<dns> with the value
 | |
| to search for. The value may optionally include SQL wildcard characters.
 | |
| 
 | |
| =item *
 | |
| 
 | |
| If C<dns> is a plain string, then the C<cond> parameter may optionally have a
 | |
| C<suffix> parameter which is a regular expression of domain names - one of
 | |
| which must match the results.
 | |
| 
 | |
| =item *
 | |
| 
 | |
| Results are ordered by time last seen.
 | |
| 
 | |
| =item *
 | |
| 
 | |
| Additional columns C<time_first_stamp> and C<time_last_stamp> provide
 | |
| preformatted timestamps of the C<time_first> and C<time_last> fields.
 | |
| 
 | |
| =item *
 | |
| 
 | |
| A JOIN is performed on the OUI table and the OUI C<company> column prefetched.
 | |
| 
 | |
| =back
 | |
| 
 | |
| To limit results only to active IPs, set C<< {active => 1} >> in C<cond>.
 | |
| 
 | |
| =cut
 | |
| 
 | |
| sub search_by_dns {
 | |
|     my ($rs, $cond, $attrs) = @_;
 | |
| 
 | |
|     die "dns field required for search_by_dns\n"
 | |
|       if ref {} ne ref $cond or !exists $cond->{dns};
 | |
| 
 | |
|     my $dns_field = delete $cond->{dns};
 | |
| 
 | |
|     (my $suffix = ($cond->{suffix} || ''))
 | |
|       =~ s|\Q(?^\E[-xismu]*|(?|g;
 | |
| 
 | |
|     if (q{} eq ref $dns_field and exists $cond->{suffix}) {
 | |
|         (my $stripped_dns_field = $dns_field) =~ s/\.\%$//;
 | |
|         (my $fqdn_field = $stripped_dns_field) .= '%';
 | |
|         $stripped_dns_field =~ s/$cond->{suffix}$// if $cond->{suffix};
 | |
|         $stripped_dns_field .= '.%';
 | |
| 
 | |
|         $cond->{dns} = [ -or =>
 | |
|           [ -and =>
 | |
|               { '-ilike' => $stripped_dns_field },
 | |
|               { '~*' => "***:$suffix" },
 | |
|           ],
 | |
|           [ -and =>
 | |
|               { '-ilike' => $dns_field },
 | |
|               { '~*' => "***:$suffix" },
 | |
|           ],
 | |
|           { '-ilike' => $fqdn_field },
 | |
|         ];
 | |
|     }
 | |
|     elsif (q{} ne ref $dns_field) {
 | |
|         $cond->{dns} = $dns_field;
 | |
|     }
 | |
|     else {
 | |
|         $cond->{dns} = { '-ilike' => $dns_field };
 | |
|     }
 | |
| 
 | |
|     delete $cond->{suffix};
 | |
|     return $rs
 | |
|       ->search_rs({}, $order_by_time_last_and_join_oui)
 | |
|       ->search($cond, $attrs);
 | |
| }
 | |
| 
 | |
| =head1 search_by_mac( \%cond, \%attrs? )
 | |
| 
 | |
|  my $set = $rs->search_by_mac({mac => '00:11:22:33:44:55', active => 1});
 | |
| 
 | |
| Like C<search()>, this returns a ResultSet of matching rows from the
 | |
| NodeIp table.
 | |
| 
 | |
| =over 4
 | |
| 
 | |
| =item *
 | |
| 
 | |
| The C<cond> parameter must be a hashref containing a key C<mac> with the value
 | |
| to search for.
 | |
| 
 | |
| =item *
 | |
| 
 | |
| Results are ordered by time last seen.
 | |
| 
 | |
| =item *
 | |
| 
 | |
| Additional columns C<time_first_stamp> and C<time_last_stamp> provide
 | |
| preformatted timestamps of the C<time_first> and C<time_last> fields.
 | |
| 
 | |
| =item *
 | |
| 
 | |
| A JOIN is performed on the OUI table and the OUI C<company> column prefetched.
 | |
| 
 | |
| =back
 | |
| 
 | |
| To limit results only to active IPs, set C<< {active => 1} >> in C<cond>.
 | |
| 
 | |
| =cut
 | |
| 
 | |
| sub search_by_mac {
 | |
|     my ($rs, $cond, $attrs) = @_;
 | |
| 
 | |
|     die "mac address required for search_by_mac\n"
 | |
|       if ref {} ne ref $cond or !exists $cond->{mac};
 | |
| 
 | |
|     return $rs
 | |
|       ->search_rs({}, $order_by_time_last_and_join_oui)
 | |
|       ->search($cond, $attrs);
 | |
| }
 | |
| 
 | |
| =head2 ip_version( $version )
 | |
| 
 | |
|  my $rset = $rs->ip_version(4);
 | |
| 
 | |
| This predefined C<search()> returns a ResultSet of matching rows from the
 | |
| NodeIp table of nodes with addresses of the supplied IP version.
 | |
| 
 | |
| =over 4
 | |
| 
 | |
| =item *
 | |
| 
 | |
| The C<version> parameter must be an integer either 4 or 6.
 | |
| 
 | |
| =back
 | |
| 
 | |
| =cut
 | |
| 
 | |
| sub ip_version {
 | |
|     my ( $rs, $version ) = @_;
 | |
| 
 | |
|     die "ip_version input must be either 4 or 6\n"
 | |
|         unless $version && ( $version == 4 || $version == 6 );
 | |
| 
 | |
|     return $rs->search_rs( \[ 'family(me.ip) = ?', $version ] );
 | |
| }
 | |
| 
 | |
| 1;
 |