diff --git a/src/config_parser.c b/src/config_parser.c index 19b1d148..cd82e812 100644 --- a/src/config_parser.c +++ b/src/config_parser.c @@ -1197,7 +1197,23 @@ struct utun_config* parse_config_from_buf(const char *buf, size_t len, const cha 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 && hex_to_binary(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_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; if (strcmp(key, "tcp_recv_buf") == 0) cfg->global.tcp_recv_buf = atoi(value); break; + case SECTION_TCP_PROXY_SERVER: + cfg->global.tcp_proxy_server_enabled = 1; + if (strcmp(key, "tcp_recv_buf") == 0) { + cfg->global.tcp_recv_buf = atoi(value); + } else if (strcmp(key, "fib") == 0) { + cfg->global.tcp_proxy_server_fib = atoi(value); + } else if (strcmp(key, "so_mark") == 0) { + cfg->global.tcp_proxy_server_so_mark = atoi(value); + } 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 { + DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%d: Unknown tcp_proxy_server option '%s'. Valid: tcp_recv_buf, fib, so_mark, netif, bind_ip", filename, line_num, key); + } + break; case SECTION_NETWORK: if (cur_network) 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") == 0 || strcasecmp(value, "1") == 0 || strcasecmp(value, "true") == 0; else if (strcmp(key, "server") == 0) { struct CFG_NTP_SERVER *ns = u_calloc(1, sizeof(struct CFG_NTP_SERVER)); if (ns) { strncpy(ns->name, value, sizeof(ns->name) - 1); ns->name[sizeof(ns->name) - 1] = '\0'; 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); 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); break; case SECTION_CHATSERVER: cfg->global.chatserver_enabled = 1; cfg->global.db_sync_enabled = 1; if (strcmp(key, "db_path") == 0) assign_string(cfg->global.db_path, sizeof(cfg->global.db_path), value); else if (parse_chatserver(key, value, &cfg->global, filename, line_num) < 0 && chat_setting_set(key, value) < 0) { DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%d: Unknown chatserver option '%s'. Valid: db_path, join_password, allowed_groups, storage_total_size, storage_unit_size, storage_autoload, opus_codec_preset, compressor_enabled, compressor_max_gain_db, compressor_rise_rate, media_download_max_peers", filename, line_num, key); } break; diff --git a/src/config_parser.h b/src/config_parser.h index df7efede..25bdf17d 100644 --- a/src/config_parser.h +++ b/src/config_parser.h @@ -191,6 +191,10 @@ struct global_config { int tcp_proxy_server_enabled; int auto_sockets; // 1 = auto-create sockets from interfaces, skip [server] int tcp_recv_buf; // SO_RCVBUF для TCP сокетов (0=default ОС) + int tcp_proxy_server_fib; // FreeBSD SO_SETFIB, 0=не менять + int tcp_proxy_server_so_mark; // Linux SO_MARK, 0=не менять + uint32_t tcp_proxy_server_netif_index; // Linux SO_BINDTODEVICE, 0=нет + char tcp_proxy_server_bind_ip[64]; // IP для bind() перед connect() // NTP configuration ([ntp] section) int ntp_enabled; diff --git a/src/proxy/tcp_proxy_server.c b/src/proxy/tcp_proxy_server.c index 657aead1..0b3bf7d6 100644 --- a/src/proxy/tcp_proxy_server.c +++ b/src/proxy/tcp_proxy_server.c @@ -13,6 +13,7 @@ #include "../lib/ll_queue.h" #include "../lib/mem.h" #include "../lib/tcp_io.h" +#include "../lib/socket_compat.h" #include #include #include @@ -21,6 +22,7 @@ #include #include #include +#include #include #endif @@ -372,6 +374,29 @@ int tcp_proxy_server_handle_connect(struct UTUN_INSTANCE* inst, struct ll_entry* (int)sock, stream_id, dest_ip[0],dest_ip[1],dest_ip[2],dest_ip[3],ntohs(dest_port), ctx->conn_count); socket_set_nonblocking(sock); + struct global_config* g = &inst->config->global; + if (g->tcp_proxy_server_bind_ip[0]) { + struct sockaddr_in local_addr = {.sin_family = AF_INET, .sin_port = 0}; + if (inet_pton(AF_INET, g->tcp_proxy_server_bind_ip, &local_addr.sin_addr) == 1) { + if (bind(sock, (struct sockaddr*)&local_addr, sizeof(local_addr)) < 0) { + DEBUG_ERROR(DEBUG_CATEGORY_PROXY, "TCP proxy server: bind(%s) failed: %s", g->tcp_proxy_server_bind_ip, strerror(errno)); + socket_close_wrapper(sock); ctx->conn_count--; u_free(rc); queue_dgram_free(entry); queue_entry_free(entry); return -1; + } + } else { + DEBUG_ERROR(DEBUG_CATEGORY_PROXY, "TCP proxy server: invalid bind_ip=%s", g->tcp_proxy_server_bind_ip); + } + } + if (g->tcp_proxy_server_so_mark > 0) socket_set_mark(sock, g->tcp_proxy_server_so_mark); +#ifdef __FreeBSD__ + if (g->tcp_proxy_server_fib > 0) { + setsockopt(sock, SOL_SOCKET, SO_SETFIB, &g->tcp_proxy_server_fib, sizeof(g->tcp_proxy_server_fib)); + } +#endif + if (g->tcp_proxy_server_netif_index > 0) { + char ifname[IF_NAMESIZE]; + if (if_indextoname(g->tcp_proxy_server_netif_index, ifname)) socket_bind_to_device(sock, ifname); + } + rc->tc = tcp_conn_create(inst->ua, sock, 1500, 8192, 4, 0, inst->config->global.tcp_recv_buf, on_fin_cb, on_error_cb, rc); if (!rc->tc) { DEBUG_ERROR(DEBUG_CATEGORY_PROXY, "TCP proxy server: tcp_conn_create failed"); socket_close_wrapper(sock); ctx->conn_count--; u_free(rc); queue_dgram_free(entry); queue_entry_free(entry); return -1; } rc->tc->on_closed = on_closed_cb; diff --git a/utun.conf.sample b/utun.conf.sample index 302ec929..e2b2a8b8 100644 --- a/utun.conf.sample +++ b/utun.conf.sample @@ -107,6 +107,11 @@ allow=all # Принимает CONNECT-запросы от других нод и открывает OS сокеты к адресатам. #[tcp_proxy_server] #enabled=yes +#tcp_recv_buf=65536 +#fib=1 ; FreeBSD: SO_SETFIB (routing table number) +#so_mark=100 ; Linux: SO_MARK (socket mark/fwmark) +#netif=eth1 ; Linux: SO_BINDTODEVICE (interface name) +#bind_ip=10.0.0.1 ; bind() local IP before connect() # --- Chatserver: headless supernode config --- #[chatserver]