Learn through the super-clean Baeldung Pro experience:
>> Membership and Baeldung Pro.
No ads, dark-mode and 6 months free of IntelliJ Idea Ultimate to start with.
Last updated: March 18, 2024
Validating an Internet Protocol (IP) address in networking can serve a useful role in automation such as when allocating resources based on IP addresses. It can also help prevent errors and security exploitation that relies on manipulating IP addresses.
In this tutorial, we’ll explore how to validate both an IPv4 and IPv6 address in Linux.
An IPv4 address consists of 32 bits which are divided into four segments or bytes. We often represent these segments in dotted decimal notation for better readability. Therefore, an IP address takes on the form A.B.C.D, where the integer values A, B, C, and D fall in the range 0-255.
Importantly, the validation procedure we apply doesn’t allow for leading zeros in any segment that exceeds a single digit. Therefore, addresses such as 192.168.09.1 or 192.168.045.000 are considered invalid. This prevents ambiguity and ensures that parsers won’t treat any segment incorrectly as octal. Additionally, it avoids the problem of dealing with a variable number of leading zeros.
Let’s explore how we can validate an IPv4 address in Linux.
One approach to validating an IPv4 address consists of three subtasks:
We can implement this procedure in a Bash script named valid_ipv4.sh:
$ cat valid_ipv4.sh
#!/usr/bin/env bash
valid_ipv4() {
local ip="$1"
err_msg='IP address is invalid'
[[ "$ip" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]] || { echo "$err_msg"; return 1; }
for i in ${ip//./ }; do
[[ "${#i}" -gt 1 && "${i:0:1}" == 0 ]] && { echo "$err_msg"; return 1; }
[[ "$i" -gt 255 ]] && { echo "$err_msg"; return 1; }
done
echo 'IP address is valid'
}
The script defines a function named valid_ipv4() whose first argument is saved in the ip variable. Then, the variable is matched against the ^([0-9]{1,3}\.){3}[0-9]{1,3}$ regex pattern using the [[]] construct:
If the ip variable doesn’t match the regex, we print a message indicating IP address is invalid, and the function exits. Otherwise, we split the four segments in the ip variable using ${ip//./ } which globally transforms each dot into a space character.
Then, we iterate through the four segments to perform checks over the segments:
If a segment meets one of these conditions, we print an IP address is invalid message and exit the function. Otherwise, we consider the IP address to be valid.
Next, we source the script to make the function available:
$ . ./valid_ipv4.sh
Finally, we test the function against a few examples:
$ valid_ipv4 127.0.0.1
IP address is valid
$ valid_ipv4 192.168.09.1
IP address is invalid
$ valid_ipv4 325.42.5.17
IP address is invalid
We see that the last two IPv4 addresses are invalid.
Another approach to validating an IPv4 address is to use a single regex pattern which can define both the IP address form and the range of values its segments can assume.
To validate against the regex pattern, we can use the grep command:
$ echo '127.0.0.1' | grep -Eo '^(([1-9]?[0-9]|1[0-9][0-9]|2([0-4][0-9]|5[0-5]))\.){3}([1-9]?[0-9]|1[0-9][0-9]|2([0-4][0-9]|5[0-5]))$'
127.0.0.1
$ echo '192.168.09.1' | grep -Eo '^(([1-9]?[0-9]|1[0-9][0-9]|2([0-4][0-9]|5[0-5]))\.){3}([1-9]?[0-9]|1[0-9][0-9]|2([0-4][0-9]|5[0-5]))$'
$ echo '325.42.5.17' | grep -Eo '^(([1-9]?[0-9]|1[0-9][0-9]|2([0-4][0-9]|5[0-5]))\.){3}([1-9]?[0-9]|1[0-9][0-9]|2([0-4][0-9]|5[0-5]))$'
$
The -E option enables extended regex, while the -o option returns the exact regex match, if any.
We can break down the regex into several parts:
A segment can consist of any of the three patterns above. We also check that the first three segments are followed by a dot and that the last one is not.
Using grep, the IPv4 address gets printed only if there’s a match. Therefore, we see that the last two examples aren’t valid IPv4 addresses.
The ipaddress module in Python allows us to validate both IPv4 and IPv6 addresses. IPv6 addresses are particularly more difficult to validate because they can take on compressed forms with zeros omitted, or may include embedded IPv4 addresses within.
Therefore, while it’s still possible to validate an IPv6 address in Bash, the program logic might easily become convoluted. Additionally, while we can validate an IPv6 address against a single regular expression, the regex pattern is very lengthy and not easy to read.
Instead, let’s use the ipaddress module in a Python script named isipvalid.py to validate both IPv4 and IPv6 addresses:
$ cat isipvalid.py
#!/usr/bin/env python3
import ipaddress, sys
try:
ip = ipaddress.ip_address(sys.argv[1])
print(f'{ip} is an IPv{ip.version} address')
except ValueError:
print('Invalid IP address')
We first import the ipaddress module, in addition to the sys module to access the script’s first argument via sys.argv[1]. Then, we try to call the ip_address method over the argument and save the result in the ip variable. We also print the value of this variable along with its IP version using an f-string. In case the argument isn’t a valid IP address, then we handle the ValueError exception by printing a message indicating Invalid IP address.
Next, we grant the script execute permissions via chmod:
$ chmod +x isipvalid.py
Finally, we test the script against several IPv4 and IPv6 addresses:
$ ./isipvalid.py 127.0.0.1
127.0.0.1 is an IPv4 address
$ ./isipvalid.py 192.168.09.1
IP is invalid
$ ./isipvalid.py 325.42.5.17
IP is invalid
$ ./isipvalid.py 2345:1425:2BA2:0000:0000:0567:5673:23b5
2345:1425:2ba2::567:5673:23b5 is an IPv6 address
$ ./isipvalid.py 2001:db8::1
2001:db8::1 is an IPv6 address
$ ./isipvalid.py ::
:: is an IPv6 address
$ ./isipvalid.py ::H231
IP is invalid
Notably, out of all the examples, we see that 192.168.09.1, 325.42.5.17, and ::H231 are invalid IP addresses.
In this article, we explored several ways to validate IP addresses in Linux. In particular, we saw methods for validating an IPv4 address using either a Bash script or a single regular expression. We also explored how to validate both IPv4 and IPv6 addresses using the ipaddress module in Python.