123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261 |
- package statistic
- import (
- "io"
- "net"
- "net/netip"
- "time"
- "github.com/metacubex/mihomo/common/atomic"
- "github.com/metacubex/mihomo/common/buf"
- N "github.com/metacubex/mihomo/common/net"
- "github.com/metacubex/mihomo/common/utils"
- C "github.com/metacubex/mihomo/constant"
- "github.com/gofrs/uuid/v5"
- )
- type Tracker interface {
- ID() string
- Close() error
- Info() *TrackerInfo
- C.Connection
- }
- type TrackerInfo struct {
- UUID uuid.UUID `json:"id"`
- Metadata *C.Metadata `json:"metadata"`
- UploadTotal atomic.Int64 `json:"upload"`
- DownloadTotal atomic.Int64 `json:"download"`
- Start time.Time `json:"start"`
- Chain C.Chain `json:"chains"`
- Rule string `json:"rule"`
- RulePayload string `json:"rulePayload"`
- }
- type tcpTracker struct {
- C.Conn `json:"-"`
- *TrackerInfo
- manager *Manager
- pushToManager bool `json:"-"`
- }
- func (tt *tcpTracker) ID() string {
- return tt.UUID.String()
- }
- func (tt *tcpTracker) Info() *TrackerInfo {
- return tt.TrackerInfo
- }
- func (tt *tcpTracker) Read(b []byte) (int, error) {
- n, err := tt.Conn.Read(b)
- download := int64(n)
- if tt.pushToManager {
- tt.manager.PushDownloaded(tt.Conn.Chains().Last(), download)
- }
- tt.DownloadTotal.Add(download)
- return n, err
- }
- func (tt *tcpTracker) ReadBuffer(buffer *buf.Buffer) (err error) {
- err = tt.Conn.ReadBuffer(buffer)
- download := int64(buffer.Len())
- if tt.pushToManager {
- tt.manager.PushDownloaded(tt.Chains().Last(), download)
- }
- tt.DownloadTotal.Add(download)
- return
- }
- func (tt *tcpTracker) UnwrapReader() (io.Reader, []N.CountFunc) {
- return tt.Conn, []N.CountFunc{func(download int64) {
- if tt.pushToManager {
- tt.manager.PushDownloaded(tt.Chains().Last(), download)
- }
- tt.DownloadTotal.Add(download)
- }}
- }
- func (tt *tcpTracker) Write(b []byte) (int, error) {
- n, err := tt.Conn.Write(b)
- upload := int64(n)
- if tt.pushToManager {
- tt.manager.PushUploaded(tt.Chains().Last(), upload)
- }
- tt.UploadTotal.Add(upload)
- return n, err
- }
- func (tt *tcpTracker) WriteBuffer(buffer *buf.Buffer) (err error) {
- upload := int64(buffer.Len())
- err = tt.Conn.WriteBuffer(buffer)
- if tt.pushToManager {
- tt.manager.PushUploaded(tt.Chains().Last(), upload)
- }
- tt.UploadTotal.Add(upload)
- return
- }
- func (tt *tcpTracker) UnwrapWriter() (io.Writer, []N.CountFunc) {
- return tt.Conn, []N.CountFunc{func(upload int64) {
- if tt.pushToManager {
- tt.manager.PushUploaded(tt.Chains().Last(), upload)
- }
- tt.UploadTotal.Add(upload)
- }}
- }
- func (tt *tcpTracker) Close() error {
- tt.manager.Leave(tt)
- return tt.Conn.Close()
- }
- func (tt *tcpTracker) Upstream() any {
- return tt.Conn
- }
- func parseRemoteDestination(addr net.Addr, conn C.Connection) string {
- if addr == nil && conn != nil {
- return conn.RemoteDestination()
- }
- if addrPort, err := netip.ParseAddrPort(addr.String()); err == nil && addrPort.Addr().IsValid() {
- return addrPort.Addr().String()
- } else {
- if conn != nil {
- return conn.RemoteDestination()
- } else {
- return ""
- }
- }
- }
- func NewTCPTracker(conn C.Conn, manager *Manager, metadata *C.Metadata, rule C.Rule, uploadTotal int64, downloadTotal int64, pushToManager bool) *tcpTracker {
- if conn != nil {
- metadata.RemoteDst = parseRemoteDestination(conn.RemoteAddr(), conn)
- }
- tt := &tcpTracker{
- Conn: conn,
- manager: manager,
- TrackerInfo: &TrackerInfo{
- UUID: utils.NewUUIDV4(),
- Start: time.Now(),
- Metadata: metadata,
- Chain: conn.Chains(),
- Rule: "",
- UploadTotal: atomic.NewInt64(uploadTotal),
- DownloadTotal: atomic.NewInt64(downloadTotal),
- },
- pushToManager: pushToManager,
- }
- if pushToManager {
- if uploadTotal > 0 {
- manager.PushUploaded(tt.Chains().Last(), uploadTotal)
- }
- if downloadTotal > 0 {
- manager.PushDownloaded(tt.Chains().Last(), downloadTotal)
- }
- }
- if rule != nil {
- tt.TrackerInfo.Rule = rule.RuleType().String()
- tt.TrackerInfo.RulePayload = rule.Payload()
- }
- manager.Join(tt)
- return tt
- }
- type udpTracker struct {
- C.PacketConn `json:"-"`
- *TrackerInfo
- manager *Manager
- pushToManager bool `json:"-"`
- }
- func (ut *udpTracker) ID() string {
- return ut.UUID.String()
- }
- func (ut *udpTracker) Info() *TrackerInfo {
- return ut.TrackerInfo
- }
- func (ut *udpTracker) ReadFrom(b []byte) (int, net.Addr, error) {
- n, addr, err := ut.PacketConn.ReadFrom(b)
- download := int64(n)
- if ut.pushToManager {
- ut.manager.PushDownloaded(ut.Chains().Last(), download)
- }
- ut.DownloadTotal.Add(download)
- return n, addr, err
- }
- func (ut *udpTracker) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) {
- data, put, addr, err = ut.PacketConn.WaitReadFrom()
- download := int64(len(data))
- if ut.pushToManager {
- ut.manager.PushDownloaded(ut.Chains().Last(), download)
- }
- ut.DownloadTotal.Add(download)
- return
- }
- func (ut *udpTracker) WriteTo(b []byte, addr net.Addr) (int, error) {
- n, err := ut.PacketConn.WriteTo(b, addr)
- upload := int64(n)
- if ut.pushToManager {
- ut.manager.PushUploaded(ut.Chains().Last(), upload)
- }
- ut.UploadTotal.Add(upload)
- return n, err
- }
- func (ut *udpTracker) Close() error {
- ut.manager.Leave(ut)
- return ut.PacketConn.Close()
- }
- func (ut *udpTracker) Upstream() any {
- return ut.PacketConn
- }
- func NewUDPTracker(conn C.PacketConn, manager *Manager, metadata *C.Metadata, rule C.Rule, uploadTotal int64, downloadTotal int64, pushToManager bool) *udpTracker {
- metadata.RemoteDst = parseRemoteDestination(nil, conn)
- ut := &udpTracker{
- PacketConn: conn,
- manager: manager,
- TrackerInfo: &TrackerInfo{
- UUID: utils.NewUUIDV4(),
- Start: time.Now(),
- Metadata: metadata,
- Chain: conn.Chains(),
- Rule: "",
- UploadTotal: atomic.NewInt64(uploadTotal),
- DownloadTotal: atomic.NewInt64(downloadTotal),
- },
- pushToManager: pushToManager,
- }
- if pushToManager {
- if uploadTotal > 0 {
- manager.PushUploaded(ut.Chains().Last(), uploadTotal)
- }
- if downloadTotal > 0 {
- manager.PushDownloaded(ut.Chains().Last(), downloadTotal)
- }
- }
- if rule != nil {
- ut.TrackerInfo.Rule = rule.RuleType().String()
- ut.TrackerInfo.RulePayload = rule.Payload()
- }
- manager.Join(ut)
- return ut
- }
|