mirror of
https://github.com/SunBK201/UA3F.git
synced 2025-12-16 16:57:08 +00:00
550 lines
17 KiB
Go
550 lines
17 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"errors"
|
|
"flag"
|
|
"fmt"
|
|
"io"
|
|
"net"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/dlclark/regexp2"
|
|
"github.com/hashicorp/golang-lru/v2/expirable"
|
|
"github.com/sirupsen/logrus"
|
|
"github.com/sunbk201/ua3f/http"
|
|
"github.com/sunbk201/ua3f/log"
|
|
)
|
|
|
|
var version = "0.5.1"
|
|
var payloadByte []byte
|
|
var payload string
|
|
var uaPattern string
|
|
var uaRegexp *regexp2.Regexp
|
|
var enablePartialReplace bool
|
|
var cache *expirable.LRU[string, string]
|
|
var HTTP_METHOD = []string{"GET", "POST", "HEAD", "PUT", "DELETE", "OPTIONS", "TRACE", "CONNECT"}
|
|
var whitelist = []string{
|
|
"MicroMessenger Client",
|
|
"ByteDancePcdn",
|
|
"Go-http-client/1.1",
|
|
}
|
|
|
|
const RDBUF = 1024 * 8
|
|
|
|
// var dpool *ants.PoolWithFunc
|
|
// var gpool *ants.PoolWithFunc
|
|
//
|
|
// type RelayConn struct {
|
|
// src net.Conn
|
|
// dst net.Conn
|
|
// destAddrPort string
|
|
// }
|
|
|
|
func main() {
|
|
var addr string
|
|
var port int
|
|
var loglevel string
|
|
|
|
flag.StringVar(&addr, "b", "127.0.0.1", "bind address (default: 127.0.0.1)")
|
|
flag.IntVar(&port, "p", 1080, "port")
|
|
flag.StringVar(&payload, "f", "FFF", "User-Agent")
|
|
flag.StringVar(&uaPattern, "r", "(iPhone|iPad|Android|Macintosh|Windows|Linux|Apple|Mac OS X)", "UA-Pattern")
|
|
flag.BoolVar(&enablePartialReplace, "s", false, "Enable Regex Partial Replace")
|
|
flag.StringVar(&loglevel, "l", "info", "Log level (default: info)")
|
|
flag.Parse()
|
|
|
|
log.SetLogConf(loglevel)
|
|
|
|
logrus.Info("UA3F v" + version)
|
|
logrus.Info(fmt.Sprintf("Port: %d", port))
|
|
logrus.Info(fmt.Sprintf("User-Agent: %s", payload))
|
|
logrus.Info(fmt.Sprintf("User-Agent Regex Pattern: %s", uaPattern))
|
|
logrus.Info(fmt.Sprintf("Enable Partial Replace: %v", enablePartialReplace))
|
|
logrus.Info(fmt.Sprintf("Log level: %s", loglevel))
|
|
|
|
cache = expirable.NewLRU[string, string](300, nil, time.Second*600)
|
|
|
|
// dpool, _ = ants.NewPoolWithFunc(1000, forward)
|
|
// gpool, _ = ants.NewPoolWithFunc(500, gforward)
|
|
// defer dpool.Release()
|
|
// defer gpool.Release()
|
|
|
|
payloadByte = []byte(payload)
|
|
|
|
server, err := net.Listen("tcp", fmt.Sprintf("%s:%d", addr, port))
|
|
if err != nil {
|
|
logrus.Fatal("Listen failed: ", err)
|
|
return
|
|
}
|
|
logrus.Info(fmt.Sprintf("Listen on %s:%d", addr, port))
|
|
uaRegexp, err = regexp2.Compile(uaPattern, regexp2.None)
|
|
if err != nil {
|
|
logrus.Fatal("Invalid User-Agent Regex Pattern: ", err)
|
|
return
|
|
}
|
|
for {
|
|
client, err := server.Accept()
|
|
if err != nil {
|
|
logrus.Error("Accept failed: ", err)
|
|
continue
|
|
}
|
|
logrus.Debug(fmt.Sprintf("Accept %s", client.RemoteAddr().String()))
|
|
go process(client)
|
|
}
|
|
}
|
|
|
|
func process(client net.Conn) {
|
|
if err := Socks5Auth(client); err != nil {
|
|
// logrus.Error("Auth failed: ", err)
|
|
client.Close()
|
|
return
|
|
}
|
|
target, destAddrPort, err := Socks5Connect(client)
|
|
if err != nil {
|
|
// UDP
|
|
if strings.Contains(err.Error(), "UDP Associate") {
|
|
Socks5UDP(client)
|
|
client.Close()
|
|
return
|
|
} else if strings.Contains(err.Error(), "connection timed out") {
|
|
logrus.Debug("Connect timeout: ", err)
|
|
return
|
|
}
|
|
logrus.Debug("Connect failed: ", err)
|
|
client.Close()
|
|
return
|
|
}
|
|
Socks5Forward(client, target, destAddrPort)
|
|
// Socks5Relay(client, target, destAddrPort)
|
|
}
|
|
|
|
func Socks5Auth(client net.Conn) (err error) {
|
|
buf := make([]byte, 256)
|
|
n, err := io.ReadFull(client, buf[:2])
|
|
if n != 2 {
|
|
if err == io.EOF {
|
|
logrus.Warn(fmt.Sprintf("[%s][Auth] read EOF", client.RemoteAddr().String()))
|
|
} else {
|
|
logrus.Error(fmt.Sprintf("[%s][Auth] read header: %s", client.RemoteAddr().String(), err.Error()))
|
|
}
|
|
return errors.New("reading header:" + err.Error())
|
|
}
|
|
ver, nMethods := int(buf[0]), int(buf[1])
|
|
if ver != 5 {
|
|
logrus.Error(fmt.Sprintf("[%s][Auth] invalid ver", client.RemoteAddr().String()))
|
|
return errors.New("invalid version")
|
|
}
|
|
n, err = io.ReadFull(client, buf[:nMethods])
|
|
if n != nMethods {
|
|
logrus.Error(fmt.Sprintf("[%s][Auth] read methods: %s", client.RemoteAddr().String(), err.Error()))
|
|
return errors.New("read methods:" + err.Error())
|
|
}
|
|
n, err = client.Write([]byte{0x05, 0x00})
|
|
if n != 2 || err != nil {
|
|
logrus.Error(fmt.Sprintf("[%s][Auth] write rsp: %s", client.RemoteAddr().String(), err.Error()))
|
|
return errors.New("write rsp:" + err.Error())
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func isAlive(conn net.Conn) bool {
|
|
one := make([]byte, 1)
|
|
conn.SetReadDeadline(time.Now().Add(time.Second * 5))
|
|
_, err := conn.Read(one)
|
|
if err != nil {
|
|
if err == io.EOF {
|
|
logrus.Debug(fmt.Sprintf("[%s] isAlive: EOF", conn.RemoteAddr().String()))
|
|
return false
|
|
} else if strings.Contains(err.Error(), "use of closed network connection") {
|
|
logrus.Debug(fmt.Sprintf("[%s] isAlive: closed", conn.RemoteAddr().String()))
|
|
return false
|
|
} else if strings.Contains(err.Error(), "i/o timeout") {
|
|
logrus.Debug(fmt.Sprintf("[%s] isAlive: timeout", conn.RemoteAddr().String()))
|
|
return true
|
|
} else {
|
|
logrus.Debug(fmt.Sprintf("[%s] isAlive: %s", conn.RemoteAddr().String(), err.Error()))
|
|
return false
|
|
}
|
|
}
|
|
conn.SetReadDeadline(time.Time{})
|
|
return true
|
|
}
|
|
|
|
func Socks5UDP(client net.Conn) {
|
|
udpserver, err := net.ListenUDP("udp4", &net.UDPAddr{IP: net.IPv4zero, Port: 0})
|
|
if err != nil {
|
|
logrus.Error(fmt.Sprintf("[%s][UDP] ListenUDP failed: %s", client.RemoteAddr().String(), err.Error()))
|
|
return
|
|
}
|
|
_, port, _ := net.SplitHostPort(udpserver.LocalAddr().String())
|
|
logrus.Debug(fmt.Sprintf("[%s][UDP] ListenUDP on %s", client.RemoteAddr().String(), port))
|
|
portInt, _ := net.LookupPort("udp", port)
|
|
portBytes := make([]byte, 2)
|
|
binary.BigEndian.PutUint16(portBytes, uint16(portInt))
|
|
_, err = client.Write([]byte{0x05, 0x00, 0x00, 0x01, 0, 0, 0, 0, portBytes[0], portBytes[1]})
|
|
if err != nil {
|
|
logrus.Error(fmt.Sprintf("[%s][UDP] Write rsp failed: %s", client.RemoteAddr().String(), err.Error()))
|
|
return
|
|
}
|
|
buf := make([]byte, 65535)
|
|
udpPortMap := make(map[string][]byte)
|
|
var clientAddr *net.UDPAddr
|
|
var isDomain bool = false
|
|
for {
|
|
udpserver.SetReadDeadline(time.Now().Add(time.Second * 10))
|
|
n, fromAddr, err := udpserver.ReadFromUDP(buf)
|
|
if err != nil {
|
|
if strings.Contains(err.Error(), "i/o timeout") {
|
|
logrus.Debug(fmt.Sprintf("[%s][UDP] ReadFromUDP failed: %s", client.RemoteAddr().String(), err.Error()))
|
|
if !isAlive(client) {
|
|
logrus.Debug(fmt.Sprintf("[%s][UDP] client is not alive", client.RemoteAddr().String()))
|
|
break
|
|
}
|
|
} else {
|
|
logrus.Error(fmt.Sprintf("[%s][UDP] ReadFromUDP failed: %s", client.RemoteAddr().String(), err.Error()))
|
|
}
|
|
continue
|
|
}
|
|
if clientAddr == nil {
|
|
clientAddr = fromAddr
|
|
}
|
|
|
|
if clientAddr.IP.Equal(fromAddr.IP) && clientAddr.Port == fromAddr.Port {
|
|
// from client
|
|
atyp := buf[3]
|
|
targetAddr := ""
|
|
var targetPort uint16 = 0
|
|
var payload []byte
|
|
var header []byte
|
|
var targetIP net.IP
|
|
if atyp == 1 {
|
|
isDomain = false
|
|
targetAddr = fmt.Sprintf("%d.%d.%d.%d", buf[4], buf[5], buf[6], buf[7])
|
|
targetIP = net.ParseIP(targetAddr)
|
|
targetPort = binary.BigEndian.Uint16(buf[8:10])
|
|
payload = buf[10:n]
|
|
header = buf[0:10]
|
|
} else if atyp == 3 {
|
|
isDomain = true
|
|
addrLen := int(buf[4])
|
|
targetAddr = string(buf[5 : 5+addrLen])
|
|
targetIPaddr, err := net.ResolveIPAddr("ip", targetAddr)
|
|
if err != nil {
|
|
logrus.Error(fmt.Sprintf("[%s][UDP] ResolveIPAddr failed: %s", client.RemoteAddr().String(), err.Error()))
|
|
break
|
|
}
|
|
targetIP = targetIPaddr.IP
|
|
targetPort = binary.BigEndian.Uint16(buf[5+addrLen : 5+addrLen+2])
|
|
payload = buf[5+addrLen+2 : n]
|
|
header = buf[0 : 5+addrLen+2]
|
|
} else if atyp == 4 {
|
|
logrus.Error(fmt.Sprintf("[%s][UDP] IPv6: no supported yet", client.RemoteAddr().String()))
|
|
break
|
|
} else {
|
|
logrus.Error(fmt.Sprintf("[%s][UDP] invalid atyp", client.RemoteAddr().String()))
|
|
break
|
|
}
|
|
// targetAddrPort := fmt.Sprintf("%s:%d", targetAddr, targetPort)
|
|
remoteAddr := &net.UDPAddr{IP: targetIP, Port: int(targetPort)}
|
|
udpPortMap[remoteAddr.String()] = make([]byte, len(header))
|
|
copy(udpPortMap[remoteAddr.String()], header)
|
|
udpserver.SetWriteDeadline(time.Now().Add(time.Second * 10))
|
|
if _, err = udpserver.WriteToUDP(payload, remoteAddr); err != nil {
|
|
logrus.Debug(fmt.Sprintf("[%s][UDP] WriteToUDP to remote failed: %s", client.RemoteAddr().String(), err.Error()))
|
|
continue
|
|
}
|
|
} else {
|
|
// from remote
|
|
header := udpPortMap[fromAddr.String()]
|
|
if header == nil {
|
|
logrus.Error(fmt.Sprintf("[%s][UDP] udpPortMap invalid header", client.RemoteAddr().String()))
|
|
continue
|
|
}
|
|
// header + body
|
|
if isDomain {
|
|
header = header[0:4]
|
|
}
|
|
body := append(header, buf[:n]...)
|
|
if _, err = udpserver.WriteToUDP(body, clientAddr); err != nil {
|
|
logrus.Debug(fmt.Sprintf("[%s][UDP] WriteToUDP to client failed: %s", client.RemoteAddr().String(), err.Error()))
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
udpserver.Close()
|
|
}
|
|
|
|
func Socks5Connect(client net.Conn) (net.Conn, string, error) {
|
|
buf := make([]byte, 256)
|
|
n, err := io.ReadFull(client, buf[:4])
|
|
if n != 4 {
|
|
return nil, "", errors.New("read header:" + err.Error())
|
|
}
|
|
ver, cmd, _, atyp := buf[0], buf[1], buf[2], buf[3]
|
|
if ver != 5 {
|
|
return nil, "", errors.New("invalid ver")
|
|
}
|
|
if cmd == 3 {
|
|
return nil, "", errors.New("UDP Associate")
|
|
}
|
|
if cmd != 1 {
|
|
return nil, "", errors.New("invalid cmd, only support connect")
|
|
}
|
|
addr := ""
|
|
switch atyp {
|
|
case 1:
|
|
n, err = io.ReadFull(client, buf[:4])
|
|
if n != 4 {
|
|
return nil, "", errors.New("invalid IPv4:" + err.Error())
|
|
}
|
|
addr = fmt.Sprintf("%d.%d.%d.%d", buf[0], buf[1], buf[2], buf[3])
|
|
case 3:
|
|
n, err = io.ReadFull(client, buf[:1])
|
|
if n != 1 {
|
|
return nil, "", errors.New("invalid hostname:" + err.Error())
|
|
}
|
|
addrLen := int(buf[0])
|
|
n, err = io.ReadFull(client, buf[:addrLen])
|
|
if n != addrLen {
|
|
return nil, "", errors.New("invalid hostname:" + err.Error())
|
|
}
|
|
addr = string(buf[:addrLen])
|
|
case 4:
|
|
return nil, "", errors.New("IPv6: no supported yet")
|
|
default:
|
|
return nil, "", errors.New("invalid atyp")
|
|
}
|
|
n, err = io.ReadFull(client, buf[:2])
|
|
if n != 2 {
|
|
return nil, "", errors.New("read port:" + err.Error())
|
|
}
|
|
port := binary.BigEndian.Uint16(buf[:2])
|
|
destAddrPort := fmt.Sprintf("%s:%d", addr, port)
|
|
logrus.Debug(fmt.Sprintf("Connecting %s", destAddrPort))
|
|
dest, err := net.Dial("tcp", destAddrPort)
|
|
if err != nil {
|
|
return nil, destAddrPort, errors.New("dial dst:" + err.Error())
|
|
}
|
|
logrus.Debug(fmt.Sprintf("Connected %s", destAddrPort))
|
|
_, err = client.Write([]byte{0x05, 0x00, 0x00, 0x01, 0, 0, 0, 0, 0, 0})
|
|
if err != nil {
|
|
dest.Close()
|
|
return nil, destAddrPort, errors.New("write rsp:" + err.Error())
|
|
}
|
|
return dest, destAddrPort, nil
|
|
}
|
|
|
|
/*
|
|
func forward(i interface{}) {
|
|
rc := i.(*RelayConn)
|
|
defer rc.src.Close()
|
|
defer rc.dst.Close()
|
|
io.Copy(rc.src, rc.dst)
|
|
}
|
|
|
|
func gforward(i interface{}) {
|
|
rc := i.(*RelayConn)
|
|
defer rc.dst.Close()
|
|
defer rc.src.Close()
|
|
CopyPileline(rc.dst, rc.src, rc.destAddrPort)
|
|
}
|
|
|
|
func Socks5Relay(client, target net.Conn, destAddrPort string) {
|
|
rc := &RelayConn{
|
|
src: client,
|
|
dst: target,
|
|
destAddrPort: destAddrPort,
|
|
}
|
|
logrus.Debug(fmt.Sprintf("dpool: %d left: %d, gpool: %d left: %d", dpool.Running(), dpool.Free(), gpool.Running(), gpool.Free()))
|
|
dpool.Invoke(rc)
|
|
if cache.Contains(destAddrPort) {
|
|
logrus.Debug(fmt.Sprintf("Hit LRU Relay Cache: %s", destAddrPort))
|
|
rc.src, rc.dst = rc.dst, rc.src
|
|
dpool.Invoke(rc)
|
|
} else {
|
|
gpool.Invoke(rc)
|
|
}
|
|
}
|
|
*/
|
|
|
|
func Socks5Forward(client, target net.Conn, destAddrPort string) {
|
|
forward := func(src, dest net.Conn) {
|
|
defer src.Close()
|
|
defer dest.Close()
|
|
io.Copy(src, dest)
|
|
}
|
|
|
|
gforward := func(dst, src net.Conn) {
|
|
defer dst.Close()
|
|
defer src.Close()
|
|
CopyPileline(dst, src, destAddrPort)
|
|
}
|
|
|
|
go forward(client, target)
|
|
if cache.Contains(destAddrPort) {
|
|
logrus.Debug(fmt.Sprintf("Hit LRU Relay Cache: %s", destAddrPort))
|
|
go forward(target, client)
|
|
} else {
|
|
go gforward(target, client)
|
|
}
|
|
}
|
|
|
|
func min(a, b int) int {
|
|
if a < b {
|
|
return a
|
|
}
|
|
return b
|
|
}
|
|
|
|
func CopyPileline(dst io.Writer, src io.Reader, destAddrPort string) {
|
|
buf := make([]byte, RDBUF)
|
|
nr, err := src.Read(buf)
|
|
if err != nil {
|
|
if err == io.EOF {
|
|
logrus.Debug(fmt.Sprintf("[%s][%s] read EOF in first phase", destAddrPort, src.(*net.TCPConn).RemoteAddr().String()))
|
|
} else if strings.Contains(err.Error(), "use of closed network connection") {
|
|
logrus.Debug(fmt.Sprintf("[%s][%s] read closed in first phase: %s", destAddrPort, src.(*net.TCPConn).RemoteAddr().String(), err.Error()))
|
|
} else {
|
|
logrus.Error(fmt.Sprintf("[%s][%s] read error in first phase: %s", destAddrPort, src.(*net.TCPConn).RemoteAddr().String(), err.Error()))
|
|
}
|
|
return
|
|
}
|
|
if nr == 0 {
|
|
logrus.Debug(fmt.Sprintf("[%s][%s] read 0 in first phase", destAddrPort, src.(*net.TCPConn).RemoteAddr().String()))
|
|
return
|
|
}
|
|
hint := string(buf[0:7])
|
|
is_http := false
|
|
for _, v := range HTTP_METHOD {
|
|
if strings.HasPrefix(hint, v) {
|
|
is_http = true
|
|
break
|
|
}
|
|
}
|
|
if !is_http {
|
|
dst.Write(buf[0:nr])
|
|
io.Copy(dst, src)
|
|
cache.Add(destAddrPort, destAddrPort)
|
|
logrus.Debug(fmt.Sprintf("Not HTTP, Hint: %v, Add LRU Relay Cache: %s, Cache Len: %d", buf[0:7], destAddrPort, cache.Len()))
|
|
return
|
|
}
|
|
for {
|
|
parser := http.NewHTTPParser()
|
|
httpBodyOffset, err := parser.Parse(buf[0:nr])
|
|
for err == http.ErrMissingData {
|
|
var m int
|
|
m, err = src.Read(buf[nr:])
|
|
if err != nil {
|
|
logrus.Debug(fmt.Sprintf("[%s] read error in http accumulation: %v", destAddrPort, err))
|
|
break
|
|
}
|
|
nr += m
|
|
httpBodyOffset, err = parser.Parse(buf[:nr])
|
|
}
|
|
value, start, end := parser.FindHeader([]byte("User-Agent"))
|
|
uaStr := string(value)
|
|
if value != nil && end > start {
|
|
isInWhiteList := false
|
|
isMatchUaPattern := true
|
|
if uaPattern != "" {
|
|
isMatchUaPattern, err = uaRegexp.MatchString(uaStr)
|
|
if err != nil {
|
|
logrus.Error(fmt.Sprintf("[%s][%s] User-Agent Regex Pattern Match Error: %s", destAddrPort, src.(*net.TCPConn).RemoteAddr().String(), err.Error()))
|
|
isMatchUaPattern = true
|
|
}
|
|
}
|
|
for _, v := range whitelist {
|
|
if v == uaStr {
|
|
isInWhiteList = true
|
|
break
|
|
}
|
|
}
|
|
if isInWhiteList || !isMatchUaPattern {
|
|
if !isMatchUaPattern {
|
|
logrus.Debug(fmt.Sprintf("[%s][%s] Not Hit User-Agent Pattern: %s", destAddrPort, src.(*net.TCPConn).RemoteAddr().String(), uaStr))
|
|
}
|
|
if isInWhiteList {
|
|
logrus.Debug(fmt.Sprintf("[%s][%s] Hit User-Agent Whitelist: %s, Add LRU Relay Cache, Cache Len: %d", destAddrPort, src.(*net.TCPConn).RemoteAddr().String(), uaStr, cache.Len()))
|
|
cache.Add(destAddrPort, destAddrPort)
|
|
}
|
|
dst.Write(buf[0:nr])
|
|
io.Copy(dst, src)
|
|
return
|
|
}
|
|
logrus.Debug(fmt.Sprintf("[%s][%s] Hit User-Agent: %s", destAddrPort, src.(*net.TCPConn).RemoteAddr().String(), uaStr))
|
|
for i := start; i < end; i++ {
|
|
buf[i] = 32
|
|
}
|
|
if enablePartialReplace && uaRegexp != nil {
|
|
newUaHearder, err := uaRegexp.Replace(uaStr, payload, -1, -1)
|
|
if err != nil {
|
|
logrus.Error(fmt.Sprintf("[%s][%s] User-Agent Replace Error: %s", destAddrPort, src.(*net.TCPConn).RemoteAddr().String(), err.Error()))
|
|
payloadByte = []byte(payload)
|
|
} else {
|
|
payloadByte = []byte(newUaHearder)
|
|
}
|
|
}
|
|
for i := range payloadByte {
|
|
if start+i >= end {
|
|
break
|
|
}
|
|
buf[start+i] = payloadByte[i]
|
|
}
|
|
} else {
|
|
logrus.Debug(fmt.Sprintf("[%s] Not found User-Agent, Add LRU Relay Cache, Cache Len: %d", destAddrPort, cache.Len()))
|
|
dst.Write(buf[0:nr])
|
|
io.Copy(dst, src)
|
|
cache.Add(destAddrPort, destAddrPort)
|
|
return
|
|
}
|
|
bodyLen := int(parser.ContentLength())
|
|
if bodyLen == -1 {
|
|
bodyLen = 0
|
|
}
|
|
|
|
_, ew := dst.Write(buf[0:min(httpBodyOffset+bodyLen, nr)])
|
|
if ew != nil {
|
|
logrus.Error(fmt.Sprintf("[%s][%s] write error: %s", destAddrPort, src.(*net.TCPConn).RemoteAddr().String(), ew.Error()))
|
|
break
|
|
}
|
|
if httpBodyOffset+bodyLen > nr {
|
|
left := httpBodyOffset + bodyLen - nr
|
|
for left > 0 {
|
|
lr := min(left, RDBUF)
|
|
m, err := src.Read(buf[0:lr])
|
|
if err != nil {
|
|
logrus.Error(fmt.Sprintf("[%s][%s] read error in large body: %s", destAddrPort, src.(*net.TCPConn).RemoteAddr().String(), err.Error()))
|
|
break
|
|
}
|
|
_, ew := dst.Write(buf[0:m])
|
|
if ew != nil {
|
|
logrus.Error(fmt.Sprintf("[%s][%s] write error in large body: %s", destAddrPort, src.(*net.TCPConn).RemoteAddr().String(), ew.Error()))
|
|
break
|
|
}
|
|
left -= m
|
|
}
|
|
nr = 0
|
|
} else if httpBodyOffset+bodyLen < nr {
|
|
copy(buf[0:], buf[httpBodyOffset+bodyLen:])
|
|
nr = nr - httpBodyOffset - bodyLen
|
|
} else {
|
|
nr = 0
|
|
}
|
|
|
|
m, err := src.Read(buf[nr:])
|
|
nr += m
|
|
if err != nil {
|
|
if err == io.EOF {
|
|
logrus.Debug(fmt.Sprintf("[%s][%s] read EOF in next phase", destAddrPort, src.(*net.TCPConn).RemoteAddr().String()))
|
|
} else if strings.Contains(err.Error(), "use of closed network connection") {
|
|
logrus.Debug(fmt.Sprintf("[%s][%s] read closed in next phase: %s", destAddrPort, src.(*net.TCPConn).RemoteAddr().String(), err.Error()))
|
|
} else {
|
|
logrus.Error(fmt.Sprintf("[%s][%s] read error in next phase: %s", destAddrPort, src.(*net.TCPConn).RemoteAddr().String(), err.Error()))
|
|
}
|
|
break
|
|
}
|
|
}
|
|
}
|