Compare commits

...

11 commits

Author SHA1 Message Date
a8dcb69e1e v0.3.3
Some checks are pending
isinetaddr / tests (macos-latest) (push) Waiting to run
isinetaddr / tests (ubuntu-latest) (push) Waiting to run
2024-03-31 10:57:47 -03:00
9d52478756 Terminate 'buf' properly
The previous approach would provide inconsistent results.
2024-03-31 10:42:52 -03:00
75dbfb7166 Avoid indexing 'str' with a negative index
On OpenBSD - this can cause a crash.
2024-03-31 06:25:52 -03:00
1c2778131f Update examples 2024-03-19 21:38:46 -03:00
5ab18f3692 v0.3.2 2024-03-05 21:14:33 -03:00
22f848dd8a Merge branch 'main' of github.com:0x1eef/isinetaddr 2024-03-04 23:57:04 -03:00
7a5ea4e973 Utilize stdbool.h 2024-03-04 23:56:29 -03:00
96c7b39a18 Deference + increment pointer on single line 2024-03-04 23:55:42 -03:00
d6b4cb0f48 Add support for 2001:DB8::8:800:200C:417A
Fix #8
2024-03-04 23:55:42 -03:00
8b94548472 Utilize stdbool.h 2024-03-04 23:54:35 -03:00
33de77f32c Utilize stdbool.h 2024-03-04 23:50:46 -03:00
9 changed files with 124 additions and 215 deletions

176
README.md
View file

