7#include <ascii-chat/util/ip.h>
8#include <ascii-chat/util/parsing.h>
9#include <ascii-chat/common.h>
10#include <ascii-chat/common/buffer_sizes.h>
11#include <ascii-chat/platform/network.h>
12#include <ascii-chat/log/logging.h>
13#include <ascii-chat/util/pcre2.h>
22#include <netinet/in.h>
42static const char *IPV4_PATTERN =
"^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\\.){3}"
43 "(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])$";
50static pcre2_code *ipv4_regex_get(
void) {
51 if (g_ipv4_regex == NULL) {
52 g_ipv4_regex = asciichat_pcre2_singleton_compile(IPV4_PATTERN, 0);
60 SET_ERRNO(ERROR_INVALID_PARAM,
"Invalid IP format: NULL");
64 size_t ip_len = strlen(ip);
66 SET_ERRNO(ERROR_INVALID_PARAM,
"Invalid IP format: empty string");
71 char ip_buffer[BUFFER_SIZE_SMALL];
72 SAFE_STRNCPY(ip_buffer, ip,
sizeof(ip_buffer));
73 SET_ERRNO(ERROR_INVALID_PARAM,
"Suspiciously long ip: %s", ip_buffer);
78 pcre2_code *regex = ipv4_regex_get();
80 log_error(
"IPv4 validator not initialized");
85 pcre2_match_data *match_data = pcre2_match_data_create_from_pattern(regex, NULL);
87 log_error(
"Failed to allocate match data for IPv4 regex");
92 int match_result = pcre2_match(regex, (PCRE2_SPTR8)ip, ip_len, 0, 0, match_data, NULL);
94 pcre2_match_data_free(match_data);
96 if (match_result < 0) {
107 SET_ERRNO(ERROR_INVALID_PARAM,
"Invalid IP format: NULL");
111 size_t ip_len = strlen(ip);
113 SET_ERRNO(ERROR_INVALID_PARAM,
"Invalid IP format: empty string");
118 char ip_buffer[BUFFER_SIZE_SMALL];
119 SAFE_STRNCPY(ip_buffer, ip,
sizeof(ip_buffer));
120 SET_ERRNO(ERROR_INVALID_PARAM,
"Suspiciously long ip: %s", ip_buffer);
125 char normalized[INET6_ADDRSTRLEN];
126 const char *ip_to_validate = ip;
133 ip_to_validate = normalized;
143 struct in6_addr addr;
144 int result = inet_pton(AF_INET6, ip_to_validate, &addr);
148 }
else if (result == 0) {
152 SET_ERRNO(ERROR_INVALID_PARAM,
"Failed to validate IPv6 address");
159 if (!input || !output || output_size == 0)
162 size_t input_len = strlen(input);
166 const char *start = input;
167 const char *end = input + input_len;
171 if (input_len < 2 || *(end - 1) !=
']')
177 if (start < end && *start ==
'[')
179 }
else if (*(end - 1) ==
']') {
184 size_t len = (size_t)(end - start);
187 if (len >= output_size)
190 memcpy(output, start, len);
196asciichat_error_t
format_ip_address(
int family,
const struct sockaddr *addr,
char *output,
size_t output_size) {
197 if (!addr || !output || output_size == 0) {
198 return SET_ERRNO(ERROR_INVALID_PARAM,
"Invalid arguments to format_ip_address");
201 const void *ip_ptr = NULL;
203 if (family == AF_INET) {
204 const struct sockaddr_in *addr_in = (
const struct sockaddr_in *)addr;
205 ip_ptr = &addr_in->sin_addr;
206 }
else if (family == AF_INET6) {
207 const struct sockaddr_in6 *addr_in6 = (
const struct sockaddr_in6 *)addr;
208 ip_ptr = &addr_in6->sin6_addr;
210 return SET_ERRNO(ERROR_INVALID_PARAM,
"Unsupported address family: %d", family);
213 if (inet_ntop(family, ip_ptr, output, (socklen_t)output_size) == NULL) {
214 return SET_ERRNO(ERROR_NETWORK,
"Failed to format IP address");
222 if (!ip || !output || output_size == 0) {
223 return SET_ERRNO(ERROR_INVALID_PARAM,
"Invalid IP format: %s", ip);
226 if (strlen(ip) == 0) {
227 return SET_ERRNO(ERROR_INVALID_PARAM,
"Invalid IP format: %s", ip);
230 if (strlen(ip) > 256) {
231 char ip_buffer[BUFFER_SIZE_SMALL];
232 SAFE_STRNCPY(ip_buffer, ip,
sizeof(ip_buffer));
233 return SET_ERRNO(ERROR_INVALID_PARAM,
"Suspiciously long ip: %s", ip_buffer);
237 if (strchr(ip,
':') != NULL) {
239 size_t written = SAFE_SNPRINTF(output, output_size,
"[%s]:%u", ip, port);
240 if (written >= output_size) {
241 return SET_ERRNO(ERROR_INVALID_PARAM,
"Invalid ip=%s or port=%u", ip, port);
245 size_t written = SAFE_SNPRINTF(output, output_size,
"%s:%u", ip, port);
246 if (written >= output_size) {
247 return SET_ERRNO(ERROR_INVALID_PARAM,
"Invalid ip=%s or port=%u", ip, port);
256static int is_valid_hostname(
const char *hostname) {
257 if (!hostname || strlen(hostname) == 0 || strlen(hostname) > 253) {
262 size_t len = strlen(hostname);
263 if (hostname[0] ==
'-' || hostname[0] ==
'.' || hostname[len - 1] ==
'-' || hostname[len - 1] ==
'.') {
269 for (
size_t i = 0; i < len; i++) {
270 char c = hostname[i];
273 if (label_len == 0 || label_len > 63) {
277 }
else if ((c >=
'a' && c <=
'z') || (c >=
'A' && c <=
'Z') || (c >=
'0' && c <=
'9') || c ==
'-') {
279 if (label_len > 63) {
288 if (label_len == 0 || label_len > 63) {
296int parse_ip_with_port(
const char *input,
char *ip_output,
size_t ip_output_size, uint16_t *port_output) {
297 if (!input || !ip_output || !port_output || ip_output_size == 0) {
298 SET_ERRNO(ERROR_INVALID_PARAM,
"Invalid IP format: %s", input);
302 if (strlen(input) == 0) {
303 SET_ERRNO(ERROR_INVALID_PARAM,
"Invalid IP format: %s", input);
307 if (strlen(input) > 256) {
308 char input_buffer[BUFFER_SIZE_SMALL];
309 SAFE_STRNCPY(input_buffer, input,
sizeof(input_buffer));
310 SET_ERRNO(ERROR_INVALID_PARAM,
"Suspiciously long ip: %s", input_buffer);
315 if (input[0] ==
'[') {
317 const char *bracket_end = strchr(input,
']');
322 size_t ip_len = (size_t)(bracket_end - input - 1);
323 if (ip_len >= ip_output_size)
326 memcpy(ip_output, input + 1, ip_len);
327 ip_output[ip_len] =
'\0';
330 if (bracket_end[1] ==
':') {
332 if (
parse_port(bracket_end + 2, port_output) != ASCIICHAT_OK) {
341 const char *colon = strrchr(input,
':');
346 size_t ip_len = (size_t)(colon - input);
347 if (ip_len >= ip_output_size)
350 memcpy(ip_output, input, ip_len);
351 ip_output[ip_len] =
'\0';
355 if (strchr(ip_output,
':') != NULL)
359 if (
parse_port(colon + 1, port_output) != ASCIICHAT_OK) {
371 uint16_t *port_output, uint16_t default_port) {
372 if (!input || !address_output || !port_output || address_output_size == 0) {
373 SET_ERRNO(ERROR_INVALID_PARAM,
"Invalid arguments to parse_address_with_optional_port");
377 size_t input_len = strlen(input);
378 if (input_len == 0) {
379 SET_ERRNO(ERROR_INVALID_PARAM,
"Empty address string");
383 if (input_len > 256) {
384 SET_ERRNO(ERROR_INVALID_PARAM,
"Address string too long");
390 if (input[0] ==
'[') {
391 const char *bracket_end = strchr(input,
']');
393 SET_ERRNO(ERROR_INVALID_PARAM,
"Malformed bracketed address (missing ']'): %s", input);
398 size_t addr_len = (size_t)(bracket_end - input - 1);
400 SET_ERRNO(ERROR_INVALID_PARAM,
"Empty bracketed address: %s", input);
403 if (addr_len >= address_output_size) {
404 SET_ERRNO(ERROR_INVALID_PARAM,
"Address too long for buffer");
408 memcpy(address_output, input + 1, addr_len);
409 address_output[addr_len] =
'\0';
413 SET_ERRNO(ERROR_INVALID_PARAM,
"Invalid IPv6 address: %s", address_output);
418 if (bracket_end[1] ==
'\0') {
420 *port_output = default_port;
421 }
else if (bracket_end[1] ==
':') {
423 if (
parse_port(bracket_end + 2, port_output) != ASCIICHAT_OK) {
424 SET_ERRNO(ERROR_INVALID_PARAM,
"Invalid port in: %s", input);
428 SET_ERRNO(ERROR_INVALID_PARAM,
"Invalid format after ']' (expected ':' or end): %s", input);
438 if (strlen(input) >= address_output_size) {
439 SET_ERRNO(ERROR_INVALID_PARAM,
"Address too long for buffer");
442 SAFE_STRNCPY(address_output, input, address_output_size);
443 *port_output = default_port;
449 const char *last_colon = strrchr(input,
':');
451 if (last_colon == NULL) {
453 if (strlen(input) >= address_output_size) {
454 SET_ERRNO(ERROR_INVALID_PARAM,
"Address too long for buffer");
460 SET_ERRNO(ERROR_INVALID_PARAM,
"Invalid address format: %s", input);
464 SAFE_STRNCPY(address_output, input, address_output_size);
465 *port_output = default_port;
470 size_t addr_len = (size_t)(last_colon - input);
472 SET_ERRNO(ERROR_INVALID_PARAM,
"Empty address before port: %s", input);
475 if (addr_len >= address_output_size) {
476 SET_ERRNO(ERROR_INVALID_PARAM,
"Address too long for buffer");
480 memcpy(address_output, input, addr_len);
481 address_output[addr_len] =
'\0';
484 if (strchr(address_output,
':') != NULL) {
485 SET_ERRNO(ERROR_INVALID_PARAM,
"IPv6 addresses must use brackets when specifying port: [%s]:%s instead of %s",
486 address_output, last_colon + 1, input);
491 if (!
is_valid_ipv4(address_output) && !is_valid_hostname(address_output)) {
492 SET_ERRNO(ERROR_INVALID_PARAM,
"Invalid address format: %s", address_output);
497 if (
parse_port(last_colon + 1, port_output) != ASCIICHAT_OK) {
498 SET_ERRNO(ERROR_INVALID_PARAM,
"Invalid port in: %s", input);
511 if (!ip || strlen(ip) == 0) {
517 if (strchr(ip,
':') != NULL) {
567 if (v1 != v2 || v1 == 0) {
573 struct in_addr addr1, addr2;
574 if (inet_pton(AF_INET, ip1, &addr1) != 1 || inet_pton(AF_INET, ip2, &addr2) != 1) {
577 return addr1.s_addr == addr2.s_addr;
580 char norm1[INET6_ADDRSTRLEN], norm2[INET6_ADDRSTRLEN];
591 struct in6_addr addr1, addr2;
592 if (inet_pton(AF_INET6, norm1, &addr1) != 1 || inet_pton(AF_INET6, norm2, &addr2) != 1) {
596 return memcmp(&addr1, &addr2,
sizeof(addr1)) == 0;
610 if (v1 == 0 && v2 == 0) {
622 return (v1 < v2) ? -1 : 1;
627 struct in_addr addr1, addr2;
628 if (inet_pton(AF_INET, ip1, &addr1) != 1 || inet_pton(AF_INET, ip2, &addr2) != 1) {
632 uint32_t val1 = ntohl(addr1.s_addr);
633 uint32_t val2 = ntohl(addr2.s_addr);
642 char norm1[INET6_ADDRSTRLEN], norm2[INET6_ADDRSTRLEN];
651 struct in6_addr addr1, addr2;
652 if (inet_pton(AF_INET6, norm1, &addr1) != 1 || inet_pton(AF_INET6, norm2, &addr2) != 1) {
656 return memcmp(&addr1, &addr2,
sizeof(addr1));
665int parse_cidr(
const char *cidr,
char *ip_out,
size_t ip_out_size,
int *prefix_out) {
666 if (!cidr || !ip_out || !prefix_out || ip_out_size == 0) {
671 const char *slash = strchr(cidr,
'/');
677 size_t ip_len = (size_t)(slash - cidr);
678 if (ip_len == 0 || ip_len >= ip_out_size) {
683 if (ip_len >=
sizeof(ip_temp)) {
687 memcpy(ip_temp, cidr, ip_len);
688 ip_temp[ip_len] =
'\0';
691 if (ip_temp[0] ==
'[') {
696 if (ip_len >= ip_out_size) {
699 memcpy(ip_out, ip_temp, ip_len + 1);
709 const char *prefix_str = slash + 1;
710 if (strlen(prefix_str) == 0) {
715 long prefix = strtol(prefix_str, &endptr, 10);
716 if (*endptr !=
'\0' || prefix < 0) {
721 if (version == 4 && (prefix > 32)) {
724 if (version == 6 && (prefix > 128)) {
728 *prefix_out = (int)prefix;
733static uint32_t apply_ipv4_mask(uint32_t ip,
int prefix_len) {
734 if (prefix_len == 0) {
737 if (prefix_len >= 32) {
740 uint32_t mask = ~((1U << (32 - prefix_len)) - 1);
745static void apply_ipv6_mask(
struct in6_addr *addr,
int prefix_len) {
746 if (prefix_len < 0 || prefix_len > 128) {
750 int bytes = prefix_len / 8;
751 int bits = prefix_len % 8;
754 for (
int i = bytes + (bits > 0 ? 1 : 0); i < 16; i++) {
755 addr->s6_addr[i] = 0;
759 if (bits > 0 && bytes < 16) {
760 uint8_t mask = (uint8_t)(0xFF << (8 - bits));
761 addr->s6_addr[bytes] &= mask;
767 if (!ip || !network) {
775 if (ip_version != net_version || ip_version == 0) {
779 if (ip_version == 4) {
781 struct in_addr ip_addr, net_addr;
782 if (inet_pton(AF_INET, ip, &ip_addr) != 1 || inet_pton(AF_INET, network, &net_addr) != 1) {
786 uint32_t ip_val = ntohl(ip_addr.s_addr);
787 uint32_t net_val = ntohl(net_addr.s_addr);
789 uint32_t ip_masked = apply_ipv4_mask(ip_val, prefix_len);
790 uint32_t net_masked = apply_ipv4_mask(net_val, prefix_len);
792 return ip_masked == net_masked;
795 char ip_norm[INET6_ADDRSTRLEN], net_norm[INET6_ADDRSTRLEN];
804 struct in6_addr ip_addr, net_addr;
805 if (inet_pton(AF_INET6, ip_norm, &ip_addr) != 1 || inet_pton(AF_INET6, net_norm, &net_addr) != 1) {
810 struct in6_addr ip_masked = ip_addr;
811 struct in6_addr net_masked = net_addr;
812 apply_ipv6_mask(&ip_masked, prefix_len);
813 apply_ipv6_mask(&net_masked, prefix_len);
815 return memcmp(&ip_masked, &net_masked,
sizeof(ip_masked)) == 0;
828 if (
parse_cidr(cidr, network,
sizeof(network), &prefix) != 0) {
841 if (!ipv4 || !ipv6_out || out_size == 0) {
842 return SET_ERRNO(ERROR_INVALID_PARAM,
"Invalid arguments to ipv4_to_ipv6_mapped");
847 return SET_ERRNO(ERROR_INVALID_PARAM,
"Invalid IPv4 address: %s", ipv4);
851 size_t written = SAFE_SNPRINTF(ipv6_out, out_size,
"::ffff:%s", ipv4);
852 if (written >= out_size) {
853 return SET_ERRNO(ERROR_INVALID_PARAM,
"Output buffer too small");
866 char normalized[INET6_ADDRSTRLEN];
876 struct in6_addr addr;
877 if (inet_pton(AF_INET6, normalized, &addr) != 1) {
883 for (
int i = 0; i < 10; i++) {
884 if (addr.s6_addr[i] != 0) {
888 if (addr.s6_addr[10] != 0xFF || addr.s6_addr[11] != 0xFF) {
897 if (!ipv6 || !ipv4_out || out_size == 0) {
898 return SET_ERRNO(ERROR_INVALID_PARAM,
"Invalid arguments to extract_ipv4_from_mapped_ipv6");
902 return SET_ERRNO(ERROR_INVALID_PARAM,
"Not an IPv4-mapped IPv6 address: %s", ipv6);
906 char normalized[INET6_ADDRSTRLEN];
908 return SET_ERRNO(ERROR_INVALID_PARAM,
"Failed to parse IPv6 address");
911 struct in6_addr addr;
912 if (inet_pton(AF_INET6, normalized, &addr) != 1) {
913 return SET_ERRNO(ERROR_INVALID_PARAM,
"Failed to convert IPv6 address");
917 struct in_addr ipv4_addr;
918 memcpy(&ipv4_addr.s_addr, &addr.s6_addr[12], 4);
920 if (inet_ntop(AF_INET, &ipv4_addr, ipv4_out, (socklen_t)out_size) == NULL) {
921 return SET_ERRNO(ERROR_NETWORK,
"Failed to format IPv4 address");
932asciichat_error_t
expand_ipv6(
const char *ipv6,
char *expanded_out,
size_t out_size) {
933 if (!ipv6 || !expanded_out || out_size == 0) {
934 return SET_ERRNO(ERROR_INVALID_PARAM,
"Invalid arguments to expand_ipv6");
938 char normalized[INET6_ADDRSTRLEN];
940 return SET_ERRNO(ERROR_INVALID_PARAM,
"Failed to parse IPv6 address");
945 return SET_ERRNO(ERROR_INVALID_PARAM,
"Invalid IPv6 address: %s", ipv6);
948 struct in6_addr addr;
949 if (inet_pton(AF_INET6, normalized, &addr) != 1) {
950 return SET_ERRNO(ERROR_INVALID_PARAM,
"Failed to convert IPv6 address");
955 SAFE_SNPRINTF(expanded_out, out_size,
"%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
956 (addr.s6_addr[0] << 8) | addr.s6_addr[1], (addr.s6_addr[2] << 8) | addr.s6_addr[3],
957 (addr.s6_addr[4] << 8) | addr.s6_addr[5], (addr.s6_addr[6] << 8) | addr.s6_addr[7],
958 (addr.s6_addr[8] << 8) | addr.s6_addr[9], (addr.s6_addr[10] << 8) | addr.s6_addr[11],
959 (addr.s6_addr[12] << 8) | addr.s6_addr[13], (addr.s6_addr[14] << 8) | addr.s6_addr[15]);
961 if (written >= out_size) {
962 return SET_ERRNO(ERROR_INVALID_PARAM,
"Output buffer too small");
970 if (!ipv6 || !canonical_out || out_size == 0) {
971 return SET_ERRNO(ERROR_INVALID_PARAM,
"Invalid arguments to canonicalize_ipv6");
975 char normalized[INET6_ADDRSTRLEN];
977 return SET_ERRNO(ERROR_INVALID_PARAM,
"Failed to parse IPv6 address");
982 return SET_ERRNO(ERROR_INVALID_PARAM,
"Invalid IPv6 address: %s", ipv6);
985 struct in6_addr addr;
986 if (inet_pton(AF_INET6, normalized, &addr) != 1) {
987 return SET_ERRNO(ERROR_INVALID_PARAM,
"Failed to convert IPv6 address");
991 if (inet_ntop(AF_INET6, &addr, canonical_out, (socklen_t)out_size) == NULL) {
992 return SET_ERRNO(ERROR_NETWORK,
"Failed to format IPv6 address");
999asciichat_error_t
compact_ipv6(
const char *ipv6,
char *compact_out,
size_t out_size) {
1010 char normalized[INET6_ADDRSTRLEN];
1020 struct in6_addr addr;
1021 if (inet_pton(AF_INET6, normalized, &addr) != 1) {
1027 if (addr.s6_addr[0] == 0x20 && addr.s6_addr[1] == 0x02 && addr.s6_addr[2] == 0xc0 && addr.s6_addr[3] == 0x58 &&
1028 addr.s6_addr[4] == 0x63 && addr.s6_addr[5] == 0x01) {
1031 for (
int i = 6; i < 16; i++) {
1032 if (addr.s6_addr[i] != 0) {
1054 if (!addr_with_port || !ip_out || ip_out_size == 0) {
1059 if (addr_with_port[0] ==
'[') {
1060 const char *bracket_end = strchr(addr_with_port,
']');
1064 size_t ip_len = (size_t)(bracket_end - addr_with_port - 1);
1065 if (ip_len >= ip_out_size) {
1068 memcpy(ip_out, addr_with_port + 1, ip_len);
1069 ip_out[ip_len] =
'\0';
1074 const char *colon = strrchr(addr_with_port,
':');
1077 SAFE_STRNCPY(ip_out, addr_with_port, ip_out_size);
1081 size_t ip_len = (size_t)(colon - addr_with_port);
1082 if (ip_len >= ip_out_size) {
1085 memcpy(ip_out, addr_with_port, ip_len);
1086 ip_out[ip_len] =
'\0';
1092 if (!ip || ip[0] ==
'\0') {
1098 if (strcmp(ip,
"0.0.0.0") == 0) {
1099 return "All Interfaces";
1103 if (strcmp(ip,
"::") == 0) {
1104 return "All Interfaces";
1134 if (!ip_port1 || !ip_port2) {
1139 if (strcmp(ip_port1, ip_port2) == 0) {
1144 char ip1[64], ip2[64];
1145 uint16_t port1 = 0, port2 = 0;
1155 if (port1 != port2) {
1164 if (version1 != version2 || version1 == 0) {
1168 if (version1 == 6) {
1170 char canonical1[INET6_ADDRSTRLEN], canonical2[INET6_ADDRSTRLEN];
1177 return (strcmp(canonical1, canonical2) == 0) ? 1 : 0;
1190 struct in_addr addr;
1191 if (inet_pton(AF_INET, ip, &addr) != 1) {
1195 uint32_t ip_val = ntohl(addr.s_addr);
1198 if ((ip_val & 0xFF000000) == 0x0A000000) {
1203 if ((ip_val & 0xFFF00000) == 0xAC100000) {
1208 if ((ip_val & 0xFFFF0000) == 0xC0A80000) {
1222 char normalized[INET6_ADDRSTRLEN];
1232 struct in6_addr addr;
1233 if (inet_pton(AF_INET6, normalized, &addr) != 1) {
1239 if ((addr.s6_addr[0] & 0xFE) == 0xFC) {
1252 struct in_addr addr;
1253 if (inet_pton(AF_INET, ip, &addr) != 1) {
1257 uint32_t ip_val = ntohl(addr.s_addr);
1260 if (ip_val == 0xFFFFFFFF) {
1274 char normalized[INET6_ADDRSTRLEN];
1284 struct in6_addr addr;
1285 if (inet_pton(AF_INET6, normalized, &addr) != 1) {
1291 if (addr.s6_addr[0] == 0xFF) {
1304 struct in_addr addr;
1305 if (inet_pton(AF_INET, ip, &addr) != 1) {
1309 uint32_t ip_val = ntohl(addr.s_addr);
1312 if ((ip_val & 0xFF000000) == 0x7F000000) {
1326 char normalized[INET6_ADDRSTRLEN];
1336 struct in6_addr addr;
1337 if (inet_pton(AF_INET6, normalized, &addr) != 1) {
1343 for (
int i = 0; i < 15; i++) {
1344 if (addr.s6_addr[i] != 0) {
1348 if (addr.s6_addr[15] != 1) {
1361 struct in_addr addr;
1362 if (inet_pton(AF_INET, ip, &addr) != 1) {
1366 uint32_t ip_val = ntohl(addr.s_addr);
1369 if ((ip_val & 0xFFFF0000) == 0xA9FE0000) {
1383 char normalized[INET6_ADDRSTRLEN];
1393 struct in6_addr addr;
1394 if (inet_pton(AF_INET6, normalized, &addr) != 1) {
1400 if (addr.s6_addr[0] == 0xFE && (addr.s6_addr[1] & 0xC0) == 0x80) {
1413 struct in_addr addr;
1414 if (inet_pton(AF_INET, ip, &addr) != 1) {
1418 uint32_t ip_val = ntohl(addr.s_addr);
1441 if ((ip_val & 0xF0000000) == 0xE0000000) {
1446 if ((ip_val & 0xFF000000) == 0x00000000) {
1451 if ((ip_val & 0xFFC00000) == 0x64400000) {
1456 if ((ip_val & 0xFFFFFF00) == 0xC0000000) {
1461 if ((ip_val & 0xFFFFFF00) == 0xC0000200) {
1466 if ((ip_val & 0xFFFE0000) == 0xC6120000) {
1471 if ((ip_val & 0xFFFFFF00) == 0xC6336400) {
1476 if ((ip_val & 0xFFFFFF00) == 0xCB007100) {
1481 if ((ip_val & 0xF0000000) == 0xF0000000) {
1496 char normalized[INET6_ADDRSTRLEN];
1506 struct in6_addr addr;
1507 if (inet_pton(AF_INET6, normalized, &addr) != 1) {
1532 int is_unspecified = 1;
1533 for (
int i = 0; i < 16; i++) {
1534 if (addr.s6_addr[i] != 0) {
1539 if (is_unspecified) {
1544 if (addr.s6_addr[0] == 0 && addr.s6_addr[1] == 0 && addr.s6_addr[2] == 0 && addr.s6_addr[3] == 0 &&
1545 addr.s6_addr[4] == 0 && addr.s6_addr[5] == 0 && addr.s6_addr[6] == 0 && addr.s6_addr[7] == 0 &&
1546 addr.s6_addr[8] == 0 && addr.s6_addr[9] == 0 && addr.s6_addr[10] == 0xFF && addr.s6_addr[11] == 0xFF) {
1551 if (addr.s6_addr[0] == 0 && addr.s6_addr[1] == 0 && addr.s6_addr[2] == 0 && addr.s6_addr[3] == 0 &&
1552 addr.s6_addr[4] == 0 && addr.s6_addr[5] == 0 && addr.s6_addr[6] == 0 && addr.s6_addr[7] == 0 &&
1553 addr.s6_addr[8] == 0 && addr.s6_addr[9] == 0 && addr.s6_addr[10] == 0 && addr.s6_addr[11] == 0) {
1555 if (addr.s6_addr[12] != 0 || addr.s6_addr[13] != 0 || addr.s6_addr[14] != 0 || addr.s6_addr[15] != 0) {
1561 if (addr.s6_addr[0] == 0x20 && addr.s6_addr[1] == 0x01 && addr.s6_addr[2] == 0x0D && addr.s6_addr[3] == 0xB8) {
1566 if (addr.s6_addr[0] == 0x20 && addr.s6_addr[1] == 0x02) {
int ip_compare(const char *ip1, const char *ip2)
asciichat_error_t expand_ipv6(const char *ipv6, char *expanded_out, size_t out_size)
int is_lan_ipv6(const char *ip)
asciichat_error_t format_ip_with_port(const char *ip, uint16_t port, char *output, size_t output_size)
int is_broadcast_ipv6(const char *ip)
int ip_in_cidr(const char *ip, const char *cidr)
int is_link_local_ipv6(const char *ip)
asciichat_error_t extract_ipv4_from_mapped_ipv6(const char *ipv6, char *ipv4_out, size_t out_size)
int is_localhost_ipv6(const char *ip)
int is_internet_ipv4(const char *ip)
int is_valid_ipv4(const char *ip)
int extract_ip_from_address(const char *addr_with_port, char *ip_out, size_t ip_out_size)
const char * get_ip_type_string(const char *ip)
int parse_ip_with_port(const char *input, char *ip_output, size_t ip_output_size, uint16_t *port_output)
int is_lan_ipv4(const char *ip)
asciichat_error_t compact_ipv6(const char *ipv6, char *compact_out, size_t out_size)
int parse_cidr(const char *cidr, char *ip_out, size_t ip_out_size, int *prefix_out)
int is_valid_ipv6(const char *ip)
int is_ipv4_mapped_ipv6(const char *ipv6)
int is_broadcast_ipv4(const char *ip)
int is_localhost_ipv4(const char *ip)
int ip_equals(const char *ip1, const char *ip2)
int parse_address_with_optional_port(const char *input, char *address_output, size_t address_output_size, uint16_t *port_output, uint16_t default_port)
int is_link_local_ipv4(const char *ip)
int is_valid_ip(const char *ip)
int is_internet_ipv6(const char *ip)
int ip_in_cidr_parsed(const char *ip, const char *network, int prefix_len)
asciichat_error_t canonicalize_ipv6(const char *ipv6, char *canonical_out, size_t out_size)
int get_ip_version(const char *ip)
int parse_ipv6_address(const char *input, char *output, size_t output_size)
int compare_ip_port_strings(const char *ip_port1, const char *ip_port2)
int is_anycast_ipv6(const char *ipv6)
asciichat_error_t format_ip_address(int family, const struct sockaddr *addr, char *output, size_t output_size)
asciichat_error_t ipv4_to_ipv6_mapped(const char *ipv4, char *ipv6_out, size_t out_size)
asciichat_error_t parse_port(const char *str, uint16_t *out_port)
pcre2_code * asciichat_pcre2_singleton_get_code(pcre2_singleton_t *singleton)
Get the compiled pcre2_code from a singleton handle.
Represents a thread-safe compiled PCRE2 regex singleton.