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.
|
||||
func (bp *Bypass) Contains(addr string) bool {
|
||||
if bp == nil {
|
||||
if bp == nil || addr == "" {
|
||||
return false
|
||||
}
|
||||
// try to strip the port
|
||||
|
58
chain.go
58
chain.go
@ -1,9 +1,7 @@
|
||||
package gost
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
@ -20,6 +18,7 @@ type Chain struct {
|
||||
isRoute bool
|
||||
Retries int
|
||||
nodeGroups []*NodeGroup
|
||||
route []Node // nodes in the selected route
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
conn, err = route.getConn()
|
||||
if err != nil {
|
||||
log.Log(err)
|
||||
continue
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 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) {
|
||||
if c.IsEmpty() {
|
||||
err = ErrEmptyChain
|
||||
@ -256,35 +251,7 @@ func (c *Chain) getConn() (conn net.Conn, err error) {
|
||||
}
|
||||
|
||||
func (c *Chain) selectRoute() (route *Chain, err error) {
|
||||
if c.IsEmpty() || c.isRoute {
|
||||
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
|
||||
return c.selectRouteFor("")
|
||||
}
|
||||
|
||||
// selectRouteFor selects route with bypass testing.
|
||||
@ -293,8 +260,8 @@ func (c *Chain) selectRouteFor(addr string) (route *Chain, err error) {
|
||||
return c, nil
|
||||
}
|
||||
|
||||
buf := bytes.Buffer{}
|
||||
route = newRoute()
|
||||
var nl []Node
|
||||
|
||||
for _, group := range c.nodeGroups {
|
||||
var node Node
|
||||
@ -304,28 +271,21 @@ func (c *Chain) selectRouteFor(addr string) (route *Chain, err error) {
|
||||
}
|
||||
|
||||
if node.Bypass.Contains(addr) {
|
||||
if Debug {
|
||||
buf.WriteString(fmt.Sprintf("[bypass]%s -> %s", node.String(), addr))
|
||||
log.Log("[route]", buf.String())
|
||||
break
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
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 = newRoute() // cutoff the chain for multiplex node.
|
||||
}
|
||||
|
||||
route.AddNode(node)
|
||||
nl = append(nl, node)
|
||||
}
|
||||
route.Retries = c.Retries
|
||||
|
||||
buf.WriteString(addr)
|
||||
log.Log("[route]", buf.String())
|
||||
route.route = nl
|
||||
|
||||
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"))
|
||||
|
||||
handler.Init(
|
||||
gost.AddrHandlerOption(node.Addr),
|
||||
// gost.AddrHandlerOption(node.Addr),
|
||||
gost.AddrHandlerOption(ln.Addr().String()),
|
||||
gost.ChainHandlerOption(chain),
|
||||
gost.UsersHandlerOption(users...),
|
||||
gost.TLSConfigHandlerOption(tlsCfg),
|
||||
@ -417,9 +418,10 @@ func (r *route) GenRouters() ([]router, error) {
|
||||
gost.BypassHandlerOption(node.Bypass),
|
||||
gost.ResolverHandlerOption(resolver),
|
||||
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.ProbeResistHandlerOption(node.Get("probe_resist")),
|
||||
gost.NodeHandlerOption(node),
|
||||
)
|
||||
|
||||
rt := router{
|
||||
@ -446,7 +448,7 @@ type router struct {
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
Hosts *Hosts
|
||||
ProbeResist string
|
||||
Node Node
|
||||
}
|
||||
|
||||
// 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 {
|
||||
options *HandlerOptions
|
||||
}
|
||||
|
276
http.go
276
http.go
@ -2,6 +2,7 @@ package gost
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"net"
|
||||
@ -108,17 +109,33 @@ func (h *httpHandler) handleRequest(conn net.Conn, req *http.Request) {
|
||||
if req == nil {
|
||||
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.
|
||||
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.Header.Del("Gost-Target")
|
||||
|
||||
resp := &http.Response{
|
||||
ProtoMajor: 1,
|
||||
@ -127,38 +144,147 @@ func (h *httpHandler) handleRequest(conn net.Conn, req *http.Request) {
|
||||
}
|
||||
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",
|
||||
conn.RemoteAddr(), req.Host, req.Host)
|
||||
conn.RemoteAddr(), conn.LocalAddr(), host)
|
||||
resp.StatusCode = http.StatusForbidden
|
||||
|
||||
if Debug {
|
||||
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)
|
||||
return
|
||||
}
|
||||
|
||||
if h.options.Bypass.Contains(req.Host) {
|
||||
log.Logf("[http] [bypass] %s", req.Host)
|
||||
if h.options.Bypass.Contains(host) {
|
||||
resp.StatusCode = http.StatusForbidden
|
||||
|
||||
log.Logf("[http] %s - %s bypass %s",
|
||||
conn.RemoteAddr(), conn.LocalAddr(), host)
|
||||
if Debug {
|
||||
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)
|
||||
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"))
|
||||
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
|
||||
if ss := strings.SplitN(h.options.ProbeResist, ":", 2); len(ss) == 2 {
|
||||
switch ss[0] {
|
||||
@ -178,9 +304,11 @@ func (h *httpHandler) handleRequest(conn net.Conn, req *http.Request) {
|
||||
defer cc.Close()
|
||||
|
||||
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)
|
||||
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
|
||||
}
|
||||
case "file":
|
||||
@ -190,22 +318,21 @@ func (h *httpHandler) handleRequest(conn net.Conn, req *http.Request) {
|
||||
if finfo, _ := f.Stat(); finfo != nil {
|
||||
resp.ContentLength = finfo.Size()
|
||||
}
|
||||
resp.Header.Set("Content-Type", "text/html")
|
||||
resp.Body = f
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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.Header.Add("Proxy-Authenticate", "Basic realm=\"gost\"")
|
||||
} else {
|
||||
resp.Header = http.Header{}
|
||||
resp.Header.Set("Server", "nginx/1.14.1")
|
||||
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 {
|
||||
resp.Header.Set("Connection", "keep-alive")
|
||||
}
|
||||
@ -213,109 +340,12 @@ func (h *httpHandler) handleRequest(conn net.Conn, req *http.Request) {
|
||||
|
||||
if Debug {
|
||||
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)
|
||||
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 {
|
||||
@ -324,9 +354,7 @@ func (h *httpHandler) forwardRequest(conn net.Conn, req *http.Request, route *Ch
|
||||
}
|
||||
lastNode := route.LastNode()
|
||||
|
||||
cc, err := route.Conn(
|
||||
RetryChainOption(1), // we control the retry manually.
|
||||
)
|
||||
cc, err := route.Conn()
|
||||
if err != nil {
|
||||
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
|
||||
}
|
||||
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
|
||||
}
|
||||
cc.SetWriteDeadline(time.Time{})
|
||||
|
206
http2.go
206
http2.go
@ -6,6 +6,7 @@ import (
|
||||
"crypto/tls"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
@ -50,6 +51,7 @@ func (c *http2Connector) Connect(conn net.Conn, addr string, options ...ConnectO
|
||||
Host: cc.addr,
|
||||
ContentLength: -1,
|
||||
}
|
||||
// TODO: use the standard CONNECT method.
|
||||
req.Header.Set("Gost-Target", addr)
|
||||
if c.User != nil {
|
||||
u := c.User.Username()
|
||||
@ -110,8 +112,20 @@ func (tr *http2Transporter) Dial(addr string, options ...DialOption) (net.Conn,
|
||||
}
|
||||
|
||||
tr.clientMutex.Lock()
|
||||
defer tr.clientMutex.Unlock()
|
||||
|
||||
client, ok := tr.clients[addr]
|
||||
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{
|
||||
TLSClientConfig: tr.tlsConfig,
|
||||
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.clientMutex.Unlock()
|
||||
|
||||
return &http2ClientConn{
|
||||
addr: addr,
|
||||
@ -283,31 +296,40 @@ func (h *http2Handler) Handle(conn net.Conn) {
|
||||
}
|
||||
|
||||
func (h *http2Handler) roundTrip(w http.ResponseWriter, r *http.Request) {
|
||||
target := r.Header.Get("Gost-Target")
|
||||
if target == "" {
|
||||
target = r.Host
|
||||
host := r.Header.Get("Gost-Target")
|
||||
if host == "" {
|
||||
host = r.Host
|
||||
}
|
||||
|
||||
if !strings.Contains(target, ":") {
|
||||
target += ":80"
|
||||
if _, port, _ := net.SplitHostPort(host); port == "" {
|
||||
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 {
|
||||
log.Logf("[http2] %s %s - %s %s", r.Method, r.RemoteAddr, target, r.Proto)
|
||||
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)
|
||||
|
||||
if !Can("tcp", target, h.options.Whitelist, h.options.Blacklist) {
|
||||
log.Logf("[http2] Unauthorized to tcp connect to %s", target)
|
||||
if !Can("tcp", host, h.options.Whitelist, h.options.Blacklist) {
|
||||
log.Logf("[http2] %s - %s : Unauthorized to tcp connect to %s",
|
||||
r.RemoteAddr, laddr, host)
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
if h.options.Bypass.Contains(target) {
|
||||
log.Logf("[http2] [bypass] %s", target)
|
||||
if h.options.Bypass.Contains(host) {
|
||||
log.Logf("[http2] %s - %s bypass %s",
|
||||
r.RemoteAddr, laddr, host)
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
@ -319,11 +341,105 @@ func (h *http2Handler) roundTrip(w http.ResponseWriter, r *http.Request) {
|
||||
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"))
|
||||
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
|
||||
if ss := strings.SplitN(h.options.ProbeResist, ":", 2); len(ss) == 2 {
|
||||
switch ss[0] {
|
||||
@ -341,11 +457,11 @@ func (h *http2Handler) roundTrip(w http.ResponseWriter, r *http.Request) {
|
||||
cc, err := net.Dial("tcp", ss[1])
|
||||
if err == nil {
|
||||
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 {
|
||||
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
|
||||
}
|
||||
case "file":
|
||||
@ -361,7 +477,7 @@ func (h *http2Handler) roundTrip(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
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.Header.Add("Proxy-Authenticate", "Basic realm=\"gost\"")
|
||||
} else {
|
||||
@ -379,65 +495,13 @@ func (h *http2Handler) roundTrip(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
if Debug {
|
||||
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)
|
||||
resp.Body.Close()
|
||||
|
||||
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) {
|
||||
|
7
node.go
7
node.go
@ -21,7 +21,7 @@ type Node struct {
|
||||
Protocol string
|
||||
Transport string
|
||||
Remote string // remote address, used by tcp/udp port forwarding
|
||||
url string // raw url
|
||||
url *url.URL // raw url
|
||||
User *url.Userinfo
|
||||
Values url.Values
|
||||
DialOptions []DialOption
|
||||
@ -55,10 +55,11 @@ func ParseNode(s string) (node Node, err error) {
|
||||
Values: u.Query(),
|
||||
User: u.User,
|
||||
marker: &failMarker{},
|
||||
url: u,
|
||||
}
|
||||
|
||||
u.RawQuery = ""
|
||||
node.url = u.String()
|
||||
u.User = nil
|
||||
|
||||
schemes := strings.Split(u.Scheme, "+")
|
||||
if len(schemes) == 1 {
|
||||
@ -139,7 +140,7 @@ func (node *Node) GetInt(key string) int {
|
||||
}
|
||||
|
||||
func (node Node) String() string {
|
||||
return node.url
|
||||
return node.url.String()
|
||||
}
|
||||
|
||||
// NodeGroup is a group of nodes.
|
||||
|
@ -173,7 +173,7 @@ func (f *FailFilter) Filter(nodes []Node) []Node {
|
||||
nl := []Node{}
|
||||
for i := range nodes {
|
||||
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) ||
|
||||
time.Since(time.Unix(marker.failTime, 0)) >= f.FailTimeout {
|
||||
nl = append(nl, nodes[i])
|
||||
|
75
sni.go
75
sni.go
@ -8,6 +8,7 @@ import (
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash/crc32"
|
||||
"io"
|
||||
"net"
|
||||
@ -55,22 +56,23 @@ func (h *sniHandler) Init(options ...HandlerOption) {
|
||||
}
|
||||
|
||||
func (h *sniHandler) Handle(conn net.Conn) {
|
||||
br := bufio.NewReader(conn)
|
||||
defer conn.Close()
|
||||
|
||||
br := bufio.NewReader(conn)
|
||||
hdr, err := br.Peek(dissector.RecordHeaderLen)
|
||||
if err != nil {
|
||||
log.Log("[sni]", err)
|
||||
conn.Close()
|
||||
log.Logf("[sni] %s -> %s : %s",
|
||||
conn.RemoteAddr(), conn.LocalAddr(), err)
|
||||
return
|
||||
}
|
||||
conn = &bufferdConn{br: br, Conn: conn}
|
||||
defer conn.Close()
|
||||
|
||||
if hdr[0] != dissector.Handshake {
|
||||
// We assume it is an HTTP request
|
||||
req, err := http.ReadRequest(bufio.NewReader(conn))
|
||||
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
|
||||
}
|
||||
if !req.URL.IsAbs() {
|
||||
@ -84,40 +86,79 @@ func (h *sniHandler) Handle(conn net.Conn) {
|
||||
|
||||
b, host, err := readClientHelloRecord(conn, "", false)
|
||||
if err != nil {
|
||||
log.Log("[sni]", err)
|
||||
log.Logf("[sni] %s -> %s : %s",
|
||||
conn.RemoteAddr(), conn.LocalAddr(), err)
|
||||
return
|
||||
}
|
||||
|
||||
addr := net.JoinHostPort(host, "443")
|
||||
host = net.JoinHostPort(host, "443")
|
||||
|
||||
if !Can("tcp", addr, h.options.Whitelist, h.options.Blacklist) {
|
||||
log.Logf("[sni] Unauthorized to tcp connect to %s", addr)
|
||||
log.Logf("[ss] %s -> %s -> %s",
|
||||
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
|
||||
}
|
||||
if h.options.Bypass.Contains(addr) {
|
||||
log.Log("[sni] [bypass]", addr)
|
||||
if h.options.Bypass.Contains(host) {
|
||||
log.Log("[sni] %s - %s bypass %s",
|
||||
conn.RemoteAddr(), conn.LocalAddr(), host)
|
||||
return
|
||||
}
|
||||
|
||||
cc, err := h.options.Chain.Dial(addr,
|
||||
RetryChainOption(h.options.Retries),
|
||||
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 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),
|
||||
HostsChainOption(h.options.Hosts),
|
||||
ResolverChainOption(h.options.Resolver),
|
||||
)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
log.Logf("[sni] %s -> %s : %s",
|
||||
conn.RemoteAddr(), conn.LocalAddr(), err)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Logf("[sni] %s -> %s : %s", conn.RemoteAddr(), addr, err)
|
||||
return
|
||||
}
|
||||
defer cc.Close()
|
||||
|
||||
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)
|
||||
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,
|
||||
|
197
socks.go
197
socks.go
@ -386,12 +386,14 @@ func (h *socks5Handler) Handle(conn net.Conn) {
|
||||
conn = gosocks5.ServerConn(conn, h.selector)
|
||||
req, err := gosocks5.ReadRequest(conn)
|
||||
if err != nil {
|
||||
log.Log("[socks5]", err)
|
||||
log.Logf("[socks5] %s -> %s : %s",
|
||||
conn.RemoteAddr(), conn.LocalAddr(), err)
|
||||
return
|
||||
}
|
||||
|
||||
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 {
|
||||
case gosocks5.CmdConnect:
|
||||
@ -410,43 +412,86 @@ func (h *socks5Handler) Handle(conn net.Conn) {
|
||||
h.handleUDPTunnel(conn, req)
|
||||
|
||||
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) {
|
||||
addr := req.Addr.String()
|
||||
if !Can("tcp", addr, h.options.Whitelist, h.options.Blacklist) {
|
||||
log.Logf("[socks5-connect] Unauthorized to tcp connect to %s", addr)
|
||||
host := req.Addr.String()
|
||||
|
||||
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.Write(conn)
|
||||
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
|
||||
}
|
||||
if h.options.Bypass.Contains(addr) {
|
||||
log.Logf("[socks5-connect] [bypass] %s", addr)
|
||||
if h.options.Bypass.Contains(host) {
|
||||
log.Logf("[socks5] %s - %s : Bypass %s",
|
||||
conn.RemoteAddr(), conn.LocalAddr(), host)
|
||||
rep := gosocks5.NewReply(gosocks5.NotAllowed, nil)
|
||||
rep.Write(conn)
|
||||
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
|
||||
}
|
||||
|
||||
cc, err := h.options.Chain.Dial(addr,
|
||||
RetryChainOption(h.options.Retries),
|
||||
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("[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),
|
||||
HostsChainOption(h.options.Hosts),
|
||||
ResolverChainOption(h.options.Resolver),
|
||||
)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
log.Logf("[socks5] %s -> %s : %s",
|
||||
conn.RemoteAddr(), conn.LocalAddr(), err)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Logf("[socks5-connect] %s -> %s : %s", conn.RemoteAddr(), req.Addr, err)
|
||||
rep := gosocks5.NewReply(gosocks5.HostUnreachable, nil)
|
||||
rep.Write(conn)
|
||||
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
|
||||
}
|
||||
@ -454,22 +499,29 @@ func (h *socks5Handler) handleConnect(conn net.Conn, req *gosocks5.Request) {
|
||||
|
||||
rep := gosocks5.NewReply(gosocks5.Succeeded, 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
|
||||
}
|
||||
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)
|
||||
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) {
|
||||
if h.options.Chain.IsEmpty() {
|
||||
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) {
|
||||
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
|
||||
}
|
||||
h.bindOn(conn, addr)
|
||||
@ -478,11 +530,13 @@ func (h *socks5Handler) handleBind(conn net.Conn, req *gosocks5.Request) {
|
||||
|
||||
cc, err := h.options.Chain.Conn()
|
||||
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.Write(conn)
|
||||
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
|
||||
}
|
||||
@ -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
|
||||
defer cc.Close()
|
||||
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)
|
||||
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) {
|
||||
bindAddr, _ := net.ResolveTCPAddr("tcp", addr)
|
||||
ln, err := net.ListenTCP("tcp", bindAddr) // strict mode: if the port already in use, it will return error
|
||||
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)
|
||||
return
|
||||
}
|
||||
@ -511,14 +566,17 @@ func (h *socks5Handler) bindOn(conn net.Conn, addr string) {
|
||||
socksAddr.Host, _, _ = net.SplitHostPort(conn.LocalAddr().String())
|
||||
reply := gosocks5.NewReply(gosocks5.Succeeded, socksAddr)
|
||||
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()
|
||||
return
|
||||
}
|
||||
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
|
||||
accept := func() <-chan error {
|
||||
@ -1142,17 +1200,18 @@ func (h *socks4Handler) Handle(conn net.Conn) {
|
||||
|
||||
req, err := gosocks4.ReadRequest(conn)
|
||||
if err != nil {
|
||||
log.Log("[socks4]", err)
|
||||
log.Logf("[socks4] %s -> %s : %s",
|
||||
conn.RemoteAddr(), conn.LocalAddr(), err)
|
||||
return
|
||||
}
|
||||
|
||||
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 {
|
||||
case gosocks4.CmdConnect:
|
||||
log.Logf("[socks4-connect] %s -> %s", conn.RemoteAddr(), req.Addr)
|
||||
h.handleConnect(conn, req)
|
||||
|
||||
case gosocks4.CmdBind:
|
||||
@ -1160,42 +1219,86 @@ func (h *socks4Handler) Handle(conn net.Conn) {
|
||||
h.handleBind(conn, req)
|
||||
|
||||
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) {
|
||||
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) {
|
||||
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.Write(conn)
|
||||
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
|
||||
}
|
||||
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.Write(conn)
|
||||
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
|
||||
}
|
||||
|
||||
cc, err := h.options.Chain.Dial(addr,
|
||||
RetryChainOption(h.options.Retries),
|
||||
TimeoutChainOption(h.options.Timeout),
|
||||
)
|
||||
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(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 {
|
||||
log.Logf("[socks4-connect] %s -> %s : %s", conn.RemoteAddr(), req.Addr, err)
|
||||
rep := gosocks4.NewReply(gosocks4.Failed, nil)
|
||||
rep.Write(conn)
|
||||
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
|
||||
}
|
||||
@ -1203,16 +1306,18 @@ func (h *socks4Handler) handleConnect(conn net.Conn, req *gosocks4.Request) {
|
||||
|
||||
rep := gosocks4.NewReply(gosocks4.Granted, 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
|
||||
}
|
||||
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)
|
||||
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) {
|
||||
|
65
ss.go
65
ss.go
@ -125,49 +125,84 @@ func (h *shadowHandler) Handle(conn net.Conn) {
|
||||
}
|
||||
cipher, err := ss.NewCipher(method, password)
|
||||
if err != nil {
|
||||
log.Log("[ss]", err)
|
||||
log.Logf("[ss] %s -> %s : %s",
|
||||
conn.RemoteAddr(), conn.LocalAddr(), err)
|
||||
return
|
||||
}
|
||||
conn = &shadowConn{conn: ss.NewConn(conn, cipher)}
|
||||
|
||||
log.Logf("[ss] %s - %s", conn.RemoteAddr(), conn.LocalAddr())
|
||||
|
||||
conn.SetReadDeadline(time.Now().Add(ReadTimeout))
|
||||
addr, err := h.getRequest(conn)
|
||||
host, err := h.getRequest(conn)
|
||||
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
|
||||
}
|
||||
// clear timer
|
||||
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) {
|
||||
log.Logf("[ss] Unauthorized to tcp connect to %s", addr)
|
||||
if !Can("tcp", host, h.options.Whitelist, h.options.Blacklist) {
|
||||
log.Logf("[ss] %s - %s : Unauthorized to tcp connect to %s",
|
||||
conn.RemoteAddr(), conn.LocalAddr(), host)
|
||||
return
|
||||
}
|
||||
|
||||
if h.options.Bypass.Contains(addr) {
|
||||
log.Logf("[ss] [bypass] %s", addr)
|
||||
if h.options.Bypass.Contains(host) {
|
||||
log.Logf("[ss] %s - %s : Bypass %s",
|
||||
conn.RemoteAddr(), conn.LocalAddr(), host)
|
||||
return
|
||||
}
|
||||
|
||||
cc, err := h.options.Chain.Dial(addr,
|
||||
RetryChainOption(h.options.Retries),
|
||||
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 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),
|
||||
HostsChainOption(h.options.Hosts),
|
||||
ResolverChainOption(h.options.Resolver),
|
||||
)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
log.Logf("[ss] %s -> %s : %s",
|
||||
conn.RemoteAddr(), conn.LocalAddr(), err)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Logf("[ss] %s -> %s : %s", conn.RemoteAddr(), addr, err)
|
||||
return
|
||||
}
|
||||
defer cc.Close()
|
||||
|
||||
log.Logf("[ss] %s <-> %s", conn.RemoteAddr(), addr)
|
||||
log.Logf("[ss] %s <-> %s", conn.RemoteAddr(), host)
|
||||
transport(conn, cc)
|
||||
log.Logf("[ss] %s >-< %s", conn.RemoteAddr(), addr)
|
||||
log.Logf("[ss] %s >-< %s", conn.RemoteAddr(), host)
|
||||
}
|
||||
|
||||
const (
|
||||
|
14
ssh.go
14
ssh.go
@ -444,15 +444,15 @@ func (h *sshForwardHandler) Init(options ...HandlerOption) {
|
||||
func (h *sshForwardHandler) Handle(conn net.Conn) {
|
||||
sshConn, chans, reqs, err := ssh.NewServerConn(conn, h.config)
|
||||
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()
|
||||
return
|
||||
}
|
||||
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)
|
||||
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) {
|
||||
@ -506,7 +506,7 @@ func (h *sshForwardHandler) handleForward(conn ssh.Conn, chans <-chan ssh.NewCha
|
||||
func (h *sshForwardHandler) directPortForwardChannel(channel ssh.Channel, raddr string) {
|
||||
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) {
|
||||
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),
|
||||
)
|
||||
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
|
||||
}
|
||||
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)
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user