sing-box/experimental/clashapi/trafficontrol/tracker.go

273 lines
6.4 KiB
Go
Raw Normal View History

2022-07-22 09:29:13 +08:00
package trafficontrol
2022-07-19 22:16:49 +08:00
import (
"net"
"time"
"github.com/sagernet/sing-box/adapter"
2024-10-21 23:38:34 +08:00
R "github.com/sagernet/sing-box/route/rule"
2022-07-22 13:51:08 +08:00
"github.com/sagernet/sing/common"
2023-04-14 20:55:05 +08:00
"github.com/sagernet/sing/common/atomic"
2023-04-24 19:01:10 +08:00
"github.com/sagernet/sing/common/bufio"
2024-06-11 21:16:33 +08:00
F "github.com/sagernet/sing/common/format"
"github.com/sagernet/sing/common/json"
2022-07-19 22:16:49 +08:00
N "github.com/sagernet/sing/common/network"
2023-04-14 20:55:05 +08:00
"github.com/gofrs/uuid/v5"
2022-07-19 22:16:49 +08:00
)
2024-06-11 21:16:33 +08:00
type TrackerMetadata struct {
ID uuid.UUID
Metadata adapter.InboundContext
CreatedAt time.Time
ClosedAt time.Time
Upload *atomic.Int64
Download *atomic.Int64
Chain []string
Rule adapter.Rule
Outbound string
OutboundType string
2022-07-19 22:16:49 +08:00
}
2024-06-11 21:16:33 +08:00
func (t TrackerMetadata) MarshalJSON() ([]byte, error) {
var inbound string
if t.Metadata.Inbound != "" {
inbound = t.Metadata.InboundType + "/" + t.Metadata.Inbound
} else {
inbound = t.Metadata.InboundType
}
var domain string
if t.Metadata.Domain != "" {
domain = t.Metadata.Domain
} else {
domain = t.Metadata.Destination.Fqdn
}
var processPath string
if t.Metadata.ProcessInfo != nil {
if t.Metadata.ProcessInfo.ProcessPath != "" {
processPath = t.Metadata.ProcessInfo.ProcessPath
} else if t.Metadata.ProcessInfo.PackageName != "" {
processPath = t.Metadata.ProcessInfo.PackageName
}
if processPath == "" {
if t.Metadata.ProcessInfo.UserId != -1 {
processPath = F.ToString(t.Metadata.ProcessInfo.UserId)
}
} else if t.Metadata.ProcessInfo.User != "" {
processPath = F.ToString(processPath, " (", t.Metadata.ProcessInfo.User, ")")
} else if t.Metadata.ProcessInfo.UserId != -1 {
processPath = F.ToString(processPath, " (", t.Metadata.ProcessInfo.UserId, ")")
}
}
var rule string
if t.Rule != nil {
2024-10-21 23:38:34 +08:00
rule = F.ToString(t.Rule, " => ", t.Rule.Action())
2024-06-11 21:16:33 +08:00
} else {
rule = "final"
}
2023-04-14 20:55:05 +08:00
return json.Marshal(map[string]any{
2024-06-11 21:16:33 +08:00
"id": t.ID,
"metadata": map[string]any{
"network": t.Metadata.Network,
"type": inbound,
"sourceIP": t.Metadata.Source.Addr,
"destinationIP": t.Metadata.Destination.Addr,
"sourcePort": F.ToString(t.Metadata.Source.Port),
"destinationPort": F.ToString(t.Metadata.Destination.Port),
"host": domain,
"dnsMode": "normal",
"processPath": processPath,
},
"upload": t.Upload.Load(),
"download": t.Download.Load(),
"start": t.CreatedAt,
2023-04-14 20:55:05 +08:00
"chains": t.Chain,
2024-06-11 21:16:33 +08:00
"rule": rule,
"rulePayload": "",
2023-04-14 20:55:05 +08:00
})
}
2024-06-11 21:16:33 +08:00
type Tracker interface {
adapter.Tracker
Metadata() TrackerMetadata
Close() error
}
type TCPConn struct {
N.ExtendedConn
metadata TrackerMetadata
manager *Manager
2022-07-19 22:16:49 +08:00
}
2024-06-11 21:16:33 +08:00
func (tt *TCPConn) Metadata() TrackerMetadata {
return tt.metadata
2022-07-19 22:16:49 +08:00
}
2024-06-11 21:16:33 +08:00
func (tt *TCPConn) Close() error {
2022-07-19 22:16:49 +08:00
tt.manager.Leave(tt)
2022-09-26 15:31:02 +08:00
return tt.ExtendedConn.Close()
2022-07-19 22:16:49 +08:00
}
2024-06-11 21:16:33 +08:00
func (tt *TCPConn) Leave() {
2022-07-26 06:56:13 +08:00
tt.manager.Leave(tt)
}
2024-06-11 21:16:33 +08:00
func (tt *TCPConn) Upstream() any {
2022-09-26 15:31:02 +08:00
return tt.ExtendedConn
}
2024-06-11 21:16:33 +08:00
func (tt *TCPConn) ReaderReplaceable() bool {
2022-09-26 15:31:02 +08:00
return true
}
2024-06-11 21:16:33 +08:00
func (tt *TCPConn) WriterReplaceable() bool {
2022-09-26 15:31:02 +08:00
return true
2022-08-08 20:56:53 +08:00
}
2024-06-11 21:16:33 +08:00
func NewTCPTracker(conn net.Conn, manager *Manager, metadata adapter.InboundContext, router adapter.Router, rule adapter.Rule) *TCPConn {
id, _ := uuid.NewV4()
var (
chain []string
next string
outbound string
outboundType string
)
2024-10-21 23:38:34 +08:00
var action adapter.RuleAction
if rule != nil {
action = rule.Action()
}
if routeAction, isRouteAction := action.(*R.RuleActionRoute); isRouteAction {
next = routeAction.Outbound
} else if defaultOutbound, err := router.DefaultOutbound(N.NetworkTCP); err == nil {
next = defaultOutbound.Tag()
2022-07-22 13:51:08 +08:00
}
for {
detour, loaded := router.Outbound(next)
if !loaded {
break
}
2024-10-21 23:38:34 +08:00
chain = append(chain, next)
2024-06-11 21:16:33 +08:00
outbound = detour.Tag()
outboundType = detour.Type()
2022-07-22 13:51:08 +08:00
group, isGroup := detour.(adapter.OutboundGroup)
if !isGroup {
break
}
next = group.Now()
}
2023-04-14 20:55:05 +08:00
upload := new(atomic.Int64)
download := new(atomic.Int64)
2024-06-11 21:16:33 +08:00
tracker := &TCPConn{
2023-04-24 19:01:10 +08:00
ExtendedConn: bufio.NewCounterConn(conn, []N.CountFunc{func(n int64) {
2022-10-01 09:56:09 +08:00
upload.Add(n)
manager.PushUploaded(n)
2023-04-24 19:01:10 +08:00
}}, []N.CountFunc{func(n int64) {
2022-10-01 09:56:09 +08:00
download.Add(n)
manager.PushDownloaded(n)
2023-04-24 19:01:10 +08:00
}}),
2024-06-11 21:16:33 +08:00
metadata: TrackerMetadata{
ID: id,
Metadata: metadata,
CreatedAt: time.Now(),
Upload: upload,
Download: download,
Chain: common.Reverse(chain),
Rule: rule,
Outbound: outbound,
OutboundType: outboundType,
2022-07-19 22:16:49 +08:00
},
2024-06-11 21:16:33 +08:00
manager: manager,
2022-07-19 22:16:49 +08:00
}
2024-06-11 21:16:33 +08:00
manager.Join(tracker)
return tracker
2022-07-19 22:16:49 +08:00
}
2024-06-11 21:16:33 +08:00
type UDPConn struct {
2022-07-19 22:16:49 +08:00
N.PacketConn `json:"-"`
2024-06-11 21:16:33 +08:00
metadata TrackerMetadata
manager *Manager
2022-07-19 22:16:49 +08:00
}
2024-06-11 21:16:33 +08:00
func (ut *UDPConn) Metadata() TrackerMetadata {
return ut.metadata
2022-07-19 22:16:49 +08:00
}
2024-06-11 21:16:33 +08:00
func (ut *UDPConn) Close() error {
2022-07-19 22:16:49 +08:00
ut.manager.Leave(ut)
return ut.PacketConn.Close()
}
2024-06-11 21:16:33 +08:00
func (ut *UDPConn) Leave() {
2022-07-26 06:56:13 +08:00
ut.manager.Leave(ut)
}
2024-06-11 21:16:33 +08:00
func (ut *UDPConn) Upstream() any {
2022-08-08 20:56:53 +08:00
return ut.PacketConn
}
2024-06-11 21:16:33 +08:00
func (ut *UDPConn) ReaderReplaceable() bool {
2022-09-26 15:31:02 +08:00
return true
}
2024-06-11 21:16:33 +08:00
func (ut *UDPConn) WriterReplaceable() bool {
2022-09-26 15:31:02 +08:00
return true
}
2024-06-11 21:16:33 +08:00
func NewUDPTracker(conn N.PacketConn, manager *Manager, metadata adapter.InboundContext, router adapter.Router, rule adapter.Rule) *UDPConn {
id, _ := uuid.NewV4()
var (
chain []string
next string
outbound string
outboundType string
)
2024-10-21 23:38:34 +08:00
var action adapter.RuleAction
if rule != nil {
action = rule.Action()
}
if routeAction, isRouteAction := action.(*R.RuleActionRoute); isRouteAction {
next = routeAction.Outbound
} else if defaultOutbound, err := router.DefaultOutbound(N.NetworkUDP); err == nil {
next = defaultOutbound.Tag()
2022-07-22 13:51:08 +08:00
}
for {
detour, loaded := router.Outbound(next)
if !loaded {
break
}
2024-10-21 23:38:34 +08:00
chain = append(chain, next)
2024-06-11 21:16:33 +08:00
outbound = detour.Tag()
outboundType = detour.Type()
2022-07-22 13:51:08 +08:00
group, isGroup := detour.(adapter.OutboundGroup)
if !isGroup {
break
}
next = group.Now()
}
2023-04-14 20:55:05 +08:00
upload := new(atomic.Int64)
download := new(atomic.Int64)
2024-06-11 21:16:33 +08:00
trackerConn := &UDPConn{
2023-04-24 19:01:10 +08:00
PacketConn: bufio.NewCounterPacketConn(conn, []N.CountFunc{func(n int64) {
2022-10-01 09:56:09 +08:00
upload.Add(n)
manager.PushUploaded(n)
2023-04-24 19:01:10 +08:00
}}, []N.CountFunc{func(n int64) {
2022-10-01 09:56:09 +08:00
download.Add(n)
manager.PushDownloaded(n)
2023-04-24 19:01:10 +08:00
}}),
2024-06-11 21:16:33 +08:00
metadata: TrackerMetadata{
ID: id,
Metadata: metadata,
CreatedAt: time.Now(),
Upload: upload,
Download: download,
Chain: common.Reverse(chain),
Rule: rule,
Outbound: outbound,
OutboundType: outboundType,
2022-07-19 22:16:49 +08:00
},
2024-06-11 21:16:33 +08:00
manager: manager,
2022-07-19 22:16:49 +08:00
}
2024-06-11 21:16:33 +08:00
manager.Join(trackerConn)
return trackerConn
2022-07-19 22:16:49 +08:00
}