Skip to content

Commit 920bb0c

Browse files
committed
Fix udp tproxy with http connect-udp
1 parent f0f4069 commit 920bb0c

2 files changed

Lines changed: 28 additions & 50 deletions

File tree

proxy/include/proxy/proxy_server.hpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ namespace proxy {
9898
// 发送队列, 用于序列化 connect-udp 数据包的 TCP 发送, 避免多个并发协程同时写入
9999
// udp_http_sock_ 导致 capsule 数据在 TCP 流上交错损坏.
100100
std::deque<std::vector<char>> send_queue_;
101+
101102
// 用于通知发送协程有新数据到达的定时器.
102103
// 当有新的 UDP 数据包推入 send_queue_ 时, 取消此定时器以唤醒发送协程.
103104
std::optional<net::steady_timer> notify_timer_;
@@ -460,8 +461,6 @@ namespace proxy {
460461
// UDP TPROXY 透明代理相关成员.
461462
std::vector<udp::socket> m_udp_tproxy_listeners;
462463

463-
std::mutex m_udp_flows_mutex;
464-
465464
// 存储每个 UDP TPROXY flow 的状态信息, 包括客户端地址、原始目标地址和 backend socket 等等.
466465
std::unordered_map<size_t, udp_tproxy_flow_ptr> m_udp_tproxy_flows;
467466

proxy/src/proxy_server.cpp

Lines changed: 27 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -865,21 +865,21 @@ void proxy_server::close() noexcept
865865
acceptor.close(ignore_ec);
866866

867867
#if defined(__linux__)
868+
868869
// 关闭 UDP TPROXY 相关资源.
870+
for (auto& [key, flow] : m_udp_tproxy_flows)
869871
{
870-
std::lock_guard<std::mutex> lock(m_udp_flows_mutex);
871-
for (auto& [key, flow] : m_udp_tproxy_flows)
872+
if (flow)
872873
{
873-
if (flow)
874-
{
875-
flow->backend_sock_.reset();
876-
flow->relay_sock_.reset();
877-
}
874+
flow->backend_sock_.reset();
875+
flow->relay_sock_.reset();
878876
}
879-
m_udp_tproxy_flows.clear();
880877
}
878+
m_udp_tproxy_flows.clear();
879+
881880
for (auto& s : m_udp_tproxy_listeners)
882881
s.close(ignore_ec);
882+
883883
#endif // defined(__linux__)
884884

885885
for (auto& [id, c] : m_clients)
@@ -1182,7 +1182,6 @@ size_t proxy_server::make_udp_flow_key(const udp::endpoint& client, const udp::e
11821182

11831183
net::awaitable<void> proxy_server::udp_tproxy_check() noexcept
11841184
{
1185-
std::lock_guard<std::mutex> lock(m_udp_flows_mutex);
11861185
std::vector<size_t> expired_keys;
11871186

11881187
for (const auto& [key, flow] : m_udp_tproxy_flows)
@@ -1539,16 +1538,14 @@ net::awaitable<void> proxy_server::udp_tproxy_response_loop(udp_tproxy_flow_ptr
15391538
return;
15401539

15411540
flow->backend_sock_.reset();
1541+
flow->relay_sock_.reset();
1542+
flow->udp_http_sock_.reset();
15421543

1543-
auto flow_key = make_udp_flow_key(
1544-
flow->client_endp_, flow->original_endp_);
1545-
1546-
std::lock_guard<std::mutex> lock(m_udp_flows_mutex);
1547-
m_udp_tproxy_flows.erase(flow_key);
1544+
m_udp_tproxy_flows.erase(flow->flow_key_);
15481545
});
15491546

1550-
if (!flow->backend_sock_)
1551-
flow->backend_sock_.emplace(m_executor);
1547+
// 创建 backend socket 用于接收来自 proxy_pass 的 UDP 数据包.
1548+
flow->backend_sock_.emplace(m_executor);
15521549

15531550
auto& backend_sock = flow->backend_sock_;
15541551
boost::system::error_code ec;
@@ -1702,9 +1699,6 @@ void proxy_server::send_response_to_client(udp_tproxy_flow_ptr flow, const char*
17021699
void proxy_server::udp_tproxy_forward_packet(
17031700
udp_tproxy_flow_ptr flow, const char* data, std::size_t len)
17041701
{
1705-
if (!flow)
1706-
return;
1707-
17081702
if (!flow->backend_sock_)
17091703
return;
17101704

@@ -1767,7 +1761,6 @@ void proxy_server::udp_tproxy_forward_packet(
17671761
<< ", dest: " << flow->original_endp_
17681762
<< ", backend endp: " << m_backend_endp;
17691763

1770-
std::lock_guard<std::mutex> lock(m_udp_flows_mutex);
17711764
m_udp_tproxy_flows.erase(flow->flow_key_);
17721765
}
17731766
}
@@ -1780,6 +1773,12 @@ net::awaitable<void> proxy_server::start_udp_tproxy_listen(udp::socket& udp_sock
17801773

17811774
boost::system::error_code ec;
17821775

1776+
auto scheme = boost::to_lower_copy(
1777+
std::string(m_option.proxy_pass_->scheme()));
1778+
1779+
// 如果上游代理是 HTTP 代理, 则通过 connect-udp 协议进行 udp 代理.
1780+
bool using_connect_udp = scheme.starts_with("http");
1781+
17831782
while (!m_abort)
17841783
{
17851784
co_await udp_sock.async_wait(net::socket_base::wait_read, net_awaitable[ec]);
@@ -1819,18 +1818,10 @@ net::awaitable<void> proxy_server::start_udp_tproxy_listen(udp::socket& udp_sock
18191818
// 计算 flow 表的 key.
18201819
size_t flow_key = make_udp_flow_key(client_ep, original_dest);
18211820

1822-
auto scheme = boost::to_lower_copy(
1823-
std::string(m_option.proxy_pass_->scheme()));
1824-
1825-
// 如果上游代理是 HTTP 代理, 则通过 connect-udp 协议进行 udp 代理.
1826-
bool using_connect_udp = scheme.starts_with("http");
1827-
18281821
std::shared_ptr<udp_tproxy_flow> flow;
18291822

18301823
auto make_tproxy_flow = [&]() mutable
18311824
{
1832-
std::lock_guard<std::mutex> lock(m_udp_flows_mutex);
1833-
18341825
auto it = m_udp_tproxy_flows.find(flow_key);
18351826
if (it != m_udp_tproxy_flows.end())
18361827
{
@@ -1891,9 +1882,6 @@ net::awaitable<void> proxy_server::start_udp_tproxy_listen(udp::socket& udp_sock
18911882
void proxy_server::udp_tproxy_forward_packet_http(
18921883
udp_tproxy_flow_ptr flow, const char* data, std::size_t len)
18931884
{
1894-
if (!flow || !flow->udp_http_sock_)
1895-
return;
1896-
18971885
// 构建 DATAGRAM capsule (RFC 9297):
18981886
// capsule type (varint) = 0x00
18991887
// capsule length (varint) = len + 1 # 这里 + 1 是因为 context ID 为 0 占用一字节
@@ -1913,8 +1901,6 @@ void proxy_server::udp_tproxy_forward_packet_http(
19131901

19141902
// 推入发送队列并通知发送协程.
19151903
{
1916-
std::lock_guard<std::mutex> lock(m_udp_flows_mutex);
1917-
19181904
flow->send_queue_.emplace_back(buf, buf + pos);
19191905

19201906
// 通知发送协程有新数据到达.
@@ -1942,7 +1928,6 @@ net::awaitable<void> proxy_server::udp_tproxy_http_udp_loop(udp_tproxy_flow_ptr
19421928
auto flow_key = make_udp_flow_key(
19431929
flow->client_endp_, flow->original_endp_);
19441930

1945-
std::lock_guard<std::mutex> lock(m_udp_flows_mutex);
19461931
m_udp_tproxy_flows.erase(flow_key);
19471932
});
19481933

@@ -2088,13 +2073,10 @@ net::awaitable<void> proxy_server::udp_tproxy_http_udp_loop(udp_tproxy_flow_ptr
20882073
{
20892074
std::vector<char> item;
20902075

2076+
if (!flow->send_queue_.empty())
20912077
{
2092-
std::lock_guard<std::mutex> lock(self->m_udp_flows_mutex);
2093-
if (!flow->send_queue_.empty())
2094-
{
2095-
item = std::move(flow->send_queue_.front());
2096-
flow->send_queue_.pop_front();
2097-
}
2078+
item = std::move(flow->send_queue_.front());
2079+
flow->send_queue_.pop_front();
20982080
}
20992081

21002082
if (item.empty())
@@ -2124,7 +2106,7 @@ net::awaitable<void> proxy_server::udp_tproxy_http_udp_loop(udp_tproxy_flow_ptr
21242106
}
21252107
}, net::detached);
21262108

2127-
// 隧道建立成功, 进入响应读取循环: 从 TCP 接收 capsule, 提取 UDP payload,
2109+
// 隧道建立成功, 进入响应读取循环: 从 http 接收 capsule, 提取 UDP payload,
21282110
// 通过 relay_sock_ 发送回客户端.
21292111
while (!m_abort)
21302112
{
@@ -2165,11 +2147,11 @@ net::awaitable<void> proxy_server::udp_tproxy_http_udp_loop(udp_tproxy_flow_ptr
21652147
}
21662148

21672149
// 解析 context ID.
2168-
auto val_data = reinterpret_cast<const uint8_t*>(
2169-
capsule_value.data());
2150+
auto val_data = reinterpret_cast<const uint8_t*>(capsule_value.data());
21702151
size_t val_len = capsule_value.size();
21712152

2172-
if (val_len == 0) continue;
2153+
if (val_len == 0)
2154+
continue;
21732155

21742156
auto [ctx_id_len, ctx_id] = varint_int_decode(val_data);
21752157
if (ctx_id != 0)
@@ -2200,10 +2182,7 @@ net::awaitable<void> proxy_server::udp_tproxy_http_udp_loop(udp_tproxy_flow_ptr
22002182
flow->udp_http_sock_.reset();
22012183
flow->backend_sock_.reset();
22022184

2203-
{
2204-
std::lock_guard<std::mutex> lock(m_udp_flows_mutex);
2205-
m_udp_tproxy_flows.erase(flow->flow_key_);
2206-
}
2185+
m_udp_tproxy_flows.erase(flow->flow_key_);
22072186

22082187
XLOG_DBG << "tproxy flow: " << flow->flow_key_
22092188
<< ", connect-udp loop ended";

0 commit comments

Comments
 (0)