Validate complete protocol versions, network keys and endpoint ports
This commit is contained in:
1 parent
7593120bd9
commit
bff354f9cc
1 file changed
+40
-36
+40
-36
@@ -73,6 +73,26 @@ static int parse_unsigned(const char* text, int base, uint64_t maximum, uint64_t
|
||||
*out = value; return 0;
|
||||
}
|
||||
|
||||
/* Версия содержит ровно три десятичных октета, без хвоста; выход применяется целиком. */
|
||||
static int parse_version(const char* value, uint8_t out[3]) {
|
||||
char text[12];
|
||||
if (assign_string(text, sizeof(text), value)) return -1;
|
||||
char* cursor = text;
|
||||
uint8_t version[3];
|
||||
for (unsigned i = 0; i < 3; i++) {
|
||||
char* dot = strchr(cursor, '.');
|
||||
if ((i < 2 && !dot) || (i == 2 && dot)) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "invalid version format, expected x.y.z"); return -1;
|
||||
}
|
||||
if (dot) *dot = '\0';
|
||||
uint64_t number;
|
||||
if (parse_unsigned(cursor, 10, UINT8_MAX, &number)) return -1;
|
||||
version[i] = (uint8_t)number;
|
||||
if (dot) cursor = dot + 1;
|
||||
}
|
||||
memcpy(out, version, sizeof(version)); return 0;
|
||||
}
|
||||
|
||||
static int parse_ip_with_netmask(const char *str, struct IP *ip, uint8_t *netmask) {
|
||||
char ip_str[64];
|
||||
if (assign_string(ip_str, sizeof(ip_str), str)) return -1;
|
||||
@@ -668,26 +688,18 @@ static int parse_nat(const char *key, const char *value, struct global_config *g
|
||||
|
||||
static int parse_server(const char *key, const char *value, struct CFG_SERVER *srv, const char *filename, int line_num) {
|
||||
if (strcmp(key, "addr") == 0) {
|
||||
if (strncmp(value, "temporary_ipv6:", 15) == 0) {
|
||||
srv->ipv6_mode = CFG_IPV6_MODE_TEMPORARY;
|
||||
const char* port_str = value + 15;
|
||||
if (!port_str[0]) return -1;
|
||||
int temporary = strncmp(value, "temporary_ipv6:", 15) == 0;
|
||||
if (temporary || strncmp(value, "permanent_ipv6:", 15) == 0) {
|
||||
uint64_t port;
|
||||
if (parse_unsigned(value + 15, 10, UINT16_MAX, &port)) return -1;
|
||||
srv->ipv6_mode = temporary ? CFG_IPV6_MODE_TEMPORARY : CFG_IPV6_MODE_PERMANENT;
|
||||
struct sockaddr_in6* sin6 = (struct sockaddr_in6*)&srv->ip;
|
||||
memset(&srv->ip, 0, sizeof(srv->ip));
|
||||
sin6->sin6_family = AF_INET6;
|
||||
sin6->sin6_port = htons((uint16_t)atoi(port_str));
|
||||
return 0;
|
||||
}
|
||||
if (strncmp(value, "permanent_ipv6:", 15) == 0) {
|
||||
srv->ipv6_mode = CFG_IPV6_MODE_PERMANENT;
|
||||
const char* port_str = value + 15;
|
||||
if (!port_str[0]) return -1;
|
||||
struct sockaddr_in6* sin6 = (struct sockaddr_in6*)&srv->ip;
|
||||
memset(&srv->ip, 0, sizeof(srv->ip));
|
||||
sin6->sin6_family = AF_INET6;
|
||||
sin6->sin6_port = htons((uint16_t)atoi(port_str));
|
||||
sin6->sin6_port = htons((uint16_t)port);
|
||||
return 0;
|
||||
}
|
||||
srv->ipv6_mode = CFG_IPV6_MODE_NONE;
|
||||
return parse_address_and_port(value, &srv->ip);
|
||||
}
|
||||
if (strcmp(key, "so_mark") == 0) {
|
||||
@@ -712,7 +724,7 @@ static int parse_server(const char *key, const char *value, struct CFG_SERVER *s
|
||||
} else if (strcmp(value, "local") == 0) {
|
||||
srv->type = CFG_SERVER_TYPE_LOCAL;
|
||||
} else {
|
||||
srv->type = CFG_SERVER_TYPE_UNKNOWN;
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%d: unknown server type '%s'", filename, line_num, value); return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -726,7 +738,8 @@ static int parse_server(const char *key, const char *value, struct CFG_SERVER *s
|
||||
}
|
||||
if (strcmp(key, "transport") == 0) {
|
||||
if (strcmp(value, "tcp") == 0) srv->transport = 1;
|
||||
else srv->transport = 0; // default udp
|
||||
else if (strcmp(value, "udp") == 0) srv->transport = 0;
|
||||
else { DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%d: unknown server transport '%s'", filename, line_num, value); return -1; }
|
||||
return 0;
|
||||
}
|
||||
if (strcmp(key, "reality") == 0) {
|
||||
@@ -798,13 +811,7 @@ static int parse_client(const char *key, const char *value, struct CFG_CLIENT *c
|
||||
return 0;
|
||||
}
|
||||
if (strcmp(key, "version") == 0) {
|
||||
int x = 0, y = 0, z = 0;
|
||||
if (sscanf(value, "%d.%d.%d", &x, &y, &z) != 3 || x < 0 || x > 255 || y < 0 || y > 255 || z < 0 || z > 255) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%d: bad client reality version '%s' (expected x.y.z)", filename, line_num, value);
|
||||
return -1;
|
||||
}
|
||||
cli->reality.version[0] = (uint8_t)x; cli->reality.version[1] = (uint8_t)y; cli->reality.version[2] = (uint8_t)z;
|
||||
return 0;
|
||||
return parse_version(value, cli->reality.version);
|
||||
}
|
||||
if (strcmp(key, "fingerprint") == 0) {
|
||||
if (strcmp(value, "openssl") == 0) { cli->reality.fingerprint = REALITY_FP_OPENSSL; return 0; }
|
||||
@@ -879,13 +886,14 @@ static int parse_chatserver(const char *key, const char *value, struct global_co
|
||||
|
||||
static int parse_network(const char *key, const char *value, struct CFG_NETWORK *net, const char *filename, int line_num) {
|
||||
if (strcmp(key, "id") == 0) {
|
||||
net->id = strtoull(value, NULL, 16);
|
||||
return 0;
|
||||
return parse_unsigned(value, 16, UINT64_C(0x00ffffffffffffff), &net->id);
|
||||
}
|
||||
if (strcmp(key, "pubkey") == 0) {
|
||||
if (config_ini_hex(value, NULL, SC_PUBKEY_SIZE)) { DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "network pubkey requires 64 HEX characters"); return -1; }
|
||||
return assign_string(net->pubkey_hex, sizeof(net->pubkey_hex), value);
|
||||
}
|
||||
if (strcmp(key, "signing_key") == 0) {
|
||||
if (config_ini_hex(value, NULL, SC_PRIVKEY_SIZE)) { DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "network signing key requires 64 HEX characters"); return -1; }
|
||||
return assign_string(net->signing_key_hex, sizeof(net->signing_key_hex), value);
|
||||
}
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%d: Unknown network option '%s'. Valid: id, pubkey, signing_key", filename, line_num, key);
|
||||
@@ -930,13 +938,7 @@ static int parse_reality(const char *key, const char *value, struct reality_conf
|
||||
return 0;
|
||||
}
|
||||
if (strcmp(key, "version") == 0) {
|
||||
int x = 0, y = 0, z = 0;
|
||||
if (sscanf(value, "%d.%d.%d", &x, &y, &z) != 3 || x < 0 || x > 255 || y < 0 || y > 255 || z < 0 || z > 255) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%d: bad reality version '%s' (expected x.y.z)", filename, line_num, value);
|
||||
return -1;
|
||||
}
|
||||
rc->version[0] = (uint8_t)x; rc->version[1] = (uint8_t)y; rc->version[2] = (uint8_t)z;
|
||||
return 0;
|
||||
return parse_version(value, rc->version);
|
||||
}
|
||||
if (strcmp(key, "time_window") == 0) { rc->time_window_sec = atoi(value); return 0; }
|
||||
if (strcmp(key, "relay_idle_timeout") == 0) { rc->relay_idle_timeout_sec = atoi(value); return 0; }
|
||||
@@ -958,11 +960,13 @@ static int parse_socks(const char *key, const char *value, struct global_config
|
||||
if (strcmp(key, "addr") == 0) {
|
||||
const char *colon = strrchr(value, ':');
|
||||
if (!colon) { DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%d: socks addr must be 'host:port'", filename, line_num); return -1; }
|
||||
int port = atoi(colon + 1);
|
||||
if (port <= 0 || port > 65535) { DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%d: bad socks port '%s'", filename, line_num, colon + 1); return -1; }
|
||||
uint64_t port;
|
||||
if (parse_unsigned(colon + 1, 10, UINT16_MAX, &port) || !port) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%d: bad socks port", filename, line_num); return -1;
|
||||
}
|
||||
char host[64];
|
||||
size_t hlen = (size_t)(colon - value);
|
||||
if (hlen >= sizeof(host)) hlen = sizeof(host) - 1;
|
||||
if (!hlen || hlen >= sizeof(host)) { DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%d: invalid socks host length", filename, line_num); return -1; }
|
||||
memcpy(host, value, hlen); host[hlen] = '\0';
|
||||
if (hlen >= 2 && host[0] == '[' && host[hlen - 1] == ']') { host[hlen - 1] = '\0'; memmove(host, host + 1, strlen(host)); }
|
||||
strncpy(global->socks_host, host, sizeof(global->socks_host) - 1);
|
||||
|
||||
Reference in new issue
Block a user