【问题标题】:How can I match an IP address in Perl?如何在 Perl 中匹配 IP 地址?
【发布时间】:2009-12-28 21:36:25
【问题描述】:

我有一个本地 DNS 脚本,它是从过去的员工那里继承而来的,它需要比较一些值以查看它们是否匹配特定的 MX 记录和 IP 地址。

MX 部分我还好:

120 $doug = doug.local
139 if ($mx_record =~ /$doug/) {
140         print ("Mail on doug.\n");
141 }
142         else {
143                 print ("Not on doug.\n");
144 }

$mx_record 是来自 mx 查询的一行,如下所示:

thomas.            302     IN      MX      10 doug.local.

现在我需要查看 A 记录是否匹配。

查询中的$a_record 变量如下所示。

thomas.            300     IN      A       10.0.0.47

如何执行条件语句来匹配 IP 地址?

我需要在变量中定义 IP,然后查看 $a_record 变量是否包含该定义的 IP。

【问题讨论】:

  • 您是否只对以点分四边形表示的 IPv4 地址感兴趣?以十六进制值表示的 IP 地址是否也是一种可能的输入?
  • 仅 IPv4 地址以点分四边形表示。
  • 这是来自 dig 之类的程序还是您正在解析文件?
  • @Schwern:来自挖掘,是的。
  • @scraft3613 那就不要费心去解析 dig 输出了。使用 Net::DNS 查询有关域的信息并将其作为整洁的对象取回。无需屏幕抓取。

标签: perl ip-address


【解决方案1】:

如果您只想匹配 IPv4 正则表达式,请使用 Regexp::Common::net

与其在整行上运行正则表达式,更安全的是对它们进行标记并根据需要匹配各个部分。

use strict;
use warnings;

use Data::Dumper;

sub parse_record {
    my $line = shift;

    # special rules for parsing different types
    my %More4Type = (
        MX      => sub { return( priority => $_[0], provider => $_[1] ) },
        default => sub { return( provider => $_[0] ) }
    );

    my(%record, @more);
    (@record{qw(host uhh class type)}, @more) = split /\s+/, $line;
    my $more_func = $More4Type{$record{type}} || $More4Type{default};
    %record = (%record, $more_func->(@more));

    return \%record;
}

while(my $line = <DATA>) {
    print Dumper parse_record($line);
}

__END__
thomas.            302     IN      MX      10 doug.local.
thomas.            300     IN      A       10.0.0.47
google.com.     24103   IN  NS  ns2.google.com.

现在您已经解析了该行,只需查看$record{type}$record{provider} 或您需要的任何内容即可。只需稍加努力,这将更加灵活且不易出错。

虽然CPAN 上可能有一些东西可以为你解析。

【讨论】:

    【解决方案2】:

    我确信有更好的方法,但这会让你非常接近:

    if($a_record =~ /((?:\d{1,3}\.){3}\d{1,3})/) {
         warn "IP was: $1";
    }
    
    # IP was: 10.0.0.47
    

    这匹配10.0.0.,然后匹配最后的47

    【讨论】:

      【解决方案3】:

      这将匹配一个看起来像 IP 地址的条目,但也将匹配 999.999.999.999。请务必在使用前验证匹配的地址。

      if ($mx_record =~ /(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/) {...}
      

      【讨论】:

      • 这是正确的方法...只要验证四边形的每个部分都在 0-25 范围内。
      【解决方案4】:

      试试这个:

      if ($mx_record =~ /A\w+(<record_ip>(?:/[0-9]{1,3}.){4})/ {
         print $record_ip
      }
      

      这将检查 A 后跟空格,然后是虚线四边形。四边形保存在变量 $record_ip

      【讨论】:

      • 为什么将模式限制为 0-5 的数字?这怎么可能匹配 192.168.x.x 空间中的私有?
      • ...因为我突然开始考虑旧的(非 CIDR 网络掩码...会修复。
      • 为什么要发布没有测试过的代码?你想要\s+,而不是\w+。您应该引用 \.,或者它匹配任何字符。正则表达式查找带有尾随点的地址。此代码可能起作用的唯一原因是行尾的 \n 被解析为地址的一部分。改用: if (/A\s+((?:[0-9]{1,3}\.){3}[0-9]{1,3})/)
      【解决方案5】:
      my $a_record = 'thomas.            300     IN      A       10.0.0.47';
      my $ip = '10.0.0.47';
      
      if ($a_record =~ /\b(\Q$ip\E)$/) {
          print "Matches: $1\n";
      }
      

      【讨论】:

        【解决方案6】:

        由于 IP 地址可能不是最紧凑的十进制表示法,我建议您应该使用 Socket 模块中的 inet_aton() 函数:

        use Socket;
        
        my $ip_to_match = inet_aton('10.0.0.47');
        ...
        if (inet_aton($field) == $ip_to_match) {
            ...
        }
        

        注意:假设 DNS 记录已被拆分为其组成部分

        【讨论】:

          猜你喜欢
          • 2012-12-13
          • 2019-06-03
          • 2012-04-27
          • 1970-01-01
          • 2012-06-26
          • 2011-02-11
          • 2012-07-01
          • 2011-01-17
          • 1970-01-01
          相关资源
          最近更新 更多