正则表达式解析DNS答案

问题描述 投票:0回答:3

我想解析以下几行

8.8.19.12.53 > 125.15.15.9.40583: [udp sum ok] 62639 q: A? mp.microsoft.com. 6/5/9 mp.microsoft.com. CNAME .mp.microsoft.com.c.footprint.net., mp.microsoft.com.c.footprint.net. A 8.250.143.254, mp.microsoft.com.c.footprint.net. A 8.250.157.254 ns: c.footprint.net. NS d.ns.c.footprint.net. ar: d.ns.c.footprint.net. A 4.26.235.155 (439)
8.8.19.12.53 > 125.15.15.9.42091: [udp sum ok] 46555 q: A? www.toto.net. 1/0/0 www.toto.net. A 120.33.1.11 (47)

并获得以下输出

125.15.15.9 mp.microsoft.com A 8.250.143.254 A 8.250.157.254
125.15.15.9 www.toto.net A 120.33.1.11

我成功用命令解析了前两个字段

sed -Eun 's/[^>]+> ([0-9.]+)\.[0-9]+:.+q: A\? ([a-z0-9.-]+)\.([^:]+).*/\1:\2:\3/pg

`

但我无法获得已解析的IP(A xx.xx.xx.xx)。实际上可能有几个。

是否可以使用sed或Perl获得此类输出?

编辑:正如我在评论中添加的,解析更大的输入样本,我还需要在输出中丢弃几行。这条线的特点是:

  • A记录的数量(“A xx.xx.xx.xx”)不为空
  • 或者该行不得包含NXDomain\*?-

我成功地满足了新的第一个需求,但不是第二个。

在@ikegami回复之后,这是我的尝试:

  perl -nle '
     my $field_value_re = qr/(?![^\s:]++:(?!\S)) \S++ (?: (?! \s++ [^\s:]++:(?!\S) ) \s++ \S++ )*+/x;

     my ($id, $rest) = /^ \s+ ( [^:]++ ) : \s++ $field_value_re ( .* ) /sx
        or next;

     my ($ip) = $id =~ /^ \S++ \s++ \S++ \s++ ( [^\s\.]++\.[^\s\.]++\.[^\s\.]++\.[^\s\.]++ )\.[^\s\.]++ \z /x
        or next;

     my %fields = $rest =~ /\G \s++ ( [^\s:]++ ) :(?!\S) \s++ ( $field_value_re ) /gsx;

     my ($query, $answers) = $fields{q} =~ /^ A\? \s++ ( \S++ ) \s++ \S++ \s++ ( .* ) /sx
        or next;

     $query =~ s/\.\z//;

     my @answers = split(/\s*+,\s*+/, $answers);
     my ($afield) = join " ", map { /^\S++\s++A\s++(\S++)/ } @answers;
     if ( length($afield) != 0)
     {
             print join " ", $ip, $query, $afield;
     }
  ' dns.sample
regex perl sed
3个回答
2
投票

每一行似乎都是这种形式

{"id" with spaces}: {stuff} [ {key}: {stuff} ]*

您似乎对“id”内部以及名为q的字段内的信息感兴趣。 q字段的值似乎是形式

A? {word} {word} {ns_return} [, {ns_return} ]*

这是一个处理上述格式的强大解决方案。

perl -nle'
   my $field_value_re = qr/(?![^\s:]++:(?!\S)) \S++ (?: (?! \s++ [^\s:]++:(?!\S) ) \s++ \S++ )*+/x;

   my ($id, $id_val, $rest) = /^ ( [^:]++ ) : \s++ ( $field_value_re ) ( .* ) /sx
      or next;

   next if $id_val =~ /\bNXDomain\b/;

   my ($ip) = $id =~ /^ \S++ \s++ \S++ \s++ ( [^\s\.]++\.[^\s\.]++\.[^\s\.]++\.[^\s\.]++ )\.[^\s\.]++ \z /x
      or next;

   my %fields = $rest =~ /\G \s++ ( [^\s:]++ ) :(?!\S) \s++ ( $field_value_re ) /gsx;

   my ($query, $answers) = $fields{q} =~ /^ A\? \s++ ( \S++ ) \s++ \S++ \s++ ( .* ) /sx
      or next;

   $query =~ s/\.\z//;

   my @answers =
      map { /^\S++\s++A\s++(\S++)/ }
         split(/\s*+,\s*+/, $answers);

   next if !@answers;

   print join " ", $ip, $query, map { "A $_" } @answers;
' log
125.15.15.9 mp.microsoft.com A 8.250.143.254 A 8.250.157.254
125.15.15.9 www.toto.net A 120.33.1.11

3
投票

这与您提供的样本数据一样

我首先构建一个匹配数字URL的正则表达式$url_re,使下面的代码更简洁。然后我在>之后立即搜索第一个URL,A?之后的命名URL以及A之后的所有以下URL

它们都存储在数组@urls中并打印出来

use strict;
use warnings 'all';
use 5.010;

my $url_re = qr/(?:\d+\.){3}\d+/;

while ( <DATA> ) {

    my @urls = ( />\s+($url_re)/, /A\?\s+([-\w.]+\w)/, /(A\s+$url_re)/g );

    say "@urls";
}

__DATA__
8.8.19.12.53 > 125.15.15.9.40583: [udp sum ok] 62639 q: A? mp.microsoft.com. 6/5/9 mp.microsoft.com. CNAME .mp.microsoft.com.c.footprint.net., mp.microsoft.com.c.footprint.net. A 8.250.143.254, mp.microsoft.com.c.footprint.net. A 8.250.157.254 ns: c.footprint.net. NS d.ns.c.footprint.net. ar: d.ns.c.footprint.net. A 4.26.235.155 (439)
8.8.19.12.53 > 125.15.15.9.42091: [udp sum ok] 46555 q: A? www.toto.net. 1/0/0 www.toto.net. A 120.33.1.11 (47)

output

125.15.15.9 mp.microsoft.com A 8.250.143.254 A 8.250.157.254 A 4.26.235.155
125.15.15.9 www.toto.net A 120.33.1.11

1
投票

这将使用map函数打印所需的输出,以某种非正统的方式忽略q:之后的任何字段

perl -lne 'print join qq/\t/, m/> ([\d\.]+)\./, map {/A\? ([^\s]+)\./, /(A [\d\.]+)/g} / q:([^:]+)/' log.txt
最新问题
© www.soinside.com 2019 - 2024. All rights reserved.