log.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. package log
  2. import (
  3. "context"
  4. "net"
  5. "regexp"
  6. "strconv"
  7. "strings"
  8. "sync"
  9. "github.com/xtls/xray-core/common"
  10. "github.com/xtls/xray-core/common/errors"
  11. "github.com/xtls/xray-core/common/log"
  12. )
  13. // Instance is a log.Handler that handles logs.
  14. type Instance struct {
  15. sync.RWMutex
  16. config *Config
  17. accessLogger log.Handler
  18. errorLogger log.Handler
  19. active bool
  20. dns bool
  21. mask4 int
  22. mask6 int
  23. }
  24. // New creates a new log.Instance based on the given config.
  25. func New(ctx context.Context, config *Config) (*Instance, error) {
  26. m4, m6, err := ParseMaskAddress(config.MaskAddress)
  27. if err != nil {
  28. return nil, err
  29. }
  30. g := &Instance{
  31. config: config,
  32. active: false,
  33. dns: config.EnableDnsLog,
  34. mask4: m4,
  35. mask6: m6,
  36. }
  37. log.RegisterHandler(g)
  38. // start logger now,
  39. // then other modules will be able to log during initialization
  40. if err := g.startInternal(); err != nil {
  41. return nil, err
  42. }
  43. errors.LogDebug(ctx, "Logger started")
  44. return g, nil
  45. }
  46. func (g *Instance) initAccessLogger() error {
  47. handler, err := createHandler(g.config.AccessLogType, HandlerCreatorOptions{
  48. Path: g.config.AccessLogPath,
  49. })
  50. if err != nil {
  51. return err
  52. }
  53. g.accessLogger = handler
  54. return nil
  55. }
  56. func (g *Instance) initErrorLogger() error {
  57. handler, err := createHandler(g.config.ErrorLogType, HandlerCreatorOptions{
  58. Path: g.config.ErrorLogPath,
  59. })
  60. if err != nil {
  61. return err
  62. }
  63. g.errorLogger = handler
  64. return nil
  65. }
  66. // Type implements common.HasType.
  67. func (*Instance) Type() interface{} {
  68. return (*Instance)(nil)
  69. }
  70. func (g *Instance) startInternal() error {
  71. g.Lock()
  72. defer g.Unlock()
  73. if g.active {
  74. return nil
  75. }
  76. g.active = true
  77. if err := g.initAccessLogger(); err != nil {
  78. return errors.New("failed to initialize access logger").Base(err).AtWarning()
  79. }
  80. if err := g.initErrorLogger(); err != nil {
  81. return errors.New("failed to initialize error logger").Base(err).AtWarning()
  82. }
  83. return nil
  84. }
  85. // Start implements common.Runnable.Start().
  86. func (g *Instance) Start() error {
  87. return g.startInternal()
  88. }
  89. // Handle implements log.Handler.
  90. func (g *Instance) Handle(msg log.Message) {
  91. g.RLock()
  92. defer g.RUnlock()
  93. if !g.active {
  94. return
  95. }
  96. var Msg log.Message
  97. if g.config.MaskAddress != "" {
  98. Msg = &MaskedMsgWrapper{
  99. Message: msg,
  100. Mask4: g.mask4,
  101. Mask6: g.mask6,
  102. }
  103. } else {
  104. Msg = msg
  105. }
  106. switch msg := msg.(type) {
  107. case *log.AccessMessage:
  108. if g.accessLogger != nil {
  109. g.accessLogger.Handle(Msg)
  110. }
  111. case *log.DNSLog:
  112. if g.dns && g.accessLogger != nil {
  113. g.accessLogger.Handle(Msg)
  114. }
  115. case *log.GeneralMessage:
  116. if g.errorLogger != nil && msg.Severity <= g.config.ErrorLogLevel {
  117. g.errorLogger.Handle(Msg)
  118. }
  119. default:
  120. // Swallow
  121. }
  122. }
  123. // Close implements common.Closable.Close().
  124. func (g *Instance) Close() error {
  125. errors.LogDebug(context.Background(), "Logger closing")
  126. g.Lock()
  127. defer g.Unlock()
  128. if !g.active {
  129. return nil
  130. }
  131. g.active = false
  132. common.Close(g.accessLogger)
  133. g.accessLogger = nil
  134. common.Close(g.errorLogger)
  135. g.errorLogger = nil
  136. return nil
  137. }
  138. func ParseMaskAddress(c string) (int, int, error) {
  139. var m4, m6 int
  140. switch c {
  141. case "half":
  142. m4, m6 = 16, 32
  143. case "quarter":
  144. m4, m6 = 8, 16
  145. case "full":
  146. m4, m6 = 0, 0
  147. case "":
  148. // do nothing
  149. default:
  150. if parts := strings.Split(c, "+"); len(parts) > 0 {
  151. if len(parts) >= 1 && parts[0] != "" {
  152. i, err := strconv.Atoi(strings.TrimPrefix(parts[0], "/"))
  153. if err != nil {
  154. return 32, 128, err
  155. }
  156. m4 = i
  157. }
  158. if len(parts) >= 2 && parts[1] != "" {
  159. i, err := strconv.Atoi(strings.TrimPrefix(parts[1], "/"))
  160. if err != nil {
  161. return 32, 128, err
  162. }
  163. m6 = i
  164. }
  165. }
  166. }
  167. if m4%8 != 0 || m4 > 32 || m4 < 0 {
  168. return 32, 128, errors.New("Log Mask: ipv4 mask must be divisible by 8 and between 0-32")
  169. }
  170. return m4, m6, nil
  171. }
  172. // MaskedMsgWrapper is to wrap the string() method to mask IP addresses in the log.
  173. type MaskedMsgWrapper struct {
  174. log.Message
  175. Mask4 int
  176. Mask6 int
  177. }
  178. var (
  179. ipv4Regex = regexp.MustCompile(`(\d{1,3}\.){3}\d{1,3}`)
  180. ipv6Regex = regexp.MustCompile(`(?:[\da-fA-F]{0,4}:[\da-fA-F]{0,4}){2,7}`)
  181. )
  182. func (m *MaskedMsgWrapper) String() string {
  183. str := m.Message.String()
  184. // Process ipv4
  185. maskedMsg := ipv4Regex.ReplaceAllStringFunc(str, func(s string) string {
  186. if m.Mask4 == 32 {
  187. return s
  188. }
  189. if m.Mask4 == 0 {
  190. return "[Masked IPv4]"
  191. }
  192. parts := strings.Split(s, ".")
  193. for i := m.Mask4 / 8; i < 4; i++ {
  194. parts[i] = "*"
  195. }
  196. return strings.Join(parts, ".")
  197. })
  198. // process ipv6
  199. maskedMsg = ipv6Regex.ReplaceAllStringFunc(maskedMsg, func(s string) string {
  200. if m.Mask6 == 128 {
  201. return s
  202. }
  203. if m.Mask6 == 0 {
  204. return "Masked IPv6"
  205. }
  206. ip := net.ParseIP(s)
  207. if ip == nil {
  208. return s
  209. }
  210. return ip.Mask(net.CIDRMask(m.Mask6, 128)).String() + "/" + strconv.Itoa(m.Mask6)
  211. })
  212. return maskedMsg
  213. }
  214. func init() {
  215. common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
  216. return New(ctx, config.(*Config))
  217. }))
  218. }