mirror of
https://github.com/SunBK201/UA3F.git
synced 2025-12-16 16:57:08 +00:00
feat: use ua regex pattern rule to match target dataflow
This commit is contained in:
parent
eacdf80b0f
commit
7b1377d5e9
12
README.md
12
README.md
@ -3,7 +3,8 @@
|
||||
UA3F 是下一代 HTTP User-Agent 修改方法,对外作为一个 SOCK5 服务,可以部署在路由器等设备等设备进行透明 UA 修改。
|
||||
|
||||
## 特性
|
||||
- User-Agent 自定义
|
||||
- 支持正则表达式规则匹配修改 User-Agent
|
||||
- 自定义 User-Agent 内容
|
||||
- 与其他网络加速代理工具共存
|
||||
- LRU 高速缓存非 HTTP 域名,加速非 HTTP 流量转发
|
||||
- 支持 LuCI Web 图形页面
|
||||
@ -34,6 +35,14 @@ UA3F 已支持 LuCI Web 页面,可以打开 Services -> UA3F 进行相关配
|
||||
|
||||

|
||||
|
||||
> [!NOTE]
|
||||
> 设置说明:
|
||||
> - Port 为 UA3F 监听端口,默认 `1080`。
|
||||
> - Bind Address 为 UA3F 监听地址,默认 `127.0.0.1`。
|
||||
> - User-Agent 为自定义 User-Agent,默认 `FFF`。
|
||||
> - User-Agent Regex Pattern 为 User-Agent 正则表达式规则。如果流量中的 User-Agent 匹配该正则表达式,则会被修改为 User-Agent 字段的内容,否则不会被修改;如果该字段为空,则所有流量 User-Agent 都会被修改。默认 `(iPhone|iPad|Android|Macintosh|Windows|Linux)`,即只修改携带设备与系统信息的 User-Agent。
|
||||
> - Log Level 为日志等级,默认 `info`, 如果需要调试排查错误可以设置为 `debug`。
|
||||
|
||||
### 作为后台服务运行
|
||||
|
||||
安装脚本执行成功后可通过以下命令启动 UA3F:
|
||||
@ -89,6 +98,7 @@ sudo -u shellcrash /usr/bin/ua3f
|
||||
|
||||
- `-p <port>`: 端口号,默认 1080
|
||||
- `-f <UA>`: 自定义 UA,默认 FFF
|
||||
- `-r <regex>`: 自定义正则匹配 User-Agent, 默认 `(iPhone|iPad|Android|Macintosh|Windows|Linux)`
|
||||
- `-b <bind addr>`: 自定义绑定监听地址,默认 127.0.0.1
|
||||
- `-l <log level>`: 日志等级,默认 info,可选:debug,默认日志位置:`/var/log/ua3f.log`
|
||||
|
||||
|
||||
2
build.sh
2
build.sh
@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
project_name="ua3f"
|
||||
release_version="0.4.0"
|
||||
release_version="0.5.0"
|
||||
target=cmd/ua3f.go
|
||||
dist=./dist
|
||||
release_dir=./bin
|
||||
|
||||
34
cmd/ua3f.go
34
cmd/ua3f.go
@ -7,6 +7,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"regexp"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
@ -17,8 +18,10 @@ import (
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var version = "0.4.0"
|
||||
var version = "0.5.0"
|
||||
var payloadByte []byte
|
||||
var uaPattern string
|
||||
var uaRegexp *regexp.Regexp
|
||||
var cache *expirable.LRU[string, string]
|
||||
var HTTP_METHOD = []string{"GET", "POST", "HEAD", "PUT", "DELETE", "OPTIONS", "TRACE", "CONNECT"}
|
||||
var whitelist = []string{
|
||||
@ -47,6 +50,7 @@ func main() {
|
||||
flag.StringVar(&addr, "b", "127.0.0.1", "bind address (default: 127.0.0.1)")
|
||||
flag.IntVar(&port, "p", 1080, "port")
|
||||
flag.StringVar(&payload, "f", "FFF", "User-Agent")
|
||||
flag.StringVar(&uaPattern, "r", "(iPhone|iPad|Android|Macintosh|Windows|Linux)", "UA-Pattern")
|
||||
flag.StringVar(&loglevel, "l", "info", "Log level (default: info)")
|
||||
flag.Parse()
|
||||
|
||||
@ -55,6 +59,7 @@ func main() {
|
||||
logrus.Info("UA3F v" + version)
|
||||
logrus.Info(fmt.Sprintf("Port: %d", port))
|
||||
logrus.Info(fmt.Sprintf("User-Agent: %s", payload))
|
||||
logrus.Info(fmt.Sprintf("User-Agent Regex Pattern: %s", uaPattern))
|
||||
logrus.Info(fmt.Sprintf("Log level: %s", loglevel))
|
||||
|
||||
cache = expirable.NewLRU[string, string](300, nil, time.Second*600)
|
||||
@ -72,6 +77,11 @@ func main() {
|
||||
return
|
||||
}
|
||||
logrus.Info(fmt.Sprintf("Listen on %s:%d", addr, port))
|
||||
uaRegexp, err = regexp.Compile(uaPattern)
|
||||
if err != nil {
|
||||
logrus.Fatal("Invalid User-Agent Regex Pattern: ", err)
|
||||
return
|
||||
}
|
||||
for {
|
||||
client, err := server.Accept()
|
||||
if err != nil {
|
||||
@ -425,15 +435,29 @@ func CopyPileline(dst io.Writer, src io.Reader, destAddrPort string) {
|
||||
httpBodyOffset, err = parser.Parse(buf[:nr])
|
||||
}
|
||||
value, start, end := parser.FindHeader([]byte("User-Agent"))
|
||||
uaStr := string(value)
|
||||
if value != nil && end > start {
|
||||
if slices.Contains(whitelist, string(value)) {
|
||||
logrus.Debug(fmt.Sprintf("[%s][%s] Hit User-Agent Whitelist: %s, Add LRU Relay Cache, Cache Len: %d", destAddrPort, src.(*net.TCPConn).RemoteAddr().String(), string(value), cache.Len()))
|
||||
isInWhiteList := false
|
||||
isMatchUaPattern := true
|
||||
if uaPattern != "" {
|
||||
isMatchUaPattern = uaRegexp.MatchString(uaStr)
|
||||
}
|
||||
if slices.Contains(whitelist, uaStr) {
|
||||
isInWhiteList = true
|
||||
}
|
||||
if isInWhiteList || !isMatchUaPattern {
|
||||
if !isMatchUaPattern {
|
||||
logrus.Debug(fmt.Sprintf("[%s][%s] Not Hit User-Agent Pattern: %s", destAddrPort, src.(*net.TCPConn).RemoteAddr().String(), uaStr))
|
||||
}
|
||||
if isInWhiteList {
|
||||
logrus.Debug(fmt.Sprintf("[%s][%s] Hit User-Agent Whitelist: %s, Add LRU Relay Cache, Cache Len: %d", destAddrPort, src.(*net.TCPConn).RemoteAddr().String(), uaStr, cache.Len()))
|
||||
cache.Add(destAddrPort, destAddrPort)
|
||||
}
|
||||
dst.Write(buf[0:nr])
|
||||
io.Copy(dst, src)
|
||||
cache.Add(destAddrPort, destAddrPort)
|
||||
return
|
||||
}
|
||||
logrus.Debug(fmt.Sprintf("[%s][%s] Hit User-Agent: %s", destAddrPort, src.(*net.TCPConn).RemoteAddr().String(), string(value)))
|
||||
logrus.Debug(fmt.Sprintf("[%s][%s] Hit User-Agent: %s", destAddrPort, src.(*net.TCPConn).RemoteAddr().String(), uaStr))
|
||||
for i := start; i < end; i++ {
|
||||
buf[i] = 32
|
||||
}
|
||||
|
||||
@ -20,7 +20,7 @@ ckcmd() {
|
||||
cd /root
|
||||
getcpucore
|
||||
|
||||
version=0.4.0
|
||||
version=0.5.0
|
||||
ua3f_tar=ua3f-$version-$cpucore.tar.gz
|
||||
|
||||
if id -u shellclash >/dev/null 2>&1; then
|
||||
|
||||
@ -3,7 +3,7 @@ local uci = require("luci.model.uci").cursor()
|
||||
ua3f = Map("ua3f",
|
||||
"UA3F",
|
||||
[[
|
||||
<a href="https://github.com/SunBK201/UA3F" target="_blank">Version: 0.4.0</a>
|
||||
<a href="https://github.com/SunBK201/UA3F" target="_blank">Version: 0.5.0</a>
|
||||
<br>
|
||||
Across the Campus we can reach every corner in the world.
|
||||
]]
|
||||
@ -34,6 +34,8 @@ bind:value("127.0.0.1")
|
||||
bind:value("0.0.0.0")
|
||||
ua = main:taboption("general", Value, "ua", "User-Agent")
|
||||
ua.placeholder = "FFF"
|
||||
uaRegexPattern = main:taboption("general", Value, "ua_regex", "User-Agent Regex Pattern")
|
||||
uaRegexPattern.placeholder = "(iPhone|iPad|Android|Macintosh|Windows|Linux)"
|
||||
log_level = main:taboption("general", ListValue, "log_level", "Log Level")
|
||||
log_level:value("debug")
|
||||
log_level:value("info")
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
Package: ua3f
|
||||
Version: 0.4.0-1
|
||||
Version: 0.5.0-1
|
||||
Depends: libc, luci-compat
|
||||
Source: /feed/openwrt
|
||||
SourceName: UA3F
|
||||
@ -7,5 +7,5 @@ License: GPL-3.0-only
|
||||
Section: net
|
||||
SourceDateEpoch: 1711267200
|
||||
Architecture: all
|
||||
Installed-Size: 2181120
|
||||
Installed-Size: 2641920
|
||||
Description: Implementation of the new generation of HTTP User-Agent modification methodology.
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
Package: ua3f
|
||||
Version: 0.4.0-1
|
||||
Version: 0.5.0-1
|
||||
Depends: libc, luci-compat
|
||||
Source: /feed/openwrt
|
||||
SourceName: UA3F
|
||||
@ -7,5 +7,5 @@ License: GPL-3.0-only
|
||||
Section: net
|
||||
SourceDateEpoch: 1711267200
|
||||
Architecture: all
|
||||
Installed-Size: 2181120
|
||||
Installed-Size: 2641920
|
||||
Description: Implementation of the new generation of HTTP User-Agent modification methodology.
|
||||
|
||||
@ -5,4 +5,5 @@ config 'ua3f' 'main'
|
||||
option port '1080'
|
||||
option bind '127.0.0.1'
|
||||
option ua 'FFF'
|
||||
option ua_regex '(iPhone|iPad|Android|Macintosh|Windows|Linux)'
|
||||
option log_level 'info'
|
||||
|
||||
@ -23,6 +23,7 @@ start_service() {
|
||||
config_get port "main" "port" "1080"
|
||||
config_get bind "main" "bind" "127.0.0.1"
|
||||
config_get ua "main" "ua" "FFF"
|
||||
config_get ua_regex "main" "ua_regex" "(iPhone|iPad|Android|Macintosh|Windows|Linux)"
|
||||
config_get log_level "main" "log_level" "info"
|
||||
|
||||
chmod o+w /var/log
|
||||
@ -32,6 +33,7 @@ start_service() {
|
||||
procd_append_param command -b "$bind"
|
||||
procd_append_param command -p $port
|
||||
procd_append_param command -f "$ua"
|
||||
procd_append_param command -r "$ua_regex"
|
||||
procd_append_param command -l $log_level
|
||||
|
||||
procd_set_param respawn
|
||||
|
||||
@ -3,7 +3,7 @@ local uci = require("luci.model.uci").cursor()
|
||||
ua3f = Map("ua3f",
|
||||
"UA3F",
|
||||
[[
|
||||
<a href="https://github.com/SunBK201/UA3F" target="_blank">Version: 0.4.0</a>
|
||||
<a href="https://github.com/SunBK201/UA3F" target="_blank">Version: 0.5.0</a>
|
||||
<br>
|
||||
Across the Campus we can reach every corner in the world.
|
||||
]]
|
||||
@ -34,6 +34,8 @@ bind:value("127.0.0.1")
|
||||
bind:value("0.0.0.0")
|
||||
ua = main:taboption("general", Value, "ua", "User-Agent")
|
||||
ua.placeholder = "FFF"
|
||||
uaRegexPattern = main:taboption("general", Value, "ua_regex", "User-Agent Regex Pattern")
|
||||
uaRegexPattern.placeholder = "(iPhone|iPad|Android|Macintosh|Windows|Linux)"
|
||||
log_level = main:taboption("general", ListValue, "log_level", "Log Level")
|
||||
log_level:value("debug")
|
||||
log_level:value("info")
|
||||
|
||||
@ -23,6 +23,7 @@ start_service() {
|
||||
config_get port "main" "port" "1080"
|
||||
config_get bind "main" "bind" "127.0.0.1"
|
||||
config_get ua "main" "ua" "FFF"
|
||||
config_get ua_regex "main" "ua_regex" "(iPhone|iPad|Android|Macintosh|Windows|Linux)"
|
||||
config_get log_level "main" "log_level" "info"
|
||||
|
||||
chmod o+w /var/log
|
||||
@ -32,6 +33,7 @@ start_service() {
|
||||
procd_append_param command -b "$bind"
|
||||
procd_append_param command -p $port
|
||||
procd_append_param command -f "$ua"
|
||||
procd_append_param command -r "$ua_regex"
|
||||
procd_append_param command -l $log_level
|
||||
|
||||
procd_set_param respawn
|
||||
|
||||
Loading…
Reference in New Issue
Block a user