编辑nmap2db.pl(更改数据库更新语句)

时间:2012-01-05 15:19:46

标签: php mysql database perl

我正在构建一个包含有关网络主机信息的数据库。我在PHPMaker生成的网站上提供这些数据。 (http://www.hkvstore.com/phpmaker/)

该项目的目的是建立一个IP地址管理系统。

重要的是我们保留数据库中任何记录的历史数据。如果我们手动更改PHPMaker构建站点上的记录,我们可以将旧记录数据写入另一个表。用于实现此目的的代码如下所示。 (可能不完全相关,但我把它放在这里,这样你就可以了解数据的样子)

$sInsertSql = "INSERT INTO IPHistoric (ip, status, hostname, last_scanned, mac, ManualHost, Reservation) 
    VALUES ('" . $rsold['ip'] . "', '" . $rsold['status'] . "', '" . $rsold['hostname'] . "', '" . $rsold['last_scanned'] . "', '" . $rsold['mac'] . "', '" . $rsold['ManualHost'] . "', '". $rsold['Reservation'] . "')";

现在,我还使用名为nmap2db.pl(http://search.cpan.org/~apersaud/Nmap-Parser-1.2/tools/nmap2db.pl)的perl脚本填充数据,这使得对子网进行nmap扫描并将该数据填充到表中非常容易。

我需要什么:

我需要perl脚本将任何旧数据保存到IPHistoric表而不是每次都覆盖。 我对脚本做了一些细微的修改(从数据库模式中删除了一些字段)

完整脚本的Pastebin: http://pastebin.com/V3AwcBVR

看起来第92到第95行是神奇发生的地方。

$S{INSERT_HOST}
    = qq{REPLACE INTO }
    . $G{TABLE}
    . qq{ (ip, mac, status, hostname) VALUES (?,?,?,?)};

所以无论如何......我不知道Perl,我不擅长SQL。是否清楚我想要实现什么?是否可以编辑此脚本来执行我想要的操作?

3 个答案:

答案 0 :(得分:1)

这看起来非常简单。

但是,现在数据库的结构方式,主键是IP地址。

#Schema for table, simple for now
$S{CREATE_TABLE} = qq{  CREATE TABLE } . $G{TABLE} . qq{ (
  ip              VARCHAR(15) PRIMARY KEY NOT NULL,
  mac             VARCHAR(17) ,
  status          VARCHAR(7) DEFAULT 'Down',
  hostname        VARCHAR(50),
  last_scanned    TIMESTAMP DEFAULT CURRENT_TIMESTAMP)
  };

此架构仅允许每个IP地址使用一条记录,这意味着如果使用新数据更新现有记录,旧数据将被丢弃。

您可以通过从IP地址的表架构中删除主键约束来防止这种情况,而是将其放在例如mac地址上。由于mac地址在统计上是唯一的,所以你不应该得到重复。如果你有一个声称拥有多个IP地址的mac地址,你可能还是想了解这一点。

从ip列中删除主键约束后,您现在可以拥有相同IP地址的多条记录。诀窍是找出哪一个是最新的。你可以用时间戳来做到这一点。在数据库中创建两个额外的列,并将其称为CREATE_TIME和END_TIME。

每次在数据库中插入记录时,都会将当前时间戳插入CREATE_TIME。如果该ip的记录已存在,请将当前时间戳插入END_TIME,然后创建新记录。这样,您就可以根据CREATE_TIME和END_TIME时间戳知道每条IP记录的分配时间。

由于END_TIME仅在更改记录时写入,因此您可以通过执行以下操作来获取当前的IP记录集:

    select * from TABLE where END_TIME is NULL;

希望有道理。

答案 1 :(得分:0)

或者,使用“历史表”主题:

use vars qw(%S %G %H);

$H{TABLE} ||='IPHistoric';

$S{INSERT_HISTORIC}
    = qq{INSERT INTO }
    . $H{TABLE}
    . qq{ (ip, status, hostname, last_scanned, mac, ManualHost, Reservation) VALUES (?,?,?,?,?,?,?)};

my $hist_ins = eval { $dbh->prepare_cached( $S{INSERT_HISTORIC} ) };
my $np = new Nmap::Parser;
$np->callback( \&insert_historic );

sub insert_historic {
    my $host = shift;
    my $os   = $host->os_sig();

    #ip, mac, status, hostname
    my @input_values = (
        $host->rsold['ip'],
        $host->rsold['status'],
        $host->rsold['hostname'],
        $host->rsold['last_scanned'],
        $host->rsold['mac'],
        $host->rsold['ManualHost'],
        $host->rsold['Reservation']
    );

    my $rv
        = $hist_ins->execute(@input_values) ? "ok" : "OOPS! - " . DBI->errstr;

    printf( "\t..> %-15s : (%4s) : %-s\n", $host->addr, $host->status, $rv );
}

这可能有一些错字,但你明白了。基本上,一旦设置了$ rsold变量,就可以调用insert_historic sub并将所有这些值保存到IPHistoric表中。

下面的代码不会独立运行,因为它依赖于您链接的代码中设置的许多其他内容。但是您应该能够复制/设置$ {INSERT_HOST}部分正下方的$ S {INSERT_HISTORIC}部分,而insert_historic子部分将位于insert_host子部分的正下方。

祝你好运!

答案 2 :(得分:0)

我们添加了INSERT_HISTORY部分。

$S{INSERT_HISTORY}
=   qq{ INSERT_INTO IPHistoric }
    . qq{ ip, status, hostname, last_scanned, mac, ManualHost, Reservation }
  . qq { SELECT ip, status, hostname, last_scanned, mac, ManualHost, Reservation FROM }
    . $G{TABLE}
    . qq { WHERE ip = ? AND ( mac <> ? OR hostname <> ? ) };

$S{UPDATE_HOST}
= qq{UPDATE }
  . $G{TABLE}
  . qq { SET mac = ? , status = ?, hostname = ?, last_scanned = CURRENT_TIMESTAMP }