mirror of
https://github.com/SunBK201/UA3F.git
synced 2025-12-16 16:57:08 +00:00
feat: support record ua mock times and i18n
This commit is contained in:
parent
830aadb22b
commit
f4d15229e3
4
build.sh
4
build.sh
@ -64,12 +64,16 @@ ipkg_build=ipkg-build.sh
|
|||||||
mkdir -p $opkg_template/usr/bin
|
mkdir -p $opkg_template/usr/bin
|
||||||
mkdir -p $opkg_template/usr/lib/lua/luci/controller
|
mkdir -p $opkg_template/usr/lib/lua/luci/controller
|
||||||
mkdir -p $opkg_template/usr/lib/lua/luci/model/cbi
|
mkdir -p $opkg_template/usr/lib/lua/luci/model/cbi
|
||||||
|
mkdir -p $opkg_template/usr/lib/lua/luci/view/ua3f
|
||||||
|
mkdir -p $opkg_template/usr/lib/lua/luci/i18n
|
||||||
mkdir -p $opkg_template/etc/init.d
|
mkdir -p $opkg_template/etc/init.d
|
||||||
mkdir -p $opkg_template/etc/config
|
mkdir -p $opkg_template/etc/config
|
||||||
cp openwrt/files/luci/controller.lua $opkg_template/usr/lib/lua/luci/controller/ua3f.lua
|
cp openwrt/files/luci/controller.lua $opkg_template/usr/lib/lua/luci/controller/ua3f.lua
|
||||||
cp openwrt/files/luci/cbi.lua $opkg_template/usr/lib/lua/luci/model/cbi/ua3f.lua
|
cp openwrt/files/luci/cbi.lua $opkg_template/usr/lib/lua/luci/model/cbi/ua3f.lua
|
||||||
|
cp openwrt/files/luci/statistics.htm $opkg_template/usr/lib/lua/luci/view/ua3f/statistics.htm
|
||||||
cp openwrt/files/ua3f.init $opkg_template/etc/init.d/ua3f
|
cp openwrt/files/ua3f.init $opkg_template/etc/init.d/ua3f
|
||||||
cp openwrt/files/ua3f.uci $opkg_template/etc/config/ua3f
|
cp openwrt/files/ua3f.uci $opkg_template/etc/config/ua3f
|
||||||
|
./po2lmo openwrt/po/zh_cn/ua3f.po $opkg_template/usr/lib/lua/luci/i18n/ua3f.zh-cn.lmo
|
||||||
for goarch in "amd64" "arm" "arm64" "mipsle" "mips64" "riscv64" "386" "mipsle-softfloat" "mipsle-hardfloat" "armv7" "armv8"; do
|
for goarch in "amd64" "arm" "arm64" "mipsle" "mips64" "riscv64" "386" "mipsle-softfloat" "mipsle-hardfloat" "armv7" "armv8"; do
|
||||||
obj_name=$project_name-$release_version-$goarch
|
obj_name=$project_name-$release_version-$goarch
|
||||||
mv $dist/bin/$obj_name $opkg_template/usr/bin/ua3f
|
mv $dist/bin/$obj_name $opkg_template/usr/bin/ua3f
|
||||||
|
|||||||
@ -7,5 +7,5 @@ License: GPL-3.0-only
|
|||||||
Section: net
|
Section: net
|
||||||
SourceDateEpoch: 1711267200
|
SourceDateEpoch: 1711267200
|
||||||
Architecture: all
|
Architecture: all
|
||||||
Installed-Size: 3686400
|
Installed-Size: 3696640
|
||||||
Description: Implementation of the next generation of HTTP User-Agent modification methodology.
|
Description: Implementation of the next generation of HTTP User-Agent modification methodology.
|
||||||
|
|||||||
@ -37,6 +37,7 @@ endef
|
|||||||
|
|
||||||
define Build/Prepare
|
define Build/Prepare
|
||||||
$(CP) ../src/* $(PKG_BUILD_DIR)
|
$(CP) ../src/* $(PKG_BUILD_DIR)
|
||||||
|
po2lmo ./po/zh_cn/ua3f.po $(PKG_BUILD_DIR)/ua3f.zh-cn.lmo
|
||||||
endef
|
endef
|
||||||
|
|
||||||
define Package/ua3f/conffiles
|
define Package/ua3f/conffiles
|
||||||
@ -57,6 +58,10 @@ define Package/ua3f/install
|
|||||||
$(INSTALL_CONF) ./files/luci/cbi.lua $(1)/usr/lib/lua/luci/model/cbi/ua3f.lua
|
$(INSTALL_CONF) ./files/luci/cbi.lua $(1)/usr/lib/lua/luci/model/cbi/ua3f.lua
|
||||||
$(INSTALL_DIR) $(1)/usr/lib/lua/luci/controller/
|
$(INSTALL_DIR) $(1)/usr/lib/lua/luci/controller/
|
||||||
$(INSTALL_CONF) ./files/luci/controller.lua $(1)/usr/lib/lua/luci/controller/ua3f.lua
|
$(INSTALL_CONF) ./files/luci/controller.lua $(1)/usr/lib/lua/luci/controller/ua3f.lua
|
||||||
|
$(INSTALL_DIR) $(1)/usr/lib/lua/luci/view/ua3f/
|
||||||
|
$(INSTALL_CONF) ./files/luci/statistics.htm $(1)/usr/lib/lua/luci/view/ua3f/statistics.htm
|
||||||
|
$(INSTALL_DIR) $(1)/usr/lib/lua/luci/i18n/
|
||||||
|
$(INSTALL_DATA) $(PKG_BUILD_DIR)/ua3f.zh-cn.lmo $(1)/usr/lib/lua/luci/i18n/ua3f.zh-cn.lmo
|
||||||
|
|
||||||
endef
|
endef
|
||||||
|
|
||||||
|
|||||||
@ -9,60 +9,63 @@ ua3f = Map("ua3f",
|
|||||||
]]
|
]]
|
||||||
)
|
)
|
||||||
|
|
||||||
enable = ua3f:section(NamedSection, "enabled", "ua3f", "Status")
|
status = ua3f:section(NamedSection, "enabled", "ua3f", translate("Status"))
|
||||||
main = ua3f:section(NamedSection, "main", "ua3f", "Settings")
|
general = ua3f:section(NamedSection, "main", "ua3f", translate("General"))
|
||||||
|
|
||||||
enable:option(Flag, "enabled", "Enabled")
|
status:option(Flag, "enabled", translate("Enabled"))
|
||||||
status = enable:option(DummyValue, "status", "Status")
|
|
||||||
status.rawhtml = true
|
running = status:option(DummyValue, "running", translate("Status"))
|
||||||
status.cfgvalue = function(self, section)
|
running.rawhtml = true
|
||||||
|
running.cfgvalue = function(self, section)
|
||||||
local pid = luci.sys.exec("pidof ua3f")
|
local pid = luci.sys.exec("pidof ua3f")
|
||||||
if pid == "" then
|
if pid == "" then
|
||||||
return "<span style='color:red'>" .. "Stopped" .. "</span>"
|
return "<input disabled type='button' style='opacity: 1;' class='btn cbi-button cbi-button-reset' value='" ..
|
||||||
|
translate("Stop") .. "'/>"
|
||||||
else
|
else
|
||||||
return "<span style='color:green'>" .. "Running" .. "</span>"
|
return "<input disabled type='button' style='opacity: 1;' class='btn cbi-button cbi-button-add' value='" ..
|
||||||
|
translate("Running") .. "'/>"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
main:tab("general", "General Settings")
|
general:tab("general", translate("Settings"))
|
||||||
main:tab("log", "Log")
|
general:tab("stats", translate("Statistics"))
|
||||||
|
general:tab("log", translate("Log"))
|
||||||
|
|
||||||
port = main:taboption("general", Value, "port", "Port")
|
port = general:taboption("general", Value, "port", translate("Port"))
|
||||||
port.placeholder = "1080"
|
port.placeholder = "1080"
|
||||||
|
|
||||||
bind = main:taboption("general", Value, "bind", "Bind Address")
|
bind = general:taboption("general", Value, "bind", translate("Bind Address"))
|
||||||
bind:value("127.0.0.1")
|
bind:value("127.0.0.1")
|
||||||
bind:value("0.0.0.0")
|
bind:value("0.0.0.0")
|
||||||
|
|
||||||
log_level = main:taboption("general", ListValue, "log_level", "Log Level")
|
log_level = general:taboption("general", ListValue, "log_level", translate("Log Level"))
|
||||||
log_level:value("debug")
|
log_level:value("debug")
|
||||||
log_level:value("info")
|
log_level:value("info")
|
||||||
log_level:value("warn")
|
log_level:value("warn")
|
||||||
log_level:value("error")
|
log_level:value("error")
|
||||||
log_level:value("fatal")
|
log_level:value("fatal")
|
||||||
log_level:value("panic")
|
log_level:value("panic")
|
||||||
log = main:taboption("log", TextValue, "")
|
|
||||||
|
ua = general:taboption("general", Value, "ua", translate("User-Agent"))
|
||||||
|
ua.placeholder = "FFF"
|
||||||
|
|
||||||
|
uaRegexPattern = general:taboption("general", Value, "ua_regex", translate("User-Agent Regex Pattern"))
|
||||||
|
uaRegexPattern.placeholder = "(iPhone|iPad|Android|Macintosh|Windows|Linux|Apple|Mac OS X|Mobile)"
|
||||||
|
uaRegexPattern.description = translate("Regular expression pattern for matching User-Agent")
|
||||||
|
|
||||||
|
partialRepalce = general:taboption("general", Flag, "partial_replace", translate("Partial Replace"))
|
||||||
|
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"
|
||||||
|
|
||||||
|
log = general:taboption("log", TextValue, "")
|
||||||
log.readonly = true
|
log.readonly = true
|
||||||
log.cfgvalue = function(self, section)
|
log.cfgvalue = function(self, section)
|
||||||
return luci.sys.exec("cat /var/log/ua3f/ua3f.log")
|
return luci.sys.exec("cat /var/log/ua3f/ua3f.log")
|
||||||
end
|
end
|
||||||
log.rows = 30
|
log.rows = 30
|
||||||
|
|
||||||
ua = main:taboption("general", Value, "ua", "User-Agent")
|
stats = general:taboption("stats", DummyValue, "")
|
||||||
ua.placeholder = "FFF"
|
stats.template = "ua3f/statistics"
|
||||||
|
|
||||||
uaRegexPattern = main:taboption("general", Value, "ua_regex", "User-Agent Regex Pattern")
|
|
||||||
uaRegexPattern.placeholder = "(iPhone|iPad|Android|Macintosh|Windows|Linux|Apple|Mac OS X|Mobile)"
|
|
||||||
uaRegexPattern.description = "Regular expression pattern for matching User-Agent"
|
|
||||||
|
|
||||||
partialRepalce = main:taboption("general", Flag, "partial_replace", "Partial Replace")
|
|
||||||
partialRepalce.description =
|
|
||||||
"Replace only the matched part of the User-Agent, only works when User-Agent Regex Pattern is not empty"
|
|
||||||
partialRepalce.default = "0"
|
|
||||||
|
|
||||||
local apply = luci.http.formvalue("cbi.apply")
|
|
||||||
if apply then
|
|
||||||
io.popen("/etc/init.d/ua3f restart")
|
|
||||||
end
|
|
||||||
|
|
||||||
return ua3f
|
return ua3f
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
module("luci.controller.ua3f", package.seeall)
|
module("luci.controller.ua3f", package.seeall)
|
||||||
|
|
||||||
function index()
|
function index()
|
||||||
entry({"admin", "services", "ua3f"}, cbi("ua3f"), "UA3F", 1)
|
entry({"admin", "services", "ua3f"}, cbi("ua3f"), _("UA3F"), 1)
|
||||||
end
|
end
|
||||||
82
openwrt/files/luci/statistics.htm
Normal file
82
openwrt/files/luci/statistics.htm
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
<%
|
||||||
|
local stats = {}
|
||||||
|
local file = io.open("/var/log/ua3f/stats", "r")
|
||||||
|
if file then
|
||||||
|
for line in file:lines() do
|
||||||
|
local host, count, origin_ua, mocked_ua = line:match("^(%S+)%s+(%d+)%s+(.-)SEQSEQ(.-)%s*$")
|
||||||
|
if host and count then
|
||||||
|
table.insert(stats, {host = host, count = count, origin_ua = origin_ua, mocked_ua = mocked_ua})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
file:close()
|
||||||
|
end
|
||||||
|
|
||||||
|
local function rowstyle(i)
|
||||||
|
return (i % 2 == 0) and "cbi-rowstyle-2" or "cbi-rowstyle-1"
|
||||||
|
end
|
||||||
|
%>
|
||||||
|
|
||||||
|
<h3><%:Statistics%></h3>
|
||||||
|
<div class="cbi-section-descr"><%:User-Agent Mock Statistics%></div>
|
||||||
|
|
||||||
|
<table id="stats-table" class="table cbi-section-table">
|
||||||
|
<tr class="tr table-titles">
|
||||||
|
<th class="th"><%:Host%></th>
|
||||||
|
<th class="th"><%:Modified Count%></th>
|
||||||
|
<th class="th"><%:Original User-Agent%></th>
|
||||||
|
<th class="th"><%:Mocked User-Agent%></th>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<% for i, item in ipairs(stats) do %>
|
||||||
|
<tr class="tr <%= rowstyle(i) %>">
|
||||||
|
<td class="td" data-title="<%:Host%>"><span><%= item.host %></span></td>
|
||||||
|
<td class="td" data-title="<%:Modified Count%>"><%= item.count %></td>
|
||||||
|
<td class="td" data-title="<%:Original User-Agent%>"><span><%= item.origin_ua %></span></td>
|
||||||
|
<td class="td" data-title="<%:Mocked User-Agent%>"><span><%= item.mocked_ua %></span></td>
|
||||||
|
</tr>
|
||||||
|
<% end %>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
async function updateStats() {
|
||||||
|
try {
|
||||||
|
const response = await fetch(window.location.href, {cache: "no-store"});
|
||||||
|
const text = await response.text();
|
||||||
|
|
||||||
|
const parser = new DOMParser();
|
||||||
|
const doc = parser.parseFromString(text, "text/html");
|
||||||
|
const newTable = doc.querySelector("#stats-table");
|
||||||
|
|
||||||
|
if (newTable) {
|
||||||
|
document.querySelector("#stats-table").innerHTML = newTable.innerHTML;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error("update stats error:", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setInterval(updateStats, 5000);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
#stats-table th:nth-child(1),
|
||||||
|
#stats-table td:nth-child(1) {
|
||||||
|
width: 20%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#stats-table th:nth-child(2),
|
||||||
|
#stats-table td:nth-child(2) {
|
||||||
|
width: 10%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#stats-table th:nth-child(3),
|
||||||
|
#stats-table td:nth-child(3) {
|
||||||
|
width: 35%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#stats-table th:nth-child(4),
|
||||||
|
#stats-table td:nth-child(4) {
|
||||||
|
width: 35%;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
66
openwrt/po/zh_cn/ua3f.po
Normal file
66
openwrt/po/zh_cn/ua3f.po
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
"Language: zh_CN\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
|
||||||
|
msgid "Status"
|
||||||
|
msgstr "状态"
|
||||||
|
|
||||||
|
msgid "General"
|
||||||
|
msgstr "常规"
|
||||||
|
|
||||||
|
msgid "Enabled"
|
||||||
|
msgstr "启用"
|
||||||
|
|
||||||
|
msgid "Running"
|
||||||
|
msgstr "运行中"
|
||||||
|
|
||||||
|
msgid "Stopped"
|
||||||
|
msgstr "未运行"
|
||||||
|
|
||||||
|
msgid "Settings"
|
||||||
|
msgstr "设置"
|
||||||
|
|
||||||
|
msgid "Statistics"
|
||||||
|
msgstr "统计信息"
|
||||||
|
|
||||||
|
msgid "Log"
|
||||||
|
msgstr "运行日志"
|
||||||
|
|
||||||
|
msgid "Port"
|
||||||
|
msgstr "端口"
|
||||||
|
|
||||||
|
msgid "Bind Address"
|
||||||
|
msgstr "绑定地址"
|
||||||
|
|
||||||
|
msgid "Log Level"
|
||||||
|
msgstr "日志级别"
|
||||||
|
|
||||||
|
msgid "User-Agent"
|
||||||
|
msgstr "User-Agent"
|
||||||
|
|
||||||
|
msgid "User-Agent Regex Pattern"
|
||||||
|
msgstr "User-Agent 正则表达式"
|
||||||
|
|
||||||
|
msgid "Regular expression pattern for matching User-Agent"
|
||||||
|
msgstr "用于匹配 User-Agent,只有匹配成功的 User-Agent 才会被修改,为空则匹配所有 User-Agent"
|
||||||
|
|
||||||
|
msgid "Partial Replace"
|
||||||
|
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 "User-Agent Mock Statistics"
|
||||||
|
msgstr "User-Agent 修改次数实时统计"
|
||||||
|
|
||||||
|
msgid "Host"
|
||||||
|
msgstr "地址"
|
||||||
|
|
||||||
|
msgid "Modified Count"
|
||||||
|
msgstr "修改次数"
|
||||||
|
|
||||||
|
msgid "Original User-Agent"
|
||||||
|
msgstr "原始 User-Agent"
|
||||||
|
|
||||||
|
msgid "Mocked User-Agent"
|
||||||
|
msgstr "修改后 User-Agent"
|
||||||
@ -11,6 +11,8 @@ import (
|
|||||||
"gopkg.in/natefinch/lumberjack.v2"
|
"gopkg.in/natefinch/lumberjack.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const log_file = "/var/log/ua3f/ua3f.log"
|
||||||
|
|
||||||
type uctFormatter struct {
|
type uctFormatter struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,7 +29,6 @@ func (formatter *uctFormatter) Format(entry *logrus.Entry) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func SetLogConf(level string) {
|
func SetLogConf(level string) {
|
||||||
log_file := "/var/log/ua3f/ua3f.log"
|
|
||||||
writer1 := &bytes.Buffer{}
|
writer1 := &bytes.Buffer{}
|
||||||
writer2 := os.Stdout
|
writer2 := os.Stdout
|
||||||
writer3 := &lumberjack.Logger{
|
writer3 := &lumberjack.Logger{
|
||||||
78
src/internal/statistics/statistics.go
Normal file
78
src/internal/statistics/statistics.go
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
package statistics
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"sort"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StatRecord struct {
|
||||||
|
Host string
|
||||||
|
Count int
|
||||||
|
OriginUA string
|
||||||
|
MockedUA string
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
statChan = make(chan StatRecord, 3000)
|
||||||
|
stats = make(map[string]*StatRecord)
|
||||||
|
)
|
||||||
|
|
||||||
|
const statsFile = "/var/log/ua3f/stats"
|
||||||
|
|
||||||
|
func StartStatWorker() {
|
||||||
|
ticker := time.NewTicker(5 * time.Second)
|
||||||
|
defer ticker.Stop()
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case dest := <-statChan:
|
||||||
|
if record, exists := stats[dest.Host]; exists {
|
||||||
|
record.Count++
|
||||||
|
record.OriginUA = dest.OriginUA
|
||||||
|
record.MockedUA = dest.MockedUA
|
||||||
|
} else {
|
||||||
|
stats[dest.Host] = &StatRecord{
|
||||||
|
Host: dest.Host,
|
||||||
|
Count: 1,
|
||||||
|
OriginUA: dest.OriginUA,
|
||||||
|
MockedUA: dest.MockedUA,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case <-ticker.C:
|
||||||
|
dumpStatsToFile()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddStat(dest *StatRecord) {
|
||||||
|
select {
|
||||||
|
case statChan <- *dest:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func dumpStatsToFile() {
|
||||||
|
f, err := os.Create(statsFile)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorf("create stats file error: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
var statList []StatRecord
|
||||||
|
for _, record := range stats {
|
||||||
|
statList = append(statList, *record)
|
||||||
|
}
|
||||||
|
sort.SliceStable(statList, func(i, j int) bool {
|
||||||
|
return statList[i].Count > statList[j].Count
|
||||||
|
})
|
||||||
|
|
||||||
|
for _, record := range statList {
|
||||||
|
line := fmt.Sprintf("%s %d %sSEQSEQ%s\n", record.Host, record.Count, record.OriginUA, record.MockedUA)
|
||||||
|
f.WriteString(line)
|
||||||
|
}
|
||||||
|
}
|
||||||
14
src/main.go
14
src/main.go
@ -15,7 +15,8 @@ import (
|
|||||||
"github.com/dlclark/regexp2"
|
"github.com/dlclark/regexp2"
|
||||||
"github.com/hashicorp/golang-lru/v2/expirable"
|
"github.com/hashicorp/golang-lru/v2/expirable"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/sunbk201/ua3f/log"
|
"github.com/sunbk201/ua3f/internal/log"
|
||||||
|
"github.com/sunbk201/ua3f/internal/statistics"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -79,6 +80,9 @@ func main() {
|
|||||||
logrus.Fatal("Invalid User-Agent Regex Pattern: ", err)
|
logrus.Fatal("Invalid User-Agent Regex Pattern: ", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
go statistics.StartStatWorker()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
client, err := server.Accept()
|
client, err := server.Accept()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -468,11 +472,17 @@ func transfer(dst net.Conn, src net.Conn, destAddrPort string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
logrus.Debug(fmt.Sprintf("[%s][%s] Hit User-Agent: %s", destAddrPort, src.(*net.TCPConn).RemoteAddr().String(), uaStr))
|
logrus.Debug(fmt.Sprintf("[%s][%s] Hit User-Agent: %s", destAddrPort, src.(*net.TCPConn).RemoteAddr().String(), uaStr))
|
||||||
request.Header.Set("User-Agent", buildNewUA(uaStr, payload, uaRegexp, enablePartialReplace))
|
mockedUA := buildNewUA(uaStr, payload, uaRegexp, enablePartialReplace)
|
||||||
|
request.Header.Set("User-Agent", mockedUA)
|
||||||
err = request.Write(dst)
|
err = request.Write(dst)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Error(fmt.Sprintf("[%s][%s] write error after replace user-agent: %s", destAddrPort, src.(*net.TCPConn).RemoteAddr().String(), err.Error()))
|
logrus.Error(fmt.Sprintf("[%s][%s] write error after replace user-agent: %s", destAddrPort, src.(*net.TCPConn).RemoteAddr().String(), err.Error()))
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
statistics.AddStat(&statistics.StatRecord{
|
||||||
|
Host: destAddrPort,
|
||||||
|
OriginUA: uaStr,
|
||||||
|
MockedUA: mockedUA,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user