fix(api): cap the client traffic list a master pushes by entry count

pushClientTraffics decoded the pushed list whole, and each "{}" became a
full traffic row, so a body under the size cap could cost the panel
close to a gigabyte. The list is now decoded entry by entry and refused
past 262144 entries. The capped decoder the node runtime already used
moves to json_util so both share it.
This commit is contained in:
MHSanaei
2026-10-31 14:25:21 +01:00
parent 44a502a407
commit fe5d704d67
5 changed files with 82 additions and 38 deletions
+12 -3
View File
@@ -8,6 +8,7 @@ import (
"github.com/mhsanaei/3x-ui/v3/internal/amneziawgkern"
"github.com/mhsanaei/3x-ui/v3/internal/database/model"
"github.com/mhsanaei/3x-ui/v3/internal/util/json_util"
"github.com/mhsanaei/3x-ui/v3/internal/util/wirecodec"
"github.com/mhsanaei/3x-ui/v3/internal/web/middleware"
"github.com/mhsanaei/3x-ui/v3/internal/web/service"
@@ -395,18 +396,26 @@ func (a *InboundController) resetAllTraffics(c *gin.Context) {
jsonMsg(c, I18nWeb(c, "pages.inbounds.toasts.resetAllTrafficSuccess"), nil)
}
// maxPushedClientTraffics bounds one push: each entry decodes into a whole traffic row.
const maxPushedClientTraffics = 1 << 18
// pushClientTraffics receives a master panel's aggregated per-client usage
// (see InboundService.AcceptGlobalTraffic for the storage semantics).
func (a *InboundController) pushClientTraffics(c *gin.Context) {
var req struct {
MasterGuid string `json:"masterGuid"`
Traffics []*xray.ClientTraffic `json:"traffics"`
MasterGuid string `json:"masterGuid"`
Traffics json.RawMessage `json:"traffics"`
}
if err := c.ShouldBindJSON(&req); err != nil {
jsonMsg(c, I18nWeb(c, "somethingWentWrong"), err)
return
}
if err := a.inboundService.AcceptGlobalTraffic(req.MasterGuid, req.Traffics); err != nil {
traffics, err := json_util.DecodeCappedList[*xray.ClientTraffic](req.Traffics, maxPushedClientTraffics)
if err != nil {
jsonMsg(c, I18nWeb(c, "somethingWentWrong"), err)
return
}
if err := a.inboundService.AcceptGlobalTraffic(req.MasterGuid, traffics); err != nil {
jsonMsg(c, I18nWeb(c, "somethingWentWrong"), err)
return
}