package SunnyProxy

/*
#include <stdlib.h>
#include "LinuxCall.h"
*/
import "C"
import (
	"Sunny/sock5/proxy"
	"Sunny/src/crypto/tls"
	"Sunny/src/net/http"
	"Sunny/src/net/http/httptest"
	"bufio"
	"bytes"
	_ "embed"
	"errors"
	"fmt"
	"github.com/qtgolang/qt"
	"io"
	"io/ioutil"
	"net"
	"net/url"
	"os"
	"os/exec"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"sync/atomic"
	"syscall"
	"time"
	"unsafe"
)

const (
	socks5Version = uint8(5)

	socks5AuthNone         = uint8(0x00)
	socks5AuthGSSAPI       = uint8(0x01)
	socks5Auth             = uint8(0x02)
	socks5AuthUnAcceptable = uint8(0xFF)

	socks5CmdConnect = uint8(0x01)
	socks5CmdBind    = uint8(0x02)
	socks5CmdUDP     = uint8(0x03)

	socks5AtypIpv4       = uint8(0x01)
	socks5AtypDomainName = uint8(0x03)
	socks5AtypIpv6       = uint8(0x04)
)

var ConnectionID uint64

type Servers struct {
	listen *net.Listener
}

type bufferedConn struct {
	rw       *bufio.ReadWriter
	net.Conn // So that most methods are embedded
}

func newBufferedConn(c net.Conn) *bufferedConn {
	r := bufio.NewReader(c)
	w := bufio.NewWriter(c)
	return &bufferedConn{bufio.NewReadWriter(r, w), c}
}
func isIPv6(str string) bool {
	ip := net.ParseIP(str)
	return ip.To4() == nil
}

func isIPv4(str string) bool {
	ip := net.ParseIP(str)
	return ip.To4() != nil
}

func authMethod(reader *bufio.Reader, writer *bufio.Writer) (bool, string) {
	defer writer.Flush()
	av, err := reader.ReadByte()
	if err != nil || av != 1 {
		//fmt.Println(ID, "Socks5 auth version invalid")
		return false, ""
	}

	uLen, err := reader.ReadByte()
	if err != nil || uLen <= 0 || uLen > 255 {
		//fmt.Println(ID, "Socks5 auth user length invalid")
		return false, ""
	}

	uBuf := make([]byte, uLen)
	nr, err := reader.Read(uBuf)
	if err != nil || nr != int(uLen) {
		//fmt.Println(ID, "Socks5 auth user error", nr)
		return false, ""
	}

	user := string(uBuf)

	pLen, err := reader.ReadByte()
	if err != nil || pLen <= 0 || pLen > 255 {
		//fmt.Println(ID, "Socks5 auth passwd length invalid", pLen)
		return false, ""
	}

	pBuf := make([]byte, pLen)
	nr, err = reader.Read(pBuf)
	if err != nil || nr != int(pLen) {
		//fmt.Println(ID, "Socks5 auth passwd error", pLen, nr)
		return false, ""
	}

	passwd := string(pBuf)
	if VerifyUser {
		if len(user) > 0 && len(passwd) > 0 {
			VerifyUserLock.Lock()
			if passwd == VerifyUserList[user] {
				VerifyUserLock.Unlock()
				_ = writer.WriteByte(0x01)
				_ = writer.WriteByte(0x00)
				return true, passwd
			}
			VerifyUserLock.Unlock()
		}
	} else {
		if len(user) > -1 || len(passwd) > -1 {
			//fmt.Println(1, user, passwd)
			_ = writer.WriteByte(0x01)
			_ = writer.WriteByte(0x00)
			return true, passwd
		}
	}
	//fmt.Println(2, user, passwd)
	_ = writer.WriteByte(0x01)
	_ = writer.WriteByte(0x01)
	return false, ""
}