@ -1,71 +1,44 @@
## About ## About
isinetaddr is a simple C library that provides an interface that can isinetaddr is a clang library that provides a set of functions for
be used to validate an IPv(<b>4</b>|<b>6</b>) address (with optional IP address validation. The library is guided by [testcases](test/)
support for CIDR notation included). The library is guided by easy to that help verify safety and correctness.
extend [testcases](test/) that help verify safety and correctness.
## Examples ## Examples
### IPv4 ### isinetaddr4
The following example demonstrates the `isinetaddr4` function with The `isinetaddr4` function returns `true` when given a valid IPv4 address:
both valid and invalid inputs. The `isinetaddr4` function returns 1
when the input given is a valid IPv4 address, and otherwise returns 0.
```C ```C
#include <isinetaddr.h> #include <isinetaddr.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
const char *valid[] = { "127.0.0.1", "1.1.1.1", "0.0.0.0" }; const char *ipv4[] = {
const char *invalid[] = { "foobar", "0.0.0.0.0", NULL }; /* valid */
void validate(const char *str); "127.0.0.1", "1.1.1.1", "0.0.0.0",
/* invalid */
"0.0.0.0.0", "foobar"
};
int int
main(void) main(void)
{ {
printf("// valid\n"); for (int i = 0; i < 5; i++) {
for (int i = 0; i < 3; i++) { if (isinetaddr4(ipv4[i])) {
validate(valid[i]); printf("%s is a valid IPv4 address.\n", ipv4[i]);
} } else {
printf("// invalid\n"); printf("%s is an invalid IPv4 address.\n", ipv4[i]);
for (int i = 0; i < 3; i++) { }
validate(invalid[i]);
}
return EXIT_SUCCESS;
}
void
validate(const char *str)
{
if (isinetaddr4(str)) {
printf("%s is a valid IPv4 address.\n", str);
} else {
printf("%s is an invalid IPv4 address.\n", str);
} }
return (EXIT_SUCCESS);
} }
``` ```
Expected output: ### iscidraddr4
``` The `iscidraddr4` function supports the same features as `isinetaddr4` plus
$ cc -Iinclude src/*.c share/isinetaddr/examples/isinetaddr4.c -o example
$ ./example
// valid
127.0.0.1 is a valid IPv4 address.
1.1.1.1 is a valid IPv4 address.
0.0.0.0 is a valid IPv4 address.
// invalid
foobar is an invalid IPv4 address.
0.0.0.0.0 is an invalid IPv4 address.
(null) is an invalid IPv4 address.
```
### CIDR notation (IPv4)
The `iscidraddr4` function supports the same feature set as `isinetaddr4`, and
in addition supports
[CIDR notation](https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing#CIDR_notation). [CIDR notation](https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing#CIDR_notation).
The following example builds on the previous example: The following example builds on the previous example:
@ -74,109 +47,62 @@ The following example builds on the previous example:
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
const char *valid[] = { "127.0.0.1", "192.168.2.1/32", "192.168.2.1/0" }; const char *ipv4[] = {
const char *invalid[] = { "foobar", "0.0.0.0.0", "192.168.2.1/33" }; /* valid */
void validate(const char *str); "127.0.0.1", "192.168.2.1/32", "192.168.2.1/0",
/* invalid */
"192.168.2.1/33", "foobar"
};
int int
main(void) main(void)
{ {
printf("// valid\n"); for (int i = 0; i < 5; i++) {
for (int i = 0; i < 3; i++) { if (iscidraddr4(ipv4[i])) {
validate(valid[i]); printf("%s is a valid IPv4 address.\n", ipv4[i]);
} } else {
printf("// invalid\n"); printf("%s is an invalid IPv4 address.\n", ipv4[i]);
for (int i = 0; i < 3; i++) { }
validate(invalid[i]);
}
return EXIT_SUCCESS;
}
void
validate(const char *str)
{
if (iscidraddr4(str)) {
printf("%s is a valid IPv4 address.\n", str);
} else {
printf("%s is an invalid IPv4 address.\n", str);
} }
return (EXIT_SUCCESS);
} }
``` ```
Expected output: ### isinetaddr6
``` The `isinetaddr6` function returns `true` when given a valid IPv6 address:
$ cc -Iinclude src/*.c share/isinetaddr/examples/iscidraddr4.c -o example
$ ./example
// valid
127.0.0.1 is a valid IPv4 address.
192.168.2.1/32 is a valid IPv4 address.
192.168.2.1/0 is a valid IPv4 address.
// invalid
foobar is an invalid IPv4 address.
0.0.0.0.0 is an invalid IPv4 address.
192.168.2.1/33 is an invalid IPv4 address.
```
### IPv6
The following example demonstrates the `isinetaddr6` function with
both valid and invalid inputs. The `isinetaddr6` function returns 1
when the input given is a valid IPv6 address, and otherwise returns 0.
```C ```C
#include <isinetaddr.h> #include <isinetaddr.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
const char *valid[] = { "::", "::1", "0000:0000:0000:0000:0000:0000:0000:0000" }; const char *ipv6[] = {
const char *invalid[] = { "foobar", "00:::0", NULL }; /* valid */
void validate(const char *str); "::", "::1", "0000:0000:0000:0000:0000:0000:0000:0000",
/* invalid */
"foobar", "00:::0"
};
int int
main(void) main(void)
{ {
printf("// valid\n"); for (int i = 0; i < 5; i++) {
for (int i = 0; i < 3; i++) { if (isinetaddr6(ipv6[i])) {
validate(valid[i]); printf("%s is a valid IPv4 address.\n", ipv6[i]);
} else {
printf("%s is an invalid IPv4 address.\n", ipv6[i]);
}
} }
printf("// invalid\n"); return (EXIT_SUCCESS);
for (int i = 0; i < 3; i++) {
validate(invalid[i]);
}
return EXIT_SUCCESS;
} }
void
validate(const char *str)
{
if (isinetaddr6(str)) {
printf("%s is a valid IPv6 address.\n", str);
} else {
printf("%s is an invalid IPv6 address.\n", str);
}
}
```
Expected output:
```
$ cc -Iinclude src/*.c share/isinetaddr/examples/isinetaddr6.c -o example
$ ./example
// valid
:: is a valid IPv6 address.
::1 is a valid IPv6 address.
0000:0000:0000:0000:0000:0000:0000:0000 is a valid IPv6 address.
// invalid
foobar is an invalid IPv6 address.
00:::0 is an invalid IPv6 address.
(null) is an invalid IPv6 address.
``` ```
## Sources ## Sources
* [Source code (GitHub)](https://github.com/0x1eef/isinetaddr#readme) * [GitHub](https://github.com/0x1eef/isinetaddr#readme)
* [Source code (GitLab)](https://gitlab.com/0x1eef/isinetaddr#about) * [GitLab](https://gitlab.com/0x1eef/isinetaddr#about)
## <a id="license"> License </a> ## <a id="license"> License </a>

View file

@ -1 +1 @@
v0.3.1 v0.3.3

View file

@ -1,4 +1,5 @@
#pragma once #pragma once
int isinetaddr4(const char *str); #include <stdbool.h>
int iscidraddr4(const char *str); bool isinetaddr4(const char *str);
int isinetaddr6(const char *str); bool iscidraddr4(const char *str);
bool isinetaddr6(const char *str);

View file

@ -2,30 +2,22 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
const char *valid[] = { "127.0.0.1", "192.168.2.1/32", "192.168.2.1/0" }; const char *ipv4[] = {
const char *invalid[] = { "foobar", "0.0.0.0.0", "192.168.2.1/33" }; /* valid */
void validate(const char *str); "127.0.0.1", "192.168.2.1/32", "192.168.2.1/0",
/* invalid */
"192.168.2.1/33", "foobar"
};
int int
main(void) main(void)
{ {
printf("// valid\n"); for (int i = 0; i < 5; i++) {
for (int i = 0; i < 3; i++) { if (iscidraddr4(ipv4[i])) {
validate(valid[i]); printf("%s is a valid IPv4 address.\n", ipv4[i]);
} } else {
printf("// invalid\n"); printf("%s is an invalid IPv4 address.\n", ipv4[i]);
for (int i = 0; i < 3; i++) { }
validate(invalid[i]);
}
return EXIT_SUCCESS;
}
void
validate(const char *str)
{
if (iscidraddr4(str)) {
printf("%s is a valid IPv4 address.\n", str);
} else {
printf("%s is an invalid IPv4 address.\n", str);
} }
return (EXIT_SUCCESS);
} }

