Skip to content

Commit

Permalink
Add API to register new metrics
Browse files Browse the repository at this point in the history
  • Loading branch information
enfein committed Nov 11, 2022
1 parent dca1328 commit 22a5a86
Show file tree
Hide file tree
Showing 15 changed files with 357 additions and 176 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
[![Releases](https://img.shields.io/github/release/enfein/mieru/all.svg?style=flat)](https://github.com/enfein/mieru/releases)
[![LICENSE](https://img.shields.io/github/license/enfein/mieru.svg?style=flat)](https://github.com/enfein/mieru/blob/main/LICENSE)
[![Go Reference](https://pkg.go.dev/badge/github.com/enfein/mieru.svg)](https://pkg.go.dev/github.com/enfein/mieru)
[![Go Report Card](https://goreportcard.com/badge/github.com/enfein/mieru)](https://goreportcard.com/badge/github.com/enfein/mieru)
[![Go Report Card](https://goreportcard.com/badge/github.com/enfein/mieru)](https://goreportcard.com/report/github.com/enfein/mieru)

[中文文档](https://github.com/enfein/mieru/blob/main/README.zh_CN.md)

Expand Down
2 changes: 1 addition & 1 deletion README.zh_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
[![Releases](https://img.shields.io/github/release/enfein/mieru/all.svg?style=flat)](https://github.com/enfein/mieru/releases)
[![LICENSE](https://img.shields.io/github/license/enfein/mieru.svg?style=flat)](https://github.com/enfein/mieru/blob/main/LICENSE)
[![Go Reference](https://pkg.go.dev/badge/github.com/enfein/mieru.svg)](https://pkg.go.dev/github.com/enfein/mieru)
[![Go Report Card](https://goreportcard.com/badge/github.com/enfein/mieru)](https://goreportcard.com/badge/github.com/enfein/mieru)
[![Go Report Card](https://goreportcard.com/badge/github.com/enfein/mieru)](https://goreportcard.com/report/github.com/enfein/mieru)

mieru【見える】是一款安全的、无流量特征、难以主动探测的,基于 TCP 或 UDP 协议的 socks5 网络代理软件。

Expand Down
22 changes: 22 additions & 0 deletions pkg/cipher/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,34 @@ package cipher
import (
"crypto/sha256"
"fmt"

"github.com/enfein/mieru/pkg/metrics"
)

const (
DefaultNonceSize = 12 // 12 bytes
DefaultOverhead = 16 // 16 bytes
DefaultKeyLen = 32 // 256 bits

ClientDecryptionMetricGroupName = "client decryption"
ServerDecryptionMetricGroupName = "server decryption"
)

var (
// Number of decryption using the cipher block associated with the connection.
ClientDirectDecrypt = metrics.RegisterMetric(ClientDecryptionMetricGroupName, "DirectDecrypt")

// Number of decryption using the stored cipher block but failed.
ClientFailedDirectDecrypt = metrics.RegisterMetric(ClientDecryptionMetricGroupName, "FailedDirectDecrypt")

// Number of decryption using the cipher block associated with the connection.
ServerDirectDecrypt = metrics.RegisterMetric(ServerDecryptionMetricGroupName, "DirectDecrypt")

// Number of decryption using the stored cipher block but failed.
ServerFailedDirectDecrypt = metrics.RegisterMetric(ServerDecryptionMetricGroupName, "FailedDirectDecrypt")

// Number of decryption that failed after iterating all possible cipher blocks.
ServerFailedIterateDecrypt = metrics.RegisterMetric(ServerDecryptionMetricGroupName, "FailedIterateDecrypt")
)

// BlockCipher is an interface of block encryption and decryption.
Expand Down
7 changes: 7 additions & 0 deletions pkg/cli/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,14 @@ var clientStartFunc = func(s []string) error {

var clientRunFunc = func(s []string) error {
log.SetFormatter(&log.DaemonFormatter{})

// Disable server side metrics.
if serverDecryptionMetricGroup := metrics.GetMetricGroupByName(cipher.ServerDecryptionMetricGroupName); serverDecryptionMetricGroup != nil {
serverDecryptionMetricGroup.DisableLogging()
}

appctl.SetAppStatus(appctlpb.AppStatus_STARTING)

logFile, err := log.NewClientLogFile()
if err == nil {
log.SetOutput(logFile)
Expand Down
7 changes: 7 additions & 0 deletions pkg/cli/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (

"github.com/enfein/mieru/pkg/appctl"
"github.com/enfein/mieru/pkg/appctl/appctlpb"
"github.com/enfein/mieru/pkg/cipher"
"github.com/enfein/mieru/pkg/log"
"github.com/enfein/mieru/pkg/metrics"
"github.com/enfein/mieru/pkg/netutil"
Expand Down Expand Up @@ -203,6 +204,12 @@ var serverRunFunc = func(s []string) error {
} else {
log.SetFormatter(&log.DaemonFormatter{})
}

// Disable client side metrics.
if clientDecryptionMetricGroup := metrics.GetMetricGroupByName(cipher.ClientDecryptionMetricGroupName); clientDecryptionMetricGroup != nil {
clientDecryptionMetricGroup.DisableLogging()
}

appctl.SetAppStatus(appctlpb.AppStatus_IDLE)

var rpcTasks sync.WaitGroup
Expand Down
2 changes: 2 additions & 0 deletions pkg/log/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Package log is is imported from https://github.com/sirupsen/logrus
package log
101 changes: 101 additions & 0 deletions pkg/metrics/log.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// Copyright (C) 2022 mieru authors
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

package metrics

import (
"fmt"
"sort"
"sync"
"time"

"github.com/enfein/mieru/pkg/log"
)

var ticker *time.Ticker
var logDuration time.Duration
var done chan struct{}
var mutex sync.Mutex

func init() {
logDuration = time.Minute
done = make(chan struct{})
}

// Enable metrics logging with the given time duration.
func EnableLogging() {
mutex.Lock()
defer mutex.Unlock()
if ticker == nil {
ticker = time.NewTicker(logDuration)
go logMetrics()
log.Infof("enabled metrics logging with duration %v", logDuration)
}
}

// Disable metrics logging.
func DisableLogging() {
mutex.Lock()
defer mutex.Unlock()
done <- struct{}{}
if ticker != nil {
ticker.Stop()
ticker = nil
log.Infof("disabled metrics logging")
}
}

// Set the metrics logging time duration.
func SetLoggingDuration(duration time.Duration) error {
if duration.Seconds() <= 0 {
return fmt.Errorf("duration must be a positive number")
}
mutex.Lock()
defer mutex.Unlock()
logDuration = duration
return nil
}

func logMetrics() {
for {
select {
case <-ticker.C:
log.Infof("[metrics]")
list := MetricGroupList{}
metricMap.Range(func(k, v any) bool {
group := v.(*MetricGroup)
if group.IsLoggingEnabled() {
list = list.Append(group)
}
return true
})
sort.Sort(list)
for _, group := range list {
log.WithFields(group.NewLogFields()).Infof(group.NewLogMsg())
}
LogUDPPackets()
LogKCPSegments()
LogUDPBytes()
LogKCPBytes()
LogTCPBytes()
LogUDPAssociation()
LogUDPErrors()
LogTCPErrors()
LogSocks5Errors()
case <-done:
return
}
}
}
130 changes: 11 additions & 119 deletions pkg/metrics/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,29 +16,24 @@
package metrics

import (
"fmt"
"sync"
"time"

"github.com/enfein/mieru/pkg/log"
)

var (
// connections
MaxConn uint64 // max number of connections ever reached
ActiveOpens uint64 // accumulated active open connections
PassiveOpens uint64 // accumulated passive open connections
CurrEstablished uint64 // current number of established connections
// Max number of connections ever reached.
MaxConn *Metric = RegisterMetric("connections", "MaxConn")

// Accumulated active open connections.
ActiveOpens *Metric = RegisterMetric("connections", "ActiveOpens")

// server decryption
ServerDirectDecrypt uint64 // number of decryption using the cipher block associated with the connection
ServerFailedDirectDecrypt uint64 // number of decryption using the stored cipher block but failed
ServerFailedIterateDecrypt uint64 // number of decryption that failed after iterating all possible cipher blocks
// Accumulated passive open connections.
PassiveOpens *Metric = RegisterMetric("connections", "PassiveOpens")

// client decryption
ClientDirectDecrypt uint64 // number of decryption using the cipher block associated with the connection
ClientFailedDirectDecrypt uint64 // number of decryption using the stored cipher block but failed
// Current number of established connections.
CurrEstablished *Metric = RegisterMetric("connections", "CurrEstablished")
)

var (
// UDP packets
InPkts uint64 // incoming packets count
OutPkts uint64 // outgoing packets count
Expand Down Expand Up @@ -67,10 +62,6 @@ var (
TCPOutBytes uint64 // TCP bytes sent
TCPPaddingSent uint64 // TCP bytes sent for padding purpose

// Replay protection
ReplayKnownSession uint64 // replay packets sent from a known session
ReplayNewSession uint64 // replay packets sent from a new session

// Socks5 UDP association
UDPAssociateInBytes uint64 // incoming UDP association bytes
UDPAssociateOutBytes uint64 // outgoing UDP association bytes
Expand All @@ -97,98 +88,6 @@ var (
Socks5UDPAssociateErrors uint64 // UDP associate errors
)

var ticker *time.Ticker
var logDuration time.Duration
var done chan struct{}
var mutex sync.Mutex

func init() {
logDuration = time.Minute
done = make(chan struct{})
}

// Enable metrics logging with the given time duration.
func EnableLogging() {
mutex.Lock()
defer mutex.Unlock()
if ticker == nil {
ticker = time.NewTicker(logDuration)
go logMetrics()
log.Infof("enabled metrics logging with duration %v", logDuration)
}
}

// Disable metrics logging.
func DisableLogging() {
mutex.Lock()
defer mutex.Unlock()
done <- struct{}{}
if ticker != nil {
ticker.Stop()
ticker = nil
log.Infof("disabled metrics logging")
}
}

// Set the metrics logging time duration.
func SetLoggingDuration(duration time.Duration) error {
if duration.Seconds() <= 0 {
return fmt.Errorf("duration must be a positive number")
}
mutex.Lock()
defer mutex.Unlock()
logDuration = duration
return nil
}

func logMetrics() {
for {
select {
case <-ticker.C:
log.Infof("[metrics]")
LogConnections()
LogServerDecryption()
LogClientDecryption()
LogUDPPackets()
LogKCPSegments()
LogUDPBytes()
LogKCPBytes()
LogTCPBytes()
LogUDPAssociation()
LogReplay()
LogUDPErrors()
LogTCPErrors()
LogSocks5Errors()
case <-done:
return
}
}
}

func LogConnections() {
log.WithFields(log.Fields{
"MaxConn": MaxConn,
"ActiveOpens": ActiveOpens,
"PassiveOpens": PassiveOpens,
"CurrEstablished": CurrEstablished,
}).Infof("[metrics - connections]")
}

func LogServerDecryption() {
log.WithFields(log.Fields{
"ServerDirectDecrypt": ServerDirectDecrypt,
"ServerFailedDirectDecrypt": ServerFailedDirectDecrypt,
"ServerFailedIterateDecrypt": ServerFailedIterateDecrypt,
}).Infof("[metrics - server decryption]")
}

func LogClientDecryption() {
log.WithFields(log.Fields{
"ClientDirectDecrypt": ClientDirectDecrypt,
"ClientFailedDirectDecrypt": ClientFailedDirectDecrypt,
}).Infof("[metrics - client decryption]")
}

func LogUDPPackets() {
log.WithFields(log.Fields{
"InPkts": InPkts,
Expand Down Expand Up @@ -241,13 +140,6 @@ func LogUDPAssociation() {
}).Infof("[metrics - socks5 UDP association]")
}

func LogReplay() {
log.WithFields(log.Fields{
"ReplayKnownSession": ReplayKnownSession,
"ReplayNewSession": ReplayNewSession,
}).Infof("[metrics - replay protection]")
}

func LogUDPErrors() {
log.WithFields(log.Fields{
"UDPInErrors": UDPInErrors,
Expand Down
Loading

0 comments on commit 22a5a86

Please sign in to comment.