// StartSocks5Proxy ...
func (sProxy *requestP) StartSocks5Proxy() {

	version, err := sProxy.reader.ReadByte()
	if err != nil {
		//fmt.Println(ID, "Socks5 version read error", err.Error())
		return
	}

	if version != socks5Version {
		//fmt.Println(ID, "Socks5 version invalid", version)
		return
	}

	nmethods, err := sProxy.reader.ReadByte()
	if err != nil {
		//fmt.Println(ID, "Socks5 nmethods read error", err.Error())
		return
	}

	if nmethods < 0 || nmethods > 255 {
		//fmt.Println(ID, "Socks5 nmethods invalid", nmethods)
		return
	}

	supportAuth := false
	method := socks5AuthNone
	for i := 0; i < int(nmethods); i++ {
		method, err = sProxy.reader.ReadByte()
		if err != nil {
			//fmt.Println(ID, "Socks5 methods read error", err.Error())
			return
		}
		if method == socks5Auth {
			supportAuth = true
		}
	}

	// |VER | METHOD |
	err = sProxy.writer.WriteByte(version)
	if err != nil {
		//fmt.Println(ID, "Socks5 write version error", err.Error())
		return
	}

	// 支持加密, 则回复加密方法.
	if supportAuth {
		method = socks5Auth
		err = sProxy.writer.WriteByte(method)
		if err != nil {
			//fmt.Println(ID, "Socks5 write socks5Auth error", err.Error())
			return
		}
	} else {
		// 服务器不支持加密, 直接通过.
		method = socks5AuthNone
		err = sProxy.writer.WriteByte(method)
		if err != nil {
			//fmt.Println(ID, "Socks5 write socks5AuthNone error", err.Error())
			return
		}
	}
	_ = sProxy.writer.Flush()
	ok := false
	pass := ""
	// Auth mode, read user passwd.
	// 暂时没啥用 现在设置的不要密码或任意账号密码都通过
	if supportAuth {
		ok, pass = authMethod(sProxy.reader, sProxy.writer)
		if !ok {
			return
		}
	} else if VerifyUser {
		return
	}

	// |VER | CMD |  RSV  | ATYP | DST.ADDR | DST.PORT |

	// 认证通过或非认证模式.
	handshakeVersion, err := sProxy.reader.ReadByte()
	if err != nil || handshakeVersion != socks5Version {
		if err != nil {
			//fmt.Println("Socks5 read handshake version error", err.Error())
		}
		return
	}

	command, err := sProxy.reader.ReadByte()
	if err != nil {
		//fmt.Println(ID, "Socks5 read command error", err.Error())
		return
	}
	if command != socks5CmdConnect &&
		command != socks5CmdBind &&
		command != socks5CmdUDP {
		//fmt.Println(ID, "Socks5 read command invalid", command)
		return
	}

	_, _ = sProxy.reader.ReadByte() // rsv byte
	atyp, err := sProxy.reader.ReadByte()
	if err != nil {
		//fmt.Println(ID, "Socks5 read atyp error", err.Error())
		return
	}
	if atyp != socks5AtypDomainName &&
		atyp != socks5AtypIpv4 &&
		atyp != socks5AtypIpv6 {
		//fmt.Println(ID, "Socks5 read atyp invalid", atyp)
		return
	}

	hostname := ""
	switch {
	case atyp == socks5AtypIpv4:
		{
			IPv4Buf := make([]byte, 4)
			nr, err := sProxy.reader.Read(IPv4Buf)
			if err != nil || nr != 4 {
				//fmt.Println(ID, "Socks5 read atyp ipv4 address error")
				return
			}

			ip := net.IP(IPv4Buf)
			hostname = ip.String()
		}
	case atyp == socks5AtypIpv6:
		{
			IPv6Buf := make([]byte, 16)
			nr, err := sProxy.reader.Read(IPv6Buf)
			if err != nil || nr != 16 {
				//fmt.Println(ID, "Socks5 read atyp ipv6 address error")
				return
			}

			ip := net.IP(IPv6Buf)
			hostname = ip.String()
		}
	case atyp == socks5AtypDomainName:
		{
			dnLen, err := sProxy.reader.ReadByte()
			if err != nil || int(dnLen) < 0 {
				//fmt.Println(ID, "Socks5 read domain len error", dnLen)
				return
			}

			domain := make([]byte, dnLen)
			nr, err := sProxy.reader.Read(domain)
			if err != nil || nr != int(dnLen) {
				//fmt.Println(ID, "Socks5 read atyp domain error", domain)
				return
			}
			addr, err := net.ResolveIPAddr("ip", string(domain))
			if err != nil {
				hostname = string(domain)
			} else {
				hostname = addr.String()
			}

		}
	}
	portNum1, err := sProxy.reader.ReadByte()
	if err != nil {
		//fmt.Println(ID, "Socks5 read atyp port byte1 error")
		return
	}
	pid := pass
	if strings.Index(pass, "pid=") == -1 {
		pid = ""
	} else {
		pid = strings.ReplaceAll(pass, "pid=", "")
	}
	portNum2, err := sProxy.reader.ReadByte()
	if err != nil {
		//fmt.Println(ID, "Socks5 read atyp port byte2 error")
		return
	}
	port := uint16(portNum1)<<8 + uint16(portNum2)
	hostname = fmt.Sprintf("%s:%d", hostname, port)
	//  |VER | REP |  RSV  | ATYP | BND.ADDR | BND.PORT |
	_ = sProxy.writer.WriteByte(socks5Version)

	//fmt.Println(ID, "Scoks5 connect to", hostname)

	// Start connect to target host.
	if command == socks5CmdUDP {
		iparr := strings.Split(sProxy.LocalTcp.LocalAddr().String(), ":")
		_ = sProxy.writer.WriteByte(0) // SOCKS5_SUCCEEDED
		_ = sProxy.writer.WriteByte(0)
		if len(iparr) != 2 {
			_ = sProxy.writer.WriteByte(socks5AtypIpv4)
			_, _ = sProxy.writer.Write(net.ParseIP("0.0.0.0").To4())
			_ = sProxy.writer.WriteByte(portNum1)
			_ = sProxy.writer.WriteByte(portNum2)
		} else {
			host := iparr[0]
			if isIPv4(host) {
				_ = sProxy.writer.WriteByte(socks5AtypIpv4)
				_, _ = sProxy.writer.Write(net.ParseIP(host).To4())
			} else if isIPv6(host) {
				_ = sProxy.writer.WriteByte(socks5AtypIpv6)
				_, _ = sProxy.writer.Write(net.ParseIP(host).To16())
			} else {
				_ = sProxy.writer.WriteByte(socks5AtypDomainName)
				_ = sProxy.writer.WriteByte(byte(len(hostname)))
				_, _ = sProxy.writer.WriteString(hostname)
			}
			portNum, _ := strconv.Atoi(iparr[1])
			portNum1 = byte(portNum >> 8)
			portNum2 = byte(portNum)
			_ = sProxy.writer.WriteByte(portNum1)
			_ = sProxy.writer.WriteByte(portNum2)
		}
		_ = sProxy.writer.Flush()
		for {
			b := make([]byte, 10)
			_, e := sProxy.reader.Read(b)
			if e != nil {
				break
			}
		}
		return
	}
	//var RemoteTCP net.Conn
	err = nil
	if strings.Index(hostname, "1.2.3.4") != -1 || strings.Index(hostname, "sunny.io") != -1 {
		_, _ = sProxy.writer.Write([]byte{0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
		_ = sProxy.writer.Flush()
		time.Sleep(100 * time.Millisecond)
		_, _ = sProxy.writer.Write([]byte("HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Type: application/x-x509-ca-cert\r\n\r\n"))
		_, _ = sProxy.writer.Write(GetCaCert())
		_ = sProxy.writer.Flush()
		time.Sleep(100 * time.Millisecond)
		return
	}
	a := strings.Split(sProxy.LocalTcp.RemoteAddr().String(), ":")
	if len(a) >= 2 {
		hostname = strings.ReplaceAll(hostname, "127.0.0.1", a[0])
	}
	if err != nil {
		//fmt.Println(hostname, err)
		_ = sProxy.writer.WriteByte(1) // SOCKS5_GENERAL_SOCKS_SERVER_FAILURE
	} else {
		_ = sProxy.writer.WriteByte(0) // SOCKS5_SUCCEEDED
	}
	_ = sProxy.writer.WriteByte(0)

	if err == nil {
		hostport := hostname
		host, _, _ := net.SplitHostPort(hostport)
		if isIPv4(host) {
			_ = sProxy.writer.WriteByte(socks5AtypIpv4)
			_, _ = sProxy.writer.Write(net.ParseIP(host).To4())
		} else if isIPv6(host) {
			_ = sProxy.writer.WriteByte(socks5AtypIpv6)
			_, _ = sProxy.writer.Write(net.ParseIP(host).To16())
		} else {
			_ = sProxy.writer.WriteByte(socks5AtypDomainName)
			_ = sProxy.writer.WriteByte(byte(len(hostname)))
			_, _ = sProxy.writer.WriteString(hostname)
		}
	} else {
		_ = sProxy.writer.WriteByte(socks5AtypDomainName)
		_ = sProxy.writer.WriteByte(byte(len(hostname)))
		_, _ = sProxy.writer.WriteString(hostname)
	}

	_ = sProxy.writer.WriteByte(portNum1)
	_ = sProxy.writer.WriteByte(portNum2)

	_ = sProxy.writer.Flush()

	if err != nil {
		return
	}
	if MustTcp {
		LocalAddr := sProxy.LocalTcp.RemoteAddr().String()
		_a := []byte("TCP-S5")
		as := &WebsocketMsg{}
		as.As = _a
		as.TcpIp = ""
		as.TcpUser = ""
		as.TcpPass = ""
		proxyX.delegate.TCPRequest(LocalAddr, hostname, 4, sProxy.TheonlyId, as, pid)
		if string(_a) != string(as.As) {
			hostname = string(as.As)
		}
		_GlobalProxyIp := GlobalProxyIp
		_GlobalProxyAuth := GlobalProxyAuth
		if as.TcpIp != "" {
			_GlobalProxyIp = "s5|" + as.TcpIp
			_GlobalProxyAuth = as.TcpUser + ":" + as.TcpPass
		}
		var RemoteTCP net.Conn
		Arrip := strings.Split(_GlobalProxyIp, "|")
		if len(Arrip) > 1 && Arrip[0] == "s5" {
			authAA := &proxy.Auth{}
			arr1 := strings.Split(_GlobalProxyAuth, ":")
			if len(arr1) == 1 {
				authAA.User = arr1[0]
			} else if len(arr1) == 2 {
				authAA.User = arr1[0]
				authAA.Password = arr1[1]
			}
			dialer, _, err := proxy.SOCKS5("tcp", Arrip[1], authAA, proxy.Direct)
			if err != nil {
				return
			}
			RemoteTCP, err = dialer.Dial("tcp", hostname)
		} else {
			RemoteTCP, err = net.Dial("tcp", hostname)
		}
		defer func() {
			if RemoteTCP != nil {
				_ = RemoteTCP.Close()
			}
		}()
		if err == nil && RemoteTCP != nil {
			proxyX.delegate.TCPRequest(LocalAddr, hostname, 0, sProxy.TheonlyId, nil, pid)
			sProxy.Tcpcallback(&RemoteTCP, hostname, pid)
		}
		return
	}
	sProxy.Local(hostname, port, pid)
}
func (sProxy *requestP) TLSTcpcallback(RemoteTCP, Load *tls.Conn, tw *bufio.Writer, serverName string, pid string, LoadR *bufio.Reader) {
	if RemoteTCP == nil {
		return
	}

	ST := new(Brw)
	ST.B = tw
	ST.C = sProxy.bcrw.Writer
	TcpSceneLock.Lock()
	TcpScenes[int(sProxy.TheonlyId)] = ST
	TcpSceneLock.Unlock()
	defer func() {
		TcpSceneLock.Lock()
		delete(TcpScenes, int(sProxy.TheonlyId))
		TcpSceneLock.Unlock()
	}()

	LocalAddr := sProxy.LocalTcp.RemoteAddr().String()
	W := bufio.NewWriter(Load)
	//读取客户端消息转发给服务端
	go proxyH(*tw, LoadR, sProxy.TheonlyId, LocalAddr, serverName, 1, pid, Load, RemoteTCP, &ST.L)
	//读取服务器消息转发给客户端
	proxyH(*W, RemoteTCP, sProxy.TheonlyId, LocalAddr, serverName, 2, pid, RemoteTCP, Load, &ST.L)
	proxyX.delegate.TCPRequest(LocalAddr, serverName, 3, sProxy.TheonlyId, nil, pid)
}
func (sProxy *requestP) Tcpcallback(RemoteTCP *net.Conn, hostname string, pid string) {
	if RemoteTCP == nil {
		return
	}
	if (*RemoteTCP) == nil {
		return
	}
	tw := bufio.NewWriter(*RemoteTCP)
	ST := new(Brw)
	ST.B = tw
	ST.C = sProxy.bcrw.Writer
	TcpSceneLock.Lock()
	TcpScenes[int(sProxy.TheonlyId)] = ST
	TcpSceneLock.Unlock()
	defer func() {
		TcpSceneLock.Lock()
		delete(TcpScenes, int(sProxy.TheonlyId))
		TcpSceneLock.Unlock()
	}()

	LocalAddr := sProxy.LocalTcp.RemoteAddr().String()

	//读取客户端消息转发给服务端
	go proxyH(*tw, sProxy.bcrw.Reader, sProxy.TheonlyId, LocalAddr, hostname, 1, pid, sProxy.LocalTcp, *RemoteTCP, &ST.L)

	//读取服务器消息转发给客户端
	proxyH(*sProxy.bcrw.Writer, *RemoteTCP, sProxy.TheonlyId, LocalAddr, hostname, 2, pid, *RemoteTCP, sProxy.LocalTcp, &ST.L)

	proxyX.delegate.TCPRequest(LocalAddr, hostname, 3, sProxy.TheonlyId, nil, pid)
}
func proxyH(dst bufio.Writer, src io.Reader, msgid int64, sname, serverName string, tcpcallType int, pid string, t1, t2 net.Conn, L *sync.Mutex) {
	as := &WebsocketMsg{}
	buf := make([]byte, 4096)
	var bufBuffer bytes.Buffer
	defer func() {
		if err := recover(); err != nil {
			fmt.Println("proxyH 出了错：", err)
		}
		bufBuffer.Reset()
		as.As = nil
		buf = nil
		if t1 != nil {
			_ = t1.Close()
		}
		if t2 != nil {
			_ = t2.Close()
		}
	}()
	if t1 == nil {
		return
	}
	for {
		L.Lock()
		_ = t1.SetDeadline(time.Now().Add(9999 * time.Hour))
		_ = t1.SetReadDeadline(time.Now().Add(165 * time.Second))
		_ = t2.SetReadDeadline(time.Now().Add(165 * time.Second))
		L.Unlock()
		nr, er := src.Read(buf[0:]) // io.ReadAtLeast(src, buf[0:], 1)
		if nr > 0 {
			bufBuffer.Grow(nr)
			for i := 0; i < nr; i++ {
				bufBuffer.WriteByte(buf[i])
			}
			as.As = bufBuffer.Bytes()
			proxyX.delegate.TCPRequest(sname, serverName, tcpcallType, msgid, as, pid)
			if len(as.As) < 1 {
				continue
			}
			L.Lock()
			nw, ew := dst.Write(as.As)
			er = dst.Flush()
			L.Unlock()
			bufBuffer.Reset()
			if nw != len(as.As) || ew != nil {
				break
			}

		}
		if er != nil {
			return
		}

	}
}

type requestP struct {
	LocalTcp  net.Conn
	bcrw      *bufio.ReadWriter
	reader    *bufio.Reader
	writer    *bufio.Writer
	TheonlyId int64
	Proxy     string
	ClientIP  []byte
}

var Theonly int64
var ConnList = make(map[int64]net.Conn)
var ConnListLock sync.Mutex

func CloseAllTCP() {
	ConnListLock.Lock()
	for k, conn := range ConnList {
		_ = conn.Close()
		delete(ConnList, k)
	}
	ConnListLock.Unlock()
}
func (s *Servers) handleClientConn(conn net.Conn) {
	Theonid := atomic.AddInt64(&Theonly, 1)
	ConnListLock.Lock()
	ConnList[Theonid] = conn
	ConnListLock.Unlock()
	defer func() {
		_ = conn.Close()
		ConnListLock.Lock()
		delete(ConnList, Theonid)
		ConnListLock.Unlock()
	}()
	bc := newBufferedConn(conn)
	reader := bc.rw.Reader
	peek, err := reader.Peek(1)
	if err != nil {
		_ = bc.Close()
		return
	}
	writer := bc.rw.Writer
	ProxyRequest := new(requestP)
	ProxyRequest.LocalTcp = conn
	ProxyRequest.writer = writer
	ProxyRequest.reader = reader
	ProxyRequest.bcrw = bc.rw
	ProxyRequest.TheonlyId = Theonid
	var b bytes.Buffer
	b.WriteString(conn.RemoteAddr().String())
	b.Write([]byte{0})
	ProxyRequest.ClientIP = b.Bytes()
	if peek[0] == 0x05 {
		ProxyRequest.StartSocks5Proxy()
	} else if VerifyUser == false && IsHTTPRequest(peek[0], reader) {
		last := ConnRead(conn, reader)

		lasts := string(last)
		host := strings.ReplaceAll(qt.String().SubString(lasts, "Host: ", "\r\n"), " ", "")
		if host == "" {
			host = qt.String().SubString(lasts, " http://", "/")
		}
		if host == "" {
			host = qt.String().SubString(lasts, " https://", "/")
		}
		if host == conn.LocalAddr().String() {
			var buffer bytes.Buffer
			buffer.Write([]byte("HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Type: application/x-x509-ca-cert\r\n\r\n"))
			buffer.Write(GetCaCert())
			_, _ = conn.Write(buffer.Bytes())
			return
		}
		ProxyRequest.StartHTTPProxy("", last, host, "", "")
	} else if VerifyUser == false && peek[0] == 22 {
		//透明代理
		_bytes, _ := reader.Peek(reader.Buffered())
		T := tls.Client(conn, &tls.Config{InsecureSkipVerify: true})
		T.Reset(_bytes)
		msg, serverName, e := T.ClientHello()
		if e == nil {
			serverName2 := serverName
			arr2 := strings.Split(serverName, ":")
			port := uint16(0)
			if len(arr2) < 2 {
				serverName2 += ":443"
				port = 443
			} else {
				_p, _ := strconv.Atoi(arr2[1])
				port = uint16(_p)
			}
			certificate, er := GetCertificate(serverName2)
			if er != nil {
				_ = T.Close()
				return
			}
			T.SetServer(&tls.Config{Certificates: []tls.Certificate{*certificate}})
			e = T.ServerHandshake(msg)
			ProxyRequest.tlsSend("", serverName, serverName, serverName2, T, port)
			_ = T.Close()
			return
		}
		_ = T.Close()
	}

	_ = bc.Close()
}

// LegitimateRequest
// 解析HTTP 请求体
func LegitimateRequest(s []byte) (bool, bool, int) {
	a := strings.ToLower(string(s))
	arrays := strings.Split(a, " ")

	if len(arrays) > 1 {
		if arrays[0] == "delete" || arrays[0] == "elete" || arrays[0] == "post" || arrays[0] == "ost" || arrays[0] == "put" || arrays[0] == "ut" {
			//Body中是否有长度
			islet := strings.Index(a, "content-length: ") != -1
			//长度值
			ContentLength, _ := strconv.Atoi(qt.String().SubString(a, "content-length: ", "\r\n"))
			if islet == false {
				ContentLength = -1
			}
			arr := bytes.Split(s, []byte{13, 10, 13, 10})
			if len(arr) < 2 {
				// 读取验证失败
				return islet, false, 0
			}
			if ContentLength == 0 {
				// 有长度  但长度为0 直接验证成功
				return islet, true, 0
			}
			var b bytes.Buffer

			for i := 0; i < len(arr); i++ {
				if i != 0 {
					b.Write(arr[i])
					b.Write([]byte{13, 10, 13, 10})
				}
			}

			if b.Len() == ContentLength || b.Len()-4 == ContentLength {
				// 有长度  读取验证成功
				return islet, true, 0
			}
			return islet, false, b.Len() - 4
		}
		arr := strings.Split(a, "\r\n\r\n")
		if len(arr) == 2 {
			//没有长度 但已读取验证成功
			return false, true, 0
		}
		//没有长度 但读取验证失败
		return false, false, 0
	}
	return false, false, 0

}
func (s *requestP) Proxy_SendHttps(req *http.Request, pid string) {
	arr := strings.Split(req.RequestURI, ":")
	_prot := 0
	if len(arr) > 1 {
		a, _ := strconv.Atoi(arr[len(arr)-1])
		_prot = a
	}
	hostname := req.Host

	_, _ = s.LocalTcp.Write(tunnelConnectionEstablished)
	s.Local(hostname, uint16(_prot), pid)
}

// StartHTTPProxy ...
func (s *requestP) StartHTTPProxy(pid string, last []byte, host, serverName string, s_proxy string) {
	host = strings.ReplaceAll(host, " ", "")
	serverName = strings.ReplaceAll(serverName, " ", "")
	var setProxyHost = func(sS string) {
		s.Proxy = sS
	}
	Mod := ""
	if len(last) > 12 {
		Mod = strings.ToUpper(SubString("+"+string(last[0:11]), "+", " "))
	}
	if (MustTcp && Mod != "CONNECT") || Mod != "GET" && Mod != "POST" && Mod != "PUT" && Mod != "DELETE" && Mod != "HEAD" && Mod != "OPTIONS" && Mod != "CONNECT" {

		LocalAddr := s.LocalTcp.RemoteAddr().String()
		var err error
		var RemoteTCP net.Conn
		_a := []byte("tcp")
		as := &WebsocketMsg{}
		as.As = _a
		as.TcpIp = ""
		as.TcpUser = ""
		as.TcpPass = ""
		if serverName != "" {
			host = serverName
		}
		proxyX.delegate.TCPRequest(LocalAddr, host, 4, s.TheonlyId, as, pid)
		if string(_a) != string(as.As) {
			host = string(as.As)
		}
		if strings.Index(host, ":") == -1 {
			host += ":80"
		}
		_GlobalProxyIp := GlobalProxyIp
		_GlobalProxyAuth := GlobalProxyAuth
		if as.TcpIp != "" {
			_GlobalProxyIp = "s5|" + as.TcpIp
			_GlobalProxyAuth = as.TcpUser + ":" + as.TcpPass
		}
		Arrip := strings.Split(_GlobalProxyIp, "|")
		if len(Arrip) > 1 && Arrip[0] == "s5" {
			authAA := &proxy.Auth{}
			arr1 := strings.Split(_GlobalProxyAuth, ":")
			if len(arr1) == 1 {
				authAA.User = arr1[0]
			} else if len(arr1) == 2 {
				authAA.User = arr1[0]
				authAA.Password = arr1[1]
			}
			dialer, _, er := proxy.SOCKS5("tcp", Arrip[1], authAA, proxy.Direct)
			if er != nil {
				return
			}
			RemoteTCP, err = dialer.Dial("tcp", host)
		} else {
			RemoteTCP, err = net.Dial("tcp", host)
		}
		defer func() {
			if RemoteTCP != nil {
				_ = RemoteTCP.Close()
			}
		}()
		if err != nil {
			return
		}
		tw := bufio.NewWriter(RemoteTCP)
		proxyX.delegate.TCPRequest(LocalAddr, host, 0, s.TheonlyId, nil, pid)

		if len(last) > 0 {
			as.As = last
			proxyX.delegate.TCPRequest(LocalAddr, host, 1, s.TheonlyId, as, pid)
			_, _ = tw.Write(as.As)
			tw.Flush()
		}

		s.Tcpcallback(&RemoteTCP, host, pid)
		return
	}
	req, BodyLen := BuildRequest(last, host, "80", setProxyHost)
	if req == nil {
		return
	}
	if req.ContentLength > 0 && BodyLen == 0 {
		s.writer.Write([]byte("HTTP/1.1 100 Continue\r\n\r\n"))
		s.writer.Flush()
		last = ConnRead(s.LocalTcp, s.reader)
		req.Body = ioutil.NopCloser(bytes.NewBuffer(last))
		req.ContentLength = int64(len(last))
	}
	if Mod == "CONNECT" {
		s.Proxy = s_proxy
		s.Proxy_SendHttps(req, pid)
		return
	}
	s.StartHTTPProxyHTTP(bufio.NewReadWriter(bufio.NewReader(s.bcrw), s.writer), req, pid)
	return
}

func BuildRequest(last []byte, host, DefaultPort string, setProxyHost func(s string)) (*http.Request, int) {
	//req, _ := http.ReadRequest(bufio.NewReader(bytes.NewReader([]byte(last))))
	//return req
	Scheme := "http://"
	if DefaultPort == "443" {
		Scheme = "https://"
	}
	var prot = func(mhost string) string {
		arr := strings.Split(mhost, ":")
		if len(arr) == 2 {
			if arr[1] == DefaultPort {
				return ""
			}
			return ":" + arr[1]
		}
		return ""
	}(host)
	var isProt = func(shost string) string {
		if strings.Index(shost, ":") == -1 {
			return shost + prot
		}
		return shost
	}
	Mod := ""
	if len(last) > 10 {
		Mod = strings.ToUpper(SubString("+"+string(last[0:10]), "+", " "))
	}
	if Mod != "GET" && Mod != "POST" && Mod != "PUT" && Mod != "DELETE" && Mod != "HEAD" && Mod != "OPTIONS" && Mod != "CONNECT" {
		return nil, 0
	}
	isHttpProxy := false
	lasts := string(last)
	Path := SubString(lasts, " ", " ")
	if strings.Index(Path, "http://") != -1 || strings.Index(Path, "https://") != -1 {
		isHttpProxy = true
		Path = strings.Replace(Path, "http://", "", 1)
		Path = strings.Replace(Path, "https://", "", 1)
		if strings.Index(Path, "/") == -1 {
			Path = ""
		} else {
			Path = strings.TrimSpace(SubString(Path+" ", "/", " "))
			if Path != "" {
				Path = "/" + Path
			}
		}
	}
	arrc := strings.Split(strings.ReplaceAll(lasts, "\r", ""), "\n\n")
	var arr []string
	if len(arrc) >= 1 {
		arr = strings.Split(arrc[0], "\n")
	}
	if len(arr) > 1 {
		arr = append(arr[:0], arr[1:]...)
	}
	Blen := 0
	req := new(http.Request)
	req.Method = Mod
	req.Header = make(http.Header)
	for index := 0; index < len(arr); index++ {
		HeadArr := strings.Split(arr[index], ": ")
		if len(HeadArr) > 1 {
			req.Header[strings.TrimSpace(strings.ReplaceAll(HeadArr[0], ":", ""))] = []string{strings.TrimSpace(HeadArr[1])}
			if req.URL == nil && strings.ToUpper(HeadArr[0]) == "HOST" {
				if len(Path) > len(host) && Path[0:len(host)] == host {
					Path = Path[len(host):]
				} else if len(Path) >= len(host)+7 && Path[0:len(host)+7] == "http://"+host {
					Path = Path[len(host)+7:]
				} else if len(Path) >= len(host)+8 && Path[0:len(host)+8] == "https://"+host {
					Path = Path[len(host)+7:]
				}
				mkhost := ""
				if isHttpProxy {
					mkhost = HeadArr[1]
				} else {
					mkhost = isProt(HeadArr[1])
				}
				if HeadArr[1] == Path {
					_u, _ := url.Parse(strings.ReplaceAll(Scheme+mkhost, " ", ""))
					req.URL = _u
					req.RequestURI = strings.ReplaceAll(Scheme+mkhost, " ", "")
				} else {
					_u, _ := url.Parse(strings.ReplaceAll(Scheme+mkhost+Path, " ", ""))
					req.URL = _u
					req.RequestURI = strings.ReplaceAll(Scheme+mkhost+Path, " ", "")
				}
				req.Host = strings.ReplaceAll(mkhost, " ", "")
				if isHttpProxy {
					setProxyHost(host)
				}
				host = strings.ReplaceAll(mkhost, " ", "")
			}
			if strings.ToUpper(HeadArr[0]) == "CONTENT-LENGTH" {
				bodyLen, _ := strconv.Atoi(HeadArr[1])
				req.ContentLength = int64(bodyLen)
				lastLen := len(last)
				bodyLenX := lastLen - bodyLen
				if bodyLenX > 0 && bodyLenX <= lastLen {
					sb := last[bodyLenX:]
					Blen = len(sb)
					req.Body = ioutil.NopCloser(bytes.NewBuffer(sb))
				}
			}
		}
	}
	if req.URL == nil {
		if len(Path) > len(host) && Path[0:len(host)] == host {
			Path = Path[len(host):]
		} else if len(Path) >= len(host)+7 && Path[0:len(host)+7] == "http://"+host {
			Path = Path[len(host)+7:]
		} else if len(Path) >= len(host)+8 && Path[0:len(host)+8] == "https://"+host {
			Path = Path[len(host)+7:]
		}
		if host == Path {
			_u, _ := url.Parse(strings.ReplaceAll(Scheme+host, " ", ""))
			req.URL = _u
		} else {
			_u, _ := url.Parse(strings.ReplaceAll(Scheme+host+Path, " ", ""))
			req.URL = _u
		}
		req.Host = strings.ReplaceAll(host, " ", "")
	}
	if req.Body != nil || Mod == "GET" || Mod == "CONNECT" || Mod == "OPTIONS" {
		return req, Blen
	}

	arr1 := bytes.Split(last, []byte{13, 10, 13, 10})
	if len(arr1) < 2 {
		return req, Blen
	}
	body := last[len(arr1[0])+4:]
	arr2 := bytes.Split(body, []byte{13, 10})
	if len(arr2) > 0 {
		BodyLen, _ := strconv.ParseInt(string(arr2[0]), 16, 64)
		if BodyLen > 0 {
			Start := len(arr1[0]) + 4 + len(arr2[0]) + 2
			Out := int(BodyLen) + Start
			if len(last) >= Out {
				body = last[Start:Out]
			}
		}
	}
	Blen = len(body)
	req.Body = ioutil.NopCloser(bytes.NewBuffer(body))
	if req.ContentLength == 0 {
		req.ContentLength = int64(Blen)
	}
	return req, Blen
}

// StartHTTPSProxy ...
func (s *requestP) StartHTTPSProxy(pid, host string, TCP *tls.Conn, serverName string) (*http.Request, error) {
	var setProxyHost = func(sS string) {
		if sS != serverName && sS != host {
			s.Proxy = sS
		}
	}
	f := bufio.NewReadWriter(bufio.NewReader(TCP), bufio.NewWriter(TCP))
	sp, _ := f.Reader.Peek(1)

	var i = 0
	if len(sp) < 1 {
		for {
			i++
			if f.Reader.Buffered() > 0 {
				sp, _ = f.Reader.Peek(1)
				break
			}
			if i > 10 {
				break
			}
			time.Sleep(time.Millisecond * 5)
		}
	}
	if len(sp) > 0 {
		if IsHTTPRequest(sp[0], f.Reader) == false {
			var Remote *tls.Conn
			LocalAddr := s.LocalTcp.RemoteAddr().String()
			as := &WebsocketMsg{}
			_a := []byte("tls-tcp")
			as.As = _a
			as.TcpIp = ""
			as.TcpUser = "1"
			as.TcpPass = "1"
			if serverName != "" {
				host = serverName
			}
			proxyX.delegate.TCPRequest(LocalAddr, host, 4, s.TheonlyId, as, pid)
			if string(_a) != string(as.As) {
				host = string(as.As)
			}
			_GlobalProxyIp := GlobalProxyIp
			_GlobalProxyAuth := GlobalProxyAuth
			if as.TcpIp != "" {
				_GlobalProxyIp = "s5|" + as.TcpIp
				_GlobalProxyAuth = as.TcpUser + ":" + as.TcpPass
			}
			Arrip := strings.Split(_GlobalProxyIp, "|")

			as.As = nil
			as = nil

			var ClientCertificate *tls.Certificate
			p := LoadP12Certificate(host)
			if p != nil {
				ClientCertificate = p.SunnyTLSCert2
			}
			fig := &tls.Config{InsecureSkipVerify: true}
			if ClientCertificate != nil {
				fig.Certificates = []tls.Certificate{*ClientCertificate}
			}
			if len(Arrip) > 1 && Arrip[0] == "s5" {
				authAA := &proxy.Auth{}
				arr1 := strings.Split(_GlobalProxyAuth, ":")
				if len(arr1) == 1 {
					authAA.User = arr1[0]
				} else if len(arr1) == 2 {
					authAA.User = arr1[0]
					authAA.Password = arr1[1]
				}
				dialer, _, er := proxy.SOCKS5("tcp", Arrip[1], authAA, proxy.Direct)
				if er != nil {
					return nil, errors.New(" S5 代理连接失败")
				}
				RemoteTCP, err := dialer.Dial("tcp", host)
				if err != nil {
					return nil, errors.New("s5 连接成功，但连接目标地址失败")
				}
				Remote = tls.Client(RemoteTCP, fig)
			} else {
				RemoteTCP, err := net.Dial("tcp", host)
				if err != nil {
					return nil, errors.New("连接目标地址失败")
				}
				Remote = tls.Client(RemoteTCP, fig)
			}
			_ = TCP.SetDeadline(time.Now().Add(3 * time.Second))
			if Remote.Handshake() != nil {
				_ = Remote.Close()
				return nil, errors.New("握手失败")
			}
			_ = TCP.SetDeadline(time.Now().Add(30 * time.Second))
			proxyX.delegate.TCPRequest(LocalAddr, host, 0, s.TheonlyId, nil, pid)
			tw := bufio.NewWriter(Remote)
			/*
				if len(data) > 0 {
					as.As = data
					proxyX.delegate.TCPRequest(LocalAddr, host, 1, s.TheonlyId, as, pid)
					_, _ = tw.Write(as.As)
					tw.Flush()

				}
			*/

			s.TLSTcpcallback(Remote, TCP, tw, host, pid, f.Reader)
			return nil, errors.New("tls tcp")
		}
	}

	last := ConnRead(TCP, f.Reader)

	req, _ := BuildRequest(last, host, "443", setProxyHost)
	if req == nil {
		return nil, errors.New("BuildRequest Fill ")
	}

	return req, nil
}
func StructureBody(heads *http.Response) []byte {
	var buffer bytes.Buffer
	buffer.Write([]byte("HTTP/1.1 200 OK\r\n"))
	if heads != nil {
		if heads.Header != nil {
			for name, values := range heads.Header {
				for _, value := range values {
					buffer.Write([]byte(name + ": " + value + "\r\n"))
				}
			}
		}
	}

	buffer.Write([]byte("\r\n"))
	if heads != nil {
		if heads.Body != nil {
			bodyBytes, _ := ioutil.ReadAll(heads.Body)
			heads.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes))
			buffer.Write(bodyBytes)
		}
	}
	return buffer.Bytes()
}
func (s *requestP) StartHTTPProxyHTTP(rw *bufio.ReadWriter, req *http.Request, pid string) {
	if req.URL == nil {
		return
	}
	if isCerRequest(req) { // 安装移动端证书
		var buffer bytes.Buffer
		buffer.Write([]byte("HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Type: application/x-x509-ca-cert\r\n\r\n"))
		buffer.Write(GetCaCert())
		_, _ = s.LocalTcp.Write(buffer.Bytes())
		return
	}
	proxyEntity, err := NewEntityWithRequest(req, s.ClientIP)
	if proxyEntity == nil {
		proxyEntity = &Entity{
			Request:  req,
			ClientIp: s.ClientIP,
		}
	}
	defer func() {
		proxyEntity.ProxyTimeout = 0
		proxyEntity.Ip = ""
		proxyEntity.Request = nil
		proxyEntity.Auth = ""
		proxyEntity.ClientIp = nil
		proxyEntity.Pid = ""
		proxyEntity.Response = nil
		proxyEntity = nil
	}()
	if err != nil {
		proxyX.Error(proxyEntity, s.LocalTcp, s.TheonlyId, err)
		return
	}

	proxyEntity.Pid = pid
	if s.Proxy != "" && s.Proxy != req.Host+":80" && s.Proxy != req.Host+":443" && s.Proxy != req.Host {
		proxyEntity.Ip = s.Proxy
		proxyEntity.ProxyTimeout = 30
	}

	if proxyX.delegate.BeforeRequest(proxyEntity, s.TheonlyId) == 1 {
		if proxyEntity.Response != nil {
			_, _ = s.LocalTcp.Write(StructureBody(proxyEntity.Response))
			return
		}
	}
	w := httptest.NewRecorder()
	if proxyX.handleWss(w, proxyEntity, s.LocalTcp, rw, false, s.TheonlyId, pid, proxyEntity.Ip, proxyEntity.Auth, proxyEntity.ProxyTimeout) {
		return
	}
	proxyEntity.Request.URL.String()
	var cnn *net.Conn
	var xs int
	var resp *http.Response
	for {
		resp, cnn, err = proxyX.doRequest(proxyEntity)
		if err != nil {
			xs++
			if xs > 3 {
				break
			}
			if resp != nil && resp.Body != nil {
				_ = resp.Body.Close()

			}
			continue
		}
		break
	}
	defer func() {
		if cnn != nil && (*cnn) != nil {
			_ = (*cnn).Close()
		}
		_ = s.LocalTcp.Close()
		if resp != nil && resp.Body != nil {
			_ = resp.Body.Close()
		}
	}()
	if err != nil || resp == nil {
		if resp == nil {
			err = errors.New("resp=nil -> 0x2")
		}
		proxyX.Error(proxyEntity, s.LocalTcp, s.TheonlyId, err)
		return
	}
	defer func() {
		if resp != nil {
			_ = resp.Body.Close()
		}
	}()
	setout := func() {
		//大数据转发时调用，避免超时问题
		_ = (*cnn).SetDeadline(time.Now().Add(time.Duration(999999) * time.Hour))
		_ = s.LocalTcp.SetDeadline(time.Now().Add(time.Duration(999999) * time.Hour))
	}

	proxyEntity.Response = resp
	var df = func(w io.Writer) {
		SetResponseHeader(proxyEntity.Response, w)
	}
	var callf = func(bs []byte, err error) []byte {
		if err != nil {
			proxyX.Error(proxyEntity, nil, s.TheonlyId, err)
			return nil
		}
		if proxyEntity.Response.Body != nil {
			proxyEntity.Response.Body.Close()
		}
		proxyEntity.Response.Body = ioutil.NopCloser(bytes.NewBuffer(bs))
		proxyX.delegate.BeforeResponse(proxyEntity, s.TheonlyId, 2)
		b, _ := proxyEntity.ReadAll(proxyEntity.Response.Body)
		return b
	}
	l, _ := strconv.Atoi(resp.Header.Get("Content-Length"))

	copyBuffer(s.LocalTcp, resp.Body, cnn, callf, l, df, resp.Header.Get("Content-Type"), setout)
	if proxyEntity.Response.Body != nil {
		proxyEntity.Response.Body.Close()
	}

}

