sfactor
sfactor

Reputation: 13062

Perl Regular expression for IP address range

I have some internet traffic data to analyze. I need to analyze only those packets that are within a certain IP range. So, I need to write a if statement. I suppose I need a regular expression for the test condition. My knowledge of regexp is a little weak. Can someone tell me how would I construct a regular expression for that condition. An example range may be like

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 

The if statement would be like

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

else { do something else }

so i would need to make the equivalent regexp for "IP in A" and "IP in B" conditions.

Upvotes: 1

Views: 3577

Answers (4)

ysth
ysth

Reputation: 98378

I'm doing something like:

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";
}

I chose NetAddr::IP over Net::Netmask for IPv6 support.

Upvotes: 1

Axeman
Axeman

Reputation: 29844

I have to echo the disagreement with using a regex to check IP addresses...however, here is a way to pull IPs out of text:

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
;

But given that general pattern, we can construct an IP parser. But for the given "ranges", I wouldn't do anything less than the following:

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

Upvotes: 1

eater
eater

Reputation: 2817

Martin is right, use Net::Netmask. If you really want to use a regex though...

$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";
}

Upvotes: 0

Martin
Martin

Reputation: 9954

I don't think that regexps provide much advantage for this problem.

Instead, use the Net::Netmask module. The "match" method should do what you want.

Upvotes: 8

Related Questions