package proxy import ( "bytes" "io" "os" "strings" "sync" _log "github.com/sirupsen/logrus" ) var normalErrMsgs []string = []string{ "read: connection reset by peer", "write: broken pipe", "i/o timeout", "net/http: TLS handshake timeout", "io: read/write on closed pipe", "connect: connection refused", "connect: connection reset by peer", "use of closed network connection", } // 仅打印预料之外的错误信息 func logErr(log *_log.Entry, err error) (loged bool) { msg := err.Error() for _, str := range normalErrMsgs { if strings.Contains(msg, str) { log.Debug(err) return } } log.Error(err) loged = true return } // 转发流量 // Read a => Write b // Read b => Write a func transfer(log *_log.Entry, a, b io.ReadWriteCloser) { done := make(chan struct{}) defer close(done) forward := func(dst io.WriteCloser, src io.Reader, ec chan<- error) { _, err := io.Copy(dst, src) dst.Close() // 当一端读结束时,结束另一端的写 select { case <-done: return case ec <- err: return } } errChan := make(chan error) go forward(a, b, errChan) go forward(b, a, errChan) for i := 0; i < 2; i++ { if err := <-errChan; err != nil { logErr(log, err) return // 如果有错误,直接返回 } } } // 尝试将 Reader 读取至 buffer 中 // 如果未达到 limit,则成功读取进入 buffer // 否则 buffer 返回 nil,且返回新 Reader,状态为未读取前 func readerToBuffer(r io.Reader, limit int64) ([]byte, io.Reader, error) { buf := bytes.NewBuffer(make([]byte, 0)) lr := io.LimitReader(r, limit) _, err := io.Copy(buf, lr) if err != nil { return nil, nil, err } // 达到上限 if int64(buf.Len()) == limit { // 返回新的 Reader return nil, io.MultiReader(bytes.NewBuffer(buf.Bytes()), r), nil } // 返回 buffer return buf.Bytes(), nil, nil } // Wireshark 解析 https 设置 var tlsKeyLogWriter io.Writer var tlsKeyLogOnce sync.Once func getTlsKeyLogWriter() io.Writer { tlsKeyLogOnce.Do(func() { logfile := os.Getenv("SSLKEYLOGFILE") if logfile == "" { return } writer, err := os.OpenFile(logfile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666) if err != nil { log.WithField("in", "getTlsKeyLogWriter").Debug(err) return } tlsKeyLogWriter = writer }) return tlsKeyLogWriter }