2010-12-16 3 views
1

Ich habe einige Internetverkehrsdaten zu analysieren. Ich muss nur die Pakete analysieren, die sich in einem bestimmten IP-Bereich befinden. Also, ich muss eine if Aussage schreiben. Ich nehme an, ich brauche einen regulären Ausdruck für die Testbedingung. Mein Wissen über Regexp ist ein wenig schwach. Kann mir jemand sagen, wie ich einen regulären Ausdruck für diese Bedingung konstruieren würde? Ein Beispiel Bereich sein kann, wiePerl Regulärer Ausdruck für IP-Adressbereich

Group A 
56.286.75.0/19 
57.256.106.0/21 
64.131.14.0/22 

Group B 
58.176.44.0/21 
58.177.92.0/19 

Die if Aussage wäre wie

if("IP in A" || "IP in B") { 
     do something 
} 

else { do something else } 

so würde ich das Äquivalent regexp für "IP in A" vornehmen müssen und "IP in B" Bedingungen.

+3

Warum zur Hölle wollen Sie Regex zum Überprüfen etwas auf Bits-Ebene definiert verwenden? – x13n

+0

@ x13n Nun, das ist nur ein erster Gedanke und einer der Gründe, die ich hier gepostet habe, um bessere Ideen zu bekommen. Ich habe zwar nicht verstanden, was Sie mit "auf Bit-Ebene definiert" meinen. – sfactor

+0

Die Netzwerkmaske (der/ Teil in jeder Ihrer Adressen) gibt an, wie viele Bits von der linken Adresse verglichen werden sollen, um festzustellen, ob eine Adresse zu einem Teilnetz gehört. Es wäre ziemlich schwierig, dafür einen regulären Ausdruck zu schreiben. – x13n

Antwort

8

Ich glaube nicht, dass Regexps viel Vorteil für dieses Problem bieten.

Verwenden Sie stattdessen das Net :: Netmask-Modul. Die "Match" -Methode sollte tun, was Sie wollen.

+0

Danke, ich werde es versuchen. – sfactor

0

Martin hat Recht, verwenden Sie Net :: Netmask. Wenn Sie wirklich ein regex obwohl verwenden mögen ...

$prefix = "192.168.1.0/25"; 
$ip1 = "192.168.1.1"; 
$ip2 = "192.168.1.129"; 

$prefix =~ s/([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)\/([0-9]+)/$mask=(2**32-1)<<(32-$5); $1<<24|$2<<16|$3<<8|$4/e; 
$ip1 =~ s/([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/$1<<24|$2<<16|$3<<8|$4/e; 
$ip2 =~ s/([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/$1<<24|$2<<16|$3<<8|$4/e; 

if (($prefix & $mask) == ($ip1 & $mask)) { 
    print "ip1 matches\n"; 
} 
if (($prefix & $mask) == ($ip2 & $mask)) { 
    print "ip2 matches\n"; 
} 
+0

Obwohl es clever ist, ist es ein Code wie der, der Perl einen schlechten Ruf beschert, da es nur Schreib-Unordnung ist, ähnlich wie Leitungsrauschen :) –

+3

Einverstanden. Tu das nicht wirklich. – eater

+0

'[0-9] +' ist eine schlechte Zeichenklasse zur Verwendung für übereinstimmende IP-Adressen, da jedes gegebene Oktett nur zwischen 0 und 255 liegen kann. So etwas wie "[12]? [1-5]? [0-9] \." Ist besser für die Anpassung eines Oktetts, aber immer noch nicht perfekt. Aus diesem Grund sollten Sie keine regulären Ausdrücke für übereinstimmende IPs verwenden. :) – friedo

1

Ich habe die Meinungsverschiedenheit Echo mit einer Regex mit IP-Adressen zu überprüfen ... aber hier ist eine Möglichkeit, IP-Adressen aus dem Text heraus zu ziehen:

qr{ 
    (?<!\d)    # No digit having come immediately before 
    (?: [1-9] \d?  # any one or two-digit number 
    | 1 \d \d   # OR any three-digit number starting with 1 
    | 2 (?: [0-4] \d # OR 200 - 249 
     | 5 [0-6] # OR 250 - 256 
     ) 
) 
    (?: \.     # followed by a dot 
     (?: [1-9] \d?  # 1-256 reprise... 
     | 1 \d \d 
     | 2 (?: [0-4 \d 
      | 5 [0-6] 
      ) 
    ) 
){3}  # that group exactly 3 times 
    (?!\d) # no digit following immediately after   
}x 
; 

Aber mit diesem allgemeinen Muster können wir einen IP-Parser konstruieren. Aber für die gegebene "im Bereich", würde ich nichts tun, weniger als die folgenden:

A => qr{ 
    (?<! \d) 
    (?: 56\.186\. 75 
    | 57\.256\.106 
    | 64\.131\. 14 
) 
    \. 
    (?: [1-9] \d? 
    | 1 \d \d 
    | 2 (?: [0-4] \d 
     | 5 [0-6] 
     ) 
) 
    (?! \d) 
    }x 

B => qr{ 
    (?<! \d) 
    58 \. 
    (?: 176\.44 
    | 177\.92 
) 
    \. 
    (?: [1-9] \d? 
    | 1 \d \d 
    | 2 (?: [0-4] \d 
     | 5 [0-6] 
     ) 
) 
    (?! \d) 
    }x 
+0

Die Präfixlänge (Nummer nach dem '/') sagt Sie, wie viele Bits bilden den Netzwerkteil der Adresse, die der einzige Teil ist, den Sie zusammenbringen sollten. Hier stimmen Sie nur die ersten 3 Oktette ab, die davon ausgehen, dass alles eine '/ 24' ist. http: //en.wikipedia.org/wiki/CIDR_notation – eater

+0

Obwohl ich sehr rate, ein Netzmaskenmodul zu verwenden, das die Bits weg abstrahiert, für diejenigen, die gebunden und entschlossen sind, eine Regex zu verwenden (was gerade aus purer Gefälligkeit ich manchmal bin :), scheint dies ein großartiger Ort zu sein Verwenden Sie eine "grammatische" Regex, mit einem '((DEFINE) ...)' Block und "Regex-Subroutinen". – tchrist

+1

Dies erfindet das Rad neu - verwenden Sie einfach [Regexp :: Common :: net] (http://search.cpan.org/perldoc?Regexp::Common::net). – Ether

1

Ich mache so etwas wie:

use NetAddr::IP; 

my @group_a = map NetAddr::IP->new($_), @group_a_masks; 
... 
my $addr = NetAddr::IP->new($ip_addr_in); 
if (grep $_->contains($addr), @group_a) { 
    print "group a"; 
} 

Ich wählte NETADDR :: IP over Net :: Netmask für IPv6-Unterstützung.