Skip to content

Commit 8ab87f5

Browse files
committed
Improve set socket option
1 parent a3c2162 commit 8ab87f5

4 files changed

Lines changed: 161 additions & 39 deletions

File tree

proxy/include/proxy/proxy_session.hpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1441,10 +1441,6 @@ namespace proxy {
14411441

14421442
//////////////////////////////////////////////////////////////////////////
14431443

1444-
// 设置透明代理 (TPROXY) 的 socket mark, 用于策略路由.
1445-
net::awaitable<void>
1446-
tproxy_set_mark(int socket_fd) const noexcept;
1447-
14481444
// 异步连接到多个目标地址 (支持 Happy Eyeballs).
14491445
net::awaitable<boost::system::error_code>
14501446
async_connect_targets(tcp::socket& socket, tcp::resolver::results_type& targets) noexcept;

proxy/include/proxy/proxy_util.hpp

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,39 @@
1717

1818
#include <boost/system/error_code.hpp>
1919
#include <boost/asio/ip/address.hpp>
20+
#include <boost/asio/error.hpp>
21+
22+
#include <boost/system/error_code.hpp>
23+
#include <boost/system/result.hpp>
24+
#include <boost/config.hpp>
25+
26+
#if defined(__linux__) || defined(__APPLE__)
27+
# include <sys/socket.h>
28+
#elif defined(BOOST_WINDOWS)
29+
# include <mstcpip.h>
30+
#endif
2031

2132
namespace proxy {
2233

2334
namespace net = boost::asio;
2435

36+
37+
inline void make_error_code(boost::system::error_code& ec, bool err) noexcept
38+
{
39+
if (!err)
40+
{
41+
ec = {};
42+
}
43+
else
44+
{
45+
#if defined(BOOST_WINDOWS)
46+
ec = boost::system::error_code(WSAGetLastError(), net::error::get_system_category());
47+
#else
48+
ec = boost::system::error_code(errno, net::error::get_system_category());
49+
#endif
50+
}
51+
}
52+
2553
// 检测 host 是否是域名或主机名, 如果是域名则返回 true, 否则返回 false.
2654
inline bool is_hostname(std::string_view host) noexcept
2755
{
@@ -38,6 +66,70 @@ namespace proxy {
3866
static std::random_device rd;
3967
return rd;
4068
}
69+
70+
#if defined(BOOST_WINDOWS)
71+
// 启用 TCP Keep-Alive 选项.
72+
inline boost::system::result<bool> set_tcp_keepalive(SOCKET fd) noexcept
73+
{
74+
boost::system::error_code ec;
75+
int ret = 0;
76+
77+
struct tcp_keepalive alive;
78+
alive.onoff = 1;
79+
alive.keepalivetime = 30000; // 30 seconds
80+
alive.keepaliveinterval = 15000; // 15 seconds
81+
ret = ::WSAIoctl(fd, SIO_KEEPALIVE_VALS, &alive, sizeof(alive), NULL, 0, NULL, NULL, NULL);
82+
make_error_code(ec, ret != 0);
83+
if (ret != 0)
84+
return ec;
85+
return true;
86+
}
87+
#else
88+
// 启用 TCP Keep-Alive 选项.
89+
inline boost::system::result<bool> set_tcp_keepalive(int fd) noexcept
90+
{
91+
boost::system::error_code ec;
92+
int ret = 0;
93+
int keepalive = 1;
94+
95+
ret = ::setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &keepalive, sizeof(keepalive));
96+
make_error_code(ec, ret != 0);
97+
if (ret != 0)
98+
return ec;
99+
100+
int idle_time = 30; // 30 seconds
101+
ret = ::setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &idle_time, sizeof(idle_time));
102+
make_error_code(ec, ret != 0);
103+
if (ret != 0)
104+
return ec;
105+
106+
int interval = 15; // 15 seconds
107+
ret = ::setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &interval, sizeof(interval));
108+
make_error_code(ec, ret != 0);
109+
if (ret != 0)
110+
return ec;
111+
112+
int maxpkt = 3; // 3 probes
113+
ret = ::setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &maxpkt, sizeof(maxpkt));
114+
make_error_code(ec, ret != 0);
115+
if (ret != 0)
116+
return ec;
117+
118+
return true;
119+
}
120+
#endif
121+
122+
inline boost::system::result<bool> set_socket_mark(int fd, uint32_t mark) noexcept
123+
{
124+
boost::system::error_code ec;
125+
#if defined(__linux__)
126+
int ret = ::setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(uint32_t));
127+
make_error_code(ec, ret != 0);
128+
if (ret != 0)
129+
return ec;
130+
#endif
131+
return true;
132+
}
41133
}
42134

43135
#endif // INCLUDE__2026_06_08__PROXY_UTIL_HPP

proxy/src/proxy_server.cpp

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1374,10 +1374,11 @@ proxy_server::connect_to_proxy(tcp::socket& remote_socket, const tcp::resolver::
13741374
if (m_option.so_mark_)
13751375
{
13761376
uint32_t mark = m_option.so_mark_.value();
1377-
if (::setsockopt(remote_socket.native_handle(), SOL_SOCKET, SO_MARK, &mark, sizeof(mark)) < 0)
1377+
auto ret = set_socket_mark(remote_socket.native_handle(), mark);
1378+
if (ret.has_error())
13781379
{
13791380
XLOG_WARN << "connect_to_proxy setsockopt SO_MARK error: "
1380-
<< strerror(errno);
1381+
<< ret.error().message();
13811382
}
13821383
}
13831384
#endif
@@ -1422,15 +1423,13 @@ net::awaitable<bool> proxy_server::do_sock5_associate()
14221423
co_return true;
14231424
}
14241425

1425-
net::socket_base::keep_alive option(true);
1426-
remote_socket.set_option(option, ec);
1427-
1428-
int idle_time = 30; // 30 seconds
1429-
setsockopt(remote_socket.native_handle(), IPPROTO_TCP, TCP_KEEPIDLE, &idle_time, sizeof(idle_time));
1430-
int interval = 15; // 15 seconds
1431-
setsockopt(remote_socket.native_handle(), IPPROTO_TCP, TCP_KEEPINTVL, &interval, sizeof(interval));
1432-
int maxpkt = 3; // 3 probes
1433-
setsockopt(remote_socket.native_handle(), IPPROTO_TCP, TCP_KEEPCNT, &maxpkt, sizeof(maxpkt));
1426+
// 设置 TCP Keep-Alive.
1427+
auto ret = set_tcp_keepalive(remote_socket.native_handle());
1428+
if (ret.has_error())
1429+
{
1430+
XLOG_WARN << "udp tproxy do_sock5_associate tcp_keepalive failed: "
1431+
<< ret.error().message();
1432+
}
14341433

14351434
// 启动与 proxy_pass 的连接和协商以获取关联的 udp endpoint.
14361435
socks_client_option opt;

proxy/src/proxy_session.cpp

Lines changed: 59 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
#include "proxy/proxy_session.hpp"
1212
#include "proxy/async_connect.hpp"
13+
#include "proxy/proxy_util.hpp"
1314
#include "proxy/fileop.hpp"
1415

1516
#ifdef USE_PAM_AUTH
@@ -1439,7 +1440,15 @@ R"x*x*x(<html>
14391440
}
14401441

14411442
if (m_option.so_mark_)
1442-
co_await tproxy_set_mark((int)remote_bind_socket->native_handle());
1443+
{
1444+
auto ret = set_socket_mark(remote_bind_socket->native_handle(), m_option.so_mark_.value());
1445+
if (ret.has_error())
1446+
{
1447+
log_conn_warning()
1448+
<< ", set socket mark error: "
1449+
<< ret.error().message();
1450+
}
1451+
}
14431452
}
14441453

