diff --git a/WireGuard/WireGuard/UI/macOS/highlighter.c b/WireGuard/WireGuard/UI/macOS/highlighter.c index 6edf575..cc4a74a 100644 --- a/WireGuard/WireGuard/UI/macOS/highlighter.c +++ b/WireGuard/WireGuard/UI/macOS/highlighter.c @@ -13,576 +13,584 @@ #include "highlighter.h" typedef struct { - const char *s; - size_t len; + const char *s; + size_t len; } string_span_t; static bool is_valid_key(string_span_t s) { - if (s.len != 44 || s.s[43] != '=') - return false; - - for (size_t i = 0; i < 43; ++i) { - if (!((s.s[i] >= '/' && s.s[i] <= '9') || - (s.s[i] >= 'A' && s.s[i] <= 'Z') || - (s.s[i] >= 'a' && s.s[i] <= 'z') || - s.s[i] == '+')) - return false; - } - return true; + if (s.len != 44 || s.s[43] != '=') + return false; + + for (size_t i = 0; i < 43; ++i) { + if (!((s.s[i] >= '/' && s.s[i] <= '9') || + (s.s[i] >= 'A' && s.s[i] <= 'Z') || + (s.s[i] >= 'a' && s.s[i] <= 'z') || + s.s[i] == '+')) + return false; + } + return true; } static bool is_valid_hostname(string_span_t s) { - size_t num_digit = 0, num_entity = s.len; - - if (s.len > 63 || !s.len) - return false; - if (s.s[0] == '-' || s.s[s.len - 1] == '-') - return false; - if (s.s[0] == '.' || s.s[s.len - 1] == '.') - return false; - - for (size_t i = 0; i < s.len; ++i) { - if (isdigit(s.s[i])) { - ++num_digit; - continue; - } - if (s.s[i] == '.') { - --num_entity; - continue; - } - - if (!((s.s[i] >= 'A' && s.s[i] <= 'Z') || - (s.s[i] >= 'a' && s.s[i] <= 'z') || - s.s[i] == '-')) - return false; - - if (i && s.s[i] == '.' && s.s[i - 1] == '.') - return false; - } - return num_digit != num_entity; + size_t num_digit = 0, num_entity = s.len; + + if (s.len > 63 || !s.len) + return false; + if (s.s[0] == '-' || s.s[s.len - 1] == '-') + return false; + if (s.s[0] == '.' || s.s[s.len - 1] == '.') + return false; + + for (size_t i = 0; i < s.len; ++i) { + if (isdigit(s.s[i])) { + ++num_digit; + continue; + } + if (s.s[i] == '.') { + --num_entity; + continue; + } + + if (!((s.s[i] >= 'A' && s.s[i] <= 'Z') || + (s.s[i] >= 'a' && s.s[i] <= 'z') || + s.s[i] == '-')) + return false; + + if (i && s.s[i] == '.' && s.s[i - 1] == '.') + return false; + } + return num_digit != num_entity; } static bool is_valid_ipv4(string_span_t s) { - for (size_t j, i = 0, pos = 0; i < 4 && pos < s.len; ++i) { - uint32_t val = 0; - - for (j = 0; j < 3 && pos + j < s.len && isdigit(s.s[pos + j]); ++j) - val = 10 * val + s.s[pos + j] - '0'; - if (j == 0 || (j > 1 && s.s[pos] == '0') || val > 255) - return false; - if (pos + j == s.len && i == 3) - return true; - if (s.s[pos + j] != '.') - return false; - pos += j + 1; - } - return false; + for (size_t j, i = 0, pos = 0; i < 4 && pos < s.len; ++i) { + uint32_t val = 0; + + for (j = 0; j < 3 && pos + j < s.len && isdigit(s.s[pos + j]); ++j) + val = 10 * val + s.s[pos + j] - '0'; + if (j == 0 || (j > 1 && s.s[pos] == '0') || val > 255) + return false; + if (pos + j == s.len && i == 3) + return true; + if (s.s[pos + j] != '.') + return false; + pos += j + 1; + } + return false; } static bool is_valid_ipv6(string_span_t s) { - size_t pos = 0; - bool seen_colon = false; - - if (s.len < 2) - return false; - if (s.s[pos] == ':' && s.s[++pos] != ':') - return false; - if (s.s[s.len - 1] == ':' && s.s[s.len - 2] != ':') - return false; - - for (size_t j, i = 0; pos < s.len; ++i) { - if (s.s[pos] == ':' && !seen_colon) { - seen_colon = true; - if (++pos == s.len) - break; - if (i == 7) - return false; - continue; - } - for (j = 0; j < 4 && pos + j < s.len && isxdigit(s.s[pos + j]); ++j); - if (j == 0) - return false; - if (pos + j == s.len && (seen_colon || i == 7)) - break; - if (i == 7) - return false; - if (s.s[pos + j] != ':') { - if (s.s[pos + j] != '.' || (i < 6 && !seen_colon)) - return false; - return is_valid_ipv4((string_span_t){ s.s + pos, s.len - pos }); - } - pos += j + 1; - } - return true; + size_t pos = 0; + bool seen_colon = false; + + if (s.len < 2) + return false; + if (s.s[pos] == ':' && s.s[++pos] != ':') + return false; + if (s.s[s.len - 1] == ':' && s.s[s.len - 2] != ':') + return false; + + for (size_t j, i = 0; pos < s.len; ++i) { + if (s.s[pos] == ':' && !seen_colon) { + seen_colon = true; + if (++pos == s.len) + break; + if (i == 7) + return false; + continue; + } + for (j = 0; j < 4 && pos + j < s.len && isxdigit(s.s[pos + j]); ++j); + if (j == 0) + return false; + if (pos + j == s.len && (seen_colon || i == 7)) + break; + if (i == 7) + return false; + if (s.s[pos + j] != ':') { + if (s.s[pos + j] != '.' || (i < 6 && !seen_colon)) + return false; + return is_valid_ipv4((string_span_t){ s.s + pos, s.len - pos }); + } + pos += j + 1; + } + return true; } static bool is_valid_u16(string_span_t s) { - uint32_t val = 0; - - if (s.len > 5 || !s.len) - return false; - - for (size_t i = 0; i < s.len; ++i) { - if (!isdigit(s.s[i])) - return false; - val = 10 * val + s.s[i] - '0'; - } - return val <= 65535; + uint32_t val = 0; + + if (s.len > 5 || !s.len) + return false; + + for (size_t i = 0; i < s.len; ++i) { + if (!isdigit(s.s[i])) + return false; + val = 10 * val + s.s[i] - '0'; + } + return val <= 65535; } static bool is_valid_port(string_span_t s) { - return is_valid_u16(s); + return is_valid_u16(s); } static bool is_valid_mtu(string_span_t s) { - return is_valid_u16(s); + return is_valid_u16(s); } static bool is_valid_persistentkeepalive(string_span_t s) { - if (s.len == 3 && !memcmp(s.s, "off", 3)) - return true; - return is_valid_u16(s); + if (s.len == 3 && !memcmp(s.s, "off", 3)) + return true; + return is_valid_u16(s); } +#ifndef MOBILE_WGQUICK_SUBSET static bool is_valid_u32(string_span_t s) { - uint64_t val = 0; - - if (s.len > 10 || !s.len) - return false; - - if (s.len > 2 && s.s[0] == '0' && s.s[1] == 'x') { - for (size_t i = 2; i < s.len; ++i) { - if (s.s[i] - '0' < 10) - val = 16 * val + (s.s[i] - '0'); - else if ((s.s[i] | 32) - 'a' < 6) - val = 16 * val + (s.s[i] | 32) - 'a' + 10; - else - return false; - } - } else { - for (size_t i = 0; i < s.len; ++i) { - if (!isdigit(s.s[i])) - return false; - val = 10 * val + s.s[i] - '0'; - } - } - return val <= 4294967295U; + uint64_t val = 0; + + if (s.len > 10 || !s.len) + return false; + + if (s.len > 2 && s.s[0] == '0' && s.s[1] == 'x') { + for (size_t i = 2; i < s.len; ++i) { + if (s.s[i] - '0' < 10) + val = 16 * val + (s.s[i] - '0'); + else if ((s.s[i] | 32) - 'a' < 6) + val = 16 * val + (s.s[i] | 32) - 'a' + 10; + else + return false; + } + } else { + for (size_t i = 0; i < s.len; ++i) { + if (!isdigit(s.s[i])) + return false; + val = 10 * val + s.s[i] - '0'; + } + } + return val <= 4294967295U; } static bool is_valid_fwmark(string_span_t s) { - if (s.len == 3 && !memcmp(s.s, "off", 3)) - return true; - return is_valid_u32(s); + if (s.len == 3 && !memcmp(s.s, "off", 3)) + return true; + return is_valid_u32(s); } static bool is_valid_table(string_span_t s) { - if (s.len == 4 && !memcmp(s.s, "auto", 3)) - return true; - if (s.len == 3 && !memcmp(s.s, "off", 3)) - return true; - /* This pretty much invalidates the other checks, but rt_names.c's - * fread_id_name does no validation aside from this. */ - if (s.len < 512) - return true; - return is_valid_u32(s); + if (s.len == 4 && !memcmp(s.s, "auto", 3)) + return true; + if (s.len == 3 && !memcmp(s.s, "off", 3)) + return true; + /* This pretty much invalidates the other checks, but rt_names.c's + * fread_id_name does no validation aside from this. */ + if (s.len < 512) + return true; + return is_valid_u32(s); } static bool is_valid_saveconfig(string_span_t s) { - return (s.len == 4 && !memcmp(s.s, "true", 4)) || - (s.len == 5 && !memcmp(s.s, "false", 5)); -} - -static bool is_valid_scope(string_span_t s) -{ - if (s.len > 64 || !s.len) - return false; - for (size_t i = 0; i < s.len; ++i) { - if (!((s.s[i] >= 'A' && s.s[i] <= 'Z') || - (s.s[i] >= 'a' && s.s[i] <= 'z') || - isdigit(s.s[i]) || s.s[i] == '_' || - s.s[i] == '=' || s.s[i] == '+' || - s.s[i] == '.' || s.s[i] == '-')) - return false; - } - return true; -} - -static bool is_valid_endpoint(string_span_t s) -{ - - if (!s.len) - return false; - - if (s.s[0] == '[') { - bool seen_scope = false; - string_span_t hostspan = { s.s + 1, 0 }; - - for (size_t i = 1; i < s.len; ++i) { - if (s.s[i] == '%') { - if (seen_scope) - return false; - seen_scope = true; - if (!is_valid_ipv6(hostspan)) - return false; - hostspan = (string_span_t){ s.s + i + 1, 0 }; - } else if (s.s[i] == ']') { - if (seen_scope) { - if (!is_valid_scope(hostspan)) - return false; - } else if (!is_valid_ipv6(hostspan)) { - return false; - } - if (i == s.len - 1 || s.s[i + 1] != ':') - return false; - return is_valid_port((string_span_t){ s.s + i + 2, s.len - i - 2 }); - } else { - ++hostspan.len; - } - } - return false; - } - for (size_t i = 0; i < s.len; ++i) { - if (s.s[i] == ':') { - string_span_t host = { s.s, i }, port = { s.s + i + 1, s.len - i - 1}; - return is_valid_port(port) && (is_valid_ipv4(host) || is_valid_hostname(host)); - } - } - return false; -} - -static bool is_valid_network(string_span_t s) -{ - for (size_t i = 0; i < s.len; ++i) { - if (s.s[i] == '/') { - string_span_t ip = { s.s, i }, cidr = { s.s + i + 1, s.len - i - 1}; - uint16_t cidrval = 0; - - if (cidr.len > 3 || !cidr.len) - return false; - - for (size_t j = 0; j < cidr.len; ++j) { - if (!isdigit(cidr.s[j])) - return false; - cidrval = 10 * cidrval + cidr.s[j] - '0'; - } - if (is_valid_ipv4(ip)) - return cidrval <= 32; - else if (is_valid_ipv6(ip)) - return cidrval <= 128; - return false; - } - } - return is_valid_ipv4(s) || is_valid_ipv6(s); -} - -static bool is_valid_dns(string_span_t s) -{ - return is_valid_ipv4(s) || is_valid_ipv6(s); + return (s.len == 4 && !memcmp(s.s, "true", 4)) || + (s.len == 5 && !memcmp(s.s, "false", 5)); } static bool is_valid_prepostupdown(string_span_t s) { - /* It's probably not worthwhile to try to validate a bash expression. - * So instead we just demand non-zero length. */ - return s.len; + /* It's probably not worthwhile to try to validate a bash expression. + * So instead we just demand non-zero length. */ + return s.len; +} +#endif + +static bool is_valid_scope(string_span_t s) +{ + if (s.len > 64 || !s.len) + return false; + for (size_t i = 0; i < s.len; ++i) { + if (!((s.s[i] >= 'A' && s.s[i] <= 'Z') || + (s.s[i] >= 'a' && s.s[i] <= 'z') || + isdigit(s.s[i]) || s.s[i] == '_' || + s.s[i] == '=' || s.s[i] == '+' || + s.s[i] == '.' || s.s[i] == '-')) + return false; + } + return true; +} + +static bool is_valid_endpoint(string_span_t s) +{ + + if (!s.len) + return false; + + if (s.s[0] == '[') { + bool seen_scope = false; + string_span_t hostspan = { s.s + 1, 0 }; + + for (size_t i = 1; i < s.len; ++i) { + if (s.s[i] == '%') { + if (seen_scope) + return false; + seen_scope = true; + if (!is_valid_ipv6(hostspan)) + return false; + hostspan = (string_span_t){ s.s + i + 1, 0 }; + } else if (s.s[i] == ']') { + if (seen_scope) { + if (!is_valid_scope(hostspan)) + return false; + } else if (!is_valid_ipv6(hostspan)) { + return false; + } + if (i == s.len - 1 || s.s[i + 1] != ':') + return false; + return is_valid_port((string_span_t){ s.s + i + 2, s.len - i - 2 }); + } else { + ++hostspan.len; + } + } + return false; + } + for (size_t i = 0; i < s.len; ++i) { + if (s.s[i] == ':') { + string_span_t host = { s.s, i }, port = { s.s + i + 1, s.len - i - 1}; + return is_valid_port(port) && (is_valid_ipv4(host) || is_valid_hostname(host)); + } + } + return false; +} + +static bool is_valid_network(string_span_t s) +{ + for (size_t i = 0; i < s.len; ++i) { + if (s.s[i] == '/') { + string_span_t ip = { s.s, i }, cidr = { s.s + i + 1, s.len - i - 1}; + uint16_t cidrval = 0; + + if (cidr.len > 3 || !cidr.len) + return false; + + for (size_t j = 0; j < cidr.len; ++j) { + if (!isdigit(cidr.s[j])) + return false; + cidrval = 10 * cidrval + cidr.s[j] - '0'; + } + if (is_valid_ipv4(ip)) + return cidrval <= 32; + else if (is_valid_ipv6(ip)) + return cidrval <= 128; + return false; + } + } + return is_valid_ipv4(s) || is_valid_ipv6(s); +} + +static bool is_valid_dns(string_span_t s) +{ + return is_valid_ipv4(s) || is_valid_ipv6(s); } enum keytype { - InterfaceSection, - PrivateKey, - ListenPort, - FwMark, - Address, - DNS, - MTU, - Table, - PreUp, PostUp, PreDown, PostDown, - SaveConfig, - - PeerSection, - PublicKey, - PresharedKey, - AllowedIPs, - Endpoint, - PersistentKeepalive, - - Invalid + InterfaceSection, + PrivateKey, + ListenPort, + Address, + DNS, + MTU, +#ifndef MOBILE_WGQUICK_SUBSET + FwMark, + Table, + PreUp, PostUp, PreDown, PostDown, + SaveConfig, +#endif + + PeerSection, + PublicKey, + PresharedKey, + AllowedIPs, + Endpoint, + PersistentKeepalive, + + Invalid }; static enum keytype section_for_keytype(enum keytype t) { - if (t > InterfaceSection && t < PeerSection) - return InterfaceSection; - if (t > PeerSection && t < Invalid) - return PeerSection; - return Invalid; + if (t > InterfaceSection && t < PeerSection) + return InterfaceSection; + if (t > PeerSection && t < Invalid) + return PeerSection; + return Invalid; } static enum keytype get_keytype(string_span_t s) { #define check_enum(t) do { if (s.len == strlen(#t) && !strncasecmp(#t, s.s, s.len)) return t; } while (0) - check_enum(PrivateKey); - check_enum(ListenPort); - check_enum(FwMark); - check_enum(Address); - check_enum(DNS); - check_enum(MTU); - check_enum(Table); - check_enum(PreUp); - check_enum(PostUp); - check_enum(PreDown); - check_enum(PostDown); - check_enum(PublicKey); - check_enum(PresharedKey); - check_enum(AllowedIPs); - check_enum(Endpoint); - check_enum(PersistentKeepalive); - check_enum(SaveConfig); - return Invalid; + check_enum(PrivateKey); + check_enum(ListenPort); + check_enum(Address); + check_enum(DNS); + check_enum(MTU); + check_enum(PublicKey); + check_enum(PresharedKey); + check_enum(AllowedIPs); + check_enum(Endpoint); + check_enum(PersistentKeepalive); +#ifndef MOBILE_WGQUICK_SUBSET + check_enum(FwMark); + check_enum(Table); + check_enum(PreUp); + check_enum(PostUp); + check_enum(PreDown); + check_enum(PostDown); + check_enum(SaveConfig); +#endif + return Invalid; #undef check_enum } static enum keytype get_sectiontype(string_span_t s) { - if (s.len == 6 && !strncasecmp("[Peer]", s.s, 6)) - return PeerSection; - if (s.len == 11 && !strncasecmp("[Interface]", s.s, 11)) - return InterfaceSection; - return Invalid; + if (s.len == 6 && !strncasecmp("[Peer]", s.s, 6)) + return PeerSection; + if (s.len == 11 && !strncasecmp("[Interface]", s.s, 11)) + return InterfaceSection; + return Invalid; } struct highlight_span_array { - size_t len, capacity; - struct highlight_span *spans; + size_t len, capacity; + struct highlight_span *spans; }; /* A useful OpenBSD-ism. */ static void *realloc_array(void *optr, size_t nmemb, size_t size) { - if ((nmemb >= (size_t)1 << (sizeof(size_t) * 4) || - size >= (size_t)1 << (sizeof(size_t) * 4)) && - nmemb > 0 && SIZE_MAX / nmemb < size) { - errno = ENOMEM; - return NULL; - } - return realloc(optr, size * nmemb); + if ((nmemb >= (size_t)1 << (sizeof(size_t) * 4) || + size >= (size_t)1 << (sizeof(size_t) * 4)) && + nmemb > 0 && SIZE_MAX / nmemb < size) { + errno = ENOMEM; + return NULL; + } + return realloc(optr, size * nmemb); } static bool append_highlight_span(struct highlight_span_array *a, const char *o, string_span_t s, enum highlight_type t) { - if (!s.len) - return true; - if (a->len >= a->capacity) { - struct highlight_span *resized; - - a->capacity = a->capacity ? a->capacity * 2 : 64; - resized = realloc_array(a->spans, a->capacity, sizeof(*resized)); - if (!resized) { - free(a->spans); - memset(a, 0, sizeof(*a)); - return false; - } - a->spans = resized; - } - a->spans[a->len++] = (struct highlight_span){ t, s.s - o, s.len }; - return true; + if (!s.len) + return true; + if (a->len >= a->capacity) { + struct highlight_span *resized; + + a->capacity = a->capacity ? a->capacity * 2 : 64; + resized = realloc_array(a->spans, a->capacity, sizeof(*resized)); + if (!resized) { + free(a->spans); + memset(a, 0, sizeof(*a)); + return false; + } + a->spans = resized; + } + a->spans[a->len++] = (struct highlight_span){ t, s.s - o, s.len }; + return true; } static void highlight_multivalue_value(struct highlight_span_array *ret, const string_span_t parent, const string_span_t s, enum keytype section) { - switch (section) { - case DNS: - append_highlight_span(ret, parent.s, s, is_valid_dns(s) ? HighlightIP : HighlightError); - break; - case Address: - case AllowedIPs: { - size_t slash; - - if (!is_valid_network(s)) { - append_highlight_span(ret, parent.s, s, HighlightError); - break; - } - for (slash = 0; slash < s.len; ++slash) { - if (s.s[slash] == '/') - break; - } - if (slash == s.len) { - append_highlight_span(ret, parent.s, s, HighlightIP); - } else { - append_highlight_span(ret, parent.s, (string_span_t){ s.s, slash }, HighlightIP); - append_highlight_span(ret, parent.s, (string_span_t){ s.s + slash, 1 }, HighlightDelimiter); - append_highlight_span(ret, parent.s, (string_span_t){ s.s + slash + 1, s.len - slash - 1 }, HighlightCidr); - } - break; - } - default: - append_highlight_span(ret, parent.s, s, HighlightError); - } + switch (section) { + case DNS: + append_highlight_span(ret, parent.s, s, is_valid_dns(s) ? HighlightIP : HighlightError); + break; + case Address: + case AllowedIPs: { + size_t slash; + + if (!is_valid_network(s)) { + append_highlight_span(ret, parent.s, s, HighlightError); + break; + } + for (slash = 0; slash < s.len; ++slash) { + if (s.s[slash] == '/') + break; + } + if (slash == s.len) { + append_highlight_span(ret, parent.s, s, HighlightIP); + } else { + append_highlight_span(ret, parent.s, (string_span_t){ s.s, slash }, HighlightIP); + append_highlight_span(ret, parent.s, (string_span_t){ s.s + slash, 1 }, HighlightDelimiter); + append_highlight_span(ret, parent.s, (string_span_t){ s.s + slash + 1, s.len - slash - 1 }, HighlightCidr); + } + break; + } + default: + append_highlight_span(ret, parent.s, s, HighlightError); + } } static void highlight_multivalue(struct highlight_span_array *ret, const string_span_t parent, const string_span_t s, enum keytype section) { - string_span_t current_span = { s.s, 0 }; - size_t len_at_last_space = 0; - - for (size_t i = 0; i < s.len; ++i) { - if (s.s[i] == ',') { - current_span.len = len_at_last_space; - highlight_multivalue_value(ret, parent, current_span, section); - append_highlight_span(ret, parent.s, (string_span_t){ s.s + i, 1 }, HighlightDelimiter); - len_at_last_space = 0; - current_span = (string_span_t){ s.s + i + 1, 0 }; - } else if (s.s[i] == ' ' || s.s[i] == '\t') { - if (&s.s[i] == current_span.s && !current_span.len) - ++current_span.s; - else - ++current_span.len; - } else { - len_at_last_space = ++current_span.len; - } - } - current_span.len = len_at_last_space; - if (current_span.len) - highlight_multivalue_value(ret, parent, current_span, section); - else if (ret->spans[ret->len - 1].type == HighlightDelimiter) - ret->spans[ret->len - 1].type = HighlightError; + string_span_t current_span = { s.s, 0 }; + size_t len_at_last_space = 0; + + for (size_t i = 0; i < s.len; ++i) { + if (s.s[i] == ',') { + current_span.len = len_at_last_space; + highlight_multivalue_value(ret, parent, current_span, section); + append_highlight_span(ret, parent.s, (string_span_t){ s.s + i, 1 }, HighlightDelimiter); + len_at_last_space = 0; + current_span = (string_span_t){ s.s + i + 1, 0 }; + } else if (s.s[i] == ' ' || s.s[i] == '\t') { + if (&s.s[i] == current_span.s && !current_span.len) + ++current_span.s; + else + ++current_span.len; + } else { + len_at_last_space = ++current_span.len; + } + } + current_span.len = len_at_last_space; + if (current_span.len) + highlight_multivalue_value(ret, parent, current_span, section); + else if (ret->spans[ret->len - 1].type == HighlightDelimiter) + ret->spans[ret->len - 1].type = HighlightError; } static void highlight_value(struct highlight_span_array *ret, const string_span_t parent, const string_span_t s, enum keytype section) { - switch (section) { - case PrivateKey: - case PublicKey: - case PresharedKey: - append_highlight_span(ret, parent.s, s, is_valid_key(s) ? HighlightKey : HighlightError); - break; - case FwMark: - append_highlight_span(ret, parent.s, s, is_valid_fwmark(s) ? HighlightFwMark : HighlightError); - break; - case Table: - append_highlight_span(ret, parent.s, s, is_valid_table(s) ? HighlightTable : HighlightError); - break; - case MTU: - append_highlight_span(ret, parent.s, s, is_valid_mtu(s) ? HighlightMTU : HighlightError); - break; - case SaveConfig: - append_highlight_span(ret, parent.s, s, is_valid_saveconfig(s) ? HighlightSaveConfig : HighlightError); - break; - case PreUp: - case PostUp: - case PreDown: - case PostDown: - append_highlight_span(ret, parent.s, s, is_valid_prepostupdown(s) ? HighlightCmd : HighlightError); - break; - case ListenPort: - append_highlight_span(ret, parent.s, s, is_valid_port(s) ? HighlightPort : HighlightError); - break; - case PersistentKeepalive: - append_highlight_span(ret, parent.s, s, is_valid_persistentkeepalive(s) ? HighlightKeepalive : HighlightError); - break; - case Endpoint: { - size_t colon; - - if (!is_valid_endpoint(s)) { - append_highlight_span(ret, parent.s, s, HighlightError); - break; - } - for (colon = s.len; colon --> 0;) { - if (s.s[colon] == ':') - break; - } - append_highlight_span(ret, parent.s, (string_span_t){ s.s, colon }, HighlightHost); - append_highlight_span(ret, parent.s, (string_span_t){ s.s + colon, 1 }, HighlightDelimiter); - append_highlight_span(ret, parent.s, (string_span_t){ s.s + colon + 1, s.len - colon - 1 }, HighlightPort); - break; - } - case Address: - case DNS: - case AllowedIPs: - highlight_multivalue(ret, parent, s, section); - break; - default: - append_highlight_span(ret, parent.s, s, HighlightError); - } + switch (section) { + case PrivateKey: + case PublicKey: + case PresharedKey: + append_highlight_span(ret, parent.s, s, is_valid_key(s) ? HighlightKey : HighlightError); + break; + case MTU: + append_highlight_span(ret, parent.s, s, is_valid_mtu(s) ? HighlightMTU : HighlightError); + break; +#ifndef MOBILE_WGQUICK_SUBSET + case SaveConfig: + append_highlight_span(ret, parent.s, s, is_valid_saveconfig(s) ? HighlightSaveConfig : HighlightError); + break; + case FwMark: + append_highlight_span(ret, parent.s, s, is_valid_fwmark(s) ? HighlightFwMark : HighlightError); + break; + case Table: + append_highlight_span(ret, parent.s, s, is_valid_table(s) ? HighlightTable : HighlightError); + break; + case PreUp: + case PostUp: + case PreDown: + case PostDown: + append_highlight_span(ret, parent.s, s, is_valid_prepostupdown(s) ? HighlightCmd : HighlightError); + break; +#endif + case ListenPort: + append_highlight_span(ret, parent.s, s, is_valid_port(s) ? HighlightPort : HighlightError); + break; + case PersistentKeepalive: + append_highlight_span(ret, parent.s, s, is_valid_persistentkeepalive(s) ? HighlightKeepalive : HighlightError); + break; + case Endpoint: { + size_t colon; + + if (!is_valid_endpoint(s)) { + append_highlight_span(ret, parent.s, s, HighlightError); + break; + } + for (colon = s.len; colon --> 0;) { + if (s.s[colon] == ':') + break; + } + append_highlight_span(ret, parent.s, (string_span_t){ s.s, colon }, HighlightHost); + append_highlight_span(ret, parent.s, (string_span_t){ s.s + colon, 1 }, HighlightDelimiter); + append_highlight_span(ret, parent.s, (string_span_t){ s.s + colon + 1, s.len - colon - 1 }, HighlightPort); + break; + } + case Address: + case DNS: + case AllowedIPs: + highlight_multivalue(ret, parent, s, section); + break; + default: + append_highlight_span(ret, parent.s, s, HighlightError); + } } struct highlight_span *highlight_config(const char *config) { - struct highlight_span_array ret = { 0 }; - const string_span_t s = { config, strlen(config) }; - string_span_t current_span = { s.s, 0 }; - enum keytype current_section = Invalid, current_keytype = Invalid; - enum { OnNone, OnKey, OnValue, OnComment, OnSection } state = OnNone; - size_t len_at_last_space = 0, equals_location = 0; - - for (size_t i = 0; i <= s.len; ++i) { - if (i == s.len || s.s[i] == '\n' || (state != OnComment && s.s[i] == '#')) { - if (state == OnKey) { - current_span.len = len_at_last_space; - append_highlight_span(&ret, s.s, current_span, HighlightError); - } else if (state == OnValue) { - if (current_span.len) { - append_highlight_span(&ret, s.s, (string_span_t){ s.s + equals_location, 1 }, HighlightDelimiter); - current_span.len = len_at_last_space; - highlight_value(&ret, s, current_span, current_keytype); - } else { - append_highlight_span(&ret, s.s, (string_span_t){ s.s + equals_location, 1 }, HighlightError); - } - } else if (state == OnSection) { - current_span.len = len_at_last_space; - current_section = get_sectiontype(current_span); - append_highlight_span(&ret, s.s, current_span, current_section == Invalid ? HighlightError : HighlightSection); - } else if (state == OnComment) { - append_highlight_span(&ret, s.s, current_span, HighlightComment); - } - if (i == s.len) - break; - len_at_last_space = 0; - current_keytype = Invalid; - if (s.s[i] == '#') { - current_span = (string_span_t){ s.s + i, 1 }; - state = OnComment; - } else { - current_span = (string_span_t){ s.s + i + 1, 0 }; - state = OnNone; - } - } else if (state == OnComment) { - ++current_span.len; - } else if (s.s[i] == ' ' || s.s[i] == '\t') { - if (&s.s[i] == current_span.s && !current_span.len) - ++current_span.s; - else - ++current_span.len; - } else if (s.s[i] == '=' && state == OnKey) { - current_span.len = len_at_last_space; - current_keytype = get_keytype(current_span); - enum keytype section = section_for_keytype(current_keytype); - if (section == Invalid || current_keytype == Invalid || section != current_section) - append_highlight_span(&ret, s.s, current_span, HighlightError); - else - append_highlight_span(&ret, s.s, current_span, HighlightKeytype); - equals_location = i; - current_span = (string_span_t){ s.s + i + 1, 0 }; - state = OnValue; - } else { - if (state == OnNone) - state = s.s[i] == '[' ? OnSection : OnKey; - len_at_last_space = ++current_span.len; - } - } - - append_highlight_span(&ret, s.s, (string_span_t){ s.s, -1 }, HighlightEnd); - return ret.spans; + struct highlight_span_array ret = { 0 }; + const string_span_t s = { config, strlen(config) }; + string_span_t current_span = { s.s, 0 }; + enum keytype current_section = Invalid, current_keytype = Invalid; + enum { OnNone, OnKey, OnValue, OnComment, OnSection } state = OnNone; + size_t len_at_last_space = 0, equals_location = 0; + + for (size_t i = 0; i <= s.len; ++i) { + if (i == s.len || s.s[i] == '\n' || (state != OnComment && s.s[i] == '#')) { + if (state == OnKey) { + current_span.len = len_at_last_space; + append_highlight_span(&ret, s.s, current_span, HighlightError); + } else if (state == OnValue) { + if (current_span.len) { + append_highlight_span(&ret, s.s, (string_span_t){ s.s + equals_location, 1 }, HighlightDelimiter); + current_span.len = len_at_last_space; + highlight_value(&ret, s, current_span, current_keytype); + } else { + append_highlight_span(&ret, s.s, (string_span_t){ s.s + equals_location, 1 }, HighlightError); + } + } else if (state == OnSection) { + current_span.len = len_at_last_space; + current_section = get_sectiontype(current_span); + append_highlight_span(&ret, s.s, current_span, current_section == Invalid ? HighlightError : HighlightSection); + } else if (state == OnComment) { + append_highlight_span(&ret, s.s, current_span, HighlightComment); + } + if (i == s.len) + break; + len_at_last_space = 0; + current_keytype = Invalid; + if (s.s[i] == '#') { + current_span = (string_span_t){ s.s + i, 1 }; + state = OnComment; + } else { + current_span = (string_span_t){ s.s + i + 1, 0 }; + state = OnNone; + } + } else if (state == OnComment) { + ++current_span.len; + } else if (s.s[i] == ' ' || s.s[i] == '\t') { + if (&s.s[i] == current_span.s && !current_span.len) + ++current_span.s; + else + ++current_span.len; + } else if (s.s[i] == '=' && state == OnKey) { + current_span.len = len_at_last_space; + current_keytype = get_keytype(current_span); + enum keytype section = section_for_keytype(current_keytype); + if (section == Invalid || current_keytype == Invalid || section != current_section) + append_highlight_span(&ret, s.s, current_span, HighlightError); + else + append_highlight_span(&ret, s.s, current_span, HighlightKeytype); + equals_location = i; + current_span = (string_span_t){ s.s + i + 1, 0 }; + state = OnValue; + } else { + if (state == OnNone) + state = s.s[i] == '[' ? OnSection : OnKey; + len_at_last_space = ++current_span.len; + } + } + + append_highlight_span(&ret, s.s, (string_span_t){ s.s, -1 }, HighlightEnd); + return ret.spans; } diff --git a/WireGuard/WireGuard/UI/macOS/highlighter.h b/WireGuard/WireGuard/UI/macOS/highlighter.h index 9368af6..d88638b 100644 --- a/WireGuard/WireGuard/UI/macOS/highlighter.h +++ b/WireGuard/WireGuard/UI/macOS/highlighter.h @@ -6,28 +6,30 @@ #include enum highlight_type { - HighlightSection, - HighlightKeytype, - HighlightKey, - HighlightCmd, - HighlightIP, - HighlightCidr, - HighlightHost, - HighlightPort, - HighlightTable, - HighlightFwMark, - HighlightMTU, - HighlightSaveConfig, - HighlightKeepalive, - HighlightComment, - HighlightDelimiter, - HighlightError, - HighlightEnd + HighlightSection, + HighlightKeytype, + HighlightKey, + HighlightIP, + HighlightCidr, + HighlightHost, + HighlightPort, + HighlightMTU, + HighlightKeepalive, + HighlightComment, + HighlightDelimiter, +#ifndef MOBILE_WGQUICK_SUBSET + HighlightTable, + HighlightFwMark, + HighlightSaveConfig, + HighlightCmd, +#endif + HighlightError, + HighlightEnd }; struct highlight_span { - enum highlight_type type; - size_t start, len; + enum highlight_type type; + size_t start, len; }; struct highlight_span *highlight_config(const char *config);