NetOpsCoding Advent Calendar 2015 This is the article on the 21st day. I'm sorry I misunderstood the schedule ...
When a network engineer writes a script, I think that the IP address may be manipulated or calculated in the script. When calculating in the same way as a normal numerical value, the IP address of the character string type should be parsed and converted to an Int weighted for each digit, and so on. can not. In addition, ipv6 has a large number of digits, and in some cases it cannot be processed by simple parsing such as abbreviated notation, so it is a little troublesome to implement it by yourself.
This time, I will introduce the ipaddress module that makes it very easy to handle the troublesome IP address! Obviously for those who know, I didn't know this convenience until recently, so I'll share it for those who don't yet.
The ipaddress module is a standard module officially implemented from python 3.3. (PEP3144) It is based on the ipaddr module developed by Google. Of course, you can use the ipaddr module in almost the same way, but this time, let's use the ip address that is installed as a standard module and does not require installation.
The ipaddress module has functions dedicated to v4 / v6 such as ʻIPv4Address ()
and ʻIPv6Address (), but functions such as ʻip_address ()` that include these are prepared and arguments. You can use it without worrying about whether it is v4 or v6.
The ipaddress module uses the following three types of functions.
As the function name suggests, ip corresponds to ʻip_address ()
, network address corresponds to ʻip_network (), and Interface address corresponds to ʻip_interface ()`.
Use this function to create an ipv4 / v6 type object. Furthermore, various conversions and calculations can be performed by using optional functions. The functions that are convenient and often used personally are as follows.
|*.version||Object is v4/v6 Determine which information you have. 4 for v4, 6 for v6|
|*.compressed||v4 is equivalent,v6 returns a shorthand string|
|*.exploded||v4 is equivalent,v6 returns a string with 0 not omitted|
|*.is_link_local||True if it is a link-local reserved address in RFC3927|
|.with_with_prefixlen||prefix Returns a long-format address as a string(10.10.10.1/24 mag)|
|.with_with_netmask||Returns a network mask format address as a string type(10.10.10.1 255.255.255.0 mag)|
You can also use various operators.
When incrementing the IP address, simply add the
- operators to the ip address module and describe the value, and the digit ups and downs will be handled arbitrarily.
The following is a sample execution example.
#! /usr/bin/env python # -*- coding: utf-8 -*- import ipaddress if __name__ == "__main__": ip = ipaddress.ip_address('10.2.3.4') nw = ipaddress.ip_network('10.0.0.0/8') if ip in nw: #It is possible to determine whether it is included in the network address with one line of ip in network print ("%s is included %s ."%(ip, nw)) else : print ("%s isn't included %s ."%(ip, nw)) print ("="*15) ip = ipaddress.ip_address('10.2.3.255') ipv6 = ipaddress.ip_address('fd00:260:301:104::104:1') ex_ipv6 = ipaddress.ip_address('fd00:0260:0301:0104:0000:0000:0104:1') #ipv4/v6 Check which address is stored print ("%s is IPv%d"%(ip,ip.version)) print ("%s is IPv%d"%(ipv6,ipv6.version)) print ("="*15) #Address increment ip = ip + 1 ipv6 = ipv6 -2 print ("increment ipv4 : %s"%ip) print ("decrement ipv6 : %s"%ipv6) print ("="*15) #Abbreviated and non-abbreviated conversion of ipv6 print ("exploded ipv6 : %s"%ipv6.exploded) print ("compressed ipv6 : %s"%ex_ipv6.compressed) print ("="*15) #Determining if it is a link local address print ("%s is linklocal : %s"%(ipv6,ipv6.is_link_local)) ipv6_ll = ipaddress.ip_address('fe80::104:1') print ("%s is linklocal : %s"%(ipv6_ll,ipv6_ll.is_link_local))
% python3 ipaddress_sample.py 10.2.3.4 is included 10.0.0.0/8 . =============== 10.2.3.255 is IPv4 fd00:260:301:104::104:1 is IPv6 =============== increment ipv4 : 10.2.4.0 decrement ipv6 : fd00:260:301:104::103:ffff =============== exploded ipv6 : fd00:0260:0301:0104:0000:0000:0103:ffff compressed ipv6 : fd00:260:301:104::104:1 =============== fd00:260:301:104::103:ffff is linklocal : False fe80::104:1 is linklocal : True
As you can see from the above, the ip_address and ip_network functions determine the processing of ipv4 / v6. If you use this module, you can save a lot of time and effort to separate the processing cases between ipv4 and ipv6.
This module was very useful for me at such times
In such a case. The ipaddress module plays an active part in the interface and BGP mapping phase by parsing the config and extracting the information. Suppose you parse a config like the one below
interface TenGigE0/0/0/0 ipv4 address 10.10.10.10 255.255.255.0 ipv6 nd suppress-ra ipv6 address fe80::222:1 link-local ipv6 address fd00:260:301:222::222:1/64 ! ....Snip.... router bgp 64540 neighbor 10.10.10.200 remote-as 64601 description "TEST-BGP-CONFIGURE" address-family ipv4 unicast route-policy as64601-sample in route-policy as64601-sample out next-hop-self soft-reconfiguration inbound always ! ! neighbor fd00:260:301:222::333:123 remote-as 64601 description "TEST-IPV6-BGP-CONFIGURE" address-family ipv6 unicast route-policy as64601-sample in route-policy as64601-sample out next-hop-self soft-reconfiguration inbound always ! !
This time, I will omit the method of parsing this config well because it is not the main point. First, parse the Interface config and retain the Interface information. Next, the Neighbor information is extracted, and if the Neighbor address is included in the Interface information, it is associated with the Interface.
For the mapping part, the same code was presented as a sample in the above, but It is possible to distinguish with just this description. (Since the perspective part is omitted, the IP is directly hitting the same address as the config)
neighbor = ipaddress.ip_address('fd00:260:301:222::333:123') #Neighbor IP interface = ipaddress.ip_interface('fd00:260:301:222::222:1/64') #Interface IP # interface.Compare after converting to network network address with network if neighbor in interface.network: print ("%s is included %s ."%(neighbor, interface)) else : print ("%s isn't included %s ."%(neighbor, interface))
fd00:260:301:222::333:123 is included fd00:260:301:222::222:1/64 .
When you look for these useful modules, they are often installed as standard or are made by third parties. It's okay to implement it with difficulty, but in fact it was possible to implement it immediately using more convenient functions. Often there is. It's not a bad thing to implement everything yourself, but if you find something convenient and suitable for your purpose, it's much faster to implement it. Don't be too enthusiastic about mounting, and make sure to "investigate".
It may be obvious, but I will write it here as a self-discipline (laugh)