vless: support fallback to a http server

This commit is contained in:
nadoo 2020-10-04 18:26:44 +08:00
parent 422869b37a
commit 829a0d7f80
6 changed files with 60 additions and 47 deletions

View File

@ -1,20 +0,0 @@
name: Publish Docker image
on:
release:
types: [published]
jobs:
push_to_registry:
name: Push Docker image to Docker Hub
runs-on: ubuntu-latest
steps:
- name: Check out the repo
uses: actions/checkout@v2
- name: Push to Docker Hub
uses: docker/build-push-action@v1
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
repository: nadoo/glider
tag_with_ref: true

View File

@ -167,7 +167,7 @@ VMess scheme:
vmess://[security:]uuid@host:port?alterID=num
VLESS scheme:
vless://uuid@host:port
vless://uuid@host:port[?fallback=127.0.0.1:80]
Trojan scheme:
trojan://pass@host:port[?skipVerify=true]

View File

@ -162,7 +162,7 @@ func usage() {
fmt.Fprintf(w, "\n")
fmt.Fprintf(w, "VLESS scheme:\n")
fmt.Fprintf(w, " vless://uuid@host:port\n")
fmt.Fprintf(w, " vless://uuid@host:port[?fallback=127.0.0.1:80]\n")
fmt.Fprintf(w, "\n")
fmt.Fprintf(w, "Trojan scheme:\n")

View File

@ -45,6 +45,8 @@ listen=socks5://:1080
# listen on 1234 as vless proxy server.
# listen=vless://uuid@:1234
# listen on 1234 as vless proxy server, fallback to 127.0.0.1:8080 http server when client auth failed.
# listen=vless://uuid@:1234?fallback=127.0.0.1:8080
# listen on 1081 as a linux transparent proxy server.
# listen=redir://:1081

View File

@ -49,41 +49,62 @@ func (s *VLess) Serve(c net.Conn) {
c.SetKeepAlive(true)
}
c = NewServerConn(c)
cmd, err := s.readHeader(c)
if err != nil {
log.F("[vless] verify header error: %v", err)
return
}
var fallback bool
var dialer proxy.Dialer
target := s.fallback
tgt, err := ReadAddrString(c)
wbuf := pool.GetWriteBuffer()
defer pool.PutWriteBuffer(wbuf)
cmd, err := s.readHeader(io.TeeReader(c, wbuf))
if err != nil {
log.F("[vless] get target error: %v", err)
return
if s.fallback == "" {
log.F("[vless] verify header error: %v", err)
return
}
fallback = true
log.F("[vless] verify header error: %v, fallback to %s", err, s.fallback)
}
network := "tcp"
dialer := s.proxy.NextDialer(tgt)
if cmd == CmdUDP {
// there is no upstream proxy, just serve it
if dialer.Addr() == "DIRECT" {
s.ServeUoT(c, tgt)
dialer = s.proxy.NextDialer(target)
if !fallback {
c = NewServerConn(c)
target, err = ReadAddrString(c)
if err != nil {
log.F("[vless] get target error: %v", err)
return
}
network = "udp"
if cmd == CmdUDP {
// there is no upstream proxy, just serve it
if dialer.Addr() == "DIRECT" {
s.ServeUoT(c, target)
return
}
network = "udp"
}
}
rc, err := dialer.Dial(network, tgt)
rc, err := dialer.Dial(network, target)
if err != nil {
log.F("[vless] %s <-> %s via %s, error in dial: %v", c.RemoteAddr(), tgt, dialer.Addr(), err)
log.F("[vless] %s <-> %s via %s, error in dial: %v", c.RemoteAddr(), target, dialer.Addr(), err)
return
}
defer rc.Close()
log.F("[vless] %s <-> %s via %s", c.RemoteAddr(), tgt, dialer.Addr())
if fallback {
_, err := rc.Write(wbuf.Bytes())
if err != nil {
log.F("[vless] write to rc error: %v", err)
return
}
}
log.F("[vless] %s <-> %s via %s", c.RemoteAddr(), target, dialer.Addr())
if err = proxy.Relay(c, rc); err != nil {
log.F("[vless] %s <-> %s via %s, relay error: %v", c.RemoteAddr(), tgt, dialer.Addr(), err)
log.F("[vless] %s <-> %s via %s, relay error: %v", c.RemoteAddr(), target, dialer.Addr(), err)
// record remote conn failure only
if !strings.Contains(err.Error(), s.addr) {
s.proxy.Record(dialer, false)
@ -91,7 +112,7 @@ func (s *VLess) Serve(c net.Conn) {
}
}
// ServeUOT serves udp over tcp requests.
// ServeUoT serves udp over tcp requests.
func (s *VLess) ServeUoT(c net.Conn, tgt string) {
rc, err := net.ListenPacket("udp", "")
if err != nil {
@ -118,6 +139,10 @@ func (s *VLess) ServeUoT(c net.Conn, tgt string) {
length := binary.BigEndian.Uint16(buf[:2])
n, err := io.ReadFull(c, buf[:length])
if err != nil {
log.F("[vless] read payload error: %s\n", err)
return
}
_, err = rc.WriteTo(buf[:n], tgtAddr)
if err != nil {
@ -127,7 +152,7 @@ func (s *VLess) ServeUoT(c net.Conn, tgt string) {
}
}()
log.F("[vless] %s <-tcp-> %s - %s <-udp-> %s via DIRECT", c.RemoteAddr(), c.LocalAddr(), rc.LocalAddr(), tgt)
log.F("[vless] %s <-tcp-> %s - %s <-udp-> %s", c.RemoteAddr(), c.LocalAddr(), rc.LocalAddr(), tgt)
buf := pool.GetBuffer(proxy.UDPBufSize)
defer pool.PutBuffer(buf)

View File

@ -24,10 +24,11 @@ const (
// VLess struct.
type VLess struct {
dialer proxy.Dialer
proxy proxy.Proxy
addr string
uuid [16]byte
dialer proxy.Dialer
proxy proxy.Proxy
addr string
uuid [16]byte
fallback string
}
func init() {
@ -55,6 +56,11 @@ func NewVLess(s string, d proxy.Dialer, p proxy.Proxy) (*VLess, error) {
uuid: uuid,
}
v.fallback = "127.0.0.1:80"
if custom := u.Query().Get("fallback"); custom != "" {
v.fallback = custom
}
return v, nil
}