Created
September 21, 2012 21:28
-
-
Save jlyo/3764025 to your computer and use it in GitHub Desktop.
Ragel IPv4/6 address validator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdbool.h> | |
#include <string.h> | |
#include <stdlib.h> | |
#include <sys/socket.h> | |
#include <netdb.h> | |
%%{ | |
machine isip; | |
octet4 = [0-9]{1,2} | |
| [0-1] . [0-9]{2} | |
| '2' . [0-4] . [0-9] | |
| '2' . '5' . [0-5]; | |
netmask = [0-9] | |
| [0-2] . [0-9] | |
| '3' . [0-2]; | |
zero = '0'{1,3}; | |
dqnetmaskoctet = '255' | |
| '254' | |
| '252' | |
| '248' | |
| '240' | |
| '224' | |
| '192' | |
| '128' | |
| zero; | |
dqnetmask = '255.'{3} dqnetmaskoctet | |
| '255.'{2} dqnetmaskoctet ('.' zero){1} | |
| '255.'{1} dqnetmaskoctet ('.' zero){2} | |
| dqnetmaskoctet ('.' zero){3}; | |
ipv4 = (octet4 '.'){3} octet4; #('/' (netmask | dqnetmask))?; | |
short6 = xdigit{1,4}; | |
prefix = '/' ( [0-9]{1,2} | |
| '1' . [0-1] . [0-9] | |
| '12' . [0-8]); | |
ipv6 = ( (short6 ':'){7} short6 | |
| (short6 ':'){7} ':' short6? | |
| (short6 ':'){6} ':' ((short6 ':'){0,1} short6)? | |
| (short6 ':'){5} ':' ((short6 ':'){0,2} short6)? | |
| (short6 ':'){4} ':' ((short6 ':'){0,3} short6)? | |
| (short6 ':'){3} ':' ((short6 ':'){0,4} short6)? | |
| (short6 ':'){2} ':' ((short6 ':'){0,5} short6)? | |
| (short6 ':'){1} ':' ((short6 ':'){0,6} short6)? | |
| '::' ((short6 ':'){0,7} short6)?); # prefix?; | |
main := ( ipv4 | |
| ipv6 | |
) ; #| '[' ipv6 ']'); | |
}%% | |
%%write data; | |
static bool isip(const char *const s, const size_t len) | |
{ | |
const char *p = s; | |
const char *const pe = s + len; | |
int cs; | |
%%{ | |
write init; | |
write exec; | |
}%% | |
return cs != isip_error; | |
} | |
/** | |
* Get a canonical IP address | |
*/ | |
static int canonical_ip(const char *s, char *const host, size_t *const host_len) | |
{ | |
struct addrinfo *res; | |
int err = 0; | |
static const struct addrinfo HINTS = { | |
AI_V4MAPPED | AI_ADDRCONFIG | AI_NUMERICHOST, | |
AF_UNSPEC, | |
0, | |
0, | |
0, | |
NULL, | |
NULL, | |
NULL | |
}; | |
if ((err = getaddrinfo(s, NULL, &HINTS, &res)) != 0) { goto err0; } | |
if ((err = getnameinfo(res->ai_addr, res->ai_addrlen, host, *host_len, | |
NULL, 0, NI_NUMERICHOST)) != 0) { goto err1; } | |
*host_len = strlen(host); | |
freeaddrinfo(res); res = NULL; | |
return 0; | |
err1: | |
freeaddrinfo(res); res = NULL; | |
err0: | |
return err; | |
} | |
int main(const int argc, const char *argv[]) | |
{ | |
int i; | |
char *host = NULL; | |
size_t host_len = NI_MAXHOST; | |
for (i = 1; i < argc; ++i) { | |
host_len = NI_MAXHOST; | |
if ( (isip(argv[i], strlen(argv[i]))) | |
&& ((host = malloc(NI_MAXHOST)) != NULL) | |
&& (canonical_ip(argv[i], host, &host_len) == 0)) | |
{ | |
fwrite(host, 1, host_len, stdout); | |
printf("\n"); | |
free(host); host = NULL; | |
} else { | |
exit(1); | |
} | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment