feat: add tcp initial syn window reset

This commit is contained in:
SunBK201 2025-11-29 18:09:15 +08:00
parent b20acf2cbe
commit 6a766e4106
8 changed files with 63 additions and 29 deletions

View File

@ -213,6 +213,10 @@ function M.add_others_fields(section)
local tcpts = section:taboption("others", Flag, "del_tcpts", translate("Delete TCP Timestamps")) local tcpts = section:taboption("others", Flag, "del_tcpts", translate("Delete TCP Timestamps"))
tcpts.description = translate("Remove TCP Timestamp option") tcpts.description = translate("Remove TCP Timestamp option")
-- TCP Initial Window
local tcp_init_window = section:taboption("others", Flag, "set_tcp_init_window", translate("Set TCP Initial Window"))
tcp_init_window.description = translate("Set the TCP Initial Window to 65535 for SYN packets")
-- IP ID Setting -- IP ID Setting
local ipid = section:taboption("others", Flag, "set_ipid", translate("Set IP ID")) local ipid = section:taboption("others", Flag, "set_ipid", translate("Set IP ID"))
ipid.description = translate("Set the IP ID to 0 for packets") ipid.description = translate("Set the IP ID to 0 for packets")

View File

@ -18,7 +18,7 @@ start_service() {
local server_mode port bind ua log_level ua_regex partial_replace local server_mode port bind ua log_level ua_regex partial_replace
local rewrite_mode rewrite_rules local rewrite_mode rewrite_rules
local set_ttl set_ipid del_tcpts local set_ttl set_ipid del_tcpts set_tcp_init_window
config_get server_mode "main" "server_mode" "TPROXY" config_get server_mode "main" "server_mode" "TPROXY"
config_get port "main" "port" "1080" config_get port "main" "port" "1080"
config_get bind "main" "bind" "127.0.0.1" config_get bind "main" "bind" "127.0.0.1"
@ -31,6 +31,7 @@ start_service() {
config_get_bool set_ttl "main" "set_ttl" 0 config_get_bool set_ttl "main" "set_ttl" 0
config_get_bool set_ipid "main" "set_ipid" 0 config_get_bool set_ipid "main" "set_ipid" 0
config_get_bool del_tcpts "main" "del_tcpts" 0 config_get_bool del_tcpts "main" "del_tcpts" 0
config_get_bool set_tcp_init_window "main" "set_tcp_init_window" 0
procd_open_instance "$NAME" procd_open_instance "$NAME"
procd_set_param command "$PROG" procd_set_param command "$PROG"
@ -46,6 +47,7 @@ start_service() {
procd_append_param env UA3F_TTL="$set_ttl" procd_append_param env UA3F_TTL="$set_ttl"
procd_append_param env UA3F_IPID="$set_ipid" procd_append_param env UA3F_IPID="$set_ipid"
procd_append_param env UA3F_TCPTS="$del_tcpts" procd_append_param env UA3F_TCPTS="$del_tcpts"
procd_append_param env UA3F_TCP_INIT_WINDOW="$set_tcp_init_window"
procd_set_param respawn procd_set_param respawn
procd_set_param stdout 1 procd_set_param stdout 1

View File

@ -14,4 +14,5 @@ config 'ua3f' 'main'
option set_ttl '0' option set_ttl '0'
option del_tcpts '0' option del_tcpts '0'
option set_ipid '0' option set_ipid '0'
option set_tcp_init_window '0'
option rewrite_rules '[{"enabled":false,"type":"DEST-PORT","action":"DIRECT","match_value":"443","rewrite_header":"User-Agent","rewrite_value":"","description":""},{"enabled":true,"type":"KEYWORD","action":"DIRECT","match_value":"MicroMessenger Client","rewrite_header":"User-Agent","rewrite_value":"","description":""},{"enabled":true,"type":"KEYWORD","action":"DIRECT","match_value":"Bilibili Freedoooooom\/MarkII","rewrite_header":"User-Agent","rewrite_value":"","description":""},{"enabled":true,"type":"KEYWORD","action":"DIRECT","match_value":"Valve\/Steam HTTP Client 1.0","rewrite_header":"User-Agent","rewrite_value":"","description":""},{"enabled":true,"type":"KEYWORD","action":"REPLACE","match_value":"Mac","rewrite_header":"User-Agent","description":"","rewrite_value":"FFF"},{"enabled":true,"type":"REGEX","action":"REPLACE","match_value":"(Apple|iPhone|iPad|Macintosh|Mac OS X|Mac|Darwin|Microsoft|Windows|Linux|Android|OpenHarmony|HUAWEI|OPPO|Vivo|XiaoMi|Mobile|Dalvik)","rewrite_header":"User-Agent","description":"","rewrite_value":"FFF"},{"enabled":true,"type":"FINAL","action":"REPLACE","match_value":"","rewrite_header":"User-Agent","description":"Default Fallback Rule","rewrite_value":"FFF"}]' option rewrite_rules '[{"enabled":false,"type":"DEST-PORT","action":"DIRECT","match_value":"443","rewrite_header":"User-Agent","rewrite_value":"","description":""},{"enabled":true,"type":"KEYWORD","action":"DIRECT","match_value":"MicroMessenger Client","rewrite_header":"User-Agent","rewrite_value":"","description":""},{"enabled":true,"type":"KEYWORD","action":"DIRECT","match_value":"Bilibili Freedoooooom\/MarkII","rewrite_header":"User-Agent","rewrite_value":"","description":""},{"enabled":true,"type":"KEYWORD","action":"DIRECT","match_value":"Valve\/Steam HTTP Client 1.0","rewrite_header":"User-Agent","rewrite_value":"","description":""},{"enabled":true,"type":"KEYWORD","action":"REPLACE","match_value":"Mac","rewrite_header":"User-Agent","description":"","rewrite_value":"FFF"},{"enabled":true,"type":"REGEX","action":"REPLACE","match_value":"(Apple|iPhone|iPad|Macintosh|Mac OS X|Mac|Darwin|Microsoft|Windows|Linux|Android|OpenHarmony|HUAWEI|OPPO|Vivo|XiaoMi|Mobile|Dalvik)","rewrite_header":"User-Agent","description":"","rewrite_value":"FFF"},{"enabled":true,"type":"FINAL","action":"REPLACE","match_value":"","rewrite_header":"User-Agent","description":"Default Fallback Rule","rewrite_value":"FFF"}]'

View File

@ -126,7 +126,7 @@ msgid "Set TTL"
msgstr "固定 TTL" msgstr "固定 TTL"
msgid "Set the TTL 64 for packets" msgid "Set the TTL 64 for packets"
msgstr "固定数据包的 TTL" msgstr "固定数据包的 TTL 为 64"
msgid "Connection Statistics" msgid "Connection Statistics"
msgstr "连接实时统计" msgstr "连接实时统计"
@ -257,6 +257,12 @@ msgstr "删除 TCP 时间戳"
msgid "Remove TCP Timestamp option" msgid "Remove TCP Timestamp option"
msgstr "移除 TCP 时间戳选项" msgstr "移除 TCP 时间戳选项"
msgid "Set TCP Initial Window"
msgstr "固定 TCP 初始接收窗口"
msgid "Set the TCP Initial Window to 65535 for SYN packets"
msgstr "固定 TCP SYN 的 TCP 初始接收窗口设置为 65535"
msgid "Set IP ID" msgid "Set IP ID"
msgstr "固定 IP ID" msgstr "固定 IP ID"

View File

@ -27,19 +27,20 @@ const (
) )
type Config struct { type Config struct {
ServerMode ServerMode ServerMode ServerMode
BindAddr string BindAddr string
Port int Port int
ListenAddr string ListenAddr string
LogLevel string LogLevel string
RewriteMode RewriteMode RewriteMode RewriteMode
Rules string Rules string
PayloadUA string PayloadUA string
UARegex string UARegex string
PartialReplace bool PartialReplace bool
SetTTL bool SetTTL bool
SetIPID bool SetIPID bool
DelTCPTimestamp bool DelTCPTimestamp bool
SetTCPInitialWindow bool
} }
func Parse() (*Config, bool) { func Parse() (*Config, bool) {
@ -97,6 +98,9 @@ func Parse() (*Config, bool) {
if os.Getenv("UA3F_IPID") == "1" { if os.Getenv("UA3F_IPID") == "1" {
cfg.SetIPID = true cfg.SetIPID = true
} }
if os.Getenv("UA3F_TCP_INIT_WINDOW") == "1" {
cfg.SetTCPInitialWindow = true
}
// Parse other options from -o flag // Parse other options from -o flag
opts := strings.Split(others, ",") opts := strings.Split(others, ",")

View File

@ -22,7 +22,7 @@ var RuleTTL = []string{
"--ttl-set", "64", "--ttl-set", "64",
} }
var RuleDelTCPTS = []string{ var RuleHookTCPSyn = []string{
"-p", "tcp", "-p", "tcp",
"--tcp-flags", "SYN", "SYN", "--tcp-flags", "SYN", "SYN",
"-j", "NFQUEUE", "-j", "NFQUEUE",
@ -61,8 +61,8 @@ func (s *Server) iptSetup() error {
} }
} }
} }
if s.cfg.DelTCPTimestamp && !s.cfg.SetIPID { if (s.cfg.DelTCPTimestamp || s.cfg.SetTCPInitialWindow) && !s.cfg.SetIPID {
err = s.IptDelTCPTS(ipt) err = s.IptHookTCPSyn(ipt)
if err != nil { if err != nil {
return err return err
} }
@ -83,7 +83,7 @@ func (s *Server) iptCleanup() error {
} }
_ = ipt.DeleteIfExists(table, chain, RuleTTL...) _ = ipt.DeleteIfExists(table, chain, RuleTTL...)
_ = ipt.DeleteIfExists(table, chain, RuleIP...) _ = ipt.DeleteIfExists(table, chain, RuleIP...)
_ = ipt.DeleteIfExists(table, chain, RuleDelTCPTS...) _ = ipt.DeleteIfExists(table, chain, RuleHookTCPSyn...)
if s.cfg.SetTTL { if s.cfg.SetTTL {
_ = s.NftCleanup() _ = s.NftCleanup()
} }
@ -98,8 +98,8 @@ func (s *Server) IptSetTTL(ipt *iptables.IPTables) error {
return nil return nil
} }
func (s *Server) IptDelTCPTS(ipt *iptables.IPTables) error { func (s *Server) IptHookTCPSyn(ipt *iptables.IPTables) error {
err := ipt.Append(table, chain, RuleDelTCPTS...) err := ipt.Append(table, chain, RuleHookTCPSyn...)
if err != nil { if err != nil {
return err return err
} }

View File

@ -45,8 +45,8 @@ func (s *Server) Start() (err error) {
slog.Error("s.Firewall.Setup", slog.Any("error", err)) slog.Error("s.Firewall.Setup", slog.Any("error", err))
return err return err
} }
slog.Info("Packet modification configuration", slog.Bool("ttl", s.cfg.SetTTL), slog.Bool("tcpts", s.cfg.DelTCPTimestamp), slog.Bool("ipid", s.cfg.SetIPID)) slog.Info("Packet modification configuration", slog.Bool("ttl", s.cfg.SetTTL), slog.Bool("tcpts", s.cfg.DelTCPTimestamp), slog.Bool("ipid", s.cfg.SetIPID), slog.Bool("tcp_init_window", s.cfg.SetTCPInitialWindow))
if s.cfg.DelTCPTimestamp || s.cfg.SetIPID { if s.cfg.DelTCPTimestamp || s.cfg.SetTCPInitialWindow || s.cfg.SetIPID {
return s.nfqServer.Start() return s.nfqServer.Start()
} }
return nil return nil
@ -63,8 +63,13 @@ func (s *Server) handlePacket(packet *netfilter.Packet) {
nf := s.nfqServer.Nf nf := s.nfqServer.Nf
modified := false modified := false
if s.cfg.DelTCPTimestamp && packet.TCP != nil { if packet.TCP != nil {
modified = s.clearTCPTimestamp(packet.TCP) || modified if s.cfg.DelTCPTimestamp {
modified = s.clearTCPTimestamp(packet.TCP) || modified
}
if s.cfg.SetTCPInitialWindow {
modified = s.setInitialTCPWindow(packet.TCP) || modified
}
} }
if s.cfg.SetIPID { if s.cfg.SetIPID {
modified = s.zeroIPID(packet) || modified modified = s.zeroIPID(packet) || modified
@ -110,6 +115,18 @@ func (s *Server) clearTCPTimestamp(tcp *layers.TCP) bool {
return modified return modified
} }
// setInitialTCPWindow sets the TCP initial window size to 65535 for SYN packets
func (s *Server) setInitialTCPWindow(tcp *layers.TCP) bool {
if !(tcp.SYN && !tcp.ACK) {
return false
}
if tcp.Window == uint16(65535) {
return false
}
tcp.Window = uint16(65535)
return true
}
// zeroIPID sets the IP ID field to zero for IPv4 packets // zeroIPID sets the IP ID field to zero for IPv4 packets
// Returns true if the packet was modified // Returns true if the packet was modified
func (s *Server) zeroIPID(packet *netfilter.Packet) bool { func (s *Server) zeroIPID(packet *netfilter.Packet) bool {

View File

@ -28,8 +28,8 @@ func (s *Server) nftSetup() error {
if s.cfg.SetTTL { if s.cfg.SetTTL {
s.NftSetTTL(tx, s.Nftable) s.NftSetTTL(tx, s.Nftable)
} }
if s.cfg.DelTCPTimestamp && !s.cfg.SetIPID { if (s.cfg.DelTCPTimestamp || s.cfg.SetTCPInitialWindow) && !s.cfg.SetIPID {
s.NftDelTCPTS(tx, s.Nftable) s.NftHookTCPSyn(tx, s.Nftable)
} }
if s.cfg.SetIPID { if s.cfg.SetIPID {
s.NftSetIP(tx, s.Nftable) s.NftSetIP(tx, s.Nftable)
@ -112,9 +112,9 @@ func (s *Server) NftSetTTLIngress(nft knftables.Interface, table *knftables.Tabl
return nil return nil
} }
func (s *Server) NftDelTCPTS(tx *knftables.Transaction, table *knftables.Table) { func (s *Server) NftHookTCPSyn(tx *knftables.Transaction, table *knftables.Table) {
chain := &knftables.Chain{ chain := &knftables.Chain{
Name: "DEL_TCPTS", Name: "HOOK_TCP_SYN",
Table: table.Name, Table: table.Name,
Type: knftables.PtrTo(knftables.FilterType), Type: knftables.PtrTo(knftables.FilterType),
Hook: knftables.PtrTo(knftables.PostroutingHook), Hook: knftables.PtrTo(knftables.PostroutingHook),