【问题标题】:editing nmap2db.pl (changing database update statements)编辑 nmap2db.pl(更改数据库更新语句)
【发布时间】:2023-04-11 04:14:01
【问题描述】:

我正在构建一个数据库,其中包含有关我网络上主机的信息。我在 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 表中,而不是每次都覆盖。 我对脚本做了一些细微的修改(从 db 架构中删除了一些字段)

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

看起来第 92 到 95 行是魔法发生的地方。

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

所以无论如何...我不了解 Perl,而且我不太擅长 SQL。清楚我想要实现的目标吗?是否可以编辑此脚本以执行我想要的操作?

【问题讨论】:

    标签: php mysql database perl


    【解决方案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;
    

    希望这是有道理的。

    【讨论】:

    • 我明白你在说什么,但我更喜欢我的方式:) 原因如下:MAC 地址不能是主要的,因为不会总是有一个......但大多数情况下我不会有一个很好的方法来显示整个 ip 范围的数据....也许我可以编写一个匹配 ip 范围的 select 语句并找到最新的记录。唔。我会考虑一下并与我的 DBA 人员讨论这个计划。我喜欢有选择,但我仍然想找到一种方法来做我最初要求的事情。
    • 啊,我明白你现在在说什么了。不知怎的,我错过了你想要一张单独的桌子。
    • 然后我将在脚本的第 98 行创建另一个函数,就在 $np->callback(\&insert_host);并调用一个名为 insert_historic 的新函数。
    【解决方案2】:

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

    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 子并将所有这些值保存到 IPHistoric 表中。

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

    祝你好运!

    【讨论】:

      【解决方案3】:

      我们添加了 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 }
      

      【讨论】:

        猜你喜欢
        • 2017-02-16
        • 2019-03-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-07-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多