【问题标题】:Perl script for checking network用于检查网络的 Perl 脚本
【发布时间】:2016-05-27 23:29:52
【问题描述】:

我是 Perl 的新手,为了练习,我正在编写一个简单的 perl 脚本来检查我的家庭网络是否有可用的 IP 地址,并检查它们的 MAC 地址、供应商和每个打开的端口。 我想放入 mysql db 中的所有信息。 这是我的代码:

#!/usr/local/bin/perl
use strict;
use warnings;
use Net::Ping;
use Net::ARP;
use DBI;
use IO::Socket::PortState qw(check_ports);
require config;
my $proto   = 'tcp';
my @ports    = (21,22,23,80,8080);
my $address;
my $ping_timeout = 1;
my $host;
for my $i (18..21)
{
        $host = "10.20.1.$i";
        my $timeout = 1;
        my $pinger  = Net::Ping->new('icmp', $timeout);
        print "$host  ";
        if ($pinger->ping($host))
        {
                my $mac = Net::ARP::arp_lookup("em0","$host");
                my $vendor = vendor_lookup($mac);
                $vendor=~ s/^\s+|\s+$//g;
                print "$mac  $vendor  ";
                foreach my $port (@ports)
                {
                        my($section, $ping_timeout, %porthash);
                        $porthash{$proto}{$port}{'name'} = $section;
                        check_ports($host, $ping_timeout, \%porthash);
                        my $open = $porthash{$proto}{$port}{'open'};
                        if ($open) {
                                print "$port ";
                        }
                }
                print "\n";
        }
}

如果我运行脚本,我会收到类似的信息:

10.20.1.18  38:ea:a7:6f:d9:05  Hewlett Packard  80 8080 
10.20.1.19  fc:15:b4:31:77:76  Hewlett Packard  80 8080 
10.20.1.20  e8:39:35:25:dd:36  Hewlett Packard  22 80 

我的问题是我似乎没有找到答案,如果我们将 $port 变量放入@array 它将具有与其他数组不同的大小。

我的数据库结构是这样的:

+----+------------+-------------------+--------------+-----------------+---------------------+
| id | ip         | mac               | opened_ports | vendor          | date                |
+----+------------+-------------------+--------------+-----------------+---------------------+
|  1 | 10.20.1.19 | fc:15:b4:31:77:76 | NULL         | Hewlett Packard | 2016-02-15 15:50:19 |
|  2 | 10.20.1.20 | e8:39:35:25:dd:36 | NULL         | Hewlett Packard | 2016-02-15 15:50:19 |
|  3 | 10.20.1.21 | 8c:dc:d4:5d:21:7b | NULL         | Hewlett Packard | 2016-02-15 15:50:19 |
|  4 | 10.20.1.18 | 38:ea:a7:6f:d9:05 | NULL         | Hewlett Packard | 2016-02-15 16:02:09 |
|  5 | 10.20.1.19 | fc:15:b4:31:77:76 | NULL         | Hewlett Packard | 2016-02-15 16:02:09 |
|  6 | 10.20.1.20 | e8:39:35:25:dd:36 | NULL         | Hewlett Packard | 2016-02-15 16:02:10 |
|  7 | 10.20.1.21 | 8c:dc:d4:5d:21:7b | NULL         | Hewlett Packard | 2016-02-15 16:02:10 |
+----+------------+-------------------+--------------+-----------------+---------------------+

这是导入的信息,没有打开端口的信息。

【问题讨论】:

  • 您决定数据库布局了吗?请edit您的问题并分享。在我看来,您需要的是标准化您的数据库。
  • 我已经共享了数据库结构。
  • opened_ports是什么数据类型?
  • 然后改变它。这里真正的问题是什么?
  • 对于多个端口号的单列,您的数据库将不在1NF 中。如果您愿意,请创建第二个包含列的表(idport)。 port 列中的每个条目都是一个端口号。

标签: mysql perl unix


【解决方案1】:

Your database is not normalized。您有一个基本的 1:N 关系,其中每行可以有零个或多个 opened_ports

处理这个问题的正确方法是创建第二个表,每个id 有 N 行。它看起来像这样:

+-------+--------------+
| id_fk | opened_ports |
+-------+--------------+
|  1    | 22           |
|  1    | 80           |
|  3    | 22           |
+-------+--------------+

然后从主表中删除列opened_ports,并通过id 链接它们。

在您的 Perl 程序中,您现在需要进行两次插入。第一个将用于大表,它还将创建您的(可能是 auto_increment)id。您可以通过调用$dbh->last_insert_id 来获取它。之后,您可以使用它在包含端口的小表上执行后续的第二个插入语句(或组合一个)。

【讨论】:

    【解决方案2】:

    在初始打印语句print "$mac $vendor "; 下方,您知道此时的mac 供应商主机和日期,因此prepare 插入语句,带有占位符(?) 的端口号

    然后在打印端口号的行添加一个执行语句,并将端口放在占位符位置

    要进行报告,请使用这样的架构

    create table scan (
      id int,
      ip char(15),
      mac char(20),
      opened_ports int,
      vendor varchar(255),
      d datetime
      );
    

    这是基于您上面示例的测试数据

    INSERT INTO SCAN (Id,IP,MAC,OPENED_PORTS,VENDOR,D) VALUES(1,'10.20.1.19','fc:15:b4:31:77:76',25,'Hewlett Packard','2016-02-15 15:50:19');
    INSERT INTO SCAN (Id,IP,MAC,OPENED_PORTS,VENDOR,D) VALUES(2,'10.20.1.20','e8:39:35:25:dd:36',80,'Hewlett Packard','2016-02-15 15:50:19');
    INSERT INTO SCAN (Id,IP,MAC,OPENED_PORTS,VENDOR,D) VALUES(3,'10.20.1.21','8c:dc:d4:5d:21:7b',8080,'Hewlett Packard','2016-02-15 15:50:19');
    INSERT INTO SCAN (Id,IP,MAC,OPENED_PORTS,VENDOR,D) VALUES(4,'10.20.1.18','38:ea:a7:6f:d9:05',137,'Hewlett Packard','2016-02-15 16:02:09');
    INSERT INTO SCAN (Id,IP,MAC,OPENED_PORTS,VENDOR,D) VALUES(5,'10.20.1.19','fc:15:b4:31:77:76',443,'Hewlett Packard','2016-02-15 16:02:09');
    INSERT INTO SCAN (Id,IP,MAC,OPENED_PORTS,VENDOR,D) VALUES(6,'10.20.1.20','e8:39:35:25:dd:36',8080,'Hewlett Packard','2016-02-15 16:02:10');
    INSERT INTO SCAN (Id,IP,MAC,OPENED_PORTS,VENDOR,D) VALUES(7,'10.20.1.21','8c:dc:d4:5d:21:7b',22,'Hewlett Packard','2016-02-15 16:02:10');
    

    这是一个根据需要进行输出的查询

    select ip,mac,GROUP_CONCAT(opened_ports) as port,vendor, d from scan group by ip;
    

    【讨论】:

    • 问题是同一个IP地址可能有任意数量的端口号。
    • 数据库中的每一行都是由“id”而不是“ip”唯一的,因此可以插入具有相同ip的多行
    • 其实你不知道。 OP在问题中没有这么说。还不如有一个唯一的索引。
    • 这可能是真的,但这不会产生规范化的数据库(不在 3NF 中)。 OP 必须说明这是否可以接受。
    • 我的回答确实符合 OP 的脚本和他们数据库的粗略描述。这就是 SO 的魔力
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-02-06
    • 2019-07-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多