#!/usr/bin/perl # # lookupip # # Copyright (C) 2006-2008 # Paul E. Jones # # This program will connect to Packetizer's IP address return service and # either tell you your current IP address or return the IP address and country # for an address provided on the command line. # # Usage: lookupip [a.b.c.d] # (If no IP address, assume your current address.) # # The XML returned by the server is in this form: # # # #
a.b.c.d
# cc #
# # We implement a small state machine to ensure that we grab the right node, # should the XML schema change in the future. # # Parsing states: # 0 = IDLE # 1 = Non-target tag found # 2 = Target found in state 0 # 3 = Target
found in state 2 # 4 = Target found in state 2 # use LWP; use XML::Parser; # ValidIP sub ValidIP { my $address = shift; my (@ip_array) = $address =~ /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/; return 0 unless ($#ip_array == 3); for (my $i=0; $i<4; $i++) { return 0 unless (($ip_array[$i] >=0) && ($ip_array[$i] <= 255)); } return 1; } # XML Initialization routine sub init_handler { # Processing state machine $parsing_state = 0; @parsing_state_stack = (); $ip_address = ""; $country = ""; } # XML Parsing call-back routines sub start_handler { my($expat, $element, %attrs) = @_; # As we find nodes in the parse tree, progress the state machine if (($parsing_state == 0) && ($element eq "IPAddress")) { push(@parsing_state_stack, $parsing_state); $parsing_state = 2; } elsif (($parsing_state == 2) && ($element eq "address")) { push(@parsing_state_stack, $parsing_state); $parsing_state = 3; } elsif (($parsing_state == 2) && ($element eq "country")) { push(@parsing_state_stack, $parsing_state); $parsing_state = 4; } else { # We are not interested in this node push(@parsing_state_stack, $parsing_state); $parsing_state = 1; } } sub char_handler { my ($expat, $chardata) = @_; # If we are processing character data in state 3, it is the IP address # (Note: the concatenation is necessary, as it might be delivered in # pieces by the XML libraries.) if ($parsing_state == 3) { $ip_address = $ip_address . $chardata; } elsif ($parsing_state == 4) { $country = $country . $chardata; } } sub end_handler { my ($expat, $element) = @_; # Since we've reached the end of an element, lets move back to the # previous parsing state. $parsing_state = pop(@parsing_state_stack); } # # MAIN # { # Service URL $url = "http://services.packetizer.com/ipaddress/"; if ($#ARGV > 0) { print "usage: lookupip [ip address]\n"; exit; } elsif ($#ARGV == 0) { $address = $ARGV[0]; if (!ValidIP($address)) { die "Error: invalid IP address\n"; } # Add the IP address as a parameter to the URL $url .= "?address=$address"; } # Define a user agent $ua = LWP::UserAgent->new; # Get the page from the server $response = $ua->get($url, "Accept" => "application/xml"); die "Error: Unable to get IP address: " . $response->status_line . "\n" unless $response->is_success; die "Error: Invalid content type: " . $response->content_type . "\n" unless $response->content_type eq "application/xml"; # Parse the XML message $parser = XML::Parser->new(ErrorContext => 2); $parser->setHandlers(Init => \&init_handler, Start => \&start_handler, End => \&end_handler, Char => \&char_handler); eval { $parser->parse($response->content); }; if ($@) { die "There was an error parsing the XML:\n$@\n"; } # Provide the IP address print "IP Address: $ip_address\n"; print "Country: $country\n"; }