// ConnRead
//从缓冲区读取字节流
func ConnRead(conn net.Conn, reader *bufio.Reader) []byte {
	var st bytes.Buffer
	length := 4096
	bs := make([]byte, length)
	var last []byte
	i := 0
	_ = conn.SetReadDeadline(time.Now().Add(3 * time.Millisecond))
	CClength := 0
	var countmap = make(map[int]int)
	defer func() {
		countmap = nil
		bs = nil
		st.Reset()
	}()
	for {
		sx, e := reader.Read(bs[0:])
		st.Write(bs[0:sx])
		if e != nil {
			if st.Len() < 512 {
				// 如果已读入字节数 小于 512 并且 超过 10次 已读入数没有变动，那么直接返回
				countmap[st.Len()]++
				if countmap[st.Len()] >= 10 {
					bs = make([]byte, 0)
					last = st.Bytes()
					if last == nil {
						last = []byte{}
					}
					_ = conn.SetDeadline(time.Now().Add(30 * time.Second))
					return last
				} else {
					continue
				}
			}
			//如果错误是超时那么进行判断 如果不是超时 那么直接返回
			if strings.Index(e.Error(), timeout) != -1 {
				i++
				//验证HTTP请求体
				//islet=是否有 HTTP Body 长度
				//ok 是否验证成功
				//bodyLen 已出Body长度
				islet, ok, bodyLen := LegitimateRequest(st.Bytes())
				if ok == false {

					//Body中没有长度
					if islet == false {
						_ = conn.SetReadDeadline(time.Now().Add(300 * time.Millisecond))
						//验证失败
						if st.Len() < length {
							if i < 10 {
								continue
							}
						} else if i < 15 {
							continue
						}
					} else {
						_ = conn.SetReadDeadline(time.Now().Add(3 * time.Millisecond))
						if CClength == bodyLen {
							if i < 1000 {
								continue
							}
						} else {
							CClength = bodyLen
							i--
							continue
						}

					}
				}
			}
			bs = make([]byte, 0)
			last = st.Bytes()
			break
		} else {
			_ = conn.SetReadDeadline(time.Now().Add(3 * time.Millisecond))
		}
	}
	_ = conn.SetDeadline(time.Now().Add(30 * time.Second))
	return last
}