View file

@ -2,30 +2,22 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
const char *valid[] = { "127.0.0.1", "1.1.1.1", "0.0.0.0" }; const char *ipv4[] = {
const char *invalid[] = { "foobar", "0.0.0.0.0", NULL }; /* valid */
void validate(const char *str); "127.0.0.1", "1.1.1.1", "0.0.0.0",
/* invalid */
"0.0.0.0.0", "foobar"
};
int int
main(void) main(void)
{ {
printf("// valid\n"); for (int i = 0; i < 5; i++) {
for (int i = 0; i < 3; i++) { if (isinetaddr4(ipv4[i])) {
validate(valid[i]); printf("%s is a valid IPv4 address.\n", ipv4[i]);
} } else {
printf("// invalid\n"); printf("%s is an invalid IPv4 address.\n", ipv4[i]);
for (int i = 0; i < 3; i++) { }
validate(invalid[i]);
}
return EXIT_SUCCESS;
}
void
validate(const char *str)
{
if (isinetaddr4(str)) {
printf("%s is a valid IPv4 address.\n", str);
} else {
printf("%s is an invalid IPv4 address.\n", str);
} }
return (EXIT_SUCCESS);
} }

View file

@ -2,30 +2,23 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
const char *valid[] = { "::", "::1", "0000:0000:0000:0000:0000:0000:0000:0000" }; const char *ipv6[] = {
const char *invalid[] = { "foobar", "00:::0", NULL }; /* valid */
void validate(const char *str); "::", "::1", "0000:0000:0000:0000:0000:0000:0000:0000",
/* invalid */
"foobar", "00:::0"
};
int int
main(void) main(void)
{ {
printf("// valid\n"); for (int i = 0; i < 5; i++) {
for (int i = 0; i < 3; i++) { if (isinetaddr6(ipv6[i])) {
validate(valid[i]); printf("%s is a valid IPv4 address.\n", ipv6[i]);
} } else {
printf("// invalid\n"); printf("%s is an invalid IPv4 address.\n", ipv6[i]);
for (int i = 0; i < 3; i++) { }
validate(invalid[i]);
}
return EXIT_SUCCESS;
}
void
validate(const char *str)
{
if (isinetaddr6(str)) {
printf("%s is a valid IPv6 address.\n", str);
} else {
printf("%s is an invalid IPv6 address.\n", str);
} }
return (EXIT_SUCCESS);
} }

View file

