diff --git a/src/config_parser.c b/src/config_parser.c index ef77f648..8a44c65a 100644 --- a/src/config_parser.c +++ b/src/config_parser.c @@ -1134,8 +1134,10 @@ struct utun_config* parse_config_from_buf(const char *buf, size_t len, const cha break; case SECTION_CONTROL: option_result = parse_control(key, value, &cfg->global, filename, line_num); break; case SECTION_ALLOWED_KEYS: - if (strcmp(key, "allow_all") == 0) - cfg->global.allowed_keys_allow_all = !strcasecmp(value, "yes") || !strcmp(value, "1") || !strcasecmp(value, "true"); + if (strcmp(key, "allow_all") == 0) { + int enabled = parse_boolean(value); if (enabled < 0) goto error; + cfg->global.allowed_keys_allow_all = enabled; + } else if (strcmp(key, "key") == 0) { struct CFG_ALLOWED_KEY* nk = u_calloc(1, sizeof(*nk)); if (!nk) goto error; @@ -1150,18 +1152,18 @@ struct utun_config* parse_config_from_buf(const char *buf, size_t len, const cha case SECTION_TCP_PROXY_CLIENT: option_result = parse_tcp_proxy_client(key, value, &cfg->global, filename, line_num); break; case SECTION_TCP_PROXY_SERVER: if (strcmp(key, "tcp_recv_buf") == 0) { - cfg->global.tcp_recv_buf = atoi(value); + option_result = parse_integer(value, 0, INT_MAX, &cfg->global.tcp_recv_buf); } else if (strcmp(key, "fib") == 0) { - cfg->global.tcp_proxy_server_fib = atoi(value); + option_result = parse_integer(value, 0, INT_MAX, &cfg->global.tcp_proxy_server_fib); } else if (strcmp(key, "so_mark") == 0) { - cfg->global.tcp_proxy_server_so_mark = atoi(value); + option_result = parse_integer(value, INT_MIN, INT_MAX, &cfg->global.tcp_proxy_server_so_mark); } else if (strcmp(key, "netif") == 0) { cfg->global.tcp_proxy_server_netif_index = get_netif_index(value); } else if (strcmp(key, "bind_ip") == 0) { strncpy(cfg->global.tcp_proxy_server_bind_ip, value, sizeof(cfg->global.tcp_proxy_server_bind_ip) - 1); cfg->global.tcp_proxy_server_bind_ip[sizeof(cfg->global.tcp_proxy_server_bind_ip) - 1] = '\0'; } else if (strcmp(key, "connect_timeout") == 0) { - cfg->global.tcp_proxy_server_connect_timeout_ms = atoi(value); + option_result = parse_integer(value, 0, INT_MAX / 10, &cfg->global.tcp_proxy_server_connect_timeout_ms); } else { DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%d: Unknown tcp_proxy_server option '%s'. Valid: tcp_recv_buf, fib, so_mark, netif, bind_ip, connect_timeout", filename, line_num, key); goto error; @@ -1169,15 +1171,17 @@ struct utun_config* parse_config_from_buf(const char *buf, size_t len, const cha break; case SECTION_NETWORK: option_result = parse_network(key, value, cur_network, filename, line_num); break; case SECTION_NTP: - if (strcmp(key, "enabled") == 0) - cfg->global.ntp_enabled = !strcasecmp(value, "yes") || !strcmp(value, "1") || !strcasecmp(value, "true"); + if (strcmp(key, "enabled") == 0) { + int enabled = parse_boolean(value); if (enabled < 0) goto error; + cfg->global.ntp_enabled = enabled; + } else if (strcmp(key, "server") == 0) { struct CFG_NTP_SERVER* ns = u_calloc(1, sizeof(*ns)); if (!ns) goto error; if (assign_string(ns->name, sizeof(ns->name), value) || !value[0]) { u_free(ns); goto error; } ns->next = cfg->global.ntp_servers; cfg->global.ntp_servers = ns; cfg->global.ntp_server_count++; } else if (strcmp(key, "interval") == 0) { - cfg->global.ntp_resync_interval = atoi(value); + option_result = parse_integer(value, 0, INT_MAX / 10000, &cfg->global.ntp_resync_interval); if (cfg->global.ntp_resync_interval < 60) cfg->global.ntp_resync_interval = 60; } else { DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%d: unknown ntp option '%s'", filename, line_num, key); goto error; } break; @@ -1199,8 +1203,9 @@ struct utun_config* parse_config_from_buf(const char *buf, size_t len, const cha case SECTION_SOCKS: option_result = parse_socks(key, value, &cfg->global, filename, line_num); break; case SECTION_STUN: if (parse_stun(key, value, &cfg->global, filename, line_num) < 0) goto error; break; case SECTION_LOG_UDP: - if (strcmp(key, "ip") == 0) strncpy(cfg->global.log_udp_ip, value, sizeof(cfg->global.log_udp_ip) - 1); - else if (strcmp(key, "port") == 0) cfg->global.log_udp_port = atoi(value); + if (strcmp(key, "ip") == 0) option_result = assign_string(cfg->global.log_udp_ip, sizeof(cfg->global.log_udp_ip), value); + else if (strcmp(key, "port") == 0) option_result = parse_integer(value, 0, UINT16_MAX, &cfg->global.log_udp_port); + else { DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%d: unknown log_udp option '%s'", filename, line_num, key); goto error; } break; default: DEBUG_WARN(DEBUG_CATEGORY_CONFIG, "%s:%d: Key outside section: %s", filename, line_num, key); break; } diff --git a/src/config_updater.c b/src/config_updater.c index 71a26520..4e026ff1 100644 --- a/src/config_updater.c +++ b/src/config_updater.c @@ -89,7 +89,10 @@ static void config_scan(const char *text, size_t length, struct config_field fie } else if (index == CFG_NODE_ID) { uint64_t id; if (config_node_id(value, &id)) fields[index].invalid = 1; - } else if (index != CFG_REALITY_ENABLED && config_ini_hex(value, NULL, SC_PRIVKEY_SIZE)) fields[index].invalid = 1; + } else if (index == CFG_REALITY_ENABLED) { + if (strcmp(value, "0") && strcmp(value, "1") && strcasecmp(value, "no") && strcasecmp(value, "yes") && + strcasecmp(value, "false") && strcasecmp(value, "true")) fields[index].invalid = 1; + } else if (config_ini_hex(value, NULL, SC_PRIVKEY_SIZE)) fields[index].invalid = 1; } pos = end; } @@ -370,7 +373,13 @@ int config_ensure_keys_and_node_id(const char *filename) { snprintf(fields[CFG_NODE_ID].value, sizeof(fields[CFG_NODE_ID].value), "%016llx", (unsigned long long)node_id); } for (int i = CFG_PRIVATE; i <= CFG_NODE_ID; i++) if (fields[i].invalid) fields[i].update = 1; - int reality_enabled = atoi(fields[CFG_REALITY_ENABLED].value) != 0; + const char* enabled = fields[CFG_REALITY_ENABLED].value; + int reality_enabled = !strcmp(enabled, "1") || !strcasecmp(enabled, "yes") || !strcasecmp(enabled, "true"); + if (fields[CFG_REALITY_ENABLED].present && !reality_enabled && + strcmp(enabled, "0") && strcasecmp(enabled, "no") && strcasecmp(enabled, "false")) { + DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s: invalid REALITY enabled value", filename); goto done; + } + if (fields[CFG_REALITY_ENABLED].invalid) fields[CFG_REALITY_ENABLED].update = 1; if (reality_enabled) { if (config_ini_hex(fields[CFG_REALITY_PRIVATE].value, reality_private, sizeof(reality_private))) { uint8_t public_part[REALITY_AUTH_KEY_SIZE];