#!/usr/bin/perl

use strict;
use warnings;
use Net::SNMP;
use Net::DNS;
use DateTime;
use Data::Dumper;

my $logfile    = "/var/log/iplog.log";
my %titles     = ("1-WANIP" => \&getip, "2-DYNIP" => \&getdynip, "3-CTLIP" => \&controlip);

sub getip {
  my $routeraddr = "192.168.1.254";
  my $community  = "public";
  my $routerifc  = "102";
  my $routeridx  = "1.3.6.1.2.1.4.20.1.2";

  my $session = Net::SNMP->session(
    -hostname => $routeraddr, 
    -community => $community
  );
  my $error = $session->error;
  return("Canīt init snmp session! ($error)") if ($error);

  my $idtable = $session->get_table(
    -baseoid => $routeridx 
  );
  $error = $session->error;
  $session->close();
  return("Canīt get ip-table! ($error)") if ($error);
  return("ip-table undefined!") if (!defined($idtable));

  my $wanid; 
  foreach (keys(%$idtable)) {
    if ($idtable -> {$_} == $routerifc) { $wanid = $_ }
  }
  return("Can't get wan-ip!") if (!defined($wanid));
  return("IP change to " . substr($wanid, length($routeridx) + 1) . "!");
}

sub getdynip {
  my $res   = Net::DNS::Resolver->new(nameservers => [qw(217.237.150.188 217.237.151.142)]);
  $res->udp_timeout(15);
  my $query = $res->search("mszet.homeip.net");
  
  if ($query) {
      foreach my $rr ($query->answer) {
          next unless $rr->type eq "A";
          return "DynDNS-IP change to " . $rr->address;
      }
  } else {
      return "query failed! (" . $res->errorstring . ")";
  }
}

sub controlip {
  my $wantag = "1-WANIP";
  my $dyntag = "2-DYNIP";
  my $msgs = shift @_;

  my $wanmsg  = $msgs->{$wantag}->{msg};
  my $wandate = $msgs->{$wantag}->{date};
  return undef if (!$wanmsg || !$wandate);
  $wanmsg =~ s/\(.*\)//g;
  my $wanip; my $wantime;
  if ($wanmsg  =~ /(\d+\.\d+\.\d+\.\d+)/) { $wanip = $1 } else { return undef }
  if ($wandate =~ /^(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)$/) { 
    $wantime = DateTime->new(year => $1, month => $2, day => $3, hour => $4, minute => $5, time_zone => 'floating');
  } else { return undef }
  my $nowtime = DateTime->now(time_zone => 'floating');
  my $duration = ($nowtime - $wantime)->delta_minutes();
  if ($duration < 120) { return undef }

  my $dynmsg  = $msgs->{$dyntag}->{msg};
  my $dynip;
  if ($dynmsg  =~ /(\d+\.\d+\.\d+\.\d+)/) { $dynip = $1 } else { 
    my $str = "Dynamic IP resolve error";
    print $str, "\n";
    return $str;
  }
  if ($dynip ne $wanip) { 
    my $str = "Dynamic IP does not match";
    print $str, "\n";
    return $str;
  }
  return undef;
}

sub logmessages {
  my $logfile = shift;
  my %titles  = %{(shift)};

  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
  $year += 1900; $mon += 1;
  my $date = sprintf("%04d-%02d-%02d %02d:%02d:%02d", $year, $mon, $mday, $hour, $min, $sec);

  open(LOG, "+>>", $logfile) or die("Can't open Logfile! ($logfile)\n");

  if (-s LOG > 1030) {
    seek(LOG, -1024, 2) or die("Can't seek Logfile! ($logfile)\n");
    <LOG>;
  } else {
    seek(LOG, 0, 0) or die("Can't seek Logfile! ($logfile)\n");
  }

  my %msgs;
  while(defined($_ = <LOG>)) {
    if (/^([-0-9]{10} [0-9:]{8}) ([-A-Z0-9]+): (.*)$/ && defined($titles{$2}) ) { 
      $msgs{$2}->{date}=$1;
      $msgs{$2}->{msg}=$3;
    }
  }
  # print Dumper(\%msgs);

  foreach my $title (sort(keys(%titles))) {
    my $message = &{$titles{$title}}(\%msgs);
    next if (!$message);
    next if (defined($msgs{$title}) && ($msgs{$title}->{msg} eq $message));

    print LOG $date, " ", $title, ": ", $message, "\n";
    $msgs{$title}->{date} = $date;
    $msgs{$title}->{msg} = $message;
  }    

  close(LOG);
}

logmessages($logfile, \%titles);