14451454
// 绑定到和 tcp socket 相同的地址.
@@ -1458,7 +1467,15 @@ R"x*x*x(<html>
14581467
// 对 local_udp_socket 也设置 SO_MARK,确保非 bridge 模式下
14591468
// 由 local_udp_socket 发出的 UDP 数据包也带有正确的标记。
14601469
if (m_option.so_mark_)
1461-
co_await tproxy_set_mark((int)local_udp_socket.native_handle());
1470+
{
1471+
auto ret = set_socket_mark(local_udp_socket.native_handle(), m_option.so_mark_.value());
1472+
if (ret.has_error())
1473+
{
1474+
log_conn_warning()
1475+
<< ", set socket mark error: "
1476+
<< ret.error().message();
1477+
}
1478+
}
14621479

14631480
if (m_proxy_pass)
14641481
{
@@ -5033,26 +5050,6 @@ R"x*x*x(<html>
50335050

50345051
//////////////////////////////////////////////////////////////////////////
50355052

5036-
net::awaitable<void>
5037-
proxy_session::tproxy_set_mark(int socket_fd) const noexcept
5038-
{
5039-
#if defined (__linux__)
5040-
if (!m_option.so_mark_)
5041-
co_return;
5042-
5043-
uint32_t mark = m_option.so_mark_.value();
5044-
5045-
if (::setsockopt(socket_fd, SOL_SOCKET, SO_MARK, &mark, sizeof(uint32_t)) < 0)
5046-
{
5047-
log_conn_warning()
5048-
<< ", tproxy setsockopt: " << socket_fd
5049-
<< ", mark: " << mark
5050-
<< ", error: " << strerror(errno);
5051-
}
5052-
#endif
5053-
co_return;
5054-
}
5055-
50565053
net::awaitable<boost::system::error_code>
50575054
proxy_session::async_connect_targets(tcp::socket& socket, tcp::resolver::results_type& targets) noexcept
50585055
{
@@ -5074,7 +5071,26 @@ R"x*x*x(<html>
50745071
},
50755072
net_awaitable[ec]);
50765073

5077-
co_await tproxy_set_mark((int)socket.native_handle());
5074+
{
5075+
auto ret = set_tcp_keepalive(socket.native_handle());
5076+
if (ret.has_error())
5077+
{
5078+
log_conn_warning()
5079+
<< ", tcp keepalive error: "
5080+
<< ret.error().message();
5081+
}
5082+
}
5083+
5084+
if (m_option.so_mark_)
5085+
{
5086+
auto ret = set_socket_mark(socket.native_handle(), m_option.so_mark_.value());
5087+
if (ret.has_error())
5088+
{
5089+
log_conn_warning()
5090+
<< ", set socket mark error: "
5091+
<< ret.error().message();
5092+
}
5093+
}
50785094

50795095
co_return ec;
50805096
}
@@ -5121,7 +5137,26 @@ R"x*x*x(<html>
51215137
net_awaitable[ec]);
51225138
if (!ec)
51235139
{
5124-
co_await tproxy_set_mark((int)socket.native_handle());
5140+
{
5141+
auto ret = set_tcp_keepalive(socket.native_handle());
5142+
if (ret.has_error())
5143+
{
5144+
log_conn_warning()
5145+
<< ", tcp keepalive error: "
5146+
<< ret.error().message();
5147+
}
5148+
}
5149+
5150+
if (m_option.so_mark_)
5151+
{
5152+
auto ret = set_socket_mark(socket.native_handle(), m_option.so_mark_.value());
5153+
if (ret.has_error())
5154+
{
5155+
log_conn_warning()
5156+
<< ", set socket mark error: "
5157+
<< ret.error().message();
5158+
}
5159+
}
51255160

51265161
break;
51275162
}

0 commit comments

Comments
 (0)