From 816feb2755b6669064c1393a237717d77199aa78 Mon Sep 17 00:00:00 2001 From: rosahaj Date: Wed, 10 Jan 2024 03:35:39 +0100 Subject: [PATCH] fix: reply with sni-specific certs --- cert.go | 160 +++++++++++++++++++++++++++++++++++++++++++++--------- config.go | 15 ++++- go.mod | 10 ++++ go.sum | 76 ++++++++++++++++++++++++++ main.go | 28 +++++++--- proxy.go | 19 ++++--- 6 files changed, 266 insertions(+), 42 deletions(-) diff --git a/cert.go b/cert.go index 17ca94e..0e9724f 100644 --- a/cert.go +++ b/cert.go @@ -1,63 +1,169 @@ package main import ( + "crypto" + "crypto/ecdsa" + "crypto/elliptic" "crypto/rand" - "crypto/rsa" "crypto/tls" "crypto/x509" - "crypto/x509/pkix" "encoding/pem" - "log" - "math/big" "os" - "time" + "strings" + + cfconfig "github.com/cloudflare/cfssl/config" + cfsr "github.com/cloudflare/cfssl/csr" + "github.com/cloudflare/cfssl/initca" + cfsigner "github.com/cloudflare/cfssl/signer" + "github.com/cloudflare/cfssl/signer/local" ) -func generateCertificate() error { - priv, err := rsa.GenerateKey(rand.Reader, 2048) +func generateCA() error { + csr := cfsr.CertificateRequest{ + CN: "ja3proxy CA", + KeyRequest: cfsr.NewKeyRequest(), + } + + certPEM, _, keyPEM, err := initca.New(&csr) if err != nil { return err } - notBefore := time.Now() - notAfter := notBefore.Add(365 * 24 * time.Hour) - template := x509.Certificate{ - SerialNumber: big.NewInt(1), - Subject: pkix.Name{CommonName: "localhost"}, - NotBefore: notBefore, - NotAfter: notAfter, - KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, - ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, - BasicConstraintsValid: true, - IsCA: true, + tlsCert, err := tls.X509KeyPair(certPEM, keyPEM) + if err != nil { + return err } - derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv) + x509Cert, err := x509.ParseCertificate(tlsCert.Certificate[0]) if err != nil { return err } - certOut, err := os.Create(Config.Cert) + CA.tlsCert = tlsCert + CA.x509Cert = x509Cert + + caOut, err := os.Create(Config.Cert) + if err != nil { + return err + } + defer caOut.Close() + _, err = caOut.Write(certPEM) if err != nil { return err } - defer certOut.Close() - pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}) keyOut, err := os.OpenFile(Config.Key, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) if err != nil { return err } defer keyOut.Close() - pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)}) + + _, err = keyOut.Write(keyPEM) + if err != nil { + return err + } + + return nil +} + +func generateSessionKey() error { + privKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + return err + } + + derBytes, err := x509.MarshalECPrivateKey(privKey) + if err != nil { + return err + } + + PEMBlock := pem.EncodeToMemory(&pem.Block{Type: "EC PRIVATE KEY", Bytes: derBytes}) + + SessionKey.privateKey = privKey + SessionKey.PEMBlock = PEMBlock + return nil } -func loadCertificate() { - cert, err := tls.LoadX509KeyPair(Config.Cert, Config.Key) +// Credit: elazarl/goproxy (https://github.com/elazarl/goproxy/blob/7cc037d33fb57d20c2fa7075adaf0e2d2862da78/https.go#L50) +func stripPort(s string) string { + var ix int + if strings.Contains(s, "[") && strings.Contains(s, "]") { + //ipv6 : for example : [2606:4700:4700::1111]:443 + + //strip '[' and ']' + s = strings.ReplaceAll(s, "[", "") + s = strings.ReplaceAll(s, "]", "") + + ix = strings.LastIndexAny(s, ":") + if ix == -1 { + return s + } + } else { + //ipv4 + ix = strings.IndexRune(s, ':') + if ix == -1 { + return s + } + + } + return s[:ix] +} + +func generateCertificate(sni string) (tls.Certificate, error) { + hostname := stripPort(sni) + request := &cfsr.CertificateRequest{ + CN: hostname, + Hosts: []string{hostname}, + KeyRequest: cfsr.NewKeyRequest(), + } + + csrBytes, err := cfsr.Generate(SessionKey.privateKey, request) + if err != nil { + return tls.Certificate{}, err + } + + cryptoSigner := CA.tlsCert.PrivateKey.(crypto.Signer) + profile := cfconfig.DefaultConfig() + policy := &cfconfig.Signing{ + Default: profile, + } + + signer, err := local.NewSigner(cryptoSigner, CA.x509Cert, cfsigner.DefaultSigAlgo(cryptoSigner), policy) if err != nil { - log.Fatal(err) + return tls.Certificate{}, err + } + + signRequest := cfsigner.SignRequest{ + Request: string(csrBytes), + Subject: &cfsigner.Subject{ + CN: request.CN, + }, + Hosts: request.Hosts, + } + + certBytes, err := signer.Sign(signRequest) + if err != nil { + return tls.Certificate{}, err + } + + tlsCert, err := tls.X509KeyPair(certBytes, SessionKey.PEMBlock) + return tlsCert, err +} + +func loadExistingCA() error { + tlsCert, err := tls.LoadX509KeyPair(Config.Cert, Config.Key) + if err != nil { + return err } else { - LoadedCert = cert + x509Cert, err := x509.ParseCertificate(tlsCert.Certificate[0]) + if err != nil { + return err + } + + CA.tlsCert = tlsCert + CA.x509Cert = x509Cert + + return nil } } diff --git a/config.go b/config.go index d66ced9..418a205 100644 --- a/config.go +++ b/config.go @@ -1,7 +1,9 @@ package main import ( + "crypto/ecdsa" "crypto/tls" + "crypto/x509" ) type RunningConfig struct { @@ -15,8 +17,19 @@ type RunningConfig struct { Upstream string } +type CertificateAuthority struct { + tlsCert tls.Certificate + x509Cert *x509.Certificate +} + +type SessionKeyHelper struct { + privateKey *ecdsa.PrivateKey + PEMBlock []byte +} + var ( Config RunningConfig - LoadedCert tls.Certificate CustomDialer *UpstreamDialer + CA CertificateAuthority + SessionKey SessionKeyHelper ) diff --git a/go.mod b/go.mod index d5d9562..94345f8 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/lylemi/ja3proxy go 1.20 require ( + github.com/cloudflare/cfssl v1.6.4 github.com/refraction-networking/utls v1.3.2 golang.org/x/net v0.7.0 ) @@ -10,7 +11,16 @@ require ( require ( github.com/andybalholm/brotli v1.0.4 // indirect github.com/gaukas/godicttls v0.0.3 // indirect + github.com/go-logr/logr v1.2.0 // indirect + github.com/google/certificate-transparency-go v1.1.4 // indirect + github.com/jmoiron/sqlx v1.3.3 // indirect github.com/klauspost/compress v1.15.15 // indirect + github.com/weppos/publicsuffix-go v0.15.1-0.20210511084619-b1f36a2d6c0b // indirect + github.com/zmap/zcrypto v0.0.0-20210511125630-18f1e0152cfc // indirect + github.com/zmap/zlint/v3 v3.1.0 // indirect golang.org/x/crypto v0.5.0 // indirect golang.org/x/sys v0.5.0 // indirect + golang.org/x/text v0.7.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + k8s.io/klog/v2 v2.80.1 // indirect ) diff --git a/go.sum b/go.sum index 2100be6..ffd421e 100644 --- a/go.sum +++ b/go.sum @@ -1,14 +1,90 @@ github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/cloudflare/cfssl v1.6.4 h1:NMOvfrEjFfC63K3SGXgAnFdsgkmiq4kATme5BfcqrO8= +github.com/cloudflare/cfssl v1.6.4/go.mod h1:8b3CQMxfWPAeom3zBnGJ6sd+G1NkL5TXqmDXacb+1J0= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/gaukas/godicttls v0.0.3 h1:YNDIf0d9adcxOijiLrEzpfZGAkNwLRzPaG6OjU7EITk= github.com/gaukas/godicttls v0.0.3/go.mod h1:l6EenT4TLWgTdwslVb4sEMOCf7Bv0JAK67deKr9/NCI= +github.com/go-logr/logr v1.2.0 h1:QK40JKJyMdUDz+h+xvCsru/bJhvG0UxvePV0ufL/AcE= +github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/google/certificate-transparency-go v1.1.4 h1:hCyXHDbtqlr/lMXU0D4WgbalXL0Zk4dSWWMbPV8VrqY= +github.com/google/certificate-transparency-go v1.1.4/go.mod h1:D6lvbfwckhNrbM9WVl1EVeMOyzC19mpIjMOI4nxBHtQ= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/jmoiron/sqlx v1.3.3 h1:j82X0bf7oQ27XeqxicSZsTU5suPwKElg3oyxNn43iTk= +github.com/jmoiron/sqlx v1.3.3/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ= github.com/klauspost/compress v1.15.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw= github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/refraction-networking/utls v1.3.2 h1:o+AkWB57mkcoW36ET7uJ002CpBWHu0KPxi6vzxvPnv8= github.com/refraction-networking/utls v1.3.2/go.mod h1:fmoaOww2bxzzEpIKOebIsnBvjQpqP7L2vcm/9KUfm/E= +github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/weppos/publicsuffix-go v0.13.1-0.20210123135404-5fd73613514e/go.mod h1:HYux0V0Zi04bHNwOHy4cXJVz/TQjYonnF6aoYhj+3QE= +github.com/weppos/publicsuffix-go v0.15.1-0.20210511084619-b1f36a2d6c0b h1:FsyNrX12e5BkplJq7wKOLk0+C6LZ+KGXvuEcKUYm5ss= +github.com/weppos/publicsuffix-go v0.15.1-0.20210511084619-b1f36a2d6c0b/go.mod h1:HYux0V0Zi04bHNwOHy4cXJVz/TQjYonnF6aoYhj+3QE= +github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE= +github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4/go.mod h1:5iU54tB79AMBcySS0R2XIyZBAVmeHranShAFELYx7is= +github.com/zmap/zcrypto v0.0.0-20210123152837-9cf5beac6d91/go.mod h1:R/deQh6+tSWlgI9tb4jNmXxn8nSCabl5ZQsBX9//I/E= +github.com/zmap/zcrypto v0.0.0-20210511125630-18f1e0152cfc h1:zkGwegkOW709y0oiAraH/3D8njopUR/pARHv4tZZ6pw= +github.com/zmap/zcrypto v0.0.0-20210511125630-18f1e0152cfc/go.mod h1:FM4U1E3NzlNMRnSUTU3P1UdukWhYGifqEsjk9fn7BCk= +github.com/zmap/zlint/v3 v3.1.0 h1:WjVytZo79m/L1+/Mlphl09WBob6YTGljN5IGWZFpAv0= +github.com/zmap/zlint/v3 v3.1.0/go.mod h1:L7t8s3sEKkb0A2BxGy1IWrxt1ZATa1R4QfJZaQOD3zU= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE= golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +k8s.io/klog/v2 v2.80.1 h1:atnLQ121W371wYYFawwYx1aEY2eUfs4l3J72wtgAwV4= +k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= diff --git a/main.go b/main.go index 75714c4..b492678 100644 --- a/main.go +++ b/main.go @@ -7,11 +7,17 @@ import ( "net/http" "os" "time" + + cflog "github.com/cloudflare/cfssl/log" ) +func init() { + cflog.Level = cflog.LevelWarning +} + func main() { - flag.StringVar(&Config.Cert, "cert", "cert.pem", "proxy tls cert") - flag.StringVar(&Config.Key, "key", "key.pem", "proxy tls key") + flag.StringVar(&Config.Cert, "cert", "cert.pem", "proxy CA cert") + flag.StringVar(&Config.Key, "key", "key.pem", "proxy CA key") flag.StringVar(&Config.Addr, "addr", "", "proxy listen host") flag.StringVar(&Config.Port, "port", "8080", "proxy listen port") flag.StringVar(&Config.TLSClient, "client", "Golang", "utls client") @@ -20,20 +26,28 @@ func main() { flag.BoolVar(&Config.Debug, "debug", false, "enable debug") flag.Parse() + if Config.Debug { + cflog.Level = cflog.LevelDebug + } + if !fileExists(Config.Cert) || !fileExists(Config.Key) { if fileExists(Config.Cert) { - log.Println("found cert, but no corresponding key") + log.Println("found CA cert, but no corresponding key") os.Exit(-1) } else if fileExists(Config.Key) { - log.Println("found key, but no corresponding cert") + log.Println("found CA key, but no corresponding cert") os.Exit(-1) } - log.Println("cert and key do not exist, generating") - generateCertificate() + log.Println("CA cert and key do not exist, generating") + err := generateCA() + if err != nil { + log.Fatal("Failed generating CA", err) + } } - loadCertificate() + loadExistingCA() + generateSessionKey() var err error CustomDialer, err = NewUpstreamDialer(Config.Upstream, time.Second*10) diff --git a/proxy.go b/proxy.go index f73eaa3..7957bb8 100644 --- a/proxy.go +++ b/proxy.go @@ -45,7 +45,7 @@ func handleTunneling(w http.ResponseWriter, r *http.Request) { if err != nil { http.Error(w, err.Error(), http.StatusServiceUnavailable) - log.Println("Tunneling err", err) + log.Println("Tunneling err: ", err) return } w.WriteHeader(http.StatusOK) @@ -59,7 +59,7 @@ func handleTunneling(w http.ResponseWriter, r *http.Request) { clientConn, _, err := hijacker.Hijack() if err != nil { http.Error(w, err.Error(), http.StatusServiceUnavailable) - log.Println("Hijack error", err) + log.Println("Hijack error: ", err) } go connect(strings.Split(r.Host, ":")[0], destConn, clientConn) } @@ -82,13 +82,18 @@ func connect(sni string, destConn net.Conn, clientConn net.Conn) { defer clientConn.Close() destTLSConn, err := customTLSWrap(destConn, sni) if err != nil { - fmt.Println("TLS handshake failed:", err) + fmt.Println("TLS handshake failed: ", err) return } + tlsCert, err := generateCertificate(sni) + if err != nil { + fmt.Println("Error generating certificate: ", err) + } + config := &tls.Config{ InsecureSkipVerify: true, - Certificates: []tls.Certificate{LoadedCert}, + Certificates: []tls.Certificate{tlsCert}, } state := destTLSConn.ConnectionState() @@ -103,7 +108,7 @@ func connect(sni string, destConn net.Conn, clientConn net.Conn) { ) err = clientTLSConn.Handshake() if err != nil { - log.Println("Failed to perform TLS handshake:", err) + log.Println("Failed to perform TLS handshake: ", err) return } @@ -120,7 +125,7 @@ func junction(destConn net.Conn, clientConn net.Conn) { go func() { _, err := io.Copy(destConn, clientConn) if err != nil { - log.Println("copy dest to client error", err) + log.Println("copy dest to client error: ", err) } chDone <- true }() @@ -128,7 +133,7 @@ func junction(destConn net.Conn, clientConn net.Conn) { go func() { _, err := io.Copy(clientConn, destConn) if err != nil { - log.Println("copy client to dest error", err) + log.Println("copy client to dest error: ", err) } chDone <- true }()