Skip to content

Commit 7b1377d

Browse files
committed
feat: use ua regex pattern rule to match target dataflow
1 parent eacdf80 commit 7b1377d

File tree

12 files changed

+58
-14
lines changed

12 files changed

+58
-14
lines changed

README.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
UA3F 是下一代 HTTP User-Agent 修改方法,对外作为一个 SOCK5 服务,可以部署在路由器等设备等设备进行透明 UA 修改。
44

55
## 特性
6-
- User-Agent 自定义
6+
- 支持正则表达式规则匹配修改 User-Agent
7+
- 自定义 User-Agent 内容
78
- 与其他网络加速代理工具共存
89
- LRU 高速缓存非 HTTP 域名,加速非 HTTP 流量转发
910
- 支持 LuCI Web 图形页面
@@ -34,6 +35,14 @@ UA3F 已支持 LuCI Web 页面,可以打开 Services -> UA3F 进行相关配
3435

3536
![UA3F-LuCI](https://sunbk201.oss-cn-beijing.aliyuncs.com/img/ua3f-luci)
3637

38+
> [!NOTE]
39+
> 设置说明:
40+
> - Port 为 UA3F 监听端口,默认 `1080`
41+
> - Bind Address 为 UA3F 监听地址,默认 `127.0.0.1`
42+
> - User-Agent 为自定义 User-Agent,默认 `FFF`
43+
> - User-Agent Regex Pattern 为 User-Agent 正则表达式规则。如果流量中的 User-Agent 匹配该正则表达式,则会被修改为 User-Agent 字段的内容,否则不会被修改;如果该字段为空,则所有流量 User-Agent 都会被修改。默认 `(iPhone|iPad|Android|Macintosh|Windows|Linux)`,即只修改携带设备与系统信息的 User-Agent。
44+
> - Log Level 为日志等级,默认 `info`, 如果需要调试排查错误可以设置为 `debug`
45+
3746
### 作为后台服务运行
3847

3948
安装脚本执行成功后可通过以下命令启动 UA3F:
@@ -89,6 +98,7 @@ sudo -u shellcrash /usr/bin/ua3f
8998

9099
- `-p <port>`: 端口号,默认 1080
91100
- `-f <UA>`: 自定义 UA,默认 FFF
101+
- `-r <regex>`: 自定义正则匹配 User-Agent, 默认 `(iPhone|iPad|Android|Macintosh|Windows|Linux)`
92102
- `-b <bind addr>`: 自定义绑定监听地址,默认 127.0.0.1
93103
- `-l <log level>`: 日志等级,默认 info,可选:debug,默认日志位置:`/var/log/ua3f.log`
94104

build.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/bin/sh
22

33
project_name="ua3f"
4-
release_version="0.4.0"
4+
release_version="0.5.0"
55
target=cmd/ua3f.go
66
dist=./dist
77
release_dir=./bin

cmd/ua3f.go

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"fmt"
88
"io"
99
"net"
10+
"regexp"
1011
"slices"
1112
"strings"
1213
"time"
@@ -17,8 +18,10 @@ import (
1718
"github.com/sirupsen/logrus"
1819
)
1920

20-
var version = "0.4.0"
21+
var version = "0.5.0"
2122
var payloadByte []byte
23+
var uaPattern string
24+
var uaRegexp *regexp.Regexp
2225
var cache *expirable.LRU[string, string]
2326
var HTTP_METHOD = []string{"GET", "POST", "HEAD", "PUT", "DELETE", "OPTIONS", "TRACE", "CONNECT"}
2427
var whitelist = []string{
@@ -47,6 +50,7 @@ func main() {
4750
flag.StringVar(&addr, "b", "127.0.0.1", "bind address (default: 127.0.0.1)")
4851
flag.IntVar(&port, "p", 1080, "port")
4952
flag.StringVar(&payload, "f", "FFF", "User-Agent")
53+
flag.StringVar(&uaPattern, "r", "(iPhone|iPad|Android|Macintosh|Windows|Linux)", "UA-Pattern")
5054
flag.StringVar(&loglevel, "l", "info", "Log level (default: info)")
5155
flag.Parse()
5256

@@ -55,6 +59,7 @@ func main() {
5559
logrus.Info("UA3F v" + version)
5660
logrus.Info(fmt.Sprintf("Port: %d", port))
5761
logrus.Info(fmt.Sprintf("User-Agent: %s", payload))
62+
logrus.Info(fmt.Sprintf("User-Agent Regex Pattern: %s", uaPattern))
5863
logrus.Info(fmt.Sprintf("Log level: %s", loglevel))
5964

6065
cache = expirable.NewLRU[string, string](300, nil, time.Second*600)
@@ -72,6 +77,11 @@ func main() {
7277
return
7378
}
7479
logrus.Info(fmt.Sprintf("Listen on %s:%d", addr, port))
80+
uaRegexp, err = regexp.Compile(uaPattern)
81+
if err != nil {
82+
logrus.Fatal("Invalid User-Agent Regex Pattern: ", err)
83+
return
84+
}
7585
for {
7686
client, err := server.Accept()
7787
if err != nil {
@@ -425,15 +435,29 @@ func CopyPileline(dst io.Writer, src io.Reader, destAddrPort string) {
425435
httpBodyOffset, err = parser.Parse(buf[:nr])
426436
}
427437
value, start, end := parser.FindHeader([]byte("User-Agent"))
438+
uaStr := string(value)
428439
if value != nil && end > start {
429-
if slices.Contains(whitelist, string(value)) {
430-
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()))
440+
isInWhiteList := false
441+
isMatchUaPattern := true
442+
if uaPattern != "" {
443+
isMatchUaPattern = uaRegexp.MatchString(uaStr)
444+
}
445+
if slices.Contains(whitelist, uaStr) {
446+
isInWhiteList = true
447+
}
448+
if isInWhiteList || !isMatchUaPattern {
449+
if !isMatchUaPattern {
450+
logrus.Debug(fmt.Sprintf("[%s][%s] Not Hit User-Agent Pattern: %s", destAddrPort, src.(*net.TCPConn).RemoteAddr().String(), uaStr))
451+
}
452+
if isInWhiteList {
453+
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()))
454+
cache.Add(destAddrPort, destAddrPort)
455+
}
431456
dst.Write(buf[0:nr])
432457
io.Copy(dst, src)
433-
cache.Add(destAddrPort, destAddrPort)
434458
return
435459
}
436-
logrus.Debug(fmt.Sprintf("[%s][%s] Hit User-Agent: %s", destAddrPort, src.(*net.TCPConn).RemoteAddr().String(), string(value)))
460+
logrus.Debug(fmt.Sprintf("[%s][%s] Hit User-Agent: %s", destAddrPort, src.(*net.TCPConn).RemoteAddr().String(), uaStr))
437461
for i := start; i < end; i++ {
438462
buf[i] = 32
439463
}

install.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ ckcmd() {
2020
cd /root
2121
getcpucore
2222

23-
version=0.4.0
23+
version=0.5.0
2424
ua3f_tar=ua3f-$version-$cpucore.tar.gz
2525

2626
if id -u shellclash >/dev/null 2>&1; then

luci/cbi.lua

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ local uci = require("luci.model.uci").cursor()
33
ua3f = Map("ua3f",
44
"UA3F",
55
[[
6-
<a href="https://github.com/SunBK201/UA3F" target="_blank">Version: 0.4.0</a>
6+
<a href="https://github.com/SunBK201/UA3F" target="_blank">Version: 0.5.0</a>
77
<br>
88
Across the Campus we can reach every corner in the world.
99
]]
@@ -34,6 +34,8 @@ bind:value("127.0.0.1")
3434
bind:value("0.0.0.0")
3535
ua = main:taboption("general", Value, "ua", "User-Agent")
3636
ua.placeholder = "FFF"
37+
uaRegexPattern = main:taboption("general", Value, "ua_regex", "User-Agent Regex Pattern")
38+
uaRegexPattern.placeholder = "(iPhone|iPad|Android|Macintosh|Windows|Linux)"
3739
log_level = main:taboption("general", ListValue, "log_level", "Log Level")
3840
log_level:value("debug")
3941
log_level:value("info")

opkg/CONTROL/control

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
Package: ua3f
2-
Version: 0.4.0-1
2+
Version: 0.5.0-1
33
Depends: libc, luci-compat
44
Source: /feed/openwrt
55
SourceName: UA3F
66
License: GPL-3.0-only
77
Section: net
88
SourceDateEpoch: 1711267200
99
Architecture: all
10-
Installed-Size: 2181120
10+
Installed-Size: 2641920
1111
Description: Implementation of the new generation of HTTP User-Agent modification methodology.

opkg/CONTROL/control-e

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
Package: ua3f
2-
Version: 0.4.0-1
2+
Version: 0.5.0-1
33
Depends: libc, luci-compat
44
Source: /feed/openwrt
55
SourceName: UA3F
66
License: GPL-3.0-only
77
Section: net
88
SourceDateEpoch: 1711267200
99
Architecture: all
10-
Installed-Size: 2181120
10+
Installed-Size: 2641920
1111
Description: Implementation of the new generation of HTTP User-Agent modification methodology.

opkg/etc/config/ua3f

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ config 'ua3f' 'main'
55
option port '1080'
66
option bind '127.0.0.1'
77
option ua 'FFF'
8+
option ua_regex '(iPhone|iPad|Android|Macintosh|Windows|Linux)'
89
option log_level 'info'

opkg/etc/init.d/ua3f

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ start_service() {
2323
config_get port "main" "port" "1080"
2424
config_get bind "main" "bind" "127.0.0.1"
2525
config_get ua "main" "ua" "FFF"
26+
config_get ua_regex "main" "ua_regex" "(iPhone|iPad|Android|Macintosh|Windows|Linux)"
2627
config_get log_level "main" "log_level" "info"
2728

2829
chmod o+w /var/log
@@ -32,6 +33,7 @@ start_service() {
3233
procd_append_param command -b "$bind"
3334
procd_append_param command -p $port
3435
procd_append_param command -f "$ua"
36+
procd_append_param command -r "$ua_regex"
3537
procd_append_param command -l $log_level
3638

3739
procd_set_param respawn

opkg/usr/lib/lua/luci/model/cbi/ua3f.lua

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ local uci = require("luci.model.uci").cursor()
33
ua3f = Map("ua3f",
44
"UA3F",
55
[[
6-
<a href="https://github.com/SunBK201/UA3F" target="_blank">Version: 0.4.0</a>
6+
<a href="https://github.com/SunBK201/UA3F" target="_blank">Version: 0.5.0</a>
77
<br>
88
Across the Campus we can reach every corner in the world.
99
]]
@@ -34,6 +34,8 @@ bind:value("127.0.0.1")
3434
bind:value("0.0.0.0")
3535
ua = main:taboption("general", Value, "ua", "User-Agent")
3636
ua.placeholder = "FFF"
37+
uaRegexPattern = main:taboption("general", Value, "ua_regex", "User-Agent Regex Pattern")
38+
uaRegexPattern.placeholder = "(iPhone|iPad|Android|Macintosh|Windows|Linux)"
3739
log_level = main:taboption("general", ListValue, "log_level", "Log Level")
3840
log_level:value("debug")
3941
log_level:value("info")

0 commit comments

Comments
 (0)