diff --git a/src/config_parser.c b/src/config_parser.c index 7482359d..ba3acca0 100644 --- a/src/config_parser.c +++ b/src/config_parser.c @@ -551,15 +551,26 @@ static int parse_nat(const char *key, const char *value, struct global_config *g return 0; } if (strcmp(key, "nat_via") == 0) { - global->nat_via_node_id = strtoull(value, NULL, 16); + char* end; + errno = 0; + uint64_t node_id = strtoull(value, &end, 16); + if (!*value || *value == '-' || *value == '+' || *end || errno == ERANGE) { + DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%d: Invalid NAT provider ID: %s", filename, line_num, value); + return -1; + } + global->nat_via_node_id = node_id; return 0; } - if (strcmp(key, "port_start") == 0) { - global->nat_port_start = (uint16_t)atoi(value); - return 0; - } - if (strcmp(key, "port_end") == 0) { - global->nat_port_end = (uint16_t)atoi(value); + if (strcmp(key, "port_start") == 0 || strcmp(key, "port_end") == 0) { + char* end; + errno = 0; + unsigned long port = strtoul(value, &end, 10); + if (!isdigit((unsigned char)*value) || *end || errno == ERANGE || port == 0 || port > 65535) { + DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%d: Invalid NAT %s: %s (expected 1..65535)", filename, line_num, key, value); + return -1; + } + if (strcmp(key, "port_start") == 0) global->nat_port_start = (uint16_t)port; + else global->nat_port_end = (uint16_t)port; return 0; } if (strcmp(key, "forward") == 0) { @@ -567,21 +578,44 @@ static int parse_nat(const char *key, const char *value, struct global_config *g DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Too many NAT forward rules (max %d)", MAX_NAT_FORWARDS); return -1; } - // Format: proto:internal_ip:internal_port:external_port - // Example: tcp:192.168.1.100:8080:8080 + // Format: proto:node_id_hex:internal_ip:internal_port:external_port. char buf[128]; - strncpy(buf, value, sizeof(buf) - 1); - buf[sizeof(buf) - 1] = '\0'; - config_ini_trim(buf); - - char* proto_str = strtok(buf, ":"); - char* ip_str = strtok(NULL, ":"); - char* int_port = strtok(NULL, ":"); - char* ext_port = strtok(NULL, ":"); - if (!proto_str || !ip_str || !int_port || !ext_port) { - DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Invalid NAT forward format: %s (expected proto:ip:internal_port:external_port)", value); + if (strlen(value) >= sizeof(buf)) { + DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%d: NAT forward value too long", filename, line_num); return -1; } + strcpy(buf, value); + char* fields[5]; + char* cursor = buf; + for (int i = 0; i < 5; i++) { + fields[i] = cursor; + char* colon = strchr(cursor, ':'); + if ((i < 4 && !colon) || (i == 4 && colon) || !*cursor || colon == cursor) { + DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%d: Invalid NAT forward: %s (proto:node_id:ip:internal_port:external_port)", + filename, line_num, value); + return -1; + } + if (colon) { *colon = '\0'; cursor = colon + 1; } + } + char* proto_str = fields[0]; + char* ip_str = fields[2]; + char* end; + errno = 0; + uint64_t node_id = strtoull(fields[1], &end, 16); + if (!node_id || *fields[1] == '-' || *fields[1] == '+' || *end || errno == ERANGE) { + DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%d: Invalid NAT forward node ID: %s", filename, line_num, fields[1]); + return -1; + } + uint16_t ports[2]; + for (int i = 0; i < 2; i++) { + errno = 0; + unsigned long port = strtoul(fields[i + 3], &end, 10); + if (!isdigit((unsigned char)*fields[i + 3]) || *end || errno == ERANGE || port == 0 || port > 65535) { + DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%d: Invalid NAT forward port: %s", filename, line_num, fields[i + 3]); + return -1; + } + ports[i] = (uint16_t)port; + } uint8_t proto; if (strcasecmp(proto_str, "tcp") == 0) proto = IPPROTO_TCP; @@ -598,13 +632,14 @@ static int parse_nat(const char *key, const char *value, struct global_config *g } int idx = global->nat_forward_count; + global->nat_forwards[idx].node_id = node_id; global->nat_forwards[idx].proto = proto; global->nat_forwards[idx].internal_ip_host = ntohl(addr.s_addr); - global->nat_forwards[idx].internal_port_net = htons((uint16_t)atoi(int_port)); - global->nat_forwards[idx].external_port = (uint16_t)atoi(ext_port); + global->nat_forwards[idx].internal_port_net = htons(ports[0]); + global->nat_forwards[idx].external_port = ports[1]; global->nat_forward_count++; - DEBUG_INFO(DEBUG_CATEGORY_CONFIG, "NAT forward: %s %s:%s -> :%s", - proto_str, ip_str, int_port, ext_port); + DEBUG_INFO(DEBUG_CATEGORY_CONFIG, "NAT forward: :%u -> node=%016llx %s %s:%u", + ports[1], (unsigned long long)node_id, proto_str, ip_str, ports[0]); return 0; } DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%d: Unknown NAT option '%s'. Valid: tun_ifname, tun_ip, nat_via, port_start, port_end, forward", filename, line_num, key); @@ -1103,7 +1138,10 @@ struct utun_config* parse_config_from_buf(const char *buf, size_t len, const cha break; case SECTION_CONTROL: 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") == 0 || strcasecmp(value, "1") == 0 || strcasecmp(value, "true") == 0; else if (strcmp(key, "key") == 0) { struct CFG_ALLOWED_KEY *nk = u_calloc(1, sizeof(struct CFG_ALLOWED_KEY)); if (nk && strlen(value) == SC_PUBKEY_SIZE * 2 && config_ini_hex(value, nk->key_bin, SC_PUBKEY_SIZE) == 0) { nk->next = cfg->global.allowed_keys; cfg->global.allowed_keys = nk; cfg->global.allowed_keys_count++; } else u_free(nk); } else DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%d: Unknown allowed_keys option '%s'", filename, line_num, key); break; - case SECTION_NAT: cfg->global.nat_enabled = 1; parse_nat(key, value, &cfg->global, filename, line_num); break; + case SECTION_NAT: + cfg->global.nat_enabled = 1; + if (parse_nat(key, value, &cfg->global, filename, line_num) < 0) goto error; + break; case SECTION_TCP_PROXY_CLIENT: cfg->global.tcp_proxy_client_enabled = 1; parse_tcp_proxy_client(key, value, &cfg->global, filename, line_num); break; case SECTION_TCP_PROXY_SERVER: cfg->global.tcp_proxy_server_enabled = 1; diff --git a/src/config_parser.h b/src/config_parser.h index e910f702..f0c03dc3 100644 --- a/src/config_parser.h +++ b/src/config_parser.h @@ -193,6 +193,7 @@ struct global_config { uint16_t nat_port_end; #define MAX_NAT_FORWARDS 64 struct { + uint64_t node_id; // Узел назначения статического проброса; ненулевой ID. uint8_t proto; uint32_t internal_ip_host; uint16_t internal_port_net; diff --git a/src/eim_nat.h b/src/eim_nat.h index 83ac74f4..6e38c159 100644 --- a/src/eim_nat.h +++ b/src/eim_nat.h @@ -65,7 +65,7 @@ int eim_nat_ingress(struct eim_nat_ctx* ctx, uint8_t* ip_data, size_t ip_len, int eim_nat_add_forward(struct eim_nat_ctx* ctx, uint8_t proto, uint32_t internal_ip_host, uint16_t internal_port_net, - uint16_t external_port); + uint16_t external_port, uint64_t node_id); #ifdef __cplusplus