@@ -2,8 +2,9 @@ package log
22
33import (
44 "context"
5- "fmt "
5+ "net "
66 "regexp"
7+ "strconv"
78 "strings"
89 "sync"
910
@@ -20,14 +21,23 @@ type Instance struct {
2021 errorLogger log.Handler
2122 active bool
2223 dns bool
24+ mask4 int
25+ mask6 int
2326}
2427
2528// New creates a new log.Instance based on the given config.
2629func New (ctx context.Context , config * Config ) (* Instance , error ) {
30+ m4 , m6 , err := ParseMaskAddress (config .MaskAddress )
31+ if err != nil {
32+ return nil , err
33+ }
34+
2735 g := & Instance {
2836 config : config ,
2937 active : false ,
3038 dns : config .EnableDnsLog ,
39+ mask4 : m4 ,
40+ mask6 : m6 ,
3141 }
3242 log .RegisterHandler (g )
3343
@@ -104,7 +114,11 @@ func (g *Instance) Handle(msg log.Message) {
104114
105115 var Msg log.Message
106116 if g .config .MaskAddress != "" {
107- Msg = & MaskedMsgWrapper {Message : msg , config : g .config }
117+ Msg = & MaskedMsgWrapper {
118+ Message : msg ,
119+ Mask4 : g .mask4 ,
120+ Mask6 : g .mask6 ,
121+ }
108122 } else {
109123 Msg = msg
110124 }
@@ -149,51 +163,87 @@ func (g *Instance) Close() error {
149163 return nil
150164}
151165
166+ func ParseMaskAddress (c string ) (int , int , error ) {
167+ var m4 , m6 int
168+ switch c {
169+ case "half" :
170+ m4 , m6 = 16 , 32
171+ case "quarter" :
172+ m4 , m6 = 8 , 16
173+ case "full" :
174+ m4 , m6 = 0 , 0
175+ case "" :
176+ // do nothing
177+ default :
178+ if parts := strings .Split (c , "+" ); len (parts ) > 0 {
179+ if len (parts ) >= 1 && parts [0 ] != "" {
180+ i , err := strconv .Atoi (strings .TrimPrefix (parts [0 ], "/" ))
181+ if err != nil {
182+ return 32 , 128 , err
183+ }
184+ m4 = i
185+ }
186+ if len (parts ) >= 2 && parts [1 ] != "" {
187+ i , err := strconv .Atoi (strings .TrimPrefix (parts [1 ], "/" ))
188+ if err != nil {
189+ return 32 , 128 , err
190+ }
191+ m6 = i
192+ }
193+ }
194+ }
195+
196+ if m4 % 8 != 0 || m4 > 32 || m4 < 0 {
197+ return 32 , 128 , errors .New ("Log Mask: ipv4 mask must be divisible by 8 and between 0-32" )
198+ }
199+
200+ return m4 , m6 , nil
201+ }
202+
152203// MaskedMsgWrapper is to wrap the string() method to mask IP addresses in the log.
153204type MaskedMsgWrapper struct {
154205 log.Message
155- config * Config
206+ Mask4 int
207+ Mask6 int
156208}
157209
210+ var (
211+ ipv4Regex = regexp .MustCompile (`(\d{1,3}\.){3}\d{1,3}` )
212+ ipv6Regex = regexp .MustCompile (`(?:[\da-fA-F]{0,4}:[\da-fA-F]{0,4}){2,7}` )
213+ )
214+
158215func (m * MaskedMsgWrapper ) String () string {
159216 str := m .Message .String ()
160217
161- ipv4Regex := regexp .MustCompile (`(\d{1,3}\.){3}\d{1,3}` )
162- ipv6Regex := regexp .MustCompile (`((?:[\da-fA-F]{0,4}:[\da-fA-F]{0,4}){2,7})(?:[\/\\%](\d{1,3}))?` )
163-
164218 // Process ipv4
165- maskedMsg := ipv4Regex .ReplaceAllStringFunc (str , func (ip string ) string {
166- parts := strings .Split (ip , "." )
167- switch m .config .MaskAddress {
168- case "half" :
169- return fmt .Sprintf ("%s.%s.*.*" , parts [0 ], parts [1 ])
170- case "quarter" :
171- return fmt .Sprintf ("%s.*.*.*" , parts [0 ])
172- case "full" :
219+ maskedMsg := ipv4Regex .ReplaceAllStringFunc (str , func (s string ) string {
220+ if m .Mask4 == 32 {
221+ return s
222+ }
223+ if m .Mask4 == 0 {
173224 return "[Masked IPv4]"
174- default :
175- return ip
176225 }
226+
227+ parts := strings .Split (s , "." )
228+ for i := m .Mask4 / 8 ; i < 4 ; i ++ {
229+ parts [i ] = "*"
230+ }
231+ return strings .Join (parts , "." )
177232 })
178233
179234 // process ipv6
180- maskedMsg = ipv6Regex .ReplaceAllStringFunc (maskedMsg , func (ip string ) string {
181- parts := strings .Split (ip , ":" )
182- switch m .config .MaskAddress {
183- case "half" :
184- if len (parts ) >= 2 {
185- return fmt .Sprintf ("%s:%s::/32" , parts [0 ], parts [1 ])
186- }
187- case "quarter" :
188- if len (parts ) >= 1 {
189- return fmt .Sprintf ("%s::/16" , parts [0 ])
190- }
191- case "full" :
192- return "Masked IPv6" // Do not use [Masked IPv6] like ipv4, or you will get "[[Masked IPv6]]" (v6 address already has [])
193- default :
194- return ip
235+ maskedMsg = ipv6Regex .ReplaceAllStringFunc (maskedMsg , func (s string ) string {
236+ if m .Mask6 == 128 {
237+ return s
238+ }
239+ if m .Mask6 == 0 {
240+ return "Masked IPv6"
241+ }
242+ ip := net .ParseIP (s )
243+ if ip == nil {
244+ return s
195245 }
196- return ip
246+ return ip . Mask ( net . CIDRMask ( m . Mask6 , 128 )). String () + "/" + strconv . Itoa ( m . Mask6 )
197247 })
198248
199249 return maskedMsg
0 commit comments