5

Using python, I'd like to accomplish two things:

  1. Need to split an ipv6 address and port combination in the format [fec2::10]:80 to fec2::10 and 80.

  2. Given an IP address and port combination, I need to determine if the IP is a v4 or v6 address. Eg: 1.2.3.4:80 and [fec2::10]:80

Please suggest a way to do it.

Thanks!

Sample code:

#!/usr/bin/env python


def main():
    server = "[fec1::1]:80"
    if server.find("[", 0, 2) == -1:
       print "IPv4"
       ip, port = server.split(':')
    else:
       print "IPv6"
       new_ip, port = server.rsplit(':', 1)
       print new_ip
       ip = new_ip.strip('[]')

    print ip
    print port

if __name__ == '__main__':
    main()

This works for all cases except when the input is specified without a port. Eg: 10.78.49.50 and [fec2::10]

Any suggestions to address this?

2
  • 1
    So what is the problem? Commented Feb 20, 2014 at 12:56
  • My bash and python scripts would receive the IP:port combination as input and the scripts need to determine the address family of the IP, followed by splitting the IP and port. Commented Feb 21, 2014 at 3:17

4 Answers 4

5

Assuming your_input is like "[fec2::10]:80" or "1.2.3.4:80", it is easy to split the port and find out the ip address:

#!/usr/bin/env python3
from ipaddress import ip_address

ip, separator, port = your_input.rpartition(':')
assert separator # separator (`:`) must be present
port = int(port) # convert to integer
ip = ip_address(ip.strip("[]")) # convert to `IPv4Address` or `IPv6Address` 
print(ip.version) # print ip version: `4` or `6`
Sign up to request clarification or add additional context in comments.

9 Comments

The ipaddress module is only new as of 3.3, what if someone is running an earlier version of python? I do think that finding the version is simpler this way, though, don't get me wrong. :)
@2rs2ts: you could use ipaddr-py on earlier versions.
Ah, nice to know. It's still not part of the standard modules, though.
@J.F.Sebastian: I'm unable to use both ipaddress and ipaddr-py modules in my script. For ipaddress, it says: Traceback (most recent call last): File "./ip_parse.py", line 4, in <module> from ipaddress import ip_address ImportError: No module named ipaddress from ipaddress import ip_address
...and for ipaddr-py, it says: File "./ip_parse.py", line 5 from ipaddr-py import ip_address ^ SyntaxError: invalid syntax
|
3

You can use urlparse (called urllib.parse in 3.x) to separate the URL into each of its components:

>>> from urlparse import urlparse
>>> ipv4address = urlparse("http://1.2.3.4:80")
>>> ipv4address
ParseResult(scheme='http', netloc='1.2.3.4:80', path='', params='', query='', fragment='')
>>> ipv6address = urlparse("http://[fec2::10]:80")
>>> ipv6address
ParseResult(scheme='http', netloc='[fec2::10]:80', path='', params='', query='', fragment='')

Then you can split the port off by finding the index of the last colon using rfind:

>>> ipv4address.netloc.rfind(':')
7
>>> ipv4address.netloc[:7], ipv4address.netloc[8:]
('1.2.3.4', '80')
>>> ipv6address.netloc.rfind(':')
10
>>> ipv6address.netloc[:10], ipv6address.netloc[11:]
('[fec2::10]', '80')

Identifying which type it is should then be as simple as if ':' in that_split_tuple[0], right? (Not 100% sure because it's been a while since I learned about how to write IPv6 addresses in URLs.)

Finally, removing the brackets from your IPv6 address is simple, there are many ways to do it:

>>> ipv6address.netloc[:10].replace('[', '').replace(']', '')
'fec2::10'
>>> ipv6address.netloc[:10].strip('[]')
'fec2::10'

Edit: since you expressed concern about not always having port numbers, you could simplify significantly by using a regular expression:

>>> import re
>>> f = lambda(n): re.split(r"(?<=\]):" if n.startswith('[') else r"(?<=\d):", n)
>>> f(ipv4address.netloc)
['1.2.3.4', '80']
>>> f(ipv6address.netloc)
['[fec2::10]', '80']
>>> f("1.2.3.4")
['1.2.3.4']
>>> f("[fec2::10]")
['[fec2::10]']

(I'm having trouble being more clever with my regular expression, hence the inline ternary.)

4 Comments

I've added a module-independent code that I wrote, to my question. It is incomplete. Any suggestions for it?
@Maddy Well, at this point I'll write a regular expression for you, but you need to tell me if you're always going to get brackets around your IPv6 addresses, and whether you're going to use hybrid addresses e.g. ::ffff:1.2.3.4.
Almost perfect answer, missing a couple things: 1. no need to parse netloc manually and no need for any evil regular expression: urlparse('//[::1]:123').hostname -> '::1' urlparse('//[::1]').port -> None. 2. No need for a full http://, the urllib documentation states that // is enough.
3. Again no evil regular expression for this: ipaddress.ip_address('::1') -> IPv6Address('::1')
0

This is the code I came up with. It looks lengthy and laborious, but it addresses all possible input scenarios. Any suggestion to condense/better it is most welcome :)

#!/usr/bin/env python

import optparse

def main():
    server = "[fec1::1]:80"

    if server.find("[", 0, 2) == -1:
       print "IPv4"
       if server.find(":", 0, len(server)) == -1:
          ip = server
          port = ""
       else:
          ip, port = server.split(':')
    else:
       print "IPv6"
       index = server.find("]", 0, len(server))
       if index == -1:
          print "Something wrong"
          new_ip = ""
          port = ""
       else:
          if server.find(":", index, len(server)) == -1:
             new_ip = server
             port = ""
          else:
             new_ip, port = server.rsplit(':', 1)
       print new_ip
       ip = new_ip.strip('[]')

    print ip
    print port

if __name__ == '__main__':
    main()

Comments

0

ip, port = server.rsplit(':', 1) suited for IPv4 and IPv6!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.