package gost import ( "crypto/rand" "crypto/rsa" "crypto/tls" "crypto/x509" "crypto/x509/pkix" "encoding/pem" "errors" "io" "math/big" "net" "net/http" "strings" "sync" "time" "github.com/go-log/log" ) // Version is the gost version. const Version = "2.11.2-EvanMod-v1.2.3" const ProxyAgent = "nginx" // Debug is a flag that enables the debug log. var Debug bool var ( tinyBufferSize = 512 smallBufferSize = 2 * 1024 // 2KB small buffer mediumBufferSize = 8 * 1024 // 8KB medium buffer largeBufferSize = 32 * 1024 // 32KB large buffer ) var ( sPool = sync.Pool{ New: func() interface{} { return make([]byte, smallBufferSize) }, } mPool = sync.Pool{ New: func() interface{} { return make([]byte, mediumBufferSize) }, } lPool = sync.Pool{ New: func() interface{} { return make([]byte, largeBufferSize) }, } ) var ( // KeepAliveTime is the keep alive time period for TCP connection. KeepAliveTime = 180 * time.Second // DialTimeout is the timeout of dial. DialTimeout = 5 * time.Second // HandshakeTimeout is the timeout of handshake. HandshakeTimeout = 5 * time.Second // ConnectTimeout is the timeout for connect. ConnectTimeout = 5 * time.Second // ReadTimeout is the timeout for reading. ReadTimeout = 10 * time.Second // WriteTimeout is the timeout for writing. WriteTimeout = 10 * time.Second // PingTimeout is the timeout for pinging. PingTimeout = 30 * time.Second // PingRetries is the reties of ping. PingRetries = 1 // default udp node TTL in second for udp port forwarding. defaultTTL = 60 * time.Second defaultBacklog = 1024 defaultQueueSize = 1024 ) var ( // DefaultTLSConfig is a default TLS config for internal use. DefaultTLSConfig *tls.Config // DefaultUserAgent is the default HTTP User-Agent header used by HTTP and websocket. DefaultUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36" // DefaultMTU is the default mtu for tun/tap device DefaultMTU = 1350 ) var ( DefaultExternalResolver Resolver DefaultDNSServer = "114.114.114.114:53" ) // SetLogger sets a new logger for internal log system. func SetLogger(logger log.Logger) { log.DefaultLogger = logger } // GenCertificate generates a random TLS certificate. func GenCertificate() (cert tls.Certificate, err error) { rawCert, rawKey, err := generateKeyPair() if err != nil { return } return tls.X509KeyPair(rawCert, rawKey) } func generateKeyPair() (rawCert, rawKey []byte, err error) { // Create private key and self-signed certificate // Adapted from https://golang.org/src/crypto/tls/generate_cert.go priv, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { return } validFor := time.Hour * 24 * 365 * 10 // ten years notBefore := time.Now() notAfter := notBefore.Add(validFor) serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) template := x509.Certificate{ SerialNumber: serialNumber, Subject: pkix.Name{ Organization: []string{"gost"}, }, NotBefore: notBefore, NotAfter: notAfter, KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, BasicConstraintsValid: true, } derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv) if err != nil { return } rawCert = pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes}) rawKey = pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)}) return } type readWriter struct { r io.Reader w io.Writer } func (rw *readWriter) Read(p []byte) (n int, err error) { return rw.r.Read(p) } func (rw *readWriter) Write(p []byte) (n int, err error) { return rw.w.Write(p) } var ( nopClientConn = &nopConn{} ) // a nop connection implements net.Conn, // it does nothing. type nopConn struct{} func (c *nopConn) Read(b []byte) (n int, err error) { return 0, &net.OpError{Op: "read", Net: "nop", Source: nil, Addr: nil, Err: errors.New("read not supported")} } func (c *nopConn) Write(b []byte) (n int, err error) { return 0, &net.OpError{Op: "write", Net: "nop", Source: nil, Addr: nil, Err: errors.New("write not supported")} } func (c *nopConn) Close() error { return nil } func (c *nopConn) LocalAddr() net.Addr { return nil } func (c *nopConn) RemoteAddr() net.Addr { return nil } func (c *nopConn) SetDeadline(t time.Time) error { return &net.OpError{Op: "set", Net: "nop", Source: nil, Addr: nil, Err: errors.New("deadline not supported")} } func (c *nopConn) SetReadDeadline(t time.Time) error { return &net.OpError{Op: "set", Net: "nop", Source: nil, Addr: nil, Err: errors.New("deadline not supported")} } func (c *nopConn) SetWriteDeadline(t time.Time) error { return &net.OpError{Op: "set", Net: "nop", Source: nil, Addr: nil, Err: errors.New("deadline not supported")} } // splitLine splits a line text by white space, mainly used by config parser. func splitLine(line string) []string { if line == "" { return nil } if n := strings.IndexByte(line, '#'); n >= 0 { line = line[:n] } line = strings.Replace(line, "\t", " ", -1) line = strings.TrimSpace(line) var ss []string for _, s := range strings.Split(line, " ") { if s = strings.TrimSpace(s); s != "" { ss = append(ss, s) } } return ss } func connStateCallback(conn net.Conn, cs http.ConnState) { switch cs { case http.StateNew: conn.SetReadDeadline(time.Now().Add(30 * time.Second)) default: } }