Skip to content

Commit

Permalink
Log: Add MaskAddress option to hide IP addresses (#3783)
Browse files Browse the repository at this point in the history
* Log: Add maskAddress option

* Correct IPv6 subnet
  • Loading branch information
Fangliding authored Sep 11, 2024
1 parent 6b1bf31 commit a247997
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 17 deletions.
31 changes: 21 additions & 10 deletions app/log/config.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions app/log/config.proto
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,5 @@ message Config {
LogType access_log_type = 4;
string access_log_path = 5;
bool enable_dns_log = 6;
string mask_address= 7;
}
66 changes: 63 additions & 3 deletions app/log/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ package log

import (
"context"
"fmt"
"regexp"
"strings"
"sync"

"github.com/xtls/xray-core/common"
Expand Down Expand Up @@ -101,18 +104,25 @@ func (g *Instance) Handle(msg log.Message) {
return
}

var Msg log.Message
if g.config.MaskAddress != "" {
Msg = &MaskedMsgWrapper{Message: msg, config: g.config}
} else {
Msg = msg
}

switch msg := msg.(type) {
case *log.AccessMessage:
if g.accessLogger != nil {
g.accessLogger.Handle(msg)
g.accessLogger.Handle(Msg)
}
case *log.DNSLog:
if g.dns && g.accessLogger != nil {
g.accessLogger.Handle(msg)
g.accessLogger.Handle(Msg)
}
case *log.GeneralMessage:
if g.errorLogger != nil && msg.Severity <= g.config.ErrorLogLevel {
g.errorLogger.Handle(msg)
g.errorLogger.Handle(Msg)
}
default:
// Swallow
Expand Down Expand Up @@ -141,6 +151,56 @@ func (g *Instance) Close() error {
return nil
}

// MaskedMsgWrapper is to wrap the string() method to mask IP addresses in the log.
type MaskedMsgWrapper struct {
log.Message
config *Config
}

func (m *MaskedMsgWrapper) String() string {
str := m.Message.String()

ipv4Regex := regexp.MustCompile(`(\d{1,3}\.){3}\d{1,3}`)
ipv6Regex := regexp.MustCompile(`((?:[\da-fA-F]{0,4}:[\da-fA-F]{0,4}){2,7})(?:[\/\\%](\d{1,3}))?`)

// Process ipv4
maskedMsg := ipv4Regex.ReplaceAllStringFunc(str, func(ip string) string {
parts := strings.Split(ip, ".")
switch m.config.MaskAddress {
case "half":
return fmt.Sprintf("%s.%s.*.*", parts[0], parts[1])
case "quarter":
return fmt.Sprintf("%s.*.*.*", parts[0])
case "full":
return "[Masked IPv4]"
default:
return ip
}
})

// process ipv6
maskedMsg = ipv6Regex.ReplaceAllStringFunc(maskedMsg, func(ip string) string {
parts := strings.Split(ip, ":")
switch m.config.MaskAddress {
case "half":
if len(parts) >= 2 {
return fmt.Sprintf("%s:%s::/32", parts[0], parts[1])
}
case "quarter":
if len(parts) >= 1 {
return fmt.Sprintf("%s::/16", parts[0])
}
case "full":
return "Masked IPv6" // Do not use [Masked IPv6] like ipv4, or you will get "[[Masked IPv6]]" (v6 address already has [])
default:
return ip
}
return ip
})

return maskedMsg
}

func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return New(ctx, config.(*Config))
Expand Down
10 changes: 6 additions & 4 deletions infra/conf/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@ func DefaultLogConfig() *log.Config {
}

type LogConfig struct {
AccessLog string `json:"access"`
ErrorLog string `json:"error"`
LogLevel string `json:"loglevel"`
DNSLog bool `json:"dnsLog"`
AccessLog string `json:"access"`
ErrorLog string `json:"error"`
LogLevel string `json:"loglevel"`
DNSLog bool `json:"dnsLog"`
MaskAddress string `json:"maskAddress"`
}

func (v *LogConfig) Build() *log.Config {
Expand Down Expand Up @@ -59,5 +60,6 @@ func (v *LogConfig) Build() *log.Config {
default:
config.ErrorLogLevel = clog.Severity_Warning
}
config.MaskAddress = v.MaskAddress
return config
}

0 comments on commit a247997

Please sign in to comment.