How to determine if a string contains a validate IP address in C
Any valid IP address consists of four numbers separated by three period (.) characters and each number ranges from 0-255 inclusive. An example IP address is “125.231.167.234″. The string function sscanf can be used to extract the four numbers and then validate each number for the range 0-255. Then use strcmp to further validate with reconstructed ip string.
The following function returns 0 if the IP address is invalid and 1 if valid.
int is_valid_ip(const char *ip_str)
{
unsigned int n1,n2,n3,n4;
if(sscanf(ip_str,"%u.%u.%u.%u", &n1, &n2, &n3, &n4) != 4) return 0;
if((n1 != 0) && (n1 <= 255) && (n2 <= 255) && (n3 <= 255) && (n4 <= 255)) {
char buf[64];
sprintf(buf,"%u.%u.%u.%u",n1,n2,n3,n4);
if(strcmp(buf,ip_str)) return 0;
return 1;
}
return 0;
}
Download: validate-ip.c
The output will be as follows if the code in validate-ip.c is executed.
[neo@techpulp ~]# gcc validate-ip.c -Wall -o validate-ip
[neo@techpulp ~]# ./validate-ip
------------------------------------------
IP Address Validation
------------------------------------------
1.1.1.1 VALID
255.255.255.255 VALID
0.123.234.12 INVALID
1.255.4.5 VALID
127.8.190.29 VALID
3hu23e832j2....wjdnw INVALID
3a.3b.2d.5t INVALID
-1.-1.-1.-1 INVALID
1.1.1.1.3 INVALID
------------------------------------------
[neo@techpulp ~]#


about 2 years ago
There’s some bugs in your code. The IP address 0.0.0.0 is valid, and sanitation check for the first octet being 0 is not checked.
Eg : 0.255.255.255 shows valid!
about 2 years ago
You are right! code is updated for the same.
about 2 years ago
It looks like it will validate addresses with more than 4 octets. The address 1.2.3.4.5 will return valid.
about 2 years ago
I have added more code to validate the ip string further. Basic idea is to compare the input ip string with reconstructed ip string from the parsed values. This additional check should identify any unwanted characters.
about 2 years ago
Nice, thanks. I fiddled with it and came up with this solution before I read yours:
…
unsigned int n5;
if(sscanf(ip_str,”%u.%u.%u.%u.%u”, &n1, &n2, &n3, &n4, &n5) != 4) return 0;
…
Basically adding one more unsigned int, and if the sscanf returns 5, it bombs out.
Thanks for this! I would have come up with a WAY more complicated method. You saved me a few hours!
about 2 years ago
How about my version of the same function. It uses standard inet_aton() to validate partially.
int is_valid_ip(const char *ip_str)
{
int rv;
unsigned long ip;
unsigned char *p;
rv = inet_aton(ip_str,(struct in_addr*)&ip);
if(rv) {
p = (unsigned char*) &ip;
if(p[0] != 0) return 1;
}
return 0;
}
about 2 years ago
If you see man page of inet_aton, it says that a string of pattern “a.b.c.d”, “a.b.c”, “a.b” and “a” are considered valid. In that case your function is going to return VALID for an ip “1.2.3″, “1.2″ and 1.
about 2 years ago
Well..in that case you can add reconstruction of ip string and comparison with the original ip string.
about 2 years ago
Hey. I think there is a problem with the function.
if you give it a large string of the form 1.2.3.498471294712987….. (very long string) it will take a very long time to (in)validate it since scanf will read until it reaches a termination character. Since the last number is so large it the result of scanf might be unpredictable and it may even validate such strings. I recently implemented such a function and used a finite automaton to catch all the error cases. The alternative is using regexp’s but I am not familiar with C support for them. It might be possible to use such an expression is scanf.
about 2 years ago
Sorry, the above version contains 2 bugs and I don’t know how to delete the post. I will post the updated version. I intentionally avoided using functions such as atoi in order to have full control of the complexity (to avoid parsing large strings). Here is my final version:
int isValidIp(const char* str)
{
int i = 0; //string iterator
char buf[3] = {0};
int partcnt = 0;
int numdots = 0;
//start reading the input
for (;;i++)
{
//read a character from str => str[i]
//test that it is valid
if ((str[i] '9') && str[i] != '.' && str[i] != '')
{
return FALSE;
}
//str[i] is a valid character
//if it is a number 0-9
if( str[i] >= '0' && str[i] = 3)
{
return FALSE;
}
//add it to the buffer
buf[partcnt] = str[i];
partcnt++;
continue;
}
//if we are at a dot or the end
if (str[i] == '.')
{
//check that we have a valid number of chars in buff.
//they are sureley valid numbers because they were verified in the condition above
if (partcnt == 0)
{
//no chars before dot, sorry
return FALSE;
}
//check validity of the buffer contents
int k;
int rank = 1;
int val = 0;
if (buf[0] == '0' && partcnt != 1)
{
return FALSE;
}
//first parse the number
for (k = partcnt-1; k>=0; k--)
{
val += ((buf[k] - '0') * rank);
rank *= 10;
}
//then check the val
if (val 255)
{
return FALSE;
}
//value is good then continue but do not forget to reset the buffer
partcnt = 0;
buf[0]=buf[1]=buf[2] = '';
numdots++;
if (numdots > 3)
{
return FALSE;
}
continue;
}
//final case
if (str[i] == '')
{
if (numdots != 3)
{
return FALSE;
}
if (partcnt == 0)
{
return FALSE;
}
//check validity of the buffer contents
int k;
int rank = 1;
int val = 0;
if (buf[0] == '0' && partcnt != 1)
{
return FALSE;
}
//first parse the number
for (k = partcnt-1; k>=0; k--)
{
val += ((buf[k] - '0') * rank);
rank *= 10;
}
//then check the val
if (val 255)
{
return FALSE;
}
return TRUE;
}
}//endfor
}
about 2 years ago
I think Loteanu has a valid point about long inputs, but wouldn’t it be easier to just make a small modification to the sscanf format? Putting a number in the %u causes sscanf to look at a maximum of that many characters between the dots.
if(sscanf(ip_str,”%3u.%3u.%3u.%3u”, &n1, &n2, &n3, &n4) != 4) return 0;
I tried it in VS 2008 (had to replace sscanf with sscanf_s and sprintf with sprintf_s) and it seemed to work just find. To make the code just a bit more bulletproof, it might be good to use snprintf and strncmp instead of the standard functions.
about 1 year ago
Hi
Thanks for sharing your code.
Why do you copy into buf in “sprintf” statement ? and compare that with ip_str ??
in your code, you does not change ip_str!
about 1 year ago
coz without that the following IP string will be considered valid.
02.03.05.23 VALID