add more detail info for routing
This commit is contained in:
parent
0bb52bc7bc
commit
7686a4bdc8
@ -152,7 +152,7 @@ func NewBypassPatterns(reversed bool, patterns ...string) *Bypass {
|
|||||||
|
|
||||||
// Contains reports whether the bypass includes addr.
|
// Contains reports whether the bypass includes addr.
|
||||||
func (bp *Bypass) Contains(addr string) bool {
|
func (bp *Bypass) Contains(addr string) bool {
|
||||||
if bp == nil {
|
if bp == nil || addr == "" {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
// try to strip the port
|
// try to strip the port
|
||||||
|
58
chain.go
58
chain.go
@ -1,9 +1,7 @@
|
|||||||
package gost
|
package gost
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -20,6 +18,7 @@ type Chain struct {
|
|||||||
isRoute bool
|
isRoute bool
|
||||||
Retries int
|
Retries int
|
||||||
nodeGroups []*NodeGroup
|
nodeGroups []*NodeGroup
|
||||||
|
route []Node // nodes in the selected route
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewChain creates a proxy chain with a list of proxy nodes.
|
// NewChain creates a proxy chain with a list of proxy nodes.
|
||||||
@ -197,18 +196,14 @@ func (c *Chain) Conn(opts ...ChainOption) (conn net.Conn, err error) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
conn, err = route.getConn()
|
conn, err = route.getConn()
|
||||||
if err != nil {
|
if err == nil {
|
||||||
log.Log(err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// getConn obtains a connection to the last node of the chain.
|
// getConn obtains a connection to the last node of the chain.
|
||||||
// It does not handshake with the last node.
|
|
||||||
func (c *Chain) getConn() (conn net.Conn, err error) {
|
func (c *Chain) getConn() (conn net.Conn, err error) {
|
||||||
if c.IsEmpty() {
|
if c.IsEmpty() {
|
||||||
err = ErrEmptyChain
|
err = ErrEmptyChain
|
||||||
@ -256,35 +251,7 @@ func (c *Chain) getConn() (conn net.Conn, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Chain) selectRoute() (route *Chain, err error) {
|
func (c *Chain) selectRoute() (route *Chain, err error) {
|
||||||
if c.IsEmpty() || c.isRoute {
|
return c.selectRouteFor("")
|
||||||
return c, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
buf := bytes.Buffer{}
|
|
||||||
route = newRoute()
|
|
||||||
|
|
||||||
for _, group := range c.nodeGroups {
|
|
||||||
node, err := group.Next()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
buf.WriteString(fmt.Sprintf("%s -> ", node.String()))
|
|
||||||
|
|
||||||
if node.Client.Transporter.Multiplex() {
|
|
||||||
node.DialOptions = append(node.DialOptions,
|
|
||||||
ChainDialOption(route),
|
|
||||||
)
|
|
||||||
route = newRoute() // cutoff the chain for multiplex.
|
|
||||||
}
|
|
||||||
|
|
||||||
route.AddNode(node)
|
|
||||||
}
|
|
||||||
route.Retries = c.Retries
|
|
||||||
|
|
||||||
if Debug {
|
|
||||||
log.Log("select route:", buf.String())
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// selectRouteFor selects route with bypass testing.
|
// selectRouteFor selects route with bypass testing.
|
||||||
@ -293,8 +260,8 @@ func (c *Chain) selectRouteFor(addr string) (route *Chain, err error) {
|
|||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
buf := bytes.Buffer{}
|
|
||||||
route = newRoute()
|
route = newRoute()
|
||||||
|
var nl []Node
|
||||||
|
|
||||||
for _, group := range c.nodeGroups {
|
for _, group := range c.nodeGroups {
|
||||||
var node Node
|
var node Node
|
||||||
@ -304,28 +271,21 @@ func (c *Chain) selectRouteFor(addr string) (route *Chain, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if node.Bypass.Contains(addr) {
|
if node.Bypass.Contains(addr) {
|
||||||
if Debug {
|
break
|
||||||
buf.WriteString(fmt.Sprintf("[bypass]%s -> %s", node.String(), addr))
|
|
||||||
log.Log("[route]", buf.String())
|
|
||||||
}
|
}
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
buf.WriteString(fmt.Sprintf("%s -> ", node.String()))
|
|
||||||
|
|
||||||
if node.Client.Transporter.Multiplex() {
|
if node.Client.Transporter.Multiplex() {
|
||||||
node.DialOptions = append(node.DialOptions,
|
node.DialOptions = append(node.DialOptions,
|
||||||
ChainDialOption(route),
|
ChainDialOption(route),
|
||||||
)
|
)
|
||||||
route = newRoute() // cutoff the chain for multiplex.
|
route = newRoute() // cutoff the chain for multiplex node.
|
||||||
}
|
}
|
||||||
|
|
||||||
route.AddNode(node)
|
route.AddNode(node)
|
||||||
|
nl = append(nl, node)
|
||||||
}
|
}
|
||||||
route.Retries = c.Retries
|
|
||||||
|
|
||||||
buf.WriteString(addr)
|
route.route = nl
|
||||||
log.Log("[route]", buf.String())
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
1
cmd/gost/.config/probe_resist.txt
Normal file
1
cmd/gost/.config/probe_resist.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
Hello World!
|
@ -1,21 +0,0 @@
|
|||||||
{
|
|
||||||
"key": "it's a secrect",
|
|
||||||
"crypt": "aes",
|
|
||||||
"mode": "fast",
|
|
||||||
"mtu" : 1350,
|
|
||||||
"sndwnd": 1024,
|
|
||||||
"rcvwnd": 1024,
|
|
||||||
"datashard": 10,
|
|
||||||
"parityshard": 3,
|
|
||||||
"dscp": 0,
|
|
||||||
"nocomp": false,
|
|
||||||
"acknodelay": false,
|
|
||||||
"nodelay": 0,
|
|
||||||
"interval": 40,
|
|
||||||
"resend": 0,
|
|
||||||
"nc": 0,
|
|
||||||
"sockbuf": 4194304,
|
|
||||||
"keepalive": 10,
|
|
||||||
"snmplog": "",
|
|
||||||
"snmpperiod": 60
|
|
||||||
}
|
|
@ -407,7 +407,8 @@ func (r *route) GenRouters() ([]router, error) {
|
|||||||
hosts := parseHosts(node.Get("hosts"))
|
hosts := parseHosts(node.Get("hosts"))
|
||||||
|
|
||||||
handler.Init(
|
handler.Init(
|
||||||
gost.AddrHandlerOption(node.Addr),
|
// gost.AddrHandlerOption(node.Addr),
|
||||||
|
gost.AddrHandlerOption(ln.Addr().String()),
|
||||||
gost.ChainHandlerOption(chain),
|
gost.ChainHandlerOption(chain),
|
||||||
gost.UsersHandlerOption(users...),
|
gost.UsersHandlerOption(users...),
|
||||||
gost.TLSConfigHandlerOption(tlsCfg),
|
gost.TLSConfigHandlerOption(tlsCfg),
|
||||||
@ -417,9 +418,10 @@ func (r *route) GenRouters() ([]router, error) {
|
|||||||
gost.BypassHandlerOption(node.Bypass),
|
gost.BypassHandlerOption(node.Bypass),
|
||||||
gost.ResolverHandlerOption(resolver),
|
gost.ResolverHandlerOption(resolver),
|
||||||
gost.HostsHandlerOption(hosts),
|
gost.HostsHandlerOption(hosts),
|
||||||
gost.RetryHandlerOption(node.GetInt("retry")),
|
gost.RetryHandlerOption(node.GetInt("retry")), // override the global retry option.
|
||||||
gost.TimeoutHandlerOption(time.Duration(node.GetInt("timeout"))*time.Second),
|
gost.TimeoutHandlerOption(time.Duration(node.GetInt("timeout"))*time.Second),
|
||||||
gost.ProbeResistHandlerOption(node.Get("probe_resist")),
|
gost.ProbeResistHandlerOption(node.Get("probe_resist")),
|
||||||
|
gost.NodeHandlerOption(node),
|
||||||
)
|
)
|
||||||
|
|
||||||
rt := router{
|
rt := router{
|
||||||
@ -446,7 +448,7 @@ type router struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *router) Serve() error {
|
func (r *router) Serve() error {
|
||||||
log.Logf("[route] start %s on %s", r.node.String(), r.server.Addr())
|
log.Logf("%s on %s", r.node.String(), r.server.Addr())
|
||||||
return r.server.Serve(r.handler)
|
return r.server.Serve(r.handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,48 +0,0 @@
|
|||||||
[//]: <> (https://gist.github.com/fntlnz/cf14feb5a46b2eda428e000157447309)
|
|
||||||
|
|
||||||
# Create Root CA (Done once)
|
|
||||||
|
|
||||||
## Create Root Key
|
|
||||||
|
|
||||||
**Attention:** this is the key used to sign the certificate requests, anyone holding this can sign certificates on your behalf. So keep it in a safe place!
|
|
||||||
|
|
||||||
```bash
|
|
||||||
openssl genrsa -des3 -out rootCA.key 4096
|
|
||||||
```
|
|
||||||
|
|
||||||
If you want a non password protected key just remove the `-des3` option
|
|
||||||
|
|
||||||
|
|
||||||
## Create and self sign the Root Certificate
|
|
||||||
|
|
||||||
```bash
|
|
||||||
openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 1024 -out rootCA.crt
|
|
||||||
```
|
|
||||||
|
|
||||||
Here we used our root key to create the root certificate that needs to be distributed in all the computers that have to trust us.
|
|
||||||
|
|
||||||
|
|
||||||
# Create a certificate (Done for each server)
|
|
||||||
|
|
||||||
This procedure needs to be followed for each server/appliance that needs a trusted certificate from our CA
|
|
||||||
|
|
||||||
## Create the certificate key
|
|
||||||
|
|
||||||
```
|
|
||||||
openssl genrsa -out mydomain.com.key 2048
|
|
||||||
```
|
|
||||||
|
|
||||||
## Create the signing request
|
|
||||||
|
|
||||||
**Important:** Please mind that while creating the signign request is important to specify the `Common Name` providing the IP address or URL for the service, otherwise the certificate
|
|
||||||
cannot be verified
|
|
||||||
|
|
||||||
```
|
|
||||||
openssl req -new -key mydomain.com.key -out mydomain.com.csr
|
|
||||||
```
|
|
||||||
|
|
||||||
## Generate the certificate using the `mydomain` csr and key along with the CA Root key
|
|
||||||
|
|
||||||
```
|
|
||||||
openssl x509 -req -in mydomain.com.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out mydomain.com.crt -days 500 -sha256
|
|
||||||
```
|
|
@ -1,23 +0,0 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIDvjCCAaYCCQC0XjV3wljvnjANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAls
|
|
||||||
b2NhbGhvc3QwHhcNMTgwNzA4MDQ1MzIyWhcNMTkxMTIwMDQ1MzIyWjAuMQswCQYD
|
|
||||||
VQQGEwJDTjELMAkGA1UEBwwCU0gxEjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJ
|
|
||||||
KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMOKgzWil/KjyRy2Axb3XlLB1nMwLFJC
|
|
||||||
pC6r8yb+1Kq/ldZghJZvymuFVjn+bihvJqvZiOv4KRtnM8gD55AhaQp6Ese5M9b+
|
|
||||||
47HLB//SkfJsQREsmnrHfHxjmUQjhMy7jrpcf9OnDOXQ5zk3v6AWEIqMtAiZ99ku
|
|
||||||
AQvyJJ07+VpwZrMuzbSGfFBCKEbbqP7yKHjSUm3QDTpTiK4AnBmzlVeThUIA68oa
|
|
||||||
XZKQVXX/8U2i6H4eq5eNpyUsKSnnuK+cryHpAIK4vNMzw96vATTfEmuWASEzkHhW
|
|
||||||
3KtfXE0CIH0GsK5zueGDo9ygnO7hjtx60SWynlGf6c6edxPwNvEmTZcCAwEAATAN
|
|
||||||
BgkqhkiG9w0BAQsFAAOCAgEApLkdhnDzErgBljY6qRaR0JlouTpqJXwi5BRi7F1P
|
|
||||||
bx5ukrZAVSOsZ7ncEkZuxkIX+ktBVFBL8twkvMEl+sMQ24R+F+TrlHWN2xPR/pez
|
|
||||||
9V19hq26yMIlYLqSq3KZ0W9ZlT2ge+3sTvY+gAJhZ6nOz9WGRJ1mi+pN/ok678QX
|
|
||||||
KdOJXcePzYr5iKqMq/5cJ2sA1xYwVl+0xrvfRVTFkp4yR6wzGODtjquB+scZ9S64
|
|
||||||
GWnFTjHAJvUKYxpeoLAt9lZHsESDqGq7hA4z1uVjhNEDJHKnXW4OhXxMB8Gk2hY8
|
|
||||||
3k4zbnKsouNNW0a7jijCMpXOem/vgQF4GK5ecp0S+Ml/AunsPoi6rGgOCX8XXmti
|
|
||||||
6DfQhsxxgn1co/JKNxhgsnQftXFwKivh73JFctSh+bMLsewfXsvq+b0K3EuuV9bV
|
|
||||||
EttVCgbUaCDYdA6IDkqD2PRx9tsotne76r+cX+ah+NjnA6XN+XY2bJgV1UaiKTrP
|
|
||||||
moNHglw+xoUqOJ7FlGJcVC7uIFPhMviNkpSZh6WxX+OSS4fPO25kxxNpldql6I+3
|
|
||||||
xb5XEHLpPCEI4PyK0rYnsjk764Loqff8YBMFRQSXIUz9ot5SgGs/FY1vsQap5OeD
|
|
||||||
Hw2usWhCvkSzr7kiXI+30BvJKK2r9GOAM7mtO9dfkM9MMKKnMzd+O2XE4r6PNLrg
|
|
||||||
Rds=
|
|
||||||
-----END CERTIFICATE-----
|
|
@ -1,16 +0,0 @@
|
|||||||
-----BEGIN CERTIFICATE REQUEST-----
|
|
||||||
MIICczCCAVsCAQAwLjELMAkGA1UEBhMCQ04xCzAJBgNVBAcMAlNIMRIwEAYDVQQD
|
|
||||||
DAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDDioM1
|
|
||||||
opfyo8kctgMW915SwdZzMCxSQqQuq/Mm/tSqv5XWYISWb8prhVY5/m4obyar2Yjr
|
|
||||||
+CkbZzPIA+eQIWkKehLHuTPW/uOxywf/0pHybEERLJp6x3x8Y5lEI4TMu466XH/T
|
|
||||||
pwzl0Oc5N7+gFhCKjLQImffZLgEL8iSdO/lacGazLs20hnxQQihG26j+8ih40lJt
|
|
||||||
0A06U4iuAJwZs5VXk4VCAOvKGl2SkFV1//FNouh+HquXjaclLCkp57ivnK8h6QCC
|
|
||||||
uLzTM8PerwE03xJrlgEhM5B4VtyrX1xNAiB9BrCuc7nhg6PcoJzu4Y7cetElsp5R
|
|
||||||
n+nOnncT8DbxJk2XAgMBAAGgADANBgkqhkiG9w0BAQsFAAOCAQEAr+AkYRAPulBU
|
|
||||||
B5HR3pAreYrf3Y2fvGLSNo4hvsJkmXJxDgMZnGsjVzW1IZLF8szn4v050y6Qm/Ne
|
|
||||||
qupabYP5zpj0vKkACYGJ2zadnowmwlTzwlxEOv27uQykC/IuRcjdloAD7ZwhNwmO
|
|
||||||
dLNjdiXn63GUeSL/JK0UHyXTqvpmiHq+6TAOdl3vmsRFCQDChRtViK2fwSeX2y87
|
|
||||||
hLicSVQyNOe0gUx7IvE9B2QPNhdzaMVPYeN8I/cayNeUKhiWxEGKhwPAaievuSXJ
|
|
||||||
fUsz11XYBYW+kjFsTqkV1OjkG0mxvwaiq5W3CRx8365w71IMdKV5t5xhc0n0TXp7
|
|
||||||
cT27XN7cdw==
|
|
||||||
-----END CERTIFICATE REQUEST-----
|
|
@ -1,27 +0,0 @@
|
|||||||
-----BEGIN RSA PRIVATE KEY-----
|
|
||||||
MIIEowIBAAKCAQEAw4qDNaKX8qPJHLYDFvdeUsHWczAsUkKkLqvzJv7Uqr+V1mCE
|
|
||||||
lm/Ka4VWOf5uKG8mq9mI6/gpG2czyAPnkCFpCnoSx7kz1v7jscsH/9KR8mxBESya
|
|
||||||
esd8fGOZRCOEzLuOulx/06cM5dDnOTe/oBYQioy0CJn32S4BC/IknTv5WnBmsy7N
|
|
||||||
tIZ8UEIoRtuo/vIoeNJSbdANOlOIrgCcGbOVV5OFQgDryhpdkpBVdf/xTaLofh6r
|
|
||||||
l42nJSwpKee4r5yvIekAgri80zPD3q8BNN8Sa5YBITOQeFbcq19cTQIgfQawrnO5
|
|
||||||
4YOj3KCc7uGO3HrRJbKeUZ/pzp53E/A28SZNlwIDAQABAoIBAGx1pMeYMw3L2R5K
|
|
||||||
urX/aVsf1xI3My5Bdo3IpGsJx+4ZrEOnb4N96FnxMF2kiXd2B44kb/TqxepEOQ2F
|
|
||||||
VOi2D2xXP5l2WZGz+ZnBUuOL6ZX8g67B/cGCasMX/4gy51Mj6UvnSKOeMeI7GDW9
|
|
||||||
fVWPR4eB+c4XkMju4ne8zKBGBs4pN4KoxTWSnZSM4p+q/Jb/DMa+kVhFfRjkqfWc
|
|
||||||
vCpDgHs1uMcHvPBNYO9flDaC2Jgk4cvV9mX0TolXAvaNo8aN0joM7WH3fvw7NCD9
|
|
||||||
LCkqCmpjOxJIqJQT1twIkSy42q7VaFi7ApyIaMfXlmnj4UTlVTe5bBO+2AgwLYtC
|
|
||||||
cKgDMjECgYEA8JPm3Pc80EsYB6d4qp/Qmy2VrnlaxZwvaRwh63Pssqthg4SZkIp5
|
|
||||||
yjXOT4MDlJdrEzMtATRZUXTCRxGFSs0tolNY2KQ2WvYRhISlN8UBkGuMEkRGLuct
|
|
||||||
p++qpPcSZJcox25kT82CKin1nQYb48k33JAOMUOWIBJO56G35sfPj28CgYEA0BOE
|
|
||||||
pa+FYj/WxZS79YT1ZbsajeuUKlNUtAIxKJ2cKSQyfFuPM+xZG3H+iroRfR8HCVai
|
|
||||||
2+Oz9/TlxZOPR7+P+2fpS8W2tT+Qkmiyz8QJAULd+Irw5XIdatkpVm343XxMx3Pa
|
|
||||||
2qtBmgj6RINvsWTWRotMqhcuDRirxqm1IIQhkFkCgYBLNmIhyOXpVODRW8k8xrQI
|
|
||||||
H6tBHc2EJD0qRlJQczCX9z6ISIdeCfzjfAjhENuos+IU4ZX7X2thLPikEVUzuou+
|
|
||||||
yQHo0QXxUCbP4Exq8Bt6FDV5bIDonvvGGgamhlvouN1V5CxWSrCcD/wquEM15q2h
|
|
||||||
NiRJwJCJvE+Q2R1OeD9q3wKBgFWDkAJf7luAjQ3KoKy4pfnXOYSWCuCSOr94Hyfo
|
|
||||||
DmPCIpWFM4dNXRmwccIl0kYv2D54QppILJB9L2lRyZLdIZlbDUA802gN5aamLMbC
|
|
||||||
dEj2aC9bOsGxcnGVKi4BKEQub4eRD6LKuz1I70H1GpQ3MvDvEuTcfeqX9xDAclYY
|
|
||||||
t4qRAoGBAI6YSTs97DUe7Zwk7q+S3PBU5uct4Dwtmy2XWZdgHwl5aP8apSLciL5Y
|
|
||||||
PMkpcTMzkuC+QFaPZ8wFcI7GLg0bOs91hkrqscDKEg4nGB9fJkU82iOQZNL4Hv1u
|
|
||||||
wO7uIGa2kcpNtQOLNO88y45WFyrn5a+T6VhDmIuc+F+TU1ZzdYdH
|
|
||||||
-----END RSA PRIVATE KEY-----
|
|
@ -1,27 +0,0 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIEpDCCAowCCQDwV08QFUCcSzANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAls
|
|
||||||
b2NhbGhvc3QwHhcNMTgwNzA4MDQ1MzE3WhcNMjEwNDI3MDQ1MzE3WjAUMRIwEAYD
|
|
||||||
VQQDDAlsb2NhbGhvc3QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDE
|
|
||||||
+71yX9vQY3l52C31e04ACvm2oNMLSCrLOXGewOTFpv9yXjinMC0Ab6Xa4yB4MPtd
|
|
||||||
ujWDSEq9gkKCkILoalVX7R4gtLDN+EdoVadBw/WHbrGB4sHnFOWwpUbjiiwwPSU5
|
|
||||||
qXjcqIqR2sA1BgoAv6c1qHq7V4bgbEjtGL71KkDoQZSIgNyJlXe1mcUKqmqeAnro
|
|
||||||
0WfwrNXyYt66L3PmCy9MIpWRxf9sa8PDsgT3SQEN4BHb70Z8hNj6RXfVGDZcpfcI
|
|
||||||
iwbrL//YnK7waRKaKD4LoLOodE0cx3fowSWYvlwUAoYx8wFKOcdtM1zaUp+QDAug
|
|
||||||
xT5g5ghU150XuqhDU6Wq1An8dLgcDU1D4cxhLk/W8OXtIk4k7yny6eUJi2zHziMm
|
|
||||||
8jfHd3M6SwohUrE3LsQI5gpvu4sAVFLMkRxaWZ95XhsVMmIsE/L5FHwDfqid0dvx
|
|
||||||
bafOKT+fI3N3BaUPJlVHCNqSzSZIW59+ufnDwBV7SmJj4KMlvixEU+EFfPFdGiCA
|
|
||||||
Lr0dSG5+Scx1aClaMUeVccCljp2f99IEa9wI+xwMPDStkOmnhVuqG1aEogggQZkD
|
|
||||||
/5yh04wrn8EwYCAiasNNUXTV7AoqIt2bgeFbGo2Qr7LdsYuUmaWEzTm0KsHogkkg
|
|
||||||
Ibd3RPBLDr/WfWI13oHMdsz8jjbXG/D1AhrcdozYDQIDAQABMA0GCSqGSIb3DQEB
|
|
||||||
CwUAA4ICAQC1EeQqn2AwrS+UVc5fKRpHzV9ZMiDpxFMRLsDWBP5kNr1nSA72yYcR
|
|
||||||
WgxvdqG/rGRds6lvRbvIaWD0zeujPkR3iCpb1V5oRXQ6lWOlY44pZEwCdnDd2M8I
|
|
||||||
yQ7BLZCHHmlCN7a51n2o0D78HeILIeeTCQlKFDc5r51qrZbZR5DZmrp9jaZ+3eCg
|
|
||||||
LQ3Onfj0WEmQFuMFGQrbJ2oaCC1GvuZWEbRh+lrxjRKOyCaRQFTY4Efe8tIwMm6J
|
|
||||||
1iyMtqK7BxminQCfizQrstB67wMljydYeUf+wwbgkiKGYc9VGopckrO3lntzKycu
|
|
||||||
9l0BmlZYkmCFt3cv23BcqAbcLdyLXh3yASwVMXaLZ4iVSaslRm4uX+gbKFCBABLa
|
|
||||||
vqu7JQHfAPOeYj7zCrN12EHejPxdCjSImBeAbe56vax4uFGAodXxDGcepRItSzax
|
|
||||||
qPKJd8U/8e3JDn+wmZNKwD9UGLZPbiuYOg7X+EWhjki0J6ZjgLc8dMleeD2rO+j2
|
|
||||||
P/Wgv1gMr6J1svUlqkNf1Ng9eSbl/nMhuOBVOGcPnK7+wCLxM7ByaR0QgeH6/9VO
|
|
||||||
4urq53/vspBC679BHsZx3gIhcg4VefmOM2cZnTRM4izPstq1JBQkbuvz+5XuT7Yj
|
|
||||||
5Fk1/xkapCUifntKYSoslkkbNHRYxAInqkc0txn3qNBI8GAQFksz5g==
|
|
||||||
-----END CERTIFICATE-----
|
|
@ -1,51 +0,0 @@
|
|||||||
-----BEGIN RSA PRIVATE KEY-----
|
|
||||||
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
|
|
||||||
-----END RSA PRIVATE KEY-----
|
|
@ -1 +0,0 @@
|
|||||||
B45E3577C258EF9E
|
|
@ -33,6 +33,7 @@ type HandlerOptions struct {
|
|||||||
Resolver Resolver
|
Resolver Resolver
|
||||||
Hosts *Hosts
|
Hosts *Hosts
|
||||||
ProbeResist string
|
ProbeResist string
|
||||||
|
Node Node
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandlerOption allows a common way to set handler options.
|
// HandlerOption allows a common way to set handler options.
|
||||||
@ -129,6 +130,13 @@ func ProbeResistHandlerOption(pr string) HandlerOption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NodeHandlerOption set the server node for server handler.
|
||||||
|
func NodeHandlerOption(node Node) HandlerOption {
|
||||||
|
return func(opts *HandlerOptions) {
|
||||||
|
opts.Node = node
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type autoHandler struct {
|
type autoHandler struct {
|
||||||
options *HandlerOptions
|
options *HandlerOptions
|
||||||
}
|
}
|
||||||
|
276
http.go
276
http.go
@ -2,6 +2,7 @@ package gost
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"bytes"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
@ -108,17 +109,33 @@ func (h *httpHandler) handleRequest(conn net.Conn, req *http.Request) {
|
|||||||
if req == nil {
|
if req == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if Debug {
|
|
||||||
dump, _ := httputil.DumpRequest(req, false)
|
|
||||||
log.Logf("[http] %s -> %s\n%s", conn.RemoteAddr(), req.Host, string(dump))
|
|
||||||
}
|
|
||||||
|
|
||||||
|
host := req.Host
|
||||||
// try to get the actual host.
|
// try to get the actual host.
|
||||||
if v := req.Header.Get("Gost-Target"); v != "" {
|
if v := req.Header.Get("Gost-Target"); v != "" {
|
||||||
if host, err := decodeServerName(v); err == nil {
|
if h, err := decodeServerName(v); err == nil {
|
||||||
|
host = h
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, port, _ := net.SplitHostPort(host); port == "" {
|
||||||
|
host = net.JoinHostPort(host, "80")
|
||||||
|
}
|
||||||
|
|
||||||
|
u, _, _ := basicProxyAuth(req.Header.Get("Proxy-Authorization"))
|
||||||
|
if u != "" {
|
||||||
|
u += "@"
|
||||||
|
}
|
||||||
|
log.Logf("[http] %s%s -> %s -> %s",
|
||||||
|
u, conn.RemoteAddr(), h.options.Node.String(), host)
|
||||||
|
|
||||||
|
if Debug {
|
||||||
|
dump, _ := httputil.DumpRequest(req, false)
|
||||||
|
log.Logf("[http] %s -> %s\n%s", conn.RemoteAddr(), conn.LocalAddr(), string(dump))
|
||||||
|
}
|
||||||
|
|
||||||
req.Host = host
|
req.Host = host
|
||||||
}
|
req.Header.Del("Gost-Target")
|
||||||
}
|
|
||||||
|
|
||||||
resp := &http.Response{
|
resp := &http.Response{
|
||||||
ProtoMajor: 1,
|
ProtoMajor: 1,
|
||||||
@ -127,38 +144,147 @@ func (h *httpHandler) handleRequest(conn net.Conn, req *http.Request) {
|
|||||||
}
|
}
|
||||||
resp.Header.Add("Proxy-Agent", "gost/"+Version)
|
resp.Header.Add("Proxy-Agent", "gost/"+Version)
|
||||||
|
|
||||||
if !Can("tcp", req.Host, h.options.Whitelist, h.options.Blacklist) {
|
if !Can("tcp", host, h.options.Whitelist, h.options.Blacklist) {
|
||||||
log.Logf("[http] %s - %s : Unauthorized to tcp connect to %s",
|
log.Logf("[http] %s - %s : Unauthorized to tcp connect to %s",
|
||||||
conn.RemoteAddr(), req.Host, req.Host)
|
conn.RemoteAddr(), conn.LocalAddr(), host)
|
||||||
resp.StatusCode = http.StatusForbidden
|
resp.StatusCode = http.StatusForbidden
|
||||||
|
|
||||||
if Debug {
|
if Debug {
|
||||||
dump, _ := httputil.DumpResponse(resp, false)
|
dump, _ := httputil.DumpResponse(resp, false)
|
||||||
log.Logf("[http] %s <- %s\n%s", conn.RemoteAddr(), req.Host, string(dump))
|
log.Logf("[http] %s <- %s\n%s", conn.RemoteAddr(), conn.LocalAddr(), string(dump))
|
||||||
}
|
}
|
||||||
|
|
||||||
resp.Write(conn)
|
resp.Write(conn)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if h.options.Bypass.Contains(req.Host) {
|
if h.options.Bypass.Contains(host) {
|
||||||
log.Logf("[http] [bypass] %s", req.Host)
|
|
||||||
resp.StatusCode = http.StatusForbidden
|
resp.StatusCode = http.StatusForbidden
|
||||||
|
|
||||||
|
log.Logf("[http] %s - %s bypass %s",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), host)
|
||||||
if Debug {
|
if Debug {
|
||||||
dump, _ := httputil.DumpResponse(resp, false)
|
dump, _ := httputil.DumpResponse(resp, false)
|
||||||
log.Logf("[http] %s <- %s\n%s", conn.RemoteAddr(), req.Host, string(dump))
|
log.Logf("[http] %s <- %s\n%s", conn.RemoteAddr(), conn.LocalAddr(), string(dump))
|
||||||
}
|
}
|
||||||
|
|
||||||
resp.Write(conn)
|
resp.Write(conn)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !h.authenticate(conn, req, resp) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.Method == "PRI" || (req.Method != http.MethodConnect && req.URL.Scheme != "http") {
|
||||||
|
resp.StatusCode = http.StatusBadRequest
|
||||||
|
|
||||||
|
if Debug {
|
||||||
|
dump, _ := httputil.DumpResponse(resp, false)
|
||||||
|
log.Logf("[http] %s <- %s\n%s",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), string(dump))
|
||||||
|
}
|
||||||
|
|
||||||
|
resp.Write(conn)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Del("Proxy-Authorization")
|
||||||
|
|
||||||
|
retries := 1
|
||||||
|
if h.options.Chain != nil && h.options.Chain.Retries > 0 {
|
||||||
|
retries = h.options.Chain.Retries
|
||||||
|
}
|
||||||
|
if h.options.Retries > 0 {
|
||||||
|
retries = h.options.Retries
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
var cc net.Conn
|
||||||
|
var route *Chain
|
||||||
|
for i := 0; i < retries; i++ {
|
||||||
|
route, err = h.options.Chain.selectRouteFor(host)
|
||||||
|
if err != nil {
|
||||||
|
log.Logf("[http] %s -> %s : %s",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := bytes.Buffer{}
|
||||||
|
fmt.Fprintf(&buf, "%s -> %s -> ",
|
||||||
|
conn.RemoteAddr(), h.options.Node.String())
|
||||||
|
for _, nd := range route.route {
|
||||||
|
fmt.Fprintf(&buf, "%d@%s -> ", nd.ID, nd.String())
|
||||||
|
}
|
||||||
|
fmt.Fprintf(&buf, "%s", host)
|
||||||
|
log.Log("[route]", buf.String())
|
||||||
|
|
||||||
|
// forward http request
|
||||||
|
lastNode := route.LastNode()
|
||||||
|
if req.Method != http.MethodConnect && lastNode.Protocol == "http" {
|
||||||
|
err = h.forwardRequest(conn, req, route)
|
||||||
|
if err == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Logf("[http] %s -> %s : %s", conn.RemoteAddr(), conn.LocalAddr(), err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
cc, err = route.Dial(host,
|
||||||
|
TimeoutChainOption(h.options.Timeout),
|
||||||
|
HostsChainOption(h.options.Hosts),
|
||||||
|
ResolverChainOption(h.options.Resolver),
|
||||||
|
)
|
||||||
|
if err == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
log.Logf("[http] %s -> %s : %s", conn.RemoteAddr(), conn.LocalAddr(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
resp.StatusCode = http.StatusServiceUnavailable
|
||||||
|
|
||||||
|
if Debug {
|
||||||
|
dump, _ := httputil.DumpResponse(resp, false)
|
||||||
|
log.Logf("[http] %s <- %s\n%s", conn.RemoteAddr(), conn.LocalAddr(), string(dump))
|
||||||
|
}
|
||||||
|
|
||||||
|
resp.Write(conn)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer cc.Close()
|
||||||
|
|
||||||
|
if req.Method == http.MethodConnect {
|
||||||
|
b := []byte("HTTP/1.1 200 Connection established\r\n" +
|
||||||
|
"Proxy-Agent: gost/" + Version + "\r\n\r\n")
|
||||||
|
if Debug {
|
||||||
|
log.Logf("[http] %s <- %s\n%s", conn.RemoteAddr(), conn.LocalAddr(), string(b))
|
||||||
|
}
|
||||||
|
conn.Write(b)
|
||||||
|
} else {
|
||||||
|
req.Header.Del("Proxy-Connection")
|
||||||
|
|
||||||
|
if err = req.Write(cc); err != nil {
|
||||||
|
log.Logf("[http] %s -> %s : %s", conn.RemoteAddr(), conn.LocalAddr(), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Logf("[http] %s <-> %s", conn.RemoteAddr(), host)
|
||||||
|
transport(conn, cc)
|
||||||
|
log.Logf("[http] %s >-< %s", conn.RemoteAddr(), host)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *httpHandler) authenticate(conn net.Conn, req *http.Request, resp *http.Response) (ok bool) {
|
||||||
u, p, _ := basicProxyAuth(req.Header.Get("Proxy-Authorization"))
|
u, p, _ := basicProxyAuth(req.Header.Get("Proxy-Authorization"))
|
||||||
if Debug && (u != "" || p != "") {
|
if Debug && (u != "" || p != "") {
|
||||||
log.Logf("[http] %s - %s : Authorization: '%s' '%s'", conn.RemoteAddr(), req.Host, u, p)
|
log.Logf("[http] %s -> %s : Authorization '%s' '%s'",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), u, p)
|
||||||
}
|
}
|
||||||
if !authenticate(u, p, h.options.Users...) {
|
if authenticate(u, p, h.options.Users...) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// probing resistance is enabled
|
// probing resistance is enabled
|
||||||
if ss := strings.SplitN(h.options.ProbeResist, ":", 2); len(ss) == 2 {
|
if ss := strings.SplitN(h.options.ProbeResist, ":", 2); len(ss) == 2 {
|
||||||
switch ss[0] {
|
switch ss[0] {
|
||||||
@ -178,9 +304,11 @@ func (h *httpHandler) handleRequest(conn net.Conn, req *http.Request) {
|
|||||||
defer cc.Close()
|
defer cc.Close()
|
||||||
|
|
||||||
req.Write(cc)
|
req.Write(cc)
|
||||||
log.Logf("[http] %s <-> %s : forward to %s", conn.LocalAddr(), req.Host, ss[1])
|
log.Logf("[http] %s <-> %s : forward to %s",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), ss[1])
|
||||||
transport(conn, cc)
|
transport(conn, cc)
|
||||||
log.Logf("[http] %s >-< %s : forward to %s", conn.LocalAddr(), req.Host, ss[1])
|
log.Logf("[http] %s >-< %s : forward to %s",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), ss[1])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case "file":
|
case "file":
|
||||||
@ -190,22 +318,21 @@ func (h *httpHandler) handleRequest(conn net.Conn, req *http.Request) {
|
|||||||
if finfo, _ := f.Stat(); finfo != nil {
|
if finfo, _ := f.Stat(); finfo != nil {
|
||||||
resp.ContentLength = finfo.Size()
|
resp.ContentLength = finfo.Size()
|
||||||
}
|
}
|
||||||
|
resp.Header.Set("Content-Type", "text/html")
|
||||||
resp.Body = f
|
resp.Body = f
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if resp.StatusCode == 0 {
|
if resp.StatusCode == 0 {
|
||||||
log.Logf("[http] %s <- %s : proxy authentication required", conn.RemoteAddr(), req.Host)
|
log.Logf("[http] %s <- %s : proxy authentication required",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr())
|
||||||
resp.StatusCode = http.StatusProxyAuthRequired
|
resp.StatusCode = http.StatusProxyAuthRequired
|
||||||
resp.Header.Add("Proxy-Authenticate", "Basic realm=\"gost\"")
|
resp.Header.Add("Proxy-Authenticate", "Basic realm=\"gost\"")
|
||||||
} else {
|
} else {
|
||||||
resp.Header = http.Header{}
|
resp.Header = http.Header{}
|
||||||
resp.Header.Set("Server", "nginx/1.14.1")
|
resp.Header.Set("Server", "nginx/1.14.1")
|
||||||
resp.Header.Set("Date", time.Now().Format(http.TimeFormat))
|
resp.Header.Set("Date", time.Now().Format(http.TimeFormat))
|
||||||
if resp.ContentLength > 0 {
|
|
||||||
resp.Header.Set("Content-Type", "text/html")
|
|
||||||
}
|
|
||||||
if resp.StatusCode == http.StatusOK {
|
if resp.StatusCode == http.StatusOK {
|
||||||
resp.Header.Set("Connection", "keep-alive")
|
resp.Header.Set("Connection", "keep-alive")
|
||||||
}
|
}
|
||||||
@ -213,120 +340,21 @@ func (h *httpHandler) handleRequest(conn net.Conn, req *http.Request) {
|
|||||||
|
|
||||||
if Debug {
|
if Debug {
|
||||||
dump, _ := httputil.DumpResponse(resp, false)
|
dump, _ := httputil.DumpResponse(resp, false)
|
||||||
log.Logf("[http] %s <- %s\n%s", conn.RemoteAddr(), req.Host, string(dump))
|
log.Logf("[http] %s <- %s\n%s",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), string(dump))
|
||||||
}
|
}
|
||||||
|
|
||||||
resp.Write(conn)
|
resp.Write(conn)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.Method == "PRI" || (req.Method != http.MethodConnect && req.URL.Scheme != "http") {
|
|
||||||
resp.StatusCode = http.StatusBadRequest
|
|
||||||
|
|
||||||
if Debug {
|
|
||||||
dump, _ := httputil.DumpResponse(resp, false)
|
|
||||||
log.Logf("[http] %s <- %s\n%s", conn.RemoteAddr(), req.Host, string(dump))
|
|
||||||
}
|
|
||||||
|
|
||||||
resp.Write(conn)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
req.Header.Del("Proxy-Authorization")
|
|
||||||
|
|
||||||
host := req.Host
|
|
||||||
if _, port, _ := net.SplitHostPort(host); port == "" {
|
|
||||||
host = net.JoinHostPort(req.Host, "80")
|
|
||||||
}
|
|
||||||
|
|
||||||
retries := 1
|
|
||||||
if h.options.Chain != nil && h.options.Chain.Retries > 0 {
|
|
||||||
retries = h.options.Chain.Retries
|
|
||||||
}
|
|
||||||
if h.options.Retries > 0 {
|
|
||||||
retries = h.options.Retries
|
|
||||||
}
|
|
||||||
|
|
||||||
var err error
|
|
||||||
var cc net.Conn
|
|
||||||
var route *Chain
|
|
||||||
for i := 0; i < retries; i++ {
|
|
||||||
route, err = h.options.Chain.selectRouteFor(req.Host)
|
|
||||||
if err != nil {
|
|
||||||
log.Logf("[http] %s -> %s : %s", conn.RemoteAddr(), req.Host, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// forward http request
|
|
||||||
lastNode := route.LastNode()
|
|
||||||
if req.Method != http.MethodConnect && lastNode.Protocol == "http" {
|
|
||||||
err = h.forwardRequest(conn, req, route)
|
|
||||||
if err == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// log.Logf("[http] %s -> %s : %s", conn.RemoteAddr(), req.Host, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
cc, err = route.Dial(host,
|
|
||||||
RetryChainOption(1),
|
|
||||||
TimeoutChainOption(h.options.Timeout),
|
|
||||||
HostsChainOption(h.options.Hosts),
|
|
||||||
ResolverChainOption(h.options.Resolver),
|
|
||||||
)
|
|
||||||
if err == nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Logf("[http] %s -> %s : %s", conn.RemoteAddr(), host, err)
|
|
||||||
resp.StatusCode = http.StatusServiceUnavailable
|
|
||||||
|
|
||||||
if Debug {
|
|
||||||
dump, _ := httputil.DumpResponse(resp, false)
|
|
||||||
log.Logf("[http] %s <- %s\n%s", conn.RemoteAddr(), host, string(dump))
|
|
||||||
}
|
|
||||||
|
|
||||||
resp.Write(conn)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer cc.Close()
|
|
||||||
|
|
||||||
if req.Method == http.MethodConnect {
|
|
||||||
b := []byte("HTTP/1.1 200 Connection established\r\n" +
|
|
||||||
"Proxy-Agent: gost/" + Version + "\r\n\r\n")
|
|
||||||
if Debug {
|
|
||||||
log.Logf("[http] %s <- %s\n%s", conn.RemoteAddr(), host, string(b))
|
|
||||||
}
|
|
||||||
conn.Write(b)
|
|
||||||
} else {
|
|
||||||
req.Header.Del("Proxy-Connection")
|
|
||||||
|
|
||||||
if err = req.Write(cc); err != nil {
|
|
||||||
log.Logf("[http] %s -> %s : %s", conn.RemoteAddr(), host, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var su string
|
|
||||||
if u != "" {
|
|
||||||
su = u + "@"
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Logf("[http] %s%s <-> %s", su, cc.LocalAddr(), host)
|
|
||||||
transport(conn, cc)
|
|
||||||
log.Logf("[http] %s%s >-< %s", su, cc.LocalAddr(), host)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *httpHandler) forwardRequest(conn net.Conn, req *http.Request, route *Chain) error {
|
func (h *httpHandler) forwardRequest(conn net.Conn, req *http.Request, route *Chain) error {
|
||||||
if route.IsEmpty() {
|
if route.IsEmpty() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
lastNode := route.LastNode()
|
lastNode := route.LastNode()
|
||||||
|
|
||||||
cc, err := route.Conn(
|
cc, err := route.Conn()
|
||||||
RetryChainOption(1), // we control the retry manually.
|
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -346,7 +374,7 @@ func (h *httpHandler) forwardRequest(conn net.Conn, req *http.Request, route *Ch
|
|||||||
req.URL.Scheme = "http" // make sure that the URL is absolute
|
req.URL.Scheme = "http" // make sure that the URL is absolute
|
||||||
}
|
}
|
||||||
if err = req.WriteProxy(cc); err != nil {
|
if err = req.WriteProxy(cc); err != nil {
|
||||||
log.Logf("[http] %s -> %s : %s", conn.RemoteAddr(), req.Host, err)
|
log.Logf("[http] %s -> %s : %s", conn.RemoteAddr(), conn.LocalAddr(), err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
cc.SetWriteDeadline(time.Time{})
|
cc.SetWriteDeadline(time.Time{})
|
||||||
|
206
http2.go
206
http2.go
@ -6,6 +6,7 @@ import (
|
|||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
@ -50,6 +51,7 @@ func (c *http2Connector) Connect(conn net.Conn, addr string, options ...ConnectO
|
|||||||
Host: cc.addr,
|
Host: cc.addr,
|
||||||
ContentLength: -1,
|
ContentLength: -1,
|
||||||
}
|
}
|
||||||
|
// TODO: use the standard CONNECT method.
|
||||||
req.Header.Set("Gost-Target", addr)
|
req.Header.Set("Gost-Target", addr)
|
||||||
if c.User != nil {
|
if c.User != nil {
|
||||||
u := c.User.Username()
|
u := c.User.Username()
|
||||||
@ -110,8 +112,20 @@ func (tr *http2Transporter) Dial(addr string, options ...DialOption) (net.Conn,
|
|||||||
}
|
}
|
||||||
|
|
||||||
tr.clientMutex.Lock()
|
tr.clientMutex.Lock()
|
||||||
|
defer tr.clientMutex.Unlock()
|
||||||
|
|
||||||
client, ok := tr.clients[addr]
|
client, ok := tr.clients[addr]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
// NOTE: due to the dummy connection, HTTP2 node in a proxy chain can not be marked as dead.
|
||||||
|
// There is no real connection to the HTTP2 server at this moment.
|
||||||
|
// So we should try to connect the server.
|
||||||
|
conn, err := opts.Chain.Dial(addr)
|
||||||
|
if err != nil {
|
||||||
|
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
conn.Close()
|
||||||
|
|
||||||
transport := http2.Transport{
|
transport := http2.Transport{
|
||||||
TLSClientConfig: tr.tlsConfig,
|
TLSClientConfig: tr.tlsConfig,
|
||||||
DialTLS: func(network, adr string, cfg *tls.Config) (net.Conn, error) {
|
DialTLS: func(network, adr string, cfg *tls.Config) (net.Conn, error) {
|
||||||
@ -128,7 +142,6 @@ func (tr *http2Transporter) Dial(addr string, options ...DialOption) (net.Conn,
|
|||||||
}
|
}
|
||||||
tr.clients[addr] = client
|
tr.clients[addr] = client
|
||||||
}
|
}
|
||||||
tr.clientMutex.Unlock()
|
|
||||||
|
|
||||||
return &http2ClientConn{
|
return &http2ClientConn{
|
||||||
addr: addr,
|
addr: addr,
|
||||||
@ -283,31 +296,40 @@ func (h *http2Handler) Handle(conn net.Conn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *http2Handler) roundTrip(w http.ResponseWriter, r *http.Request) {
|
func (h *http2Handler) roundTrip(w http.ResponseWriter, r *http.Request) {
|
||||||
target := r.Header.Get("Gost-Target")
|
host := r.Header.Get("Gost-Target")
|
||||||
if target == "" {
|
if host == "" {
|
||||||
target = r.Host
|
host = r.Host
|
||||||
}
|
}
|
||||||
|
|
||||||
if !strings.Contains(target, ":") {
|
if _, port, _ := net.SplitHostPort(host); port == "" {
|
||||||
target += ":80"
|
host = net.JoinHostPort(host, "80")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
laddr := h.options.Addr
|
||||||
|
u, _, _ := basicProxyAuth(r.Header.Get("Proxy-Authorization"))
|
||||||
|
if u != "" {
|
||||||
|
u += "@"
|
||||||
|
}
|
||||||
|
log.Logf("[http2] %s%s -> %s -> %s",
|
||||||
|
u, r.RemoteAddr, h.options.Node.String(), host)
|
||||||
|
|
||||||
if Debug {
|
if Debug {
|
||||||
log.Logf("[http2] %s %s - %s %s", r.Method, r.RemoteAddr, target, r.Proto)
|
|
||||||
dump, _ := httputil.DumpRequest(r, false)
|
dump, _ := httputil.DumpRequest(r, false)
|
||||||
log.Log("[http2]", string(dump))
|
log.Logf("[http2] %s - %s\n%s", r.RemoteAddr, laddr, string(dump))
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Header().Set("Proxy-Agent", "gost/"+Version)
|
w.Header().Set("Proxy-Agent", "gost/"+Version)
|
||||||
|
|
||||||
if !Can("tcp", target, h.options.Whitelist, h.options.Blacklist) {
|
if !Can("tcp", host, h.options.Whitelist, h.options.Blacklist) {
|
||||||
log.Logf("[http2] Unauthorized to tcp connect to %s", target)
|
log.Logf("[http2] %s - %s : Unauthorized to tcp connect to %s",
|
||||||
|
r.RemoteAddr, laddr, host)
|
||||||
w.WriteHeader(http.StatusForbidden)
|
w.WriteHeader(http.StatusForbidden)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if h.options.Bypass.Contains(target) {
|
if h.options.Bypass.Contains(host) {
|
||||||
log.Logf("[http2] [bypass] %s", target)
|
log.Logf("[http2] %s - %s bypass %s",
|
||||||
|
r.RemoteAddr, laddr, host)
|
||||||
w.WriteHeader(http.StatusForbidden)
|
w.WriteHeader(http.StatusForbidden)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -319,11 +341,105 @@ func (h *http2Handler) roundTrip(w http.ResponseWriter, r *http.Request) {
|
|||||||
Body: ioutil.NopCloser(bytes.NewReader([]byte{})),
|
Body: ioutil.NopCloser(bytes.NewReader([]byte{})),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !h.authenticate(w, r, resp) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete the proxy related headers.
|
||||||
|
r.Header.Del("Proxy-Authorization")
|
||||||
|
r.Header.Del("Proxy-Connection")
|
||||||
|
|
||||||
|
retries := 1
|
||||||
|
if h.options.Chain != nil && h.options.Chain.Retries > 0 {
|
||||||
|
retries = h.options.Chain.Retries
|
||||||
|
}
|
||||||
|
if h.options.Retries > 0 {
|
||||||
|
retries = h.options.Retries
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
var cc net.Conn
|
||||||
|
var route *Chain
|
||||||
|
for i := 0; i < retries; i++ {
|
||||||
|
route, err = h.options.Chain.selectRouteFor(host)
|
||||||
|
if err != nil {
|
||||||
|
log.Logf("[http2] %s -> %s : %s",
|
||||||
|
r.RemoteAddr, laddr, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := bytes.Buffer{}
|
||||||
|
fmt.Fprintf(&buf, "%s -> %s -> ",
|
||||||
|
r.RemoteAddr, h.options.Node.String())
|
||||||
|
for _, nd := range route.route {
|
||||||
|
fmt.Fprintf(&buf, "%d@%s -> ", nd.ID, nd.String())
|
||||||
|
}
|
||||||
|
fmt.Fprintf(&buf, "%s", host)
|
||||||
|
log.Log("[route]", buf.String())
|
||||||
|
|
||||||
|
cc, err = route.Dial(host,
|
||||||
|
TimeoutChainOption(h.options.Timeout),
|
||||||
|
HostsChainOption(h.options.Hosts),
|
||||||
|
ResolverChainOption(h.options.Resolver),
|
||||||
|
)
|
||||||
|
if err == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
log.Logf("[http2] %s -> %s : %s", r.RemoteAddr, laddr, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusServiceUnavailable)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer cc.Close()
|
||||||
|
|
||||||
|
if r.Method == http.MethodConnect {
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
if fw, ok := w.(http.Flusher); ok {
|
||||||
|
fw.Flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
// compatible with HTTP1.x
|
||||||
|
if hj, ok := w.(http.Hijacker); ok && r.ProtoMajor == 1 {
|
||||||
|
// we take over the underly connection
|
||||||
|
conn, _, err := hj.Hijack()
|
||||||
|
if err != nil {
|
||||||
|
log.Logf("[http2] %s -> %s : %s",
|
||||||
|
r.RemoteAddr, laddr, err)
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
log.Logf("[http2] %s <-> %s : downgrade to HTTP/1.1", r.RemoteAddr, host)
|
||||||
|
transport(conn, cc)
|
||||||
|
log.Logf("[http2] %s >-< %s", r.RemoteAddr, host)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Logf("[http2] %s <-> %s", r.RemoteAddr, host)
|
||||||
|
transport(&readWriter{r: r.Body, w: flushWriter{w}}, cc)
|
||||||
|
log.Logf("[http2] %s >-< %s", r.RemoteAddr, host)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Logf("[http2] %s <-> %s", r.RemoteAddr, host)
|
||||||
|
if err := h.forwardRequest(w, r, cc); err != nil {
|
||||||
|
log.Logf("[http2] %s - %s : %s", r.RemoteAddr, host, err)
|
||||||
|
}
|
||||||
|
log.Logf("[http2] %s >-< %s", r.RemoteAddr, host)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *http2Handler) authenticate(w http.ResponseWriter, r *http.Request, resp *http.Response) (ok bool) {
|
||||||
|
laddr := h.options.Addr
|
||||||
u, p, _ := basicProxyAuth(r.Header.Get("Proxy-Authorization"))
|
u, p, _ := basicProxyAuth(r.Header.Get("Proxy-Authorization"))
|
||||||
if Debug && (u != "" || p != "") {
|
if Debug && (u != "" || p != "") {
|
||||||
log.Logf("[http2] %s - %s : Authorization: '%s' '%s'", r.RemoteAddr, target, u, p)
|
log.Logf("[http2] %s - %s : Authorization '%s' '%s'", r.RemoteAddr, laddr, u, p)
|
||||||
|
}
|
||||||
|
if authenticate(u, p, h.options.Users...) {
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
if !authenticate(u, p, h.options.Users...) {
|
|
||||||
// probing resistance is enabled
|
// probing resistance is enabled
|
||||||
if ss := strings.SplitN(h.options.ProbeResist, ":", 2); len(ss) == 2 {
|
if ss := strings.SplitN(h.options.ProbeResist, ":", 2); len(ss) == 2 {
|
||||||
switch ss[0] {
|
switch ss[0] {
|
||||||
@ -341,11 +457,11 @@ func (h *http2Handler) roundTrip(w http.ResponseWriter, r *http.Request) {
|
|||||||
cc, err := net.Dial("tcp", ss[1])
|
cc, err := net.Dial("tcp", ss[1])
|
||||||
if err == nil {
|
if err == nil {
|
||||||
defer cc.Close()
|
defer cc.Close()
|
||||||
log.Logf("[http2] %s <-> %s : forward to %s", r.RemoteAddr, target, ss[1])
|
log.Logf("[http2] %s <-> %s : forward to %s", r.RemoteAddr, laddr, ss[1])
|
||||||
if err := h.forwardRequest(w, r, cc); err != nil {
|
if err := h.forwardRequest(w, r, cc); err != nil {
|
||||||
log.Logf("[http2] %s - %s : %s", r.RemoteAddr, target, err)
|
log.Logf("[http2] %s - %s : %s", r.RemoteAddr, laddr, err)
|
||||||
}
|
}
|
||||||
log.Logf("[http2] %s >-< %s : forward to %s", r.RemoteAddr, target, ss[1])
|
log.Logf("[http2] %s >-< %s : forward to %s", r.RemoteAddr, laddr, ss[1])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case "file":
|
case "file":
|
||||||
@ -361,7 +477,7 @@ func (h *http2Handler) roundTrip(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if resp.StatusCode == 0 {
|
if resp.StatusCode == 0 {
|
||||||
log.Logf("[http2] %s <- %s : proxy authentication required", r.RemoteAddr, target)
|
log.Logf("[http2] %s <- %s : proxy authentication required", r.RemoteAddr, laddr)
|
||||||
resp.StatusCode = http.StatusProxyAuthRequired
|
resp.StatusCode = http.StatusProxyAuthRequired
|
||||||
resp.Header.Add("Proxy-Authenticate", "Basic realm=\"gost\"")
|
resp.Header.Add("Proxy-Authenticate", "Basic realm=\"gost\"")
|
||||||
} else {
|
} else {
|
||||||
@ -379,7 +495,7 @@ func (h *http2Handler) roundTrip(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
if Debug {
|
if Debug {
|
||||||
dump, _ := httputil.DumpResponse(resp, false)
|
dump, _ := httputil.DumpResponse(resp, false)
|
||||||
log.Logf("[http2] %s <- %s\n%s", r.RemoteAddr, target, string(dump))
|
log.Logf("[http2] %s <- %s\n%s", r.RemoteAddr, laddr, string(dump))
|
||||||
}
|
}
|
||||||
|
|
||||||
h.writeResponse(w, resp)
|
h.writeResponse(w, resp)
|
||||||
@ -388,58 +504,6 @@ func (h *http2Handler) roundTrip(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
r.Header.Del("Proxy-Authorization")
|
|
||||||
r.Header.Del("Proxy-Connection")
|
|
||||||
|
|
||||||
cc, err := h.options.Chain.Dial(target,
|
|
||||||
RetryChainOption(h.options.Retries),
|
|
||||||
TimeoutChainOption(h.options.Timeout),
|
|
||||||
HostsChainOption(h.options.Hosts),
|
|
||||||
ResolverChainOption(h.options.Resolver),
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
log.Logf("[http2] %s -> %s : %s", r.RemoteAddr, target, err)
|
|
||||||
w.WriteHeader(http.StatusServiceUnavailable)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer cc.Close()
|
|
||||||
|
|
||||||
if r.Method == http.MethodConnect {
|
|
||||||
w.WriteHeader(http.StatusOK)
|
|
||||||
if fw, ok := w.(http.Flusher); ok {
|
|
||||||
fw.Flush()
|
|
||||||
}
|
|
||||||
|
|
||||||
// compatible with HTTP1.x
|
|
||||||
if hj, ok := w.(http.Hijacker); ok && r.ProtoMajor == 1 {
|
|
||||||
// we take over the underly connection
|
|
||||||
conn, _, err := hj.Hijack()
|
|
||||||
if err != nil {
|
|
||||||
log.Logf("[http2] %s -> %s : %s", r.RemoteAddr, target, err)
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer conn.Close()
|
|
||||||
|
|
||||||
log.Logf("[http2] %s <-> %s : downgrade to HTTP/1.1", r.RemoteAddr, target)
|
|
||||||
transport(conn, cc)
|
|
||||||
log.Logf("[http2] %s >-< %s", r.RemoteAddr, target)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Logf("[http2] %s <-> %s", r.RemoteAddr, target)
|
|
||||||
transport(&readWriter{r: r.Body, w: flushWriter{w}}, cc)
|
|
||||||
log.Logf("[http2] %s >-< %s", r.RemoteAddr, target)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Logf("[http2] %s <-> %s", r.RemoteAddr, target)
|
|
||||||
if err := h.forwardRequest(w, r, cc); err != nil {
|
|
||||||
log.Logf("[http2] %s - %s : %s", r.RemoteAddr, target, err)
|
|
||||||
}
|
|
||||||
log.Logf("[http2] %s >-< %s", r.RemoteAddr, target)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *http2Handler) forwardRequest(w http.ResponseWriter, r *http.Request, rw io.ReadWriter) (err error) {
|
func (h *http2Handler) forwardRequest(w http.ResponseWriter, r *http.Request, rw io.ReadWriter) (err error) {
|
||||||
if err = r.Write(rw); err != nil {
|
if err = r.Write(rw); err != nil {
|
||||||
return
|
return
|
||||||
|
7
node.go
7
node.go
@ -21,7 +21,7 @@ type Node struct {
|
|||||||
Protocol string
|
Protocol string
|
||||||
Transport string
|
Transport string
|
||||||
Remote string // remote address, used by tcp/udp port forwarding
|
Remote string // remote address, used by tcp/udp port forwarding
|
||||||
url string // raw url
|
url *url.URL // raw url
|
||||||
User *url.Userinfo
|
User *url.Userinfo
|
||||||
Values url.Values
|
Values url.Values
|
||||||
DialOptions []DialOption
|
DialOptions []DialOption
|
||||||
@ -55,10 +55,11 @@ func ParseNode(s string) (node Node, err error) {
|
|||||||
Values: u.Query(),
|
Values: u.Query(),
|
||||||
User: u.User,
|
User: u.User,
|
||||||
marker: &failMarker{},
|
marker: &failMarker{},
|
||||||
|
url: u,
|
||||||
}
|
}
|
||||||
|
|
||||||
u.RawQuery = ""
|
u.RawQuery = ""
|
||||||
node.url = u.String()
|
u.User = nil
|
||||||
|
|
||||||
schemes := strings.Split(u.Scheme, "+")
|
schemes := strings.Split(u.Scheme, "+")
|
||||||
if len(schemes) == 1 {
|
if len(schemes) == 1 {
|
||||||
@ -139,7 +140,7 @@ func (node *Node) GetInt(key string) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (node Node) String() string {
|
func (node Node) String() string {
|
||||||
return node.url
|
return node.url.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
// NodeGroup is a group of nodes.
|
// NodeGroup is a group of nodes.
|
||||||
|
@ -173,7 +173,7 @@ func (f *FailFilter) Filter(nodes []Node) []Node {
|
|||||||
nl := []Node{}
|
nl := []Node{}
|
||||||
for i := range nodes {
|
for i := range nodes {
|
||||||
marker := nodes[i].marker.Clone()
|
marker := nodes[i].marker.Clone()
|
||||||
// log.Logf("%s: %d/%d %d/%d", nodes[i], marker.failCount, f.MaxFails, marker.failTime, f.FailTimeout)
|
// log.Logf("%s: %d/%d %v/%v", nodes[i], marker.failCount, f.MaxFails, marker.failTime, f.FailTimeout)
|
||||||
if marker.failCount < uint32(f.MaxFails) ||
|
if marker.failCount < uint32(f.MaxFails) ||
|
||||||
time.Since(time.Unix(marker.failTime, 0)) >= f.FailTimeout {
|
time.Since(time.Unix(marker.failTime, 0)) >= f.FailTimeout {
|
||||||
nl = append(nl, nodes[i])
|
nl = append(nl, nodes[i])
|
||||||
|
75
sni.go
75
sni.go
@ -8,6 +8,7 @@ import (
|
|||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"hash/crc32"
|
"hash/crc32"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
@ -55,22 +56,23 @@ func (h *sniHandler) Init(options ...HandlerOption) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *sniHandler) Handle(conn net.Conn) {
|
func (h *sniHandler) Handle(conn net.Conn) {
|
||||||
br := bufio.NewReader(conn)
|
defer conn.Close()
|
||||||
|
|
||||||
|
br := bufio.NewReader(conn)
|
||||||
hdr, err := br.Peek(dissector.RecordHeaderLen)
|
hdr, err := br.Peek(dissector.RecordHeaderLen)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Log("[sni]", err)
|
log.Logf("[sni] %s -> %s : %s",
|
||||||
conn.Close()
|
conn.RemoteAddr(), conn.LocalAddr(), err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
conn = &bufferdConn{br: br, Conn: conn}
|
conn = &bufferdConn{br: br, Conn: conn}
|
||||||
defer conn.Close()
|
|
||||||
|
|
||||||
if hdr[0] != dissector.Handshake {
|
if hdr[0] != dissector.Handshake {
|
||||||
// We assume it is an HTTP request
|
// We assume it is an HTTP request
|
||||||
req, err := http.ReadRequest(bufio.NewReader(conn))
|
req, err := http.ReadRequest(bufio.NewReader(conn))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Logf("[sni] %s - %s : %s", conn.RemoteAddr(), conn.LocalAddr(), err)
|
log.Logf("[sni] %s -> %s : %s",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !req.URL.IsAbs() {
|
if !req.URL.IsAbs() {
|
||||||
@ -84,40 +86,79 @@ func (h *sniHandler) Handle(conn net.Conn) {
|
|||||||
|
|
||||||
b, host, err := readClientHelloRecord(conn, "", false)
|
b, host, err := readClientHelloRecord(conn, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Log("[sni]", err)
|
log.Logf("[sni] %s -> %s : %s",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
addr := net.JoinHostPort(host, "443")
|
host = net.JoinHostPort(host, "443")
|
||||||
|
|
||||||
if !Can("tcp", addr, h.options.Whitelist, h.options.Blacklist) {
|
log.Logf("[ss] %s -> %s -> %s",
|
||||||
log.Logf("[sni] Unauthorized to tcp connect to %s", addr)
|
conn.RemoteAddr(), h.options.Node.String(), host)
|
||||||
|
|
||||||
|
if !Can("tcp", host, h.options.Whitelist, h.options.Blacklist) {
|
||||||
|
log.Logf("[sni] %s -> %s : Unauthorized to tcp connect to %s",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), host)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if h.options.Bypass.Contains(addr) {
|
if h.options.Bypass.Contains(host) {
|
||||||
log.Log("[sni] [bypass]", addr)
|
log.Log("[sni] %s - %s bypass %s",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), host)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cc, err := h.options.Chain.Dial(addr,
|
retries := 1
|
||||||
RetryChainOption(h.options.Retries),
|
if h.options.Chain != nil && h.options.Chain.Retries > 0 {
|
||||||
|
retries = h.options.Chain.Retries
|
||||||
|
}
|
||||||
|
if h.options.Retries > 0 {
|
||||||
|
retries = h.options.Retries
|
||||||
|
}
|
||||||
|
|
||||||
|
var cc net.Conn
|
||||||
|
var route *Chain
|
||||||
|
for i := 0; i < retries; i++ {
|
||||||
|
route, err = h.options.Chain.selectRouteFor(host)
|
||||||
|
if err != nil {
|
||||||
|
log.Logf("[sni] %s -> %s : %s",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := bytes.Buffer{}
|
||||||
|
fmt.Fprintf(&buf, "%s -> %s -> ",
|
||||||
|
conn.RemoteAddr(), h.options.Node.String())
|
||||||
|
for _, nd := range route.route {
|
||||||
|
fmt.Fprintf(&buf, "%d@%s -> ", nd.ID, nd.String())
|
||||||
|
}
|
||||||
|
fmt.Fprintf(&buf, "%s", host)
|
||||||
|
log.Log("[route]", buf.String())
|
||||||
|
|
||||||
|
cc, err = route.Dial(host,
|
||||||
TimeoutChainOption(h.options.Timeout),
|
TimeoutChainOption(h.options.Timeout),
|
||||||
HostsChainOption(h.options.Hosts),
|
HostsChainOption(h.options.Hosts),
|
||||||
ResolverChainOption(h.options.Resolver),
|
ResolverChainOption(h.options.Resolver),
|
||||||
)
|
)
|
||||||
|
if err == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
log.Logf("[sni] %s -> %s : %s",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), err)
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Logf("[sni] %s -> %s : %s", conn.RemoteAddr(), addr, err)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer cc.Close()
|
defer cc.Close()
|
||||||
|
|
||||||
if _, err := cc.Write(b); err != nil {
|
if _, err := cc.Write(b); err != nil {
|
||||||
log.Logf("[sni] %s -> %s : %s", conn.RemoteAddr(), addr, err)
|
log.Logf("[sni] %s -> %s : %s",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Logf("[sni] %s <-> %s", cc.LocalAddr(), addr)
|
log.Logf("[sni] %s <-> %s", cc.LocalAddr(), host)
|
||||||
transport(conn, cc)
|
transport(conn, cc)
|
||||||
log.Logf("[sni] %s >-< %s", cc.LocalAddr(), addr)
|
log.Logf("[sni] %s >-< %s", cc.LocalAddr(), host)
|
||||||
}
|
}
|
||||||
|
|
||||||
// sniSniffConn is a net.Conn that reads from r, fails on Writes,
|
// sniSniffConn is a net.Conn that reads from r, fails on Writes,
|
||||||
|
197
socks.go
197
socks.go
@ -386,12 +386,14 @@ func (h *socks5Handler) Handle(conn net.Conn) {
|
|||||||
conn = gosocks5.ServerConn(conn, h.selector)
|
conn = gosocks5.ServerConn(conn, h.selector)
|
||||||
req, err := gosocks5.ReadRequest(conn)
|
req, err := gosocks5.ReadRequest(conn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Log("[socks5]", err)
|
log.Logf("[socks5] %s -> %s : %s",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if Debug {
|
if Debug {
|
||||||
log.Logf("[socks5] %s - %s\n%s", conn.RemoteAddr(), req.Addr, req)
|
log.Logf("[socks5] %s -> %s\n%s",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), req)
|
||||||
}
|
}
|
||||||
switch req.Cmd {
|
switch req.Cmd {
|
||||||
case gosocks5.CmdConnect:
|
case gosocks5.CmdConnect:
|
||||||
@ -410,43 +412,86 @@ func (h *socks5Handler) Handle(conn net.Conn) {
|
|||||||
h.handleUDPTunnel(conn, req)
|
h.handleUDPTunnel(conn, req)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
log.Log("[socks5] Unrecognized request:", req.Cmd)
|
log.Logf("[socks5] %s - %s : Unrecognized request: %d",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), req.Cmd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *socks5Handler) handleConnect(conn net.Conn, req *gosocks5.Request) {
|
func (h *socks5Handler) handleConnect(conn net.Conn, req *gosocks5.Request) {
|
||||||
addr := req.Addr.String()
|
host := req.Addr.String()
|
||||||
if !Can("tcp", addr, h.options.Whitelist, h.options.Blacklist) {
|
|
||||||
log.Logf("[socks5-connect] Unauthorized to tcp connect to %s", addr)
|
log.Logf("[socks5] %s -> %s -> %s",
|
||||||
|
conn.RemoteAddr(), h.options.Node.String(), host)
|
||||||
|
|
||||||
|
if !Can("tcp", host, h.options.Whitelist, h.options.Blacklist) {
|
||||||
|
log.Logf("[socks5] %s - %s : Unauthorized to tcp connect to %s",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), host)
|
||||||
rep := gosocks5.NewReply(gosocks5.NotAllowed, nil)
|
rep := gosocks5.NewReply(gosocks5.NotAllowed, nil)
|
||||||
rep.Write(conn)
|
rep.Write(conn)
|
||||||
if Debug {
|
if Debug {
|
||||||
log.Logf("[socks5-connect] %s <- %s\n%s", conn.RemoteAddr(), req.Addr, rep)
|
log.Logf("[socks5] %s <- %s\n%s",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), rep)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if h.options.Bypass.Contains(addr) {
|
if h.options.Bypass.Contains(host) {
|
||||||
log.Logf("[socks5-connect] [bypass] %s", addr)
|
log.Logf("[socks5] %s - %s : Bypass %s",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), host)
|
||||||
rep := gosocks5.NewReply(gosocks5.NotAllowed, nil)
|
rep := gosocks5.NewReply(gosocks5.NotAllowed, nil)
|
||||||
rep.Write(conn)
|
rep.Write(conn)
|
||||||
if Debug {
|
if Debug {
|
||||||
log.Logf("[socks5-connect] %s <- %s\n%s", conn.RemoteAddr(), req.Addr, rep)
|
log.Logf("[socks5] %s <- %s\n%s",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), rep)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cc, err := h.options.Chain.Dial(addr,
|
retries := 1
|
||||||
RetryChainOption(h.options.Retries),
|
if h.options.Chain != nil && h.options.Chain.Retries > 0 {
|
||||||
|
retries = h.options.Chain.Retries
|
||||||
|
}
|
||||||
|
if h.options.Retries > 0 {
|
||||||
|
retries = h.options.Retries
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
var cc net.Conn
|
||||||
|
var route *Chain
|
||||||
|
for i := 0; i < retries; i++ {
|
||||||
|
route, err = h.options.Chain.selectRouteFor(host)
|
||||||
|
if err != nil {
|
||||||
|
log.Logf("[socks5] %s -> %s : %s",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := bytes.Buffer{}
|
||||||
|
fmt.Fprintf(&buf, "%s -> %s -> ",
|
||||||
|
conn.RemoteAddr(), h.options.Node.String())
|
||||||
|
for _, nd := range route.route {
|
||||||
|
fmt.Fprintf(&buf, "%d@%s -> ", nd.ID, nd.String())
|
||||||
|
}
|
||||||
|
fmt.Fprintf(&buf, "%s", host)
|
||||||
|
log.Log("[route]", buf.String())
|
||||||
|
|
||||||
|
cc, err = route.Dial(host,
|
||||||
TimeoutChainOption(h.options.Timeout),
|
TimeoutChainOption(h.options.Timeout),
|
||||||
HostsChainOption(h.options.Hosts),
|
HostsChainOption(h.options.Hosts),
|
||||||
ResolverChainOption(h.options.Resolver),
|
ResolverChainOption(h.options.Resolver),
|
||||||
)
|
)
|
||||||
|
if err == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
log.Logf("[socks5] %s -> %s : %s",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), err)
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Logf("[socks5-connect] %s -> %s : %s", conn.RemoteAddr(), req.Addr, err)
|
|
||||||
rep := gosocks5.NewReply(gosocks5.HostUnreachable, nil)
|
rep := gosocks5.NewReply(gosocks5.HostUnreachable, nil)
|
||||||
rep.Write(conn)
|
rep.Write(conn)
|
||||||
if Debug {
|
if Debug {
|
||||||
log.Logf("[socks5-connect] %s <- %s\n%s", conn.RemoteAddr(), req.Addr, rep)
|
log.Logf("[socks5] %s <- %s\n%s",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), rep)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -454,22 +499,29 @@ func (h *socks5Handler) handleConnect(conn net.Conn, req *gosocks5.Request) {
|
|||||||
|
|
||||||
rep := gosocks5.NewReply(gosocks5.Succeeded, nil)
|
rep := gosocks5.NewReply(gosocks5.Succeeded, nil)
|
||||||
if err := rep.Write(conn); err != nil {
|
if err := rep.Write(conn); err != nil {
|
||||||
log.Logf("[socks5-connect] %s <- %s : %s", conn.RemoteAddr(), req.Addr, err)
|
log.Logf("[socks5] %s <- %s : %s",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if Debug {
|
if Debug {
|
||||||
log.Logf("[socks5-connect] %s <- %s\n%s", conn.RemoteAddr(), req.Addr, rep)
|
log.Logf("[socks5] %s <- %s\n%s",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), rep)
|
||||||
}
|
}
|
||||||
log.Logf("[socks5-connect] %s <-> %s", conn.RemoteAddr(), req.Addr)
|
log.Logf("[socks5] %s <-> %s", conn.RemoteAddr(), host)
|
||||||
transport(conn, cc)
|
transport(conn, cc)
|
||||||
log.Logf("[socks5-connect] %s >-< %s", conn.RemoteAddr(), req.Addr)
|
log.Logf("[socks5] %s >-< %s", conn.RemoteAddr(), host)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *socks5Handler) handleBind(conn net.Conn, req *gosocks5.Request) {
|
func (h *socks5Handler) handleBind(conn net.Conn, req *gosocks5.Request) {
|
||||||
if h.options.Chain.IsEmpty() {
|
|
||||||
addr := req.Addr.String()
|
addr := req.Addr.String()
|
||||||
|
|
||||||
|
log.Logf("[socks5-bind] %s -> %s -> %s",
|
||||||
|
conn.RemoteAddr(), h.options.Node.String(), addr)
|
||||||
|
|
||||||
|
if h.options.Chain.IsEmpty() {
|
||||||
if !Can("rtcp", addr, h.options.Whitelist, h.options.Blacklist) {
|
if !Can("rtcp", addr, h.options.Whitelist, h.options.Blacklist) {
|
||||||
log.Logf("Unauthorized to tcp bind to %s", addr)
|
log.Logf("[socks5-bind] %s - %s : Unauthorized to tcp bind to %s",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), addr)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
h.bindOn(conn, addr)
|
h.bindOn(conn, addr)
|
||||||
@ -478,11 +530,13 @@ func (h *socks5Handler) handleBind(conn net.Conn, req *gosocks5.Request) {
|
|||||||
|
|
||||||
cc, err := h.options.Chain.Conn()
|
cc, err := h.options.Chain.Conn()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Logf("[socks5-bind] %s <- %s : %s", conn.RemoteAddr(), req.Addr, err)
|
log.Logf("[socks5-bind] %s <- %s : %s",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), err)
|
||||||
reply := gosocks5.NewReply(gosocks5.Failure, nil)
|
reply := gosocks5.NewReply(gosocks5.Failure, nil)
|
||||||
reply.Write(conn)
|
reply.Write(conn)
|
||||||
if Debug {
|
if Debug {
|
||||||
log.Logf("[socks5-bind] %s <- %s\n%s", conn.RemoteAddr(), req.Addr, reply)
|
log.Logf("[socks5-bind] %s <- %s\n%s",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), reply)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -492,16 +546,17 @@ func (h *socks5Handler) handleBind(conn net.Conn, req *gosocks5.Request) {
|
|||||||
// so we don't need to authenticate it, as it's as explicit as whitelisting
|
// so we don't need to authenticate it, as it's as explicit as whitelisting
|
||||||
defer cc.Close()
|
defer cc.Close()
|
||||||
req.Write(cc)
|
req.Write(cc)
|
||||||
log.Logf("[socks5-bind] %s <-> %s", conn.RemoteAddr(), cc.RemoteAddr())
|
log.Logf("[socks5-bind] %s <-> %s", conn.RemoteAddr(), addr)
|
||||||
transport(conn, cc)
|
transport(conn, cc)
|
||||||
log.Logf("[socks5-bind] %s >-< %s", conn.RemoteAddr(), cc.RemoteAddr())
|
log.Logf("[socks5-bind] %s >-< %s", conn.RemoteAddr(), addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *socks5Handler) bindOn(conn net.Conn, addr string) {
|
func (h *socks5Handler) bindOn(conn net.Conn, addr string) {
|
||||||
bindAddr, _ := net.ResolveTCPAddr("tcp", addr)
|
bindAddr, _ := net.ResolveTCPAddr("tcp", addr)
|
||||||
ln, err := net.ListenTCP("tcp", bindAddr) // strict mode: if the port already in use, it will return error
|
ln, err := net.ListenTCP("tcp", bindAddr) // strict mode: if the port already in use, it will return error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Logf("[socks5-bind] %s -> %s : %s", conn.RemoteAddr(), addr, err)
|
log.Logf("[socks5-bind] %s -> %s : %s",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), err)
|
||||||
gosocks5.NewReply(gosocks5.Failure, nil).Write(conn)
|
gosocks5.NewReply(gosocks5.Failure, nil).Write(conn)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -511,14 +566,17 @@ func (h *socks5Handler) bindOn(conn net.Conn, addr string) {
|
|||||||
socksAddr.Host, _, _ = net.SplitHostPort(conn.LocalAddr().String())
|
socksAddr.Host, _, _ = net.SplitHostPort(conn.LocalAddr().String())
|
||||||
reply := gosocks5.NewReply(gosocks5.Succeeded, socksAddr)
|
reply := gosocks5.NewReply(gosocks5.Succeeded, socksAddr)
|
||||||
if err := reply.Write(conn); err != nil {
|
if err := reply.Write(conn); err != nil {
|
||||||
log.Logf("[socks5-bind] %s <- %s : %s", conn.RemoteAddr(), addr, err)
|
log.Logf("[socks5-bind] %s <- %s : %s",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), err)
|
||||||
ln.Close()
|
ln.Close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if Debug {
|
if Debug {
|
||||||
log.Logf("[socks5-bind] %s <- %s\n%s", conn.RemoteAddr(), addr, reply)
|
log.Logf("[socks5-bind] %s <- %s\n%s",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), reply)
|
||||||
}
|
}
|
||||||
log.Logf("[socks5-bind] %s - %s BIND ON %s OK", conn.RemoteAddr(), addr, socksAddr)
|
log.Logf("[socks5-bind] %s - %s BIND ON %s OK",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), socksAddr)
|
||||||
|
|
||||||
var pconn net.Conn
|
var pconn net.Conn
|
||||||
accept := func() <-chan error {
|
accept := func() <-chan error {
|
||||||
@ -1142,17 +1200,18 @@ func (h *socks4Handler) Handle(conn net.Conn) {
|
|||||||
|
|
||||||
req, err := gosocks4.ReadRequest(conn)
|
req, err := gosocks4.ReadRequest(conn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Log("[socks4]", err)
|
log.Logf("[socks4] %s -> %s : %s",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if Debug {
|
if Debug {
|
||||||
log.Logf("[socks4] %s -> %s\n%s", conn.RemoteAddr(), req.Addr, req)
|
log.Logf("[socks4] %s -> %s\n%s",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), req)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch req.Cmd {
|
switch req.Cmd {
|
||||||
case gosocks4.CmdConnect:
|
case gosocks4.CmdConnect:
|
||||||
log.Logf("[socks4-connect] %s -> %s", conn.RemoteAddr(), req.Addr)
|
|
||||||
h.handleConnect(conn, req)
|
h.handleConnect(conn, req)
|
||||||
|
|
||||||
case gosocks4.CmdBind:
|
case gosocks4.CmdBind:
|
||||||
@ -1160,42 +1219,86 @@ func (h *socks4Handler) Handle(conn net.Conn) {
|
|||||||
h.handleBind(conn, req)
|
h.handleBind(conn, req)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
log.Logf("[socks4] Unrecognized request: %d", req.Cmd)
|
log.Logf("[socks4] %s - %s : Unrecognized request: %d",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), req.Cmd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *socks4Handler) handleConnect(conn net.Conn, req *gosocks4.Request) {
|
func (h *socks4Handler) handleConnect(conn net.Conn, req *gosocks4.Request) {
|
||||||
addr := req.Addr.String()
|
addr := req.Addr.String()
|
||||||
|
|
||||||
|
log.Logf("[socks4] %s -> %s -> %s",
|
||||||
|
conn.RemoteAddr(), h.options.Node.String(), addr)
|
||||||
|
|
||||||
if !Can("tcp", addr, h.options.Whitelist, h.options.Blacklist) {
|
if !Can("tcp", addr, h.options.Whitelist, h.options.Blacklist) {
|
||||||
log.Logf("[socks4-connect] Unauthorized to tcp connect to %s", addr)
|
log.Logf("[socks4] %s - %s : Unauthorized to tcp connect to %s",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), addr)
|
||||||
rep := gosocks4.NewReply(gosocks4.Rejected, nil)
|
rep := gosocks4.NewReply(gosocks4.Rejected, nil)
|
||||||
rep.Write(conn)
|
rep.Write(conn)
|
||||||
if Debug {
|
if Debug {
|
||||||
log.Logf("[socks4-connect] %s <- %s\n%s", conn.RemoteAddr(), req.Addr, rep)
|
log.Logf("[socks4] %s <- %s\n%s",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), rep)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if h.options.Bypass.Contains(addr) {
|
if h.options.Bypass.Contains(addr) {
|
||||||
log.Log("[socks4-connect] [bypass]", addr)
|
log.Log("[socks4] %s - %s : Bypass %s",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), addr)
|
||||||
rep := gosocks4.NewReply(gosocks4.Rejected, nil)
|
rep := gosocks4.NewReply(gosocks4.Rejected, nil)
|
||||||
rep.Write(conn)
|
rep.Write(conn)
|
||||||
if Debug {
|
if Debug {
|
||||||
log.Logf("[socks4-connect] %s <- %s\n%s", conn.RemoteAddr(), req.Addr, rep)
|
log.Logf("[socks4] %s <- %s\n%s",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), rep)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cc, err := h.options.Chain.Dial(addr,
|
retries := 1
|
||||||
RetryChainOption(h.options.Retries),
|
if h.options.Chain != nil && h.options.Chain.Retries > 0 {
|
||||||
TimeoutChainOption(h.options.Timeout),
|
retries = h.options.Chain.Retries
|
||||||
)
|
}
|
||||||
|
if h.options.Retries > 0 {
|
||||||
|
retries = h.options.Retries
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
var cc net.Conn
|
||||||
|
var route *Chain
|
||||||
|
for i := 0; i < retries; i++ {
|
||||||
|
route, err = h.options.Chain.selectRouteFor(addr)
|
||||||
|
if err != nil {
|
||||||
|
log.Logf("[socks4] %s -> %s : %s",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := bytes.Buffer{}
|
||||||
|
fmt.Fprintf(&buf, "%s -> %s -> ",
|
||||||
|
conn.RemoteAddr(), h.options.Node.String())
|
||||||
|
for _, nd := range route.route {
|
||||||
|
fmt.Fprintf(&buf, "%d@%s -> ", nd.ID, nd.String())
|
||||||
|
}
|
||||||
|
fmt.Fprintf(&buf, "%s", addr)
|
||||||
|
log.Log("[route]", buf.String())
|
||||||
|
|
||||||
|
cc, err = route.Dial(addr,
|
||||||
|
TimeoutChainOption(h.options.Timeout),
|
||||||
|
HostsChainOption(h.options.Hosts),
|
||||||
|
ResolverChainOption(h.options.Resolver),
|
||||||
|
)
|
||||||
|
if err == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
log.Logf("[socks4] %s -> %s : %s",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), err)
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Logf("[socks4-connect] %s -> %s : %s", conn.RemoteAddr(), req.Addr, err)
|
|
||||||
rep := gosocks4.NewReply(gosocks4.Failed, nil)
|
rep := gosocks4.NewReply(gosocks4.Failed, nil)
|
||||||
rep.Write(conn)
|
rep.Write(conn)
|
||||||
if Debug {
|
if Debug {
|
||||||
log.Logf("[socks4-connect] %s <- %s\n%s", conn.RemoteAddr(), req.Addr, rep)
|
log.Logf("[socks4] %s <- %s\n%s",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), rep)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1203,16 +1306,18 @@ func (h *socks4Handler) handleConnect(conn net.Conn, req *gosocks4.Request) {
|
|||||||
|
|
||||||
rep := gosocks4.NewReply(gosocks4.Granted, nil)
|
rep := gosocks4.NewReply(gosocks4.Granted, nil)
|
||||||
if err := rep.Write(conn); err != nil {
|
if err := rep.Write(conn); err != nil {
|
||||||
log.Logf("[socks4-connect] %s <- %s : %s", conn.RemoteAddr(), req.Addr, err)
|
log.Logf("[socks4] %s <- %s : %s",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if Debug {
|
if Debug {
|
||||||
log.Logf("[socks4-connect] %s <- %s\n%s", conn.RemoteAddr(), req.Addr, rep)
|
log.Logf("[socks4] %s <- %s\n%s",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), rep)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Logf("[socks4-connect] %s <-> %s", conn.RemoteAddr(), req.Addr)
|
log.Logf("[socks4] %s <-> %s", conn.RemoteAddr(), addr)
|
||||||
transport(conn, cc)
|
transport(conn, cc)
|
||||||
log.Logf("[socks4-connect] %s >-< %s", conn.RemoteAddr(), req.Addr)
|
log.Logf("[socks4] %s >-< %s", conn.RemoteAddr(), addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *socks4Handler) handleBind(conn net.Conn, req *gosocks4.Request) {
|
func (h *socks4Handler) handleBind(conn net.Conn, req *gosocks4.Request) {
|
||||||
|
65
ss.go
65
ss.go
@ -125,49 +125,84 @@ func (h *shadowHandler) Handle(conn net.Conn) {
|
|||||||
}
|
}
|
||||||
cipher, err := ss.NewCipher(method, password)
|
cipher, err := ss.NewCipher(method, password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Log("[ss]", err)
|
log.Logf("[ss] %s -> %s : %s",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
conn = &shadowConn{conn: ss.NewConn(conn, cipher)}
|
conn = &shadowConn{conn: ss.NewConn(conn, cipher)}
|
||||||
|
|
||||||
log.Logf("[ss] %s - %s", conn.RemoteAddr(), conn.LocalAddr())
|
|
||||||
|
|
||||||
conn.SetReadDeadline(time.Now().Add(ReadTimeout))
|
conn.SetReadDeadline(time.Now().Add(ReadTimeout))
|
||||||
addr, err := h.getRequest(conn)
|
host, err := h.getRequest(conn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Logf("[ss] %s - %s : %s", conn.RemoteAddr(), conn.LocalAddr(), err)
|
log.Logf("[ss] %s -> %s : %s",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// clear timer
|
// clear timer
|
||||||
conn.SetReadDeadline(time.Time{})
|
conn.SetReadDeadline(time.Time{})
|
||||||
|
|
||||||
log.Logf("[ss] %s -> %s", conn.RemoteAddr(), addr)
|
log.Logf("[ss] %s -> %s -> %s",
|
||||||
|
conn.RemoteAddr(), h.options.Node.String(), host)
|
||||||
|
|
||||||
if !Can("tcp", addr, h.options.Whitelist, h.options.Blacklist) {
|
if !Can("tcp", host, h.options.Whitelist, h.options.Blacklist) {
|
||||||
log.Logf("[ss] Unauthorized to tcp connect to %s", addr)
|
log.Logf("[ss] %s - %s : Unauthorized to tcp connect to %s",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), host)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if h.options.Bypass.Contains(addr) {
|
if h.options.Bypass.Contains(host) {
|
||||||
log.Logf("[ss] [bypass] %s", addr)
|
log.Logf("[ss] %s - %s : Bypass %s",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), host)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cc, err := h.options.Chain.Dial(addr,
|
retries := 1
|
||||||
RetryChainOption(h.options.Retries),
|
if h.options.Chain != nil && h.options.Chain.Retries > 0 {
|
||||||
|
retries = h.options.Chain.Retries
|
||||||
|
}
|
||||||
|
if h.options.Retries > 0 {
|
||||||
|
retries = h.options.Retries
|
||||||
|
}
|
||||||
|
|
||||||
|
var cc net.Conn
|
||||||
|
var route *Chain
|
||||||
|
for i := 0; i < retries; i++ {
|
||||||
|
route, err = h.options.Chain.selectRouteFor(host)
|
||||||
|
if err != nil {
|
||||||
|
log.Logf("[ss] %s -> %s : %s",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := bytes.Buffer{}
|
||||||
|
fmt.Fprintf(&buf, "%s -> %s -> ",
|
||||||
|
conn.RemoteAddr(), h.options.Node.String())
|
||||||
|
for _, nd := range route.route {
|
||||||
|
fmt.Fprintf(&buf, "%d@%s -> ", nd.ID, nd.String())
|
||||||
|
}
|
||||||
|
fmt.Fprintf(&buf, "%s", host)
|
||||||
|
log.Log("[route]", buf.String())
|
||||||
|
|
||||||
|
cc, err = route.Dial(host,
|
||||||
TimeoutChainOption(h.options.Timeout),
|
TimeoutChainOption(h.options.Timeout),
|
||||||
HostsChainOption(h.options.Hosts),
|
HostsChainOption(h.options.Hosts),
|
||||||
ResolverChainOption(h.options.Resolver),
|
ResolverChainOption(h.options.Resolver),
|
||||||
)
|
)
|
||||||
|
if err == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
log.Logf("[ss] %s -> %s : %s",
|
||||||
|
conn.RemoteAddr(), conn.LocalAddr(), err)
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Logf("[ss] %s -> %s : %s", conn.RemoteAddr(), addr, err)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer cc.Close()
|
defer cc.Close()
|
||||||
|
|
||||||
log.Logf("[ss] %s <-> %s", conn.RemoteAddr(), addr)
|
log.Logf("[ss] %s <-> %s", conn.RemoteAddr(), host)
|
||||||
transport(conn, cc)
|
transport(conn, cc)
|
||||||
log.Logf("[ss] %s >-< %s", conn.RemoteAddr(), addr)
|
log.Logf("[ss] %s >-< %s", conn.RemoteAddr(), host)
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
14
ssh.go
14
ssh.go
@ -444,15 +444,15 @@ func (h *sshForwardHandler) Init(options ...HandlerOption) {
|
|||||||
func (h *sshForwardHandler) Handle(conn net.Conn) {
|
func (h *sshForwardHandler) Handle(conn net.Conn) {
|
||||||
sshConn, chans, reqs, err := ssh.NewServerConn(conn, h.config)
|
sshConn, chans, reqs, err := ssh.NewServerConn(conn, h.config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Logf("[ssh-forward] %s -> %s : %s", conn.RemoteAddr(), h.options.Addr, err)
|
log.Logf("[ssh-forward] %s -> %s : %s", conn.RemoteAddr(), h.options.Node.Addr, err)
|
||||||
conn.Close()
|
conn.Close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer sshConn.Close()
|
defer sshConn.Close()
|
||||||
|
|
||||||
log.Logf("[ssh-forward] %s <-> %s", conn.RemoteAddr(), h.options.Addr)
|
log.Logf("[ssh-forward] %s <-> %s", conn.RemoteAddr(), h.options.Node.Addr)
|
||||||
h.handleForward(sshConn, chans, reqs)
|
h.handleForward(sshConn, chans, reqs)
|
||||||
log.Logf("[ssh-forward] %s >-< %s", conn.RemoteAddr(), h.options.Addr)
|
log.Logf("[ssh-forward] %s >-< %s", conn.RemoteAddr(), h.options.Node.Addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *sshForwardHandler) handleForward(conn ssh.Conn, chans <-chan ssh.NewChannel, reqs <-chan *ssh.Request) {
|
func (h *sshForwardHandler) handleForward(conn ssh.Conn, chans <-chan ssh.NewChannel, reqs <-chan *ssh.Request) {
|
||||||
@ -506,7 +506,7 @@ func (h *sshForwardHandler) handleForward(conn ssh.Conn, chans <-chan ssh.NewCha
|
|||||||
func (h *sshForwardHandler) directPortForwardChannel(channel ssh.Channel, raddr string) {
|
func (h *sshForwardHandler) directPortForwardChannel(channel ssh.Channel, raddr string) {
|
||||||
defer channel.Close()
|
defer channel.Close()
|
||||||
|
|
||||||
log.Logf("[ssh-tcp] %s - %s", h.options.Addr, raddr)
|
log.Logf("[ssh-tcp] %s - %s", h.options.Node.Addr, raddr)
|
||||||
|
|
||||||
if !Can("tcp", raddr, h.options.Whitelist, h.options.Blacklist) {
|
if !Can("tcp", raddr, h.options.Whitelist, h.options.Blacklist) {
|
||||||
log.Logf("[ssh-tcp] Unauthorized to tcp connect to %s", raddr)
|
log.Logf("[ssh-tcp] Unauthorized to tcp connect to %s", raddr)
|
||||||
@ -525,14 +525,14 @@ func (h *sshForwardHandler) directPortForwardChannel(channel ssh.Channel, raddr
|
|||||||
ResolverChainOption(h.options.Resolver),
|
ResolverChainOption(h.options.Resolver),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Logf("[ssh-tcp] %s - %s : %s", h.options.Addr, raddr, err)
|
log.Logf("[ssh-tcp] %s - %s : %s", h.options.Node.Addr, raddr, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
log.Logf("[ssh-tcp] %s <-> %s", h.options.Addr, raddr)
|
log.Logf("[ssh-tcp] %s <-> %s", h.options.Node.Addr, raddr)
|
||||||
transport(conn, channel)
|
transport(conn, channel)
|
||||||
log.Logf("[ssh-tcp] %s >-< %s", h.options.Addr, raddr)
|
log.Logf("[ssh-tcp] %s >-< %s", h.options.Node.Addr, raddr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// tcpipForward is structure for RFC 4254 7.1 "tcpip-forward" request
|
// tcpipForward is structure for RFC 4254 7.1 "tcpip-forward" request
|
||||||
|
Loading…
Reference in New Issue
Block a user