func (s *requestP) Local(host string, prot uint16, pid string) {
	if host == "" || prot < 1 {
		return
	}
	if strings.Index(host, ":") == -1 {
		host += ":" + strconv.Itoa(int(prot))
	}
	certificate, err := GetCertificate(host)
	if err != nil {
		return
	}

	var tlsConn *tls.Conn
	var serverName2 string
	var serverName string
	if MustTcp {
		last := ConnRead(s.LocalTcp, s.reader)
		s.StartHTTPProxy(pid, last, host, host, host)
		return
	}
	tlsConn = tls.Server(s.LocalTcp, &tls.Config{Certificates: []tls.Certificate{*certificate}, InsecureSkipVerify: true})

	defer func() { _ = tlsConn.Close() }()
	_ = tlsConn.SetDeadline(time.Now().Add(2 * time.Second))
	TlsBuf := tlsConn.Peek(1)
	if len(TlsBuf) == 1 {
		//发送数据 如果 不是 HEX 16 或 17 那么肯定不是HTTPS 或TLS-TCP
		//HEX 16=ANSI 22 HEX 17=ANSI 23
		if TlsBuf[0] == 22 || TlsBuf[0] == 23 {
			_ = tlsConn.SetDeadline(time.Now().Add(3 * time.Second))
			msg, _serverName, _err := tlsConn.ClientHello()
			_ = tlsConn.SetDeadline(time.Now().Add(30 * time.Second))
			serverName = _serverName
			err = _err
			serverName2 = serverName
			if msg != nil {
				if err != nil {
					return
				}
				if serverName != "" {
					arr := strings.Split(host, ":")
					if len(arr) == 2 {
						arr2 := strings.Split(serverName, ":")
						if len(arr2) < 2 {
							serverName2 = serverName + ":" + arr[1]
						} else {
							serverName2 = arr2[0] + ":" + arr[1]
						}
					} else {
						arr2 := strings.Split(serverName, ":")
						if len(arr2) < 2 {
							serverName2 = serverName + ":443"
						} else {
							serverName2 = arr2[0] + ":" + arr[1]
						}
					}
					certificate, err = GetCertificate(serverName2)

					tlsConn.SetServer(&tls.Config{Certificates: []tls.Certificate{*certificate}})
				}
				err = tlsConn.ServerHandshake(msg)
			}

		} else {
			err = errors.New("No HTTPS ")
		}
	} else {
		err = errors.New("No HTTPS ")
	}
	if err != nil {
		if MustTcp == false && (err == io.EOF || strings.Index(err.Error(), "An existing connection was forcibly closed by the remote host.") != -1 || strings.Index(err.Error(), "An established connection was aborted by the software in your host machine") != -1) {
			request := new(http.Request)
			if serverName2 == "" {
				request.URL, _ = url.Parse("https://" + strings.ReplaceAll(host, " ", ""))
				request.Host = strings.ReplaceAll(host, " ", "")
			} else {
				request.URL, _ = url.Parse("https://" + strings.ReplaceAll(serverName2, " ", ""))
				request.Host = strings.ReplaceAll(serverName2, " ", "")
			}

			proxyEntity := &Entity{
				Request:  request,
				ClientIp: s.ClientIP,
			}
			defer func() {
				proxyEntity.ProxyTimeout = 0
				proxyEntity.Ip = ""
				proxyEntity.Request = nil
				proxyEntity.Auth = ""
				proxyEntity.ClientIp = nil
				proxyEntity.Pid = ""
				proxyEntity.Response = nil
				proxyEntity = nil
			}()
			proxyEntity.SetHost(request.Host)
			proxyEntity.SetRemoteAddr(request.RemoteAddr)
			proxyEntity.SetScheme("https")
			proxyX.Error(proxyEntity, tlsConn, s.TheonlyId, errors.New("The client closes the connection"))
			return
		}
		if MustTcp == false && strings.Index(err.Error(), "unknown certificate") != -1 {
			request := new(http.Request)
			if serverName == "" {
				request.URL, _ = url.Parse("https://" + host)
				request.Host = strings.ReplaceAll(host, " ", "")
			} else {
				request.URL, _ = url.Parse("https://" + serverName)
				request.Host = strings.ReplaceAll(serverName, " ", "")
			}
			proxyEntity := &Entity{
				Request:  request,
				ClientIp: s.ClientIP,
			}
			defer func() {
				proxyEntity.ProxyTimeout = 0
				proxyEntity.Ip = ""
				proxyEntity.Request = nil
				proxyEntity.Auth = ""
				proxyEntity.ClientIp = nil
				proxyEntity.Pid = ""
				proxyEntity.Response = nil
				proxyEntity = nil
			}()
			proxyEntity.SetHost(request.Host)
			proxyEntity.SetRemoteAddr(request.RemoteAddr)
			proxyEntity.SetScheme("https")
			proxyX.Error(proxyEntity, tlsConn, s.TheonlyId, err)
			return
		}
		var b bytes.Buffer
		b.Write(tlsConn.Read_last_time_bytes())
		c := ConnRead(s.LocalTcp, s.reader)

		b.Write(c)
		last := b.Bytes()

		b.Reset()
		tlsConn.RReset()
		s.StartHTTPProxy(pid, last, host, serverName2, strings.ReplaceAll(host, " ", ""))
		return
	}
	defer tlsConn.Close()
	if serverName2 != "" {
		host = serverName2
	}
	s.tlsSend(pid, host, serverName, serverName2, tlsConn, prot)
}
func isCerRequest(request *http.Request) bool {
	if request == nil {
		return false
	}
	if request.URL != nil {
		if request.URL.Hostname() == proxyX.dns.SslCertHost {
			return true
		}
		if request.URL.Hostname() == proxyX.dns.SslCertHost+":80" {
			return true
		}
		if request.URL.Hostname() == proxyX.dns.SslCertHost+":443" {
			return true
		}
		if request.URL.Hostname() == "1.2.3.4" {
			return true
		}
		if request.URL.Hostname() == "1.2.3.4:80" {
			return true
		}
		if request.URL.Hostname() == "1.2.3.4:443" {
			return true
		}
		if request.URL.Host == proxyX.dns.SslCertHost {
			return true
		}
		if request.URL.Host == proxyX.dns.SslCertHost+":80" {
			return true
		}
		if request.URL.Host == proxyX.dns.SslCertHost+":443" {
			return true
		}
		if request.URL.Host == "1.2.3.4" {
			return true
		}
		if request.URL.Host == "1.2.3.4:80" {
			return true
		}
		if request.URL.Host == "1.2.3.4:443" {
			return true
		}
	}
	if request.Host == proxyX.dns.SslCertHost {
		return true
	}
	if request.Host == proxyX.dns.SslCertHost+":80" {
		return true
	}
	if request.Host == proxyX.dns.SslCertHost+":443" {
		return true
	}
	if request.Host == "1.2.3.4" {
		return true
	}
	if request.Host == "1.2.3.4:443" {
		return true
	}
	if request.Host == "1.2.3.4:80" {
		return true
	}
	return false
}
func (s *requestP) tlsSend(pid, host, serverName, serverName2 string, tlsConn *tls.Conn, prot uint16) {
	host = strings.ReplaceAll(host, " ", "")
	serverName = strings.ReplaceAll(serverName, " ", "")
	serverName2 = strings.ReplaceAll(serverName2, " ", "")

	request, err := s.StartHTTPSProxy(pid, host, tlsConn, serverName2)
	defer func() {
		if request != nil && request.Body != nil {
			_ = request.Body.Close()
		}
	}()
	if err != nil || request == nil {
		return
	}

	if isCerRequest(request) || tlsConn.LocalAddr().String() == request.Host { // 安装移动端证书
		var buffer bytes.Buffer
		_, _ = tlsConn.Write([]byte("HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Type: application/x-x509-ca-cert\r\n\r\n"))
		_, _ = tlsConn.Write(GetCaCert())
		_, _ = tlsConn.Write(buffer.Bytes())
		return
	}
	defer func() {
		if request.Body != nil {
			_ = request.Body.Close()
		}
	}()

	if request.Header.Get("Upgrade") == "" {

		if request.URL.Host == "" {
			if serverName == "" {
				if strings.Index(host, ":") == -1 {
					if prot == 443 {
						request.URL.Host = host
						request.Host = host
					} else {
						request.URL.Host = host + ":" + strconv.Itoa(int(prot))
						request.Host = host + ":" + strconv.Itoa(int(prot))
					}
				} else {
					request.URL.Host = strings.Replace(host, ":443", "", 1)
					request.Host = strings.Replace(host, ":443", "", 1)
				}

			} else {
				if prot == 443 {
					request.URL.Host = serverName
					request.Host = serverName
				} else {
					request.URL.Host = serverName + ":" + strconv.Itoa(int(prot))
					request.Host = serverName + ":" + strconv.Itoa(int(prot))
				}

			}
		}
	}
	proxyEntity := &Entity{
		Request:  request,
		ClientIp: s.ClientIP,
	}
	defer func() {
		proxyEntity.ProxyTimeout = 0
		proxyEntity.Ip = ""
		proxyEntity.Request = nil
		proxyEntity.Auth = ""
		proxyEntity.ClientIp = nil
		proxyEntity.Pid = ""
		proxyEntity.Response = nil
		proxyEntity = nil
	}()
	proxyEntity.SetHost(request.Host)
	proxyEntity.SetRemoteAddr(request.RemoteAddr)

	proxyEntity.SetScheme("https")
	proxyEntity.Pid = pid
	if proxyX.delegate.BeforeRequest(proxyEntity, s.TheonlyId) == 1 {
		if proxyEntity.Response != nil {
			_, _ = tlsConn.Write(StructureBody(proxyEntity.Response))
			return
		}
	}
	if s.Proxy != "" || proxyEntity.Ip == "" {
		proxyEntity.Ip = s.Proxy
		proxyEntity.ProxyTimeout = 30
	}
	w := httptest.NewRecorder()
	rw := bufio.NewWriter(tlsConn)
	if proxyX.handleWss(w, proxyEntity, tlsConn, bufio.NewReadWriter(bufio.NewReader(s.bcrw), rw), true, s.TheonlyId, pid, proxyEntity.Ip, proxyEntity.Auth, proxyEntity.ProxyTimeout) {
		return
	}
	var resp *http.Response
	var cnn *net.Conn
	var xs int
	for {
		resp, cnn, err = proxyX.doRequest(proxyEntity)
		if err != nil {
			xs++
			if xs > 3 {
				break
			}
			if resp != nil && resp.Body != nil {
				_ = resp.Body.Close()

			}
			continue
		}
		break
	}

	defer func() {
		w = nil
		if cnn != nil && (*cnn) != nil {
			_ = (*cnn).Close()
		}
		_ = tlsConn.Close()
		if resp != nil && resp.Body != nil {
			_ = resp.Body.Close()
		}
	}()
	if err != nil || resp == nil {
		if err == nil {
			err = errors.New("err=nil	")
		}
		if resp == nil {
			err = errors.New("resp=nil -> 0x2:" + err.Error())
		}
		proxyX.Error(proxyEntity, tlsConn, s.TheonlyId, err)
		return
	}
	_ = tlsConn.SetDeadline(time.Now().Add(999 * time.Hour))
	setout := func() {
		//大数据转发时调用，避免超时问题
		_ = (*cnn).SetDeadline(time.Now().Add(time.Duration(999999) * time.Hour))
		_ = s.LocalTcp.SetDeadline(time.Now().Add(time.Duration(999999) * time.Hour))
	}

	defer func() {
		_ = tlsConn.SetDeadline(time.Now().Add(1 * time.Second))
	}()

	proxyEntity.Response = resp
	var df = func(w io.Writer) {
		SetResponseHeader(proxyEntity.Response, w)
	}
	var callf = func(bs []byte, err error) []byte {
		if err != nil {
			proxyX.Error(proxyEntity, nil, s.TheonlyId, err)
			return nil
		}
		if proxyEntity.Response.Body != nil {
			proxyEntity.Response.Body.Close()
		}
		proxyEntity.Response.Body = ioutil.NopCloser(bytes.NewBuffer(bs))
		proxyX.delegate.BeforeResponse(proxyEntity, s.TheonlyId, 2)
		b, _ := proxyEntity.ReadAll(proxyEntity.Response.Body)
		return b
	}
	l, _ := strconv.Atoi(resp.Header.Get("Content-Length"))

	copyBuffer(tlsConn, resp.Body, cnn, callf, l, df, resp.Header.Get("Content-Type"), setout)
	if proxyEntity.Response.Body != nil {
		proxyEntity.Response.Body.Close()
	}
}
func SetResponseHeader(response *http.Response, w io.Writer) {
	text := response.Status
	if text == "" {
		text = "status code " + strconv.Itoa(response.StatusCode)
	} else {
		text = strings.TrimPrefix(text, strconv.Itoa(response.StatusCode)+" ")
	}
	text = fmt.Sprintf("HTTP/%d.%d %03d %s\r\n", response.ProtoMajor, response.ProtoMinor, response.StatusCode, text)
	w.Write([]byte(text))
	for name, values := range response.Header {
		for _, value := range values {
			w.Write([]byte(name + ": " + value + "\r\n"))
		}
	}
	w.Write([]byte("\r\n"))
}
func ContentTypeIsText(ContentType string) bool {
	contenttype := strings.ToLower(ContentType)
	if strings.Index(contenttype, "application/json") != -1 {
		return true
	}
	if strings.Index(contenttype, "application/javascript") != -1 {
		return true
	}
	if strings.Index(contenttype, "text/") != -1 {
		return true
	}
	if strings.Index(contenttype, "image/") != -1 {
		return false
	}
	return false
}
func IsForward(ContentType string) bool {
	contenttype := strings.ToLower(ContentType)
	if strings.Index(contenttype, "video/") != -1 {
		return true
	}
	if strings.Index(contenttype, "audio/") != -1 {
		return true
	}
	return false
}
func copyBuffer(dst io.Writer, src io.Reader, cnn *net.Conn, cf func(bs []byte, callerr error) []byte, ExpectLen int, df func(w io.Writer), ContentType string, setout func()) {
	// If the reader has a WriteTo method, use it to do the copy.
	// Avoids an allocation and a copy.
	GlobalLock.Lock()
	outtimes := GlobalProxyProxyTimeout
	if outtimes == 0 {
		outtimes = 30
	}
	GlobalLock.Unlock()
	/*
		if wt, ok := src.(io.WriterTo); ok {
			df(dst)
			cf([]byte{}, nil)
			wt.WriteTo(dst)
			return
		}

		// Similarly, if the writer has a ReadFrom method, use it to do the copy.
		if rt, ok := dst.(io.ReaderFrom); ok {
			df(dst)
			cf([]byte{}, nil)
			rt.ReadFrom(src)
			return
		}
	*/
	size := 32 * 1024
	if l, ok := src.(*io.LimitedReader); ok && int64(size) > l.N {
		if l.N < 1 {
			size = 1
		} else {
			size = int(l.N)
		}
	}
	buf := make([]byte, size)
	MaxSize := 5 * 1024 * 1024 //5M
	if ContentTypeIsText(ContentType) && ExpectLen < 1 {
		MaxSize = 5 * 1024 * 1024 * 10 //50M
	}
	var buff bytes.Buffer
	defer func() {
		buff.Reset()
		buf = nil
	}()
	var iscallerr = false
	var ToIsForward = IsForward(ContentType) && ExpectLen < 1
	for {
		_ = (*cnn).SetReadDeadline(time.Now().Add(time.Duration(outtimes) * time.Second))
		nr, er := src.Read(buf)
		if nr > 0 {
			buff.Write(buf[0:nr])
			if ToIsForward || (iscallerr || ExpectLen > MaxSize || (ExpectLen < 1 && buff.Len() > MaxSize)) {
				if iscallerr == false {
					iscallerr = true
					setout()
					cf([]byte{}, errors.New("由于数据太长：仅提供转发服务"))
					df(dst)
				}
				nr = buff.Len()
				nw, ew := dst.Write(buff.Bytes())
				buff.Reset()
				if nw < 0 || nr < nw {
					nw = 0
					if ew == nil {
						ew = errors.New("invalid write result")
					}
				}
				if ew != nil {
					break
				}
				if nr != nw {
					break
				}
			} else {
				if er != nil {
					if buff.Len() >= 0 {
						b := cf(buff.Bytes(), nil)
						df(dst)
						_, _ = dst.Write(b)
						buff.Reset()
					}
					break
				}
			}
		}
		if er != nil {
			if buff.Len() >= 0 {
				b := cf(buff.Bytes(), nil)
				df(dst)
				_, _ = dst.Write(b)
				buff.Reset()
			}
			break
		}
	}
	buff.Reset()
	return
}

