223 lines
5.5 KiB
Go
223 lines
5.5 KiB
Go
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:
|
|
}
|
|
}
|