From 309f2625e983ef164c52543b492365fe92eed6d5 Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Sun, 3 Dec 2023 19:50:55 -0600 Subject: [PATCH] Update: The f_network_is_ip_address() to use f_string_range_double_t (soon to be f_range_double_t). This allows for getting both the address and port range positions. The POSIX/libc functions do not support the bracket notation in an IPV6 address. The string detected by this must then have the brackets filtered out. This new structure allows for saving the range. I did a quick run-through write-up of the logic for these changes but I have not spent any time reviewing or testing the logic. Hopefully there are not logic bugs or mistakes. --- level_0/f_network/c/network.c | 129 +++++++++++++++++++++++++++++++----------- level_0/f_network/c/network.h | 23 ++++++-- 2 files changed, 116 insertions(+), 36 deletions(-) diff --git a/level_0/f_network/c/network.c b/level_0/f_network/c/network.c index fb0018f..2dedc5b 100644 --- a/level_0/f_network/c/network.c +++ b/level_0/f_network/c/network.c @@ -112,7 +112,7 @@ extern "C" { #endif // _di_f_network_from_ip_string_ #ifndef _di_f_network_is_ip_address_ - void f_network_is_ip_address(const f_string_static_t address, f_number_unsigned_t * const port, f_state_t * const state) { + void f_network_is_ip_address(const f_string_static_t address, f_string_range_double_t * const where, f_state_t * const state) { if (!state) return; @@ -126,6 +126,7 @@ extern "C" { uint8_t flag = 0x0; // 0x1 == is IPv6. uint8_t set = 0; uint8_t count = 0; + f_string_range_double_t at = f_string_range_double_t_initialize; for (; i < address.used; ++i) { @@ -138,7 +139,13 @@ extern "C" { if (isxdigit(address.string[i])) { if (address.string[i] < f_string_ascii_0_s.string[0] || address.string[i] > f_string_ascii_9_s.string[0]) { - flag = 0x1; + flag |= 0x1; + } + + if (!where) { + if (at.start_1 > at.stop_1) { + at.start_1 = at.stop_1 = i; + } } ++count; @@ -157,19 +164,21 @@ extern "C" { break; } - else if (address.string[i] == f_string_ascii_colon_s.string[0]) { + + if (address.string[i] == f_string_ascii_colon_s.string[0]) { flag = 0x1; break; } - else if (address.string[i] == f_string_ascii_bracket_open_s.string[0]) { + + if (address.string[i] == f_string_ascii_bracket_open_s.string[0]) { if (flag) { state->status = F_false; return; } - flag = 0x3; + flag |= 0x3; break; } @@ -185,7 +194,7 @@ extern "C" { return; } - f_number_unsigned_t j = 0; + at.start_1 = i; if (flag & 0x1) { @@ -196,27 +205,36 @@ extern "C" { state->status = F_network_version_six_not; - if (count > 4) return; + if (count > 4 || i == address.used) return; if (!count) { - for (j = i; i < address.used && !address.string[j]; ++j) { + + // Skip past NULL characters. + for (; i < address.used && !address.string[i]; ++i) { if (state->interrupt) { state->interrupt((void *) state, 0); if (F_status_set_fine(state->status) == F_interrupt) return; + + // Restore status in case the interrupt callback changed it. state->status = F_network_version_six_not; } } // for - if (j == address.used) return; + if (i == address.used) return; if (!(flag & 0x2)) flag |= 0x10; + + at.start_1 = i; } + // Process address, counting all sets. for (; i < address.used; ++i) { if (state->interrupt) { state->interrupt((void *) state, 0); if (F_status_set_fine(state->status) == F_interrupt) return; + + // Restore status in case the interrupt callback changed it. state->status = F_network_version_six_not; } @@ -232,39 +250,50 @@ extern "C" { else if (address.string[i] == f_string_ascii_colon_s.string[0]) { if (flag & 0x4) return; - j = i + 1; + at.stop_1 = i; + at.start_2 = i + 1; + + if (at.start_2 < address.used) { - if (j < address.used) { - for (; j < address.used && !address.string[j]; ++j) { + // Skip past NULL characters. + for (; at.start_2 < address.used && !address.string[at.start_2]; ++at.start_2) { if (state->interrupt) { state->interrupt((void *) state, 0); if (F_status_set_fine(state->status) == F_interrupt) return; + + // Restore status in case the interrupt callback changed it. state->status = F_network_version_six_not; } } // for - if (address.string[j] == f_string_ascii_colon_s.string[0]) { + if (at.start_2 == address.used) return; + + if (address.string[at.start_2] == f_string_ascii_colon_s.string[0]) { if (flag & 0x8) return; - i = j; flag |= 0x8; - for (; i < address.used && !address.string[i]; ++i) { + // Skip past NULL characters. + for (; at.start_2 < address.used && !address.string[at.start_2]; ++at.start_2) { if (state->interrupt) { state->interrupt((void *) state, 0); if (F_status_set_fine(state->status) == F_interrupt) return; + + // Restore status in case the interrupt callback changed it. state->status = F_network_version_six_not; } } // for // Must not end on a double-colon. - if (i + 1 == address.used) return; + if (at.start_2 == address.used) return; } // Colons must be followed by a hexidecimal digit. - if (!isxdigit(address.string[i + 1])) return; + if (!isxdigit(address.string[at.start_2])) return; + + i = at.stop_1 = at.start_2; } else { @@ -284,45 +313,56 @@ extern "C" { else if (address.string[i] == f_string_ascii_bracket_close_s.string[0]) { if (!(flag & 0x2)) return; - for (j = i + 1; j < address.used && !address.string[j]; ++j) { + if (!where) { + at.stop_1 = i - 1; + } + + // Skip past NULL characters. + for (at.start_2 = i + 1; at.start_2 < address.used && !address.string[at.start_2]; ++at.start_2) { if (state->interrupt) { state->interrupt((void *) state, 0); if (F_status_set_fine(state->status) == F_interrupt) return; + + // Restore status in case the interrupt callback changed it. state->status = F_network_version_six_not; } } // for - if (j < address.used) { - if (address.string[j] == f_string_ascii_colon_s.string[0]) { - while (++j < address.used && !address.string[j]) { + if (at.start_2 < address.used) { + if (address.string[at.start_2] == f_string_ascii_colon_s.string[0]) { + + // Skip past NULL characters. + while (++at.start_2 < address.used && !address.string[at.start_2]) { if (state->interrupt) { state->interrupt((void *) state, 0); if (F_status_set_fine(state->status) == F_interrupt) return; + + // Restore status in case the interrupt callback changed it. state->status = F_network_version_six_not; } } // while // The colon used to designate the port number must be followed by a (base-10) number. - for (i = j; j < address.used; ++j) { + for (at.stop_2 = at.start_2; at.stop_2 < address.used; ++at.stop_2) { if (state->interrupt) { state->interrupt((void *) state, 0); if (F_status_set_fine(state->status) == F_interrupt) return; + + // Restore status in case the interrupt callback changed it. state->status = F_network_version_six_not; } - if (!address.string[j]) continue; - if (!isdigit(address.string[j])) return; + if (!address.string[at.stop_2]) continue; + if (!isdigit(address.string[at.stop_2])) return; } // for // The double colon either must exist when set is smaller than 7 or the double colon must not exist at all. if (set < 7 && !(flag & 0x8) || set == 7 && (flag & 0x8)) return; state->status = F_network_version_six; - - if (port) *port = i; } else { @@ -337,7 +377,12 @@ extern "C" { state->status = F_network_version_six; - if (port) *port = 0; + at.start_2 = 1; + at.stop_2 = 0; + + if (where) { + *where = at; + } } return; @@ -356,7 +401,12 @@ extern "C" { if (!(flag & 0x10) || set || count) { state->status = F_network_version_six; - if (port) *port = 0; + at.start_2 = 1; + at.stop_2 = 0; + + if (where) { + *where = at; + } } return; @@ -372,6 +422,8 @@ extern "C" { if (state->interrupt) { state->interrupt((void *) state, 0); if (F_status_set_fine(state->status) == F_interrupt) return; + + // Restore status in case the interrupt callback changed it. state->status = F_network_version_four_not; } @@ -380,8 +432,15 @@ extern "C" { if (isdigit(address.string[i])) { if (flag & 0x4) { if (!(flag & 0x8) && ++count > 3) return; + + if (flag & 0x2) { + at.stop_2 = i; + } + } + else if (flag & 0x2) { + at.stop_2 = i; } - else if (!(flag & 0x2)) { + else { if (++count > 3) return; } } @@ -402,12 +461,16 @@ extern "C" { if (state->interrupt) { state->interrupt((void *) state, 0); if (F_status_set_fine(state->status) == F_interrupt) return; + + // Restore status in case the interrupt callback changed it. state->status = F_network_version_four_not; } } // for + if (i == address.used) return; + flag |= 0x2; - j = i + 1; // Save the position that might represent the start of the port number. + at.start_2 = i + 1; // Save the position that might represent the start of the port number. } else if (address.string[i] == f_string_ascii_slash_forward_s.string[0]) { if ((flag & 0x4) || set != 3) return; @@ -421,9 +484,11 @@ extern "C" { } // for if (set == 3) { - state->status = F_network_version_four; + if (where) { + *where = at; + } - if (port) *port = j; + state->status = F_network_version_four; } else { state->status = F_network_version_four_not; diff --git a/level_0/f_network/c/network.h b/level_0/f_network/c/network.h index 224ed44..63a73bf 100644 --- a/level_0/f_network/c/network.h +++ b/level_0/f_network/c/network.h @@ -136,6 +136,7 @@ extern "C" { * The human-friendly IP address string. * @param to * The converted IP version 4 or version 6 family integer. + * For IPv6, the use of a port number requires the address to be encases in brackets, like: [::1]:80. * * @return * F_okay on success. @@ -161,12 +162,26 @@ extern "C" { * * For IPv6, this only accepts port numbers when the IPv6 address is wrapped in brackets ('[' (U+005B) and ']' (U+005D)). * + * This allows NULL characters to exist within the IP address, but the standard POSIX/libc does not. + * The address from this string should be sanitized to not have NULL characters before passing to a POSIX/libc function. + * * @param address * The string to parse. - * @param port - * (optional) This gets updated with the location where the first digit of the port number begins. - * This is set to 0 if there is no port number. + * @param where + * (optional) This utilizes a strange range where the first set (start_1 to stop_1) represents the address range and the second set (start_2 to stop_2) represents the port range. + * For IPv4, an address of '127.0.0.1:123' would have the first set represent '127.0.0.1' and the second set represent '123'. + * For IPv6, an address of '[::1]:123' would have the first set represent '::1' and the second set represent '123'. + * + * Notice that for IPv6, the address of '::1's does not include the open and close brackets. + * Notice that for both the IPv4 and the IPv6, the address and port number do not include the colon separating the address from the port. + * + * The goal here is to be able to present the strings to functions like inet_pton(). + * + * The start_1 to stop_1 range represents the address part. + * The start_2 to stop_2 range represents the port part (start_2 will be greater than stop_2 if there is no port). + * * On any error, this value is not changed. + * If the given address is not valid, then this value is not changed. * * Set to NULL to disable. * @param state @@ -190,7 +205,7 @@ extern "C" { * F_interrupt (with or without error bit) if stopping due to an interrupt. */ #ifndef _di_f_network_is_ip_address_ - extern void f_network_is_ip_address(const f_string_static_t address, f_number_unsigned_t * const port, f_state_t * const state); + extern void f_network_is_ip_address(const f_string_static_t address, f_string_range_double_t * const where, f_state_t * const state); #endif // _di_f_network_is_ip_address_ /** -- 1.8.3.1