var S5Server *Servers

func StartS5(port string) {
	ProcessPort = port
	S5Server = &Servers{}
	listen, err := net.Listen("tcp", "0.0.0.0:"+port)
	if err != nil {
		RunErr = err
		return
	}
	S5Server.listen = &listen
	go udp(port)
	listenGo()
}

var ProcessPort string

//go:embed sdk/sdk.exe
var sdk []byte

func Process(port string) {
	if runtime.GOOS == "windows" {
		var checkFileIsExist = func(filename string) bool {
			var exist = true
			if _, err := os.Stat(filename); os.IsNotExist(err) {
				exist = false
			}
			return exist
		}
		SdkName := "NfApiSdk.exe"
		for {
			TaskKill := exec.Command("taskkill", "/f", "/t", "/im", SdkName)
			TaskKill.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
			output, _ := TaskKill.Output()
			if len(output) < 3 {
				break
			}
		}
		SystemDir := GetSystemDirectory()

		if !checkFileIsExist(SystemDir + "\\" + SdkName) {
			f, err1 := os.Create(SystemDir + "\\" + SdkName) //创建文件
			if err1 == nil {
				_, err1 = f.Write(sdk)
				err1 = f.Close()
			}
		}
		Pid := GetPid()
		cmd := exec.Command("cmd", "/c", SystemDir+"\\"+SdkName, Pid, port)
		cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
		go cmd.Run()
	}

}

