mirror of
https://github.com/SunBK201/UA3F.git
synced 2025-12-16 08:44:29 +00:00
feat: add direct forwarding option
This commit is contained in:
parent
47a2a1d29a
commit
77ca782fa2
@ -66,6 +66,11 @@ partialRepalce.description =
|
||||
translate("Replace only the matched part of the User-Agent, only works when User-Agent Regex Pattern is not empty")
|
||||
partialRepalce.default = "0"
|
||||
|
||||
directForward = general:taboption("general", Flag, "direct_forward", translate("Direct Forward"))
|
||||
directForward.description =
|
||||
translate("Directly forward packets without rewriting")
|
||||
directForward.default = "0"
|
||||
|
||||
log = general:taboption("log", TextValue, "log")
|
||||
log.readonly = true
|
||||
log.rows = 30
|
||||
|
||||
@ -455,7 +455,7 @@ start_service() {
|
||||
|
||||
LOG "Starting $NAME service..."
|
||||
|
||||
local port bind ua log_level ua_regex partial_replace set_ttl
|
||||
local port bind ua log_level ua_regex partial_replace set_ttl direct_forward
|
||||
config_get server_mode "main" "server_mode" "SOCKS5"
|
||||
config_get port "main" "port" "1080"
|
||||
config_get bind "main" "bind" "127.0.0.1"
|
||||
@ -464,6 +464,7 @@ start_service() {
|
||||
config_get_bool partial_replace "main" "partial_replace" 0
|
||||
config_get log_level "main" "log_level" "info"
|
||||
config_get_bool set_ttl "main" "set_ttl" 0
|
||||
config_get_bool direct_forward "main" "direct_forward" 0
|
||||
|
||||
SERVER_MODE="$(echo "$server_mode" | tr '[:lower:]' '[:upper:]')"
|
||||
SERVER_MODE="$server_mode"
|
||||
@ -477,6 +478,7 @@ start_service() {
|
||||
LOG "User-Agent Regex: $ua_regex"
|
||||
LOG "Log level: $log_level"
|
||||
LOG "Partial Replace: $partial_replace"
|
||||
LOG "Direct Forward: $direct_forward"
|
||||
LOG "Set TTL: $SET_TTL"
|
||||
|
||||
set_ua3f_group
|
||||
@ -579,6 +581,7 @@ start_service() {
|
||||
procd_append_param command -r "$ua_regex"
|
||||
procd_append_param command -l "$log_level"
|
||||
[ "$partial_replace" = "1" ] && procd_append_param command -s
|
||||
[ "$direct_forward" = "1" ] && procd_append_param command -d
|
||||
|
||||
procd_set_param respawn
|
||||
procd_set_param stdout 1
|
||||
|
||||
@ -7,7 +7,8 @@ config 'ua3f' 'main'
|
||||
option bind '0.0.0.0'
|
||||
option ua 'FFF'
|
||||
option ua_regex '(Apple|iPhone|iPad|Macintosh|Mac OS X|Mac|Darwin|Microsoft|Windows|Linux|Android|OpenHarmony|HUAWEI|OPPO|Vivo|XiaoMi|Mobile|Dalvik)'
|
||||
option partial_replace false
|
||||
option partial_replace '0'
|
||||
option direct_forward '0'
|
||||
option log_level 'error'
|
||||
option log_lines '1000'
|
||||
option set_ttl '0'
|
||||
@ -56,6 +56,12 @@ msgstr "部分替换"
|
||||
msgid "Replace only the matched part of the User-Agent, only works when User-Agent Regex Pattern is not empty"
|
||||
msgstr "仅替换 User-Agent 正则匹配的部分,仅在 User-Agent 正则表达式非空时有效"
|
||||
|
||||
msgid "Direct Forward"
|
||||
msgstr "直接转发"
|
||||
|
||||
msgid "Directly forward packets without rewriting"
|
||||
msgstr "不进行重写直接转发数据包"
|
||||
|
||||
msgid "User-Agent Rewrite Statistics"
|
||||
msgstr "User-Agent 重写次数实时统计"
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ require (
|
||||
github.com/dlclark/regexp2 v1.11.4
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
golang.org/x/sys v0.26.0
|
||||
golang.org/x/sys v0.30.0
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
||||
)
|
||||
|
||||
|
||||
@ -14,8 +14,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
|
||||
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
|
||||
|
||||
@ -14,47 +14,51 @@ const (
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
ServerMode string
|
||||
BindAddr string
|
||||
Port int
|
||||
ListenAddr string
|
||||
LogLevel string
|
||||
PayloadUA string
|
||||
UARegex string
|
||||
EnablePartialReplace bool
|
||||
ServerMode string
|
||||
BindAddr string
|
||||
Port int
|
||||
ListenAddr string
|
||||
LogLevel string
|
||||
PayloadUA string
|
||||
UARegex string
|
||||
PartialReplace bool
|
||||
DirectForward bool
|
||||
}
|
||||
|
||||
func Parse() (*Config, bool) {
|
||||
var (
|
||||
serverMode string
|
||||
bindAddr string
|
||||
port int
|
||||
loglevel string
|
||||
payloadUA string
|
||||
uaRegx string
|
||||
partial bool
|
||||
showVer bool
|
||||
serverMode string
|
||||
bindAddr string
|
||||
port int
|
||||
loglevel string
|
||||
payloadUA string
|
||||
uaRegx string
|
||||
partial bool
|
||||
directForward bool
|
||||
showVer bool
|
||||
)
|
||||
|
||||
flag.StringVar(&serverMode, "m", ServerModeSocks5, "server mode: HTTP, SOCKS5, TPROXY, REDIRECT (default: SOCKS5)")
|
||||
flag.StringVar(&bindAddr, "b", "127.0.0.1", "bind address (default: 127.0.0.1)")
|
||||
flag.IntVar(&port, "p", 1080, "port")
|
||||
flag.StringVar(&serverMode, "m", ServerModeSocks5, "Server mode: HTTP, SOCKS5, TPROXY, REDIRECT")
|
||||
flag.StringVar(&bindAddr, "b", "127.0.0.1", "Bind address")
|
||||
flag.IntVar(&port, "p", 1080, "Port")
|
||||
flag.StringVar(&loglevel, "l", "info", "Log level")
|
||||
flag.StringVar(&payloadUA, "f", "FFF", "User-Agent")
|
||||
flag.StringVar(&uaRegx, "r", "", "UA-Pattern")
|
||||
flag.BoolVar(&partial, "s", false, "Enable Regex Partial Replace")
|
||||
flag.StringVar(&loglevel, "l", "info", "Log level (default: info)")
|
||||
flag.BoolVar(&showVer, "v", false, "show version")
|
||||
flag.StringVar(&uaRegx, "r", "", "User-Agent regex")
|
||||
flag.BoolVar(&partial, "s", false, "Enable regex partial replace")
|
||||
flag.BoolVar(&directForward, "d", false, "Pure Forwarding (no User-Agent rewriting)")
|
||||
flag.BoolVar(&showVer, "v", false, "Show version")
|
||||
flag.Parse()
|
||||
|
||||
cfg := &Config{
|
||||
ServerMode: strings.ToUpper(serverMode),
|
||||
BindAddr: bindAddr,
|
||||
Port: port,
|
||||
ListenAddr: fmt.Sprintf("%s:%d", bindAddr, port),
|
||||
LogLevel: loglevel,
|
||||
PayloadUA: payloadUA,
|
||||
UARegex: uaRegx,
|
||||
EnablePartialReplace: partial,
|
||||
ServerMode: strings.ToUpper(serverMode),
|
||||
BindAddr: bindAddr,
|
||||
Port: port,
|
||||
ListenAddr: fmt.Sprintf("%s:%d", bindAddr, port),
|
||||
LogLevel: loglevel,
|
||||
PayloadUA: payloadUA,
|
||||
UARegex: uaRegx,
|
||||
DirectForward: directForward,
|
||||
PartialReplace: partial,
|
||||
}
|
||||
if serverMode == ServerModeRedirect {
|
||||
cfg.BindAddr = "0.0.0.0"
|
||||
|
||||
@ -74,7 +74,8 @@ func LogHeader(version string, cfg *config.Config) {
|
||||
logrus.Infof("Listen on %s", cfg.ListenAddr)
|
||||
logrus.Infof("User-Agent: %s", cfg.PayloadUA)
|
||||
logrus.Infof("User-Agent Regex: '%s'", cfg.UARegex)
|
||||
logrus.Infof("Partial Replace: %v", cfg.EnablePartialReplace)
|
||||
logrus.Infof("Partial Replace: %v", cfg.PartialReplace)
|
||||
logrus.Infof("Direct Forward: %v", cfg.DirectForward)
|
||||
logrus.Infof("Log level: %s", cfg.LogLevel)
|
||||
}
|
||||
|
||||
|
||||
@ -44,7 +44,7 @@ func New(cfg *config.Config) (*Rewriter, error) {
|
||||
return &Rewriter{
|
||||
payloadUA: cfg.PayloadUA,
|
||||
pattern: cfg.UARegex,
|
||||
partialReplace: cfg.EnablePartialReplace,
|
||||
partialReplace: cfg.PartialReplace,
|
||||
uaRegex: uaRegex,
|
||||
Cache: expirable.NewLRU[string, struct{}](1024, nil, 30*time.Minute),
|
||||
whitelist: []string{
|
||||
|
||||
@ -26,9 +26,9 @@ func (m *mockConn) SetWriteDeadline(t time.Time) error { return nil }
|
||||
|
||||
func newTestRewriter(t *testing.T) *Rewriter {
|
||||
cfg := &config.Config{
|
||||
UARegex: "TestUA",
|
||||
PayloadUA: "MockUA/1.0",
|
||||
EnablePartialReplace: false,
|
||||
UARegex: "TestUA",
|
||||
PayloadUA: "MockUA/1.0",
|
||||
PartialReplace: false,
|
||||
}
|
||||
rewriter, err := New(cfg)
|
||||
assert.NoError(t, err)
|
||||
@ -37,15 +37,15 @@ func newTestRewriter(t *testing.T) *Rewriter {
|
||||
|
||||
func TestNewRewriter(t *testing.T) {
|
||||
cfg := &config.Config{
|
||||
UARegex: "TestUA",
|
||||
PayloadUA: "FFF0",
|
||||
EnablePartialReplace: false,
|
||||
UARegex: "TestUA",
|
||||
PayloadUA: "FFF0",
|
||||
PartialReplace: false,
|
||||
}
|
||||
rewriter, err := New(cfg)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, cfg.PayloadUA, rewriter.payloadUA)
|
||||
assert.Equal(t, cfg.UARegex, rewriter.pattern)
|
||||
assert.Equal(t, cfg.EnablePartialReplace, rewriter.partialReplace)
|
||||
assert.Equal(t, cfg.PartialReplace, rewriter.partialReplace)
|
||||
assert.NotNil(t, rewriter.uaRegex)
|
||||
assert.NotNil(t, rewriter.Cache)
|
||||
}
|
||||
|
||||
@ -58,10 +58,18 @@ func (s *Server) handleHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
}
|
||||
defer target.Close()
|
||||
|
||||
err = s.rewriteAndForward(target, req, req.Host, req.RemoteAddr)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusServiceUnavailable)
|
||||
return
|
||||
if s.cfg.DirectForward {
|
||||
err = req.Write(target)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusServiceUnavailable)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
err = s.rewriteAndForward(target, req, req.Host, req.RemoteAddr)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusServiceUnavailable)
|
||||
return
|
||||
}
|
||||
}
|
||||
resp, err := http.ReadResponse(bufio.NewReader(target), req)
|
||||
if err != nil {
|
||||
@ -123,6 +131,11 @@ func (s *Server) ForwardTCP(client, target net.Conn, destAddr string) {
|
||||
// Server -> Client (raw)
|
||||
go utils.CopyHalf(client, target)
|
||||
|
||||
if s.cfg.DirectForward {
|
||||
// Client -> Server (raw)
|
||||
go utils.CopyHalf(target, client)
|
||||
return
|
||||
}
|
||||
// Client -> Server (rewriter)
|
||||
go utils.ProxyHalf(target, client, s.rw, destAddr)
|
||||
}
|
||||
|
||||
@ -71,6 +71,11 @@ func (s *Server) ForwardTCP(client, target net.Conn, destAddr string) {
|
||||
// Server -> Client (raw)
|
||||
go utils.CopyHalf(client, target)
|
||||
|
||||
if s.cfg.DirectForward {
|
||||
// Client -> Server (raw)
|
||||
go utils.CopyHalf(target, client)
|
||||
return
|
||||
}
|
||||
// Client -> Server (rewriter)
|
||||
go utils.ProxyHalf(target, client, s.rw, destAddr)
|
||||
}
|
||||
|
||||
@ -213,6 +213,11 @@ func (s *Server) ForwardTCP(client, target net.Conn, destAddr string) {
|
||||
// Server -> Client (raw)
|
||||
go utils.CopyHalf(client, target)
|
||||
|
||||
if s.cfg.DirectForward {
|
||||
// Client -> Server (raw)
|
||||
go utils.CopyHalf(target, client)
|
||||
return
|
||||
}
|
||||
// Client -> Server (rewriter)
|
||||
go utils.ProxyHalf(target, client, s.rw, destAddr)
|
||||
}
|
||||
|
||||
@ -92,6 +92,11 @@ func (s *Server) ForwardTCP(client, target net.Conn, destAddr string) {
|
||||
// Server -> Client (raw)
|
||||
go utils.CopyHalf(client, target)
|
||||
|
||||
if s.cfg.DirectForward {
|
||||
// Client -> Server (raw)
|
||||
go utils.CopyHalf(target, client)
|
||||
return
|
||||
}
|
||||
// Client -> Server (rewriter)
|
||||
go utils.ProxyHalf(target, client, s.rw, destAddr)
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user