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

223 lines
4.7 KiB
Go
Raw Normal View History

2022-07-22 01:29:13 +00:00
package trafficontrol
2022-07-19 14:16:49 +00:00
import (
"net"
"net/netip"
"time"
"github.com/sagernet/sing-box/adapter"
2022-07-22 05:51:08 +00:00
"github.com/sagernet/sing/common"
2022-07-19 14:16:49 +00:00
"github.com/sagernet/sing/common/buf"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
"github.com/gofrs/uuid"
"go.uber.org/atomic"
)
type Metadata struct {
NetWork string `json:"network"`
Type string `json:"type"`
SrcIP netip.Addr `json:"sourceIP"`
DstIP netip.Addr `json:"destinationIP"`
SrcPort string `json:"sourcePort"`
DstPort string `json:"destinationPort"`
Host string `json:"host"`
DNSMode string `json:"dnsMode"`
ProcessPath string `json:"processPath"`
}
type tracker interface {
ID() string
Close() error
2022-07-25 22:56:13 +00:00
Leave()
2022-07-19 14:16:49 +00:00
}
type trackerInfo struct {
UUID uuid.UUID `json:"id"`
Metadata Metadata `json:"metadata"`
UploadTotal *atomic.Int64 `json:"upload"`
DownloadTotal *atomic.Int64 `json:"download"`
Start time.Time `json:"start"`
Chain []string `json:"chains"`
Rule string `json:"rule"`
RulePayload string `json:"rulePayload"`
}
type tcpTracker struct {
net.Conn `json:"-"`
*trackerInfo
manager *Manager
}
func (tt *tcpTracker) ID() string {
return tt.UUID.String()
}
func (tt *tcpTracker) Read(b []byte) (int, error) {
n, err := tt.Conn.Read(b)
2022-07-20 01:41:44 +00:00
upload := int64(n)
tt.manager.PushUploaded(upload)
tt.UploadTotal.Add(upload)
2022-07-19 14:16:49 +00:00
return n, err
}
func (tt *tcpTracker) Write(b []byte) (int, error) {
n, err := tt.Conn.Write(b)
2022-07-20 01:41:44 +00:00
download := int64(n)
tt.manager.PushDownloaded(download)
tt.DownloadTotal.Add(download)
2022-07-19 14:16:49 +00:00
return n, err
}
func (tt *tcpTracker) Close() error {
tt.manager.Leave(tt)
return tt.Conn.Close()
}
2022-07-25 22:56:13 +00:00
func (tt *tcpTracker) Leave() {
tt.manager.Leave(tt)
}
2022-08-08 12:56:53 +00:00
func (tt *tcpTracker) Upstream() any {
return tt.Conn
}
2022-07-22 05:51:08 +00:00
func NewTCPTracker(conn net.Conn, manager *Manager, metadata Metadata, router adapter.Router, rule adapter.Rule) *tcpTracker {
2022-07-19 14:16:49 +00:00
uuid, _ := uuid.NewV4()
2022-07-22 05:51:08 +00:00
var chain []string
var next string
if rule == nil {
2022-07-29 16:29:22 +00:00
next = router.DefaultOutbound(N.NetworkTCP).Tag()
2022-07-22 05:51:08 +00:00
} else {
next = rule.Outbound()
}
for {
chain = append(chain, next)
detour, loaded := router.Outbound(next)
if !loaded {
break
}
group, isGroup := detour.(adapter.OutboundGroup)
if !isGroup {
break
}
next = group.Now()
}
2022-07-19 14:16:49 +00:00
t := &tcpTracker{
Conn: conn,
manager: manager,
trackerInfo: &trackerInfo{
UUID: uuid,
Start: time.Now(),
Metadata: metadata,
2022-07-22 05:51:08 +00:00
Chain: common.Reverse(chain),
2022-07-19 14:16:49 +00:00
Rule: "",
UploadTotal: atomic.NewInt64(0),
DownloadTotal: atomic.NewInt64(0),
},
}
if rule != nil {
2022-07-22 05:51:08 +00:00
t.trackerInfo.Rule = rule.String() + " => " + rule.Outbound()
} else {
t.trackerInfo.Rule = "final"
2022-07-19 14:16:49 +00:00
}
manager.Join(t)
return t
}
type udpTracker struct {
N.PacketConn `json:"-"`
*trackerInfo
manager *Manager
}
func (ut *udpTracker) ID() string {
return ut.UUID.String()
}
func (ut *udpTracker) ReadPacket(buffer *buf.Buffer) (destination M.Socksaddr, err error) {
destination, err = ut.PacketConn.ReadPacket(buffer)
if err == nil {
2022-07-20 01:41:44 +00:00
upload := int64(buffer.Len())
ut.manager.PushUploaded(upload)
ut.UploadTotal.Add(upload)
2022-07-19 14:16:49 +00:00
}
return
}
func (ut *udpTracker) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error {
2022-07-20 01:41:44 +00:00
download := int64(buffer.Len())
2022-07-19 14:16:49 +00:00
err := ut.PacketConn.WritePacket(buffer, destination)
if err != nil {
return err
}
2022-07-20 01:41:44 +00:00
ut.manager.PushDownloaded(download)
ut.DownloadTotal.Add(download)
2022-07-19 14:16:49 +00:00
return nil
}
func (ut *udpTracker) Close() error {
ut.manager.Leave(ut)
return ut.PacketConn.Close()
}
2022-07-25 22:56:13 +00:00
func (ut *udpTracker) Leave() {
ut.manager.Leave(ut)
}
2022-08-08 12:56:53 +00:00
func (ut *udpTracker) Upstream() any {
return ut.PacketConn
}
2022-07-22 05:51:08 +00:00
func NewUDPTracker(conn N.PacketConn, manager *Manager, metadata Metadata, router adapter.Router, rule adapter.Rule) *udpTracker {
2022-07-19 14:16:49 +00:00
uuid, _ := uuid.NewV4()
2022-07-22 05:51:08 +00:00
var chain []string
var next string
if rule == nil {
2022-07-29 16:29:22 +00:00
next = router.DefaultOutbound(N.NetworkUDP).Tag()
2022-07-22 05:51:08 +00:00
} else {
next = rule.Outbound()
}
for {
chain = append(chain, next)
detour, loaded := router.Outbound(next)
if !loaded {
break
}
group, isGroup := detour.(adapter.OutboundGroup)
if !isGroup {
break
}
next = group.Now()
}
2022-07-19 14:16:49 +00:00
ut := &udpTracker{
PacketConn: conn,
manager: manager,
trackerInfo: &trackerInfo{
UUID: uuid,
Start: time.Now(),
Metadata: metadata,
2022-07-22 05:51:08 +00:00
Chain: common.Reverse(chain),
2022-07-19 14:16:49 +00:00
Rule: "",
UploadTotal: atomic.NewInt64(0),
DownloadTotal: atomic.NewInt64(0),
},
}
if rule != nil {
2022-07-22 05:51:08 +00:00
ut.trackerInfo.Rule = rule.String() + " => " + rule.Outbound()
} else {
ut.trackerInfo.Rule = "final"
2022-07-19 14:16:49 +00:00
}
manager.Join(ut)
return ut
}