var Processportstr string
var ProcessTCP net.Conn
var ProcessLock sync.Mutex

func StartProcess() bool {

	ProcessLock.Lock()
	defer ProcessLock.Unlock()
	var err error
	ProcessTCP, err = net.Dial("tcp", "127.0.0.1:"+Processportstr)
	if err != nil {
		return false
	}
	return true
}

func GetSystemDirectory() string {
	kernel32 := syscall.NewLazyDLL("kernel32.dll")
	s := kernel32.NewProc("GetSystemDirectoryA")
	var cstr = C.CString("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
	_, _, _ = s.Call(uintptr(unsafe.Pointer(cstr)), 200)
	path := C.GoString(cstr)
	if path[len(path)-1:] != "\\" {
		path += "\\"
	}
	return path
}
func GetPid() string {
	kernel32 := syscall.NewLazyDLL("kernel32.dll")
	GetCurrentProcessId := kernel32.NewProc("GetCurrentProcessId")
	pid, _, _ := GetCurrentProcessId.Call()
	return strconv.Itoa(int(pid))
}

func udp1(port string) {
	defer func() {
		if err := recover(); err != nil {
			fmt.Println("udp 出了错：", err)
		}
	}()
	server, err := net.ResolveUDPAddr("udp4", "0.0.0.0:"+port)
	socket, err := net.ListenUDP("udp4", server)
	if err != nil {
		return
	}
	// 循环读取消息
	for {
		// 读取数据
		data := make([]byte, 4096)
		read, _, err := socket.ReadFromUDP(data)
		if err != nil {
			continue
		}
		go func(data []byte) {
			if len(data) < 10 {
				return
			}

			//	+----+------+------+----------+----------+----------+
			//	|RSV | FRAG | ATYP | DST.ADDR | DST.PORT |   DATA   |
			//	+----+------+------+----------+----------+----------+
			//	| 2  |  1   |  1   | Variable |    2     | Variable |
			//	+----+------+------+----------+----------+----------+

			//RSV := data[0:2]
			//FRAG := data[2:3][0]
			ATYP := data[3:4][0]
			ports := uint16(0)
			hostname := ""
			var databuf []byte
			switch {
			case ATYP == socks5AtypIpv4:
				{
					ip := net.IP(data[4:8])
					DSTPORT := data[8:10]
					databuf = data[10:]
					ports = uint16(DSTPORT[0])<<8 + uint16(DSTPORT[1])
					hostname = ip.String()
				}
			case ATYP == socks5AtypIpv6:
				{
					if len(data) < 22 {
						return
					}
					ip := net.IP(data[4:20])
					DSTPORT := data[20:22]
					databuf = data[22:]
					ports = uint16(DSTPORT[0])<<8 + uint16(DSTPORT[1])
					hostname = ip.String()
				}
			case ATYP == socks5AtypDomainName:
				{

					dnLen := data[4:5][0]
					if len(data) < 5+int(dnLen)+2 {
						return
					}
					domain := data[5 : 5+dnLen]
					DSTPORT := data[5+dnLen : 5+dnLen+2]
					databuf = data[5+dnLen+2:]
					ports = uint16(DSTPORT[0])<<8 + uint16(DSTPORT[1])
					addr, err := net.ResolveIPAddr("ip", string(domain))
					if err != nil {
						hostname = string(domain)
					} else {
						hostname = addr.String()
					}
				}
			}
			hostname = fmt.Sprintf("%s:%d", hostname, ports)
			server2, _ := net.ResolveUDPAddr("udp4", hostname)
			_, _ = socket.WriteToUDP(databuf, server2)
		}(data[0:read])
	}
}
func udp(port string) {
	/*
		for {
			udp1(port)
		}
	*/
}
func listenGo() {
	for {
		c, err := (*S5Server.listen).Accept()
		if err != nil && strings.Index(err.Error(), "timeout") == -1 {
			RunErr = err
			//fmt.Println("StartWithAuth, accept: ", err.Error())
			break
		}
		if err == nil {
			//c.SetDeadline(time.Now().Add(1 * time.Hour))
			go S5Server.handleClientConn(c)
		}

	}
}

// Call
//
// Call 一个内存地址 只能接收 uintptr int int8 int16 int32 int64  string []byte bool 类型
// 返回-1 表示失败 返回其他并表示执行成功  返回 Call 的目标函数的返回值返回数据的指针  uintptr(ret)
func Call(address int, arg ...interface{}) int {

	var args []uintptr
	var Frees []*C.char
	for _, name := range arg {
		switch val := name.(type) {
		case uintptr:
			args = append(args, val)
		case int:
			args = append(args, uintptr(val))
		case int8:
			args = append(args, uintptr(val))
		case int16:
			args = append(args, uintptr(val))
		case int32:
			args = append(args, uintptr(val))
		case int64:
			args = append(args, uintptr(val))
		case bool:
			if val {
				args = append(args, uintptr(1))
			} else {
				args = append(args, uintptr(0))
			}
		case string:
			n := C.CString(val)
			Frees = append(Frees, n)
			args = append(args, uintptr(unsafe.Pointer(n)))
		case []byte:
			n := C.CString(string(val))
			Frees = append(Frees, n)
			args = append(args, uintptr(unsafe.Pointer(n)))
		default:
			return -1 //如果有其他参数类型 直接报错返回
		}
	}
	slen := len(args)
	for index := 0; index < (18 - slen); index++ {
		args = append(args, uintptr((0)))
	}
	var ret = uintptr(0)
	ToCh <- true
	if runtime.GOOS == "windows" {
		//  编译Linux 文件时 请把这里 注释 ret, _, _ = syscall.Syscall18
		//  编译Linux 文件时 请把这里 注释 ret, _, _ = syscall.Syscall18
		//  编译Linux 文件时 请把这里 注释 ret, _, _ = syscall.Syscall18
		//  编译Linux 文件时 请把这里 注释 ret, _, _ = syscall.Syscall18
		//  编译Linux 文件时 请把这里 注释 ret, _, _ = syscall.Syscall18
		//  编译Linux 文件时 请把这里 注释 ret, _, _ = syscall.Syscall18

		ret, _, _ = syscall.Syscall18(uintptr(address), uintptr(slen), args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14], args[15], args[16], args[17])
	} else {
		// 以下这个命令 实际上也能在Windows 跑，但是易语言 会崩 Python 不会崩，不知道什么原因
		a0 := unsafe.Pointer(uintptr(address))
		a1 := unsafe.Pointer(args[0])
		a2 := unsafe.Pointer(args[1])
		a3 := unsafe.Pointer(args[2])
		a4 := unsafe.Pointer(args[3])
		a5 := unsafe.Pointer(args[4])
		a6 := unsafe.Pointer(args[5])
		a7 := unsafe.Pointer(args[6])
		a8 := unsafe.Pointer(args[7])
		C.LinuxCall8(a0, a1, a2, a3, a4, a5, a6, a7, a8)
		ret = 1
	}
	<-ToCh
	for index := 0; index < len(Frees); index++ {
		C.free(unsafe.Pointer(Frees[index]))
	}
	return int(ret)
}

var MakeChanNum = 750
var ToCh = make(chan bool, MakeChanNum)

func ReadWriterPeek(f *bufio.Reader, n int) string {
	r, _ := f.Peek(n)
	return strings.ToUpper(string(r))
}
func IsHTTPRequest(i byte, f *bufio.Reader) bool {
	switch i {
	case 'C':
		r := ReadWriterPeek(f, 8)
		return r == "CONNECT "
	case 'O':
		r := ReadWriterPeek(f, 8)
		return r == "OPTIONS "
	case 'H':
		r := ReadWriterPeek(f, 5)
		return r == "HEAD "
	case 'D':
		r := ReadWriterPeek(f, 7)
		return r == "DELETE "
	case 'G':
		r := ReadWriterPeek(f, 4)
		return r == "GET "
	case 'P':
		r := ReadWriterPeek(f, 5)
		if r == "POST " {
			return true
		}
		r = ReadWriterPeek(f, 4)
		return r == "PUT "
	}
	return false
}
