What's the best way to validate that an IP entered by the user is valid? It comes in as a string.
-
I just want to point out that if a broadcast address is not considered a valid address, then every single one of the solutions suggested so far fail. You have to test against a subnet mask to see if it is a broadcast address. – Bitt Oct 10 '14 at 10:12
-
`import ipaddress; ipaddress.ipaddress(your_input_text)` and catch the `ValueError`. It's in the stdlib. – Boris Verkhovskiy Nov 11 '19 at 19:33
11 Answers
Don't parse it. Just ask.
import socket
try:
socket.inet_aton(addr)
# legal
except socket.error:
# Not legal

- 89,080
- 21
- 111
- 133
-
23Hmm, seems to accept things like "4" and "192.168" and silently pads the rest with zeros. Technically valid, I'm sure, but not quite what I expected. – krupan Nov 25 '08 at 23:58
-
1Those are valid representations of IP addresses. 127.1 is localhost, 1172703390 is my web server. If you want to ensure it's in dotted quad, you can also verify that len(addr.split('.')) == 4 – Dustin Nov 26 '08 at 00:05
-
1@krupan: you could combine the above with a test for "len(addr.split(".")) == 4" if you would like to reject shorter addresses. – Greg Hewgill Nov 26 '08 at 00:13
-
6No, does not work with all legal IP addresses: >>> socket.inet_aton("2001:660::1") Traceback (most recent call last): File "
", line 1, in – bortzmeyer Dec 01 '08 at 10:53socket.error: illegal IP address string passed to inet_aton -
26@bortzmeyer: socket.inet_pton(socket_family, address) is what you want if you want to support ip6. You still need to specify the family. inet_aton specifically does not support anything but ip4. – richo May 26 '10 at 05:15
-
9It looks like Richo's response solves krupan and bortzmeyer's questions. Use socket.inet_pton with socket.AF_INET or socket.AF_INET6 as family to validate ipv4 and ipv6 without incomplete addresses being accepted. – freb Nov 23 '11 at 01:26
-
Now, there is an official way to manipulate IPv4 and Ipv6 address in python [PEP 3144](http://www.python.org/dev/peps/pep-3144/). See my answer above. – Yohann May 28 '12 at 10:41
-
9inet_aton() isn't accepting "invalid" IPs when it accepts "4", "192.168" and "127.1", it is merely using the underlying C behaviour - see the documentation. 127.1 puts 127 in the top octet and parses the 1 as a 24-bit number that it splits across the remaining three octets. The idea is to support /16 ranges that increment IPs, so you can go 172.16.1...172.16.255 and then 172.16.256, rather than having alter your maths to go to 172.16.1.0. – IBBoard Dec 07 '12 at 15:32
-
1@richo - `inet_pton` is only available on some variations of Unix, and it's not available on Windows at all. – ArtOfWarfare Jun 22 '15 at 18:07
-
-
1It is worth noting that there are security concerns with the socket module, which utilises the glibc inet_aton() function which "accepts trailing garbage for historical reasons", as reported here: https://bugzilla.redhat.com/show_bug.cgi?id=1347549. Red Had Product Security has rated this issue as having medium security impact and, as such, it's not likely to be addressed any time soon. Given this, I'd contend that a good regex is the the best tool for this. – aitch-hat Apr 04 '17 at 16:17
-
-
@MartinThoma from the [inet](https://man7.org/linux/man-pages/man3/inet.3.html) man page, "The value a is interpreted as a 32-bit value that is stored directly into the binary address without any byte rearrangement" – Brad Solomon Nov 01 '20 at 16:26
-
From Python 3.4 on, the best way to check if an IPv6 or IPv4 address is correct, is to use the Python Standard Library module ipaddress
- IPv4/IPv6 manipulation library s.a. https://docs.python.org/3/library/ipaddress.html for complete documentation.
Example :
#!/usr/bin/env python
import ipaddress
import sys
try:
ip = ipaddress.ip_address(sys.argv[1])
print('%s is a correct IP%s address.' % (ip, ip.version))
except ValueError:
print('address/netmask is invalid: %s' % sys.argv[1])
except:
print('Usage : %s ip' % sys.argv[0])
For other versions: Github, phihag / Philipp Hagemeister,"Python 3.3's ipaddress for older Python versions", https://github.com/phihag/ipaddress
The backport from phihag is available e.g. in Anaconda Python 2.7 & is included in Installer. s.a. https://docs.continuum.io/anaconda/pkg-docs
To install with pip:
pip install ipaddress
s.a.: ipaddress 1.0.17, "IPv4/IPv6 manipulation library", "Port of the 3.3+ ipaddress module", https://pypi.python.org/pypi/ipaddress/1.0.17

- 6,047
- 3
- 26
- 33
-
I'm getting this error `C:\Python\Codes>check_ip.py File "C:\Python\Codes\check_ip.py", line 8 print '%s is a correct IP%s address.' % (ip, ip.version) ^ SyntaxError: invalid syntax C:\Python\Codes>` – Mar 10 '18 at 03:49
-
2Thanks @Yohann. For Python 3.5, parenthesis is required on print. Else, the code will produce an error. Since this space is limited, I'll update the code on answer section below. Hope this will helps others too. – Mar 10 '18 at 05:45
-
This will return incorrect response for `test.example.com`. I got `IPv6Address(u'7465:7374:2e65:7861:6d70:6c65:2e63:6f6d')` – SharkIng Jun 22 '20 at 21:02
-
Sorry, newb here. What role does `sys.argv[0]/[1]` play in this example? Are these just test parameters (sample IP addresses) you are passing when firing the script or are they required when implementing? From reading [here](https://www.geeksforgeeks.org/how-to-use-sys-argv-in-python/), seems like they are just test params. – ericOnline Feb 17 '21 at 19:48
import socket
def is_valid_ipv4_address(address):
try:
socket.inet_pton(socket.AF_INET, address)
except AttributeError: # no inet_pton here, sorry
try:
socket.inet_aton(address)
except socket.error:
return False
return address.count('.') == 3
except socket.error: # not a valid address
return False
return True
def is_valid_ipv6_address(address):
try:
socket.inet_pton(socket.AF_INET6, address)
except socket.error: # not a valid address
return False
return True

- 18,626
- 15
- 91
- 127

- 92,761
- 29
- 141
- 204
-
1Why the line: "return address.count('.') == 3" ?? Is that left over from your debugging? – quux Dec 15 '10 at 15:32
-
21@quux: no. It's a long discussion, and people don't like the fact that at least on Linux and Windows shortened addresses are considered acceptable. For example, `socket.inet_aton('127.1')` evaluates to `'\x7f\x00\x00\x01'` (i.e. exactly like '127.0.0.1' does). I've had this tiresome and lengthy discussion elsewhere on SO, can't bother to remember where, though. – tzot Dec 15 '10 at 19:44
-
2
-
-
2@cowlinator `inet_pton` exists only in Unix, and `inet_aton` exists in all platforms, so this is a “unix-mostly” answer. – tzot Feb 26 '18 at 10:11
The IPy module (a module designed for dealing with IP addresses) will throw a ValueError exception for invalid addresses.
>>> from IPy import IP
>>> IP('127.0.0.1')
IP('127.0.0.1')
>>> IP('277.0.0.1')
Traceback (most recent call last):
...
ValueError: '277.0.0.1': single byte must be 0 <= byte < 256
>>> IP('foobar')
Traceback (most recent call last):
...
ValueError: invalid literal for long() with base 10: 'foobar'
However, like Dustin's answer, it will accept things like "4" and "192.168" since, as mentioned, these are valid representations of IP addresses.
If you're using Python 3.3 or later, it now includes the ipaddress module:
>>> import ipaddress
>>> ipaddress.ip_address('127.0.0.1')
IPv4Address('127.0.0.1')
>>> ipaddress.ip_address('277.0.0.1')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.3/ipaddress.py", line 54, in ip_address
address)
ValueError: '277.0.0.1' does not appear to be an IPv4 or IPv6 address
>>> ipaddress.ip_address('foobar')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.3/ipaddress.py", line 54, in ip_address
address)
ValueError: 'foobar' does not appear to be an IPv4 or IPv6 address
For Python 2, you can get the same functionality using ipaddress if you install python-ipaddress:
pip install ipaddress
This module is compatible with Python 2 and provides a very similar API to that of the ipaddress module included in the Python Standard Library since Python 3.3. More details here. In Python 2 you will need to explicitly convert the IP address string to unicode: ipaddress.ip_address(u'127.0.0.1')
.

- 8,713
- 7
- 76
- 161

- 15,758
- 4
- 20
- 13
-
Excellent idea. The only solution presented until now which works with all IP addresses. >>> from IPy import IP >>> IP("2001:660::1") IP('2001:660::1') – bortzmeyer Dec 01 '08 at 10:56
-
-
Regarding `import ipaddress`, when I passed an IPv4 address, I got output like `IPv4Address('127.0.0.1')`. But when I tried to convert it to `string` to check if it contains `IPv4` or `IPv6`, I just got the IP. How can I know in code if it is a `IPv4` or `IPv6`? Is `if "IPv4" in str(type(val)):` a good idea? – Aakash Goyal Jun 15 '16 at 07:39
-
Use the exact same steps and got `ipaddress.AddressValueError: '127.0.0.1' does not appear to be a n IPv4 or IPv6 address. Did you pass in a bytes (str in Python 2) instead of a unicode object?`. The help presented in the error message helped me fix the issue. You need `u'...'` in Python 2. – rbaleksandar Mar 05 '18 at 09:38
-
1The solution is as simple as this: `try: return bool(ipaddress.ip_address(ip)) except ValueError: return False` – Hett Dec 25 '19 at 15:14
def is_valid_ip(ip):
"""Validates IP addresses.
"""
return is_valid_ipv4(ip) or is_valid_ipv6(ip)
IPv4:
def is_valid_ipv4(ip):
"""Validates IPv4 addresses.
"""
pattern = re.compile(r"""
^
(?:
# Dotted variants:
(?:
# Decimal 1-255 (no leading 0's)
[3-9]\d?|2(?:5[0-5]|[0-4]?\d)?|1\d{0,2}
|
0x0*[0-9a-f]{1,2} # Hexadecimal 0x0 - 0xFF (possible leading 0's)
|
0+[1-3]?[0-7]{0,2} # Octal 0 - 0377 (possible leading 0's)
)
(?: # Repeat 0-3 times, separated by a dot
\.
(?:
[3-9]\d?|2(?:5[0-5]|[0-4]?\d)?|1\d{0,2}
|
0x0*[0-9a-f]{1,2}
|
0+[1-3]?[0-7]{0,2}
)
){0,3}
|
0x0*[0-9a-f]{1,8} # Hexadecimal notation, 0x0 - 0xffffffff
|
0+[0-3]?[0-7]{0,10} # Octal notation, 0 - 037777777777
|
# Decimal notation, 1-4294967295:
429496729[0-5]|42949672[0-8]\d|4294967[01]\d\d|429496[0-6]\d{3}|
42949[0-5]\d{4}|4294[0-8]\d{5}|429[0-3]\d{6}|42[0-8]\d{7}|
4[01]\d{8}|[1-3]\d{0,9}|[4-9]\d{0,8}
)
$
""", re.VERBOSE | re.IGNORECASE)
return pattern.match(ip) is not None
IPv6:
def is_valid_ipv6(ip):
"""Validates IPv6 addresses.
"""
pattern = re.compile(r"""
^
\s* # Leading whitespace
(?!.*::.*::) # Only a single whildcard allowed
(?:(?!:)|:(?=:)) # Colon iff it would be part of a wildcard
(?: # Repeat 6 times:
[0-9a-f]{0,4} # A group of at most four hexadecimal digits
(?:(?<=::)|(?<!::):) # Colon unless preceeded by wildcard
){6} #
(?: # Either
[0-9a-f]{0,4} # Another group
(?:(?<=::)|(?<!::):) # Colon unless preceeded by wildcard
[0-9a-f]{0,4} # Last group
(?: (?<=::) # Colon iff preceeded by exacly one colon
| (?<!:) #
| (?<=:) (?<!::) : #
) # OR
| # A v4 address with NO leading zeros
(?:25[0-4]|2[0-4]\d|1\d\d|[1-9]?\d)
(?: \.
(?:25[0-4]|2[0-4]\d|1\d\d|[1-9]?\d)
){3}
)
\s* # Trailing whitespace
$
""", re.VERBOSE | re.IGNORECASE | re.DOTALL)
return pattern.match(ip) is not None
The IPv6 version uses "(?:(?<=::)|(?<!::):)
", which could be replaced with "(?(?<!::):)
" on regex engines that support conditionals with look-arounds. (i.e. PCRE, .NET)
Edit:
- Dropped the native variant.
- Expanded the regex to comply with the RFC.
- Added another regex for IPv6 addresses.
Edit2:
I found some links discussing how to parse IPv6 addresses with regex:
- A Regular Expression for IPv6 Addresses - InterMapper Forums
- Working IPv6 regular expression - Patrick’s playground blog
- test-ipv6-regex.pl - Perl script with tons of test-cases. It seems my regex fails on a few of those tests.
Edit3:
Finally managed to write a pattern that passes all tests, and that I am also happy with.

- 1
- 1

- 86,735
- 21
- 136
- 138
-
1
-
-
Doesn't seem to work with IPv6 addresses which make use of square brackets (e.g. to specify a port number): `[2001:4860:4860::8888]:80` – winklerrr Apr 24 '19 at 12:05
-
1I think this way is highly non-pythonic and overly complicated. Using simple call from ipaddress.ip_address should be enough. – Hett Dec 25 '19 at 15:13
I hope it's simple and pythonic enough:
def is_valid_ip(ip):
m = re.match(r"^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$", ip)
return bool(m) and all(map(lambda n: 0 <= int(n) <= 255, m.groups()))

- 9,962
- 1
- 33
- 22
-
-
8
-
2@warfaresthat is for a reason, it needs the groups separated in order to check if the values are in the range 0 and 255, that's what the second part of the return is doing, if you want to use your regex use return bool(m) only. – alsotoes May 29 '19 at 23:11
I think this would do it...
def validIP(address):
parts = address.split(".")
if len(parts) != 4:
return False
for item in parts:
if not 0 <= int(item) <= 255:
return False
return True

- 14,201
- 3
- 42
- 77
-
2You may want to catch the ValueError exception from int() in case the user types "a.b.c.d" and not integers. – Greg Hewgill Nov 26 '08 at 00:05
-
9
-
3Python's int() coercion is too lax here; for example, it strips spaces. – Daira Hopwood Nov 20 '11 at 00:45
-
2
-
1
Consider IPv4 address as "ip".
if re.match(r'^((\d{1,2}|1\d{2}|2[0-4]\d|25[0-5])\.){3}(\d{1,2}|1\d{2}|2[0-4]\d|25[0-5])$', ip):
print("Valid IP")
else:
print("Invalid IP")

- 3
- 2

- 179
- 2
- 3
I have to give a great deal of credit to Markus Jarderot for his post - the majority of my post is inspired from his.
I found that Markus' answer still fails some of the IPv6 examples in the Perl script referenced by his answer.
Here is my regex that passes all of the examples in that Perl script:
r"""^
\s* # Leading whitespace
# Zero-width lookaheads to reject too many quartets
(?:
# 6 quartets, ending IPv4 address; no wildcards
(?:[0-9a-f]{1,4}(?::(?!:))){6}
(?:25[0-4]|2[0-4]\d|1\d\d|[1-9]\d|\d)
(?:\.(?:25[0-4]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}
|
# 0-5 quartets, wildcard, ending IPv4 address
(?:(?:[0-9a-f]{1,4}(?::(?!:))){0,4}[0-9a-f]{1,4})?
(?:::(?!:))
(?:25[0-4]|2[0-4]\d|1\d\d|[1-9]\d|\d)
(?:\.(?:25[0-4]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}
|
# 0-4 quartets, wildcard, 0-1 quartets, ending IPv4 address
(?:(?:[0-9a-f]{1,4}(?::(?!:))){0,3}[0-9a-f]{1,4})?
(?:::(?!:))
(?:[0-9a-f]{1,4}(?::(?!:)))?
(?:25[0-4]|2[0-4]\d|1\d\d|[1-9]\d|\d)
(?:\.(?:25[0-4]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}
|
# 0-3 quartets, wildcard, 0-2 quartets, ending IPv4 address
(?:(?:[0-9a-f]{1,4}(?::(?!:))){0,2}[0-9a-f]{1,4})?
(?:::(?!:))
(?:[0-9a-f]{1,4}(?::(?!:))){0,2}
(?:25[0-4]|2[0-4]\d|1\d\d|[1-9]\d|\d)
(?:\.(?:25[0-4]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}
|
# 0-2 quartets, wildcard, 0-3 quartets, ending IPv4 address
(?:(?:[0-9a-f]{1,4}(?::(?!:))){0,1}[0-9a-f]{1,4})?
(?:::(?!:))
(?:[0-9a-f]{1,4}(?::(?!:))){0,3}
(?:25[0-4]|2[0-4]\d|1\d\d|[1-9]\d|\d)
(?:\.(?:25[0-4]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}
|
# 0-1 quartets, wildcard, 0-4 quartets, ending IPv4 address
(?:[0-9a-f]{1,4}){0,1}
(?:::(?!:))
(?:[0-9a-f]{1,4}(?::(?!:))){0,4}
(?:25[0-4]|2[0-4]\d|1\d\d|[1-9]\d|\d)
(?:\.(?:25[0-4]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}
|
# wildcard, 0-5 quartets, ending IPv4 address
(?:::(?!:))
(?:[0-9a-f]{1,4}(?::(?!:))){0,5}
(?:25[0-4]|2[0-4]\d|1\d\d|[1-9]\d|\d)
(?:\.(?:25[0-4]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}
|
# 8 quartets; no wildcards
(?:[0-9a-f]{1,4}(?::(?!:))){7}[0-9a-f]{1,4}
|
# 0-7 quartets, wildcard
(?:(?:[0-9a-f]{1,4}(?::(?!:))){0,6}[0-9a-f]{1,4})?
(?:::(?!:))
|
# 0-6 quartets, wildcard, 0-1 quartets
(?:(?:[0-9a-f]{1,4}(?::(?!:))){0,5}[0-9a-f]{1,4})?
(?:::(?!:))
(?:[0-9a-f]{1,4})?
|
# 0-5 quartets, wildcard, 0-2 quartets
(?:(?:[0-9a-f]{1,4}(?::(?!:))){0,4}[0-9a-f]{1,4})?
(?:::(?!:))
(?:(?:[0-9a-f]{1,4}(?::(?!:))){0,1}[0-9a-f]{1,4})?
|
# 0-4 quartets, wildcard, 0-3 quartets
(?:(?:[0-9a-f]{1,4}(?::(?!:))){0,3}[0-9a-f]{1,4})?
(?:::(?!:))
(?:(?:[0-9a-f]{1,4}(?::(?!:))){0,2}[0-9a-f]{1,4})?
|
# 0-3 quartets, wildcard, 0-4 quartets
(?:(?:[0-9a-f]{1,4}(?::(?!:))){0,2}[0-9a-f]{1,4})?
(?:::(?!:))
(?:(?:[0-9a-f]{1,4}(?::(?!:))){0,3}[0-9a-f]{1,4})?
|
# 0-2 quartets, wildcard, 0-5 quartets
(?:(?:[0-9a-f]{1,4}(?::(?!:))){0,1}[0-9a-f]{1,4})?
(?:::(?!:))
(?:(?:[0-9a-f]{1,4}(?::(?!:))){0,4}[0-9a-f]{1,4})?
|
# 0-1 quartets, wildcard, 0-6 quartets
(?:[0-9a-f]{1,4})?
(?:::(?!:))
(?:(?:[0-9a-f]{1,4}(?::(?!:))){0,5}[0-9a-f]{1,4})?
|
# wildcard, 0-7 quartets
(?:::(?!:))
(?:(?:[0-9a-f]{1,4}(?::(?!:))){0,6}[0-9a-f]{1,4})?
)
(?:/(?:1(?:2[0-7]|[01]\d)|\d\d?))? # With an optional CIDR routing prefix (0-128)
\s* # Trailing whitespace
$"""
I also put together a Python script to test all of those IPv6 examples; it's here on Pastebin because it was too large to post here.
You can run the script with test result and example arguments in the form of "[result]=[example]", so like:
python script.py Fail=::1.2.3.4: pass=::127.0.0.1 false=::: True=::1
or you can simply run all of the tests by specifying no arguments, so like:
python script.py
Anyway, I hope this helps somebody else!

- 119
- 2
- 6
-
4Although I admire your effort as well, I think there's a huge design flaw in your construct: It's way too big! I would never trust a regex of this size that was not used by thousands of people for years. – erikbstack Apr 16 '14 at 12:05
-
1@erikb85: Take a look at the script I posted to Pastebin. It contains 1154 tests of different IPv6 formats, and it passes **every single one** of them. If you think more tests are necessary, feel free to modify my script, add tests, and post the results. – blag May 24 '14 at 09:36
-
I found out that simply doing `ipaddress.IPv6Address(my_addr)` also matches every test case result you posted so if you have Python 3.3+ you can use that... note that the corresponding IPv4 function was not so great and failed a number of (different) test cases involving leading zeros... – user9645 Nov 29 '22 at 18:16
I came up with this simple version
def ip_checkv4(ip):
parts=ip.split(".")
if len(parts)<4 or len(parts)>4:
return "invalid IP length should be 4 not greater or less than 4"
else:
while len(parts)== 4:
a=int(parts[0])
b=int(parts[1])
c=int(parts[2])
d=int(parts[3])
if a<= 0 or a == 127 :
return "invalid IP address"
elif d == 0:
return "host id should not be 0 or less than zero "
elif a>=255:
return "should not be 255 or greater than 255 or less than 0 A"
elif b>=255 or b<0:
return "should not be 255 or greater than 255 or less than 0 B"
elif c>=255 or c<0:
return "should not be 255 or greater than 255 or less than 0 C"
elif d>=255 or c<0:
return "should not be 255 or greater than 255 or less than 0 D"
else:
return "Valid IP address ", ip
p=raw_input("Enter IP address")
print ip_checkv4(p)

- 783
- 1
- 7
- 9
I only needed to parse IP v4 addresses. My solution based on Chills strategy follows:
def getIP():
valid = False
while not valid :
octets = raw_input( "Remote Machine IP Address:" ).strip().split(".")
try: valid=len( filter( lambda(item):0<=int(item)<256, octets) ) == 4
except: valid = False
return ".".join( octets )

- 1