@ -2,10 +2,11 @@
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdbool.h>
static int in_range(char buf[4], int min, int max); static bool in_range(char buf[4], int min, int max);
int bool
iscidraddr4(const char *str) iscidraddr4(const char *str)
{ {
size_t offset = 0; size_t offset = 0;
@ -29,14 +30,14 @@ iscidraddr4(const char *str)
} }
} }
static int static bool
in_range(char buf[4], int min, int max) in_range(char buf[4], int min, int max)
{ {
char *err; char *err;
long r; long r;
errno = 0; errno = 0;
if (strnlen(buf, 1) == 0) { if (strnlen(buf, 1) == 0) {
return 0; return false;
} else { } else {
r = strtol(buf, &err, 10); r = strtol(buf, &err, 10);
return *err == '\0' && errno == 0 && (r >= min && r <= max); return *err == '\0' && errno == 0 && (r >= min && r <= max);

View file

@ -1,6 +1,7 @@
#include <ctype.h> #include <ctype.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdbool.h>
#include <isinetaddr.h> #include <isinetaddr.h>
static const int MAX_BUFLEN = 3; static const int MAX_BUFLEN = 3;
@ -8,44 +9,43 @@ static const int MAX_OCTETS = 4;
static const int MAX_DIGITLEN = 12; static const int MAX_DIGITLEN = 12;
static const int MAX_STRLEN = 16; static const int MAX_STRLEN = 16;
static const char SEP = '.'; static const char SEP = '.';
static int within_range(char buf[MAX_BUFLEN]); static bool within_range(char buf[MAX_BUFLEN]);
int bool
isinetaddr4(const char *str) isinetaddr4(const char *str)
{ {
char buf[MAX_BUFLEN + 1]; char buf[MAX_BUFLEN + 1];
int digits = 0, octets = 1, buflen = 0; int digits = 0, octets = 1, buflen = 0;
size_t len = (str == NULL ? 0 : strnlen(str, MAX_STRLEN)); size_t len = (str == NULL ? 0 : strnlen(str, MAX_STRLEN));
buf[MAX_BUFLEN] = '\0';
for (size_t i = 0; i < len; i++) { for (size_t i = 0; i < len; i++) {
if (str[i] == SEP) { if (str[i] == SEP) {
if (octets == MAX_OCTETS || buflen == 0) { if (octets == MAX_OCTETS || buflen == 0) {
return 0; return false;
} else { } else {
buflen = 0; buflen = 0;
bzero(buf, MAX_BUFLEN);
} }
} else if (isdigit(str[i])) { } else if (isdigit(str[i])) {
if (buflen == MAX_BUFLEN) { if (buflen == MAX_BUFLEN) {
return 0; return false;
} else { } else {
buf[buflen++] = str[i]; buf[buflen++] = str[i];
buf[buflen] = '\0';
digits++; digits++;
if (!within_range(buf)) { if (!within_range(buf)) {
return 0; return false;
} else if (str[i-1] == SEP) { } else if (i > 0 && str[i-1] == SEP) {
octets++; octets++;
} }
} }
} else { } else {
return 0; return false;
} }
} }
return octets == MAX_OCTETS && digits <= MAX_DIGITLEN; return octets == MAX_OCTETS && digits <= MAX_DIGITLEN;
} }
static int static bool
within_range(char buf[MAX_BUFLEN]) within_range(char buf[MAX_BUFLEN])
{ {
int n = atoi(buf); int n = atoi(buf);

View file

@ -1,6 +1,7 @@
#include <ctype.h> #include <ctype.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdbool.h>
#include <isinetaddr.h> #include <isinetaddr.h>
static const int MAX_DIGITLEN = 4; static const int MAX_DIGITLEN = 4;
@ -9,24 +10,27 @@ static const int MAX_HEXDIGITS = 32;
static const int MAX_STRLEN = 40; static const int MAX_STRLEN = 40;
static const char SEP = ':'; static const char SEP = ':';
static int has_consecutive_chars(const char *str, char c, int n); static bool has_consecutive_chars(const char *str, char c, int n);
static char* expand(const char *str, size_t strlen, char *new_str, size_t headlen); static char* expand(const char *str, size_t strlen, char *new_str, size_t headlen);
static size_t get_offset(char *tail); static size_t get_offset(char *tail);
int bool
isinetaddr6(const char *str) isinetaddr6(const char *str)
{ {
int hextets = 1, digitlen = 0, hexdigits = 0; int hextets = 1, digitlen = 0, hexdigits = 0;
size_t len = (str == NULL ? 0 : strnlen(str, MAX_STRLEN)); size_t len = (str == NULL ? 0 : strnlen(str, MAX_STRLEN));
if (len == 0) {
return false;
} else if (strncasecmp(str, "::ffff", 6) == 0) {
return isinetaddr4(&str[7]);
}
for (size_t i = 0; i < len; i++) { for (size_t i = 0; i < len; i++) {
if (has_consecutive_chars(&str[i], SEP, 3)) { if (has_consecutive_chars(&str[i], SEP, 3)) {
return 0; return false;
} else if (i == 0 && strncasecmp(str, "::ffff", 6) == 0) {
return isinetaddr4(&str[7]);
} else if (has_consecutive_chars(&str[i], SEP, 2)) { } else if (has_consecutive_chars(&str[i], SEP, 2)) {
if (i == 0 && isinetaddr4(&str[3])) { if (i == 0 && isinetaddr4(&str[3])) {
return 1; return true;
} else { } else {
char new_str[MAX_STRLEN]; char new_str[MAX_STRLEN];
return isinetaddr6(expand(str, len, new_str, i)); return isinetaddr6(expand(str, len, new_str, i));
@ -37,18 +41,18 @@ isinetaddr6(const char *str)
digitlen++; digitlen++;
hexdigits++; hexdigits++;
if (digitlen > MAX_DIGITLEN) { if (digitlen > MAX_DIGITLEN) {
return 0; return false;
} else if (str[i-1] == SEP) { } else if (str[i-1] == SEP) {
hextets++; hextets++;
} }
} else { } else {
return 0; return false;
} }
} }
return hextets == MAX_HEXTETS && hexdigits <= MAX_HEXDIGITS; return hextets == MAX_HEXTETS && hexdigits <= MAX_HEXDIGITS;
} }
static int static bool
has_consecutive_chars(const char *str, char c, int n) has_consecutive_chars(const char *str, char c, int n)
{ {
for (int i = 0; i < n; i++) { for (int i = 0; i < n; i++) {