vless: spport server mode

This commit is contained in:
nadoo 2020-10-03 20:51:27 +08:00
parent 1ed7fbff65
commit 8b6739f12c
15 changed files with 328 additions and 97 deletions

View File

@ -4,7 +4,7 @@
[![GitHub release](https://img.shields.io/github/v/release/nadoo/glider.svg?style=flat-square&include_prereleases)](https://github.com/nadoo/glider/releases)
[![Actions Status](https://img.shields.io/github/workflow/status/nadoo/glider/Build?style=flat-square)](https://github.com/nadoo/glider/actions)
glider is a forward proxy with multiple protocols support, and also a dns forwarding server with ipset management features(like dnsmasq).
glider is a forward proxy with multiple protocols support, and also a dns/dhcp forwarding server with ipset management features(like dnsmasq).
we can set up local listeners as proxy servers, and forward requests to internet via forwarders.

View File

@ -14,6 +14,7 @@ import (
var flag = conflag.New()
// Config is global config struct.
type Config struct {
Verbose bool

7
go.mod
View File

@ -10,10 +10,9 @@ require (
github.com/nadoo/ipset v0.3.0
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
github.com/xtaci/kcp-go/v5 v5.5.17
golang.org/x/crypto v0.0.0-20201002094018-c90954cbb977
golang.org/x/net v0.0.0-20200930145003-4acb6c075d10 // indirect
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f // indirect
golang.org/x/tools v0.0.0-20201002055958-0d28ed0cbe40 // indirect
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0
golang.org/x/net v0.0.0-20201002202402-0a1ea396d57c // indirect
golang.org/x/tools v0.0.0-20201002184944-ecd9fd270d5d // indirect
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect
)

12
go.sum
View File

@ -118,8 +118,8 @@ golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de h1:ikNHVSjEfnvz6sxdSPCaPt572qowuyMDMJLLm3Db3ig=
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201002094018-c90954cbb977 h1:yH6opeNE+0SY+7pXT4gclZUoKHogXeC2EvOSHGOMGPU=
golang.org/x/crypto v0.0.0-20201002094018-c90954cbb977/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0 h1:hb9wdF1z5waM+dSIICn1l0DkLVDT3hqhhQsDNUmHPRE=
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
@ -141,8 +141,8 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgN
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200930145003-4acb6c075d10 h1:YfxMZzv3PjGonQYNUaeU2+DhAdqOxerQ30JFB6WgAXo=
golang.org/x/net v0.0.0-20200930145003-4acb6c075d10/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201002202402-0a1ea396d57c h1:dk0ukUIHmGHqASjP0iue2261isepFCC6XRCSd1nHgDw=
golang.org/x/net v0.0.0-20201002202402-0a1ea396d57c/go.mod h1:iQL9McJNjoIa5mjH6nYTCTZXUN6RP+XW3eib7Ya3XcI=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -173,8 +173,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20200425043458-8463f397d07c h1:iHhCR0b26amDCiiO+kBguKZom9aMF+NrFxh9zeKR/XU=
golang.org/x/tools v0.0.0-20200425043458-8463f397d07c/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200808161706-5bf02b21f123/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20201002055958-0d28ed0cbe40 h1:ErPN1Z9An7dXc56pRUCKgWJkjYzc3hE+y15ky9E8qxU=
golang.org/x/tools v0.0.0-20201002055958-0d28ed0cbe40/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
golang.org/x/tools v0.0.0-20201002184944-ecd9fd270d5d h1:vWQvJ/Z0Lu+9/8oQ/pAYXNzbc7CMnBl+tULGVHOy3oE=
golang.org/x/tools v0.0.0-20201002184944-ecd9fd270d5d/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=

View File

@ -154,12 +154,12 @@ func (s *Socks5) Serve(c net.Conn) {
func (s *Socks5) ListenAndServeUDP() {
lc, err := net.ListenPacket("udp", s.addr)
if err != nil {
log.F("[socks5-udp] failed to listen on %s: %v", s.addr, err)
log.F("[socks5] failed to listen on UDP %s: %v", s.addr, err)
return
}
defer lc.Close()
log.F("[socks5-udp] listening UDP on %s", s.addr)
log.F("[socks5] listening UDP on %s", s.addr)
var nm sync.Map
buf := make([]byte, proxy.UDPBufSize)
@ -169,7 +169,7 @@ func (s *Socks5) ListenAndServeUDP() {
n, raddr, err := c.ReadFrom(buf)
if err != nil {
log.F("[socks5-udp] remote read error: %v", err)
log.F("[socks5u] remote read error: %v", err)
continue
}
@ -177,13 +177,13 @@ func (s *Socks5) ListenAndServeUDP() {
v, ok := nm.Load(raddr.String())
if !ok && v == nil {
if c.tgtAddr == nil {
log.F("[socks5-udp] can not get target address, not a valid request")
log.F("[socks5u] can not get target address, not a valid request")
continue
}
lpc, nextHop, err := s.proxy.DialUDP("udp", c.tgtAddr.String())
if err != nil {
log.F("[socks5-udp] remote dial error: %v", err)
log.F("[socks5u] remote dial error: %v", err)
continue
}
@ -196,7 +196,7 @@ func (s *Socks5) ListenAndServeUDP() {
nm.Delete(raddr.String())
}()
log.F("[socks5-udp] %s <-> %s", raddr, c.tgtAddr)
log.F("[socks5u] %s <-> %s", raddr, c.tgtAddr)
} else {
pc = v.(*PktConn)
@ -204,11 +204,11 @@ func (s *Socks5) ListenAndServeUDP() {
_, err = pc.WriteTo(buf[:n], pc.writeAddr)
if err != nil {
log.F("[socks5-udp] remote write error: %v", err)
log.F("[socks5u] remote write error: %v", err)
continue
}
// log.F("[socks5-udp] %s <-> %s", raddr, c.tgtAddr)
// log.F("[socks5u] %s <-> %s", raddr, c.tgtAddr)
}
}

View File

@ -117,7 +117,7 @@ func (s *SS) Serve(c net.Conn) {
if uot && dialer.Addr() == "DIRECT" {
rc, err := net.ListenPacket("udp", "")
if err != nil {
log.F("[ss-uottun] UDP remote listen error: %v", err)
log.F("[ssuot] UDP remote listen error: %v", err)
}
defer rc.Close()
@ -126,7 +126,7 @@ func (s *SS) Serve(c net.Conn) {
n, err := c.Read(buf)
if err != nil {
log.F("[ss-uottun] error in read: %s\n", err)
log.F("[ssuot] error in read: %s\n", err)
return
}
@ -135,7 +135,7 @@ func (s *SS) Serve(c net.Conn) {
n, _, err = rc.ReadFrom(buf)
if err != nil {
log.F("[ss-uottun] read error: %v", err)
log.F("[ssuot] read error: %v", err)
}
c.Write(buf[:n])
@ -172,14 +172,14 @@ func (s *SS) Serve(c net.Conn) {
func (s *SS) ListenAndServeUDP() {
lc, err := net.ListenPacket("udp", s.addr)
if err != nil {
log.F("[ssu] failed to listen on %s: %v", s.addr, err)
log.F("[ss] failed to listen on UDP %s: %v", s.addr, err)
return
}
defer lc.Close()
lc = s.PacketConn(lc)
log.F("[ssu] listening UDP on %s", s.addr)
log.F("[ss] listening UDP on %s", s.addr)
var nm sync.Map
buf := make([]byte, proxy.UDPBufSize)

View File

@ -11,7 +11,7 @@ import (
"github.com/nadoo/glider/proxy/socks"
)
// PktConn .
// PktConn is a udp Packet.Conn.
type PktConn struct {
net.Conn
@ -58,7 +58,7 @@ func (pc *PktConn) ReadFrom(b []byte) (int, net.Addr, error) {
// Payload
n, err := io.ReadFull(pc.Conn, b[:length])
if err != nil {
return 0, nil, err
return n, nil, err
}
// TODO: check the addr in return value, it's a fake packetConn so the addr is not valid

View File

@ -17,7 +17,7 @@ import (
"github.com/nadoo/glider/proxy/socks"
)
// Trojan is a base trojan struct
// Trojan is a base trojan struct.
type Trojan struct {
dialer proxy.Dialer
proxy proxy.Proxy
@ -67,7 +67,7 @@ func NewTrojan(s string, d proxy.Dialer, p proxy.Proxy) (*Trojan, error) {
t.tlsConfig = &tls.Config{
ServerName: t.serverName,
InsecureSkipVerify: t.skipVerify,
NextProtos: []string{"http/1.1", "h2"},
NextProtos: []string{"http/1.1"},
ClientSessionCache: tls.NewLRUClientSessionCache(64),
MinVersion: tls.VersionTLS10,
}

View File

@ -1,8 +1,12 @@
package vless
import (
"encoding/binary"
"io"
"net"
"strconv"
"github.com/nadoo/glider/pool"
)
// Atyp is vless addr type.
@ -19,6 +23,9 @@ const (
// Addr is vless addr.
type Addr []byte
// MaxHostLen is the maximum size of host in bytes.
const MaxHostLen = 255
// Port is vless addr port.
type Port uint16
@ -43,7 +50,7 @@ func ParseAddr(s string) (Atyp, Addr, Port, error) {
copy(addr[:], ip)
}
} else {
if len(host) > 255 {
if len(host) > MaxHostLen {
return 0, nil, 0, err
}
addr = make([]byte, 1+len(host))
@ -59,3 +66,67 @@ func ParseAddr(s string) (Atyp, Addr, Port, error) {
return atyp, addr, Port(portnum), err
}
// ReadAddr reads just enough bytes from r to get addr.
func ReadAddr(r io.Reader) (atyp Atyp, host Addr, port Port, err error) {
buf := pool.GetBuffer(2)
defer pool.PutBuffer(buf)
// port
_, err = io.ReadFull(r, buf[:2])
if err != nil {
return
}
port = Port(binary.BigEndian.Uint16(buf[:2]))
// atyp
_, err = io.ReadFull(r, buf[:1])
if err != nil {
return
}
atyp = Atyp(buf[0])
switch atyp {
case AtypIP4:
host = make([]byte, net.IPv4len)
_, err = io.ReadFull(r, host)
return
case AtypIP6:
host = make([]byte, net.IPv6len)
_, err = io.ReadFull(r, host)
return
case AtypDomain:
_, err = io.ReadFull(r, buf[:1])
if err != nil {
return
}
host = make([]byte, int(buf[0]))
_, err = io.ReadFull(r, host)
return
}
return
}
// ReadAddrString reads just enough bytes from r to get addr string.
func ReadAddrString(r io.Reader) (string, error) {
atyp, host, port, err := ReadAddr(r)
if err != nil {
return "", err
}
return AddrString(atyp, host, port), nil
}
// AddrString returns a addr string inf format "host:port".
func AddrString(atyp Atyp, addr Addr, port Port) string {
var host string
switch atyp {
case AtypIP4, AtypIP6:
host = net.IP(addr).String()
case AtypDomain:
host = string(addr)
}
return net.JoinHostPort(host, strconv.Itoa(int(port)))
}

View File

@ -2,33 +2,55 @@ package vless
import (
"encoding/binary"
"encoding/hex"
"errors"
"io"
"io/ioutil"
"net"
"strings"
"github.com/nadoo/glider/pool"
"github.com/nadoo/glider/proxy"
)
const Version byte = 0
// NewVLessDialer returns a vless proxy dialer.
func NewVLessDialer(s string, dialer proxy.Dialer) (proxy.Dialer, error) {
return NewVLess(s, dialer, nil)
}
// CMD types.
const (
CmdTCP byte = 1
CmdUDP byte = 2
)
// Addr returns forwarder's address.
func (s *VLess) Addr() string {
if s.addr == "" {
return s.dialer.Addr()
}
return s.addr
}
// Conn is a vless client connection.
type Conn struct {
// Dial connects to the address addr on the network net via the proxy.
func (s *VLess) Dial(network, addr string) (net.Conn, error) {
rc, err := s.dialer.Dial("tcp", s.addr)
if err != nil {
return nil, err
}
return NewClientConn(rc, s.uuid, network, addr)
}
// DialUDP connects to the given address via the proxy.
func (s *VLess) DialUDP(network, addr string) (net.PacketConn, net.Addr, error) {
c, err := s.Dial("udp", addr)
if err != nil {
return nil, nil, err
}
pkc := NewPktConn(c)
return pkc, nil, nil
}
// ClientConn is a vless client connection.
type ClientConn struct {
net.Conn
rcved bool
}
// ClientConn returns a new vless client conn.
func ClientConn(c net.Conn, uuid [16]byte, network, target string) (*Conn, error) {
// NewClientConn returns a new vless client conn.
func NewClientConn(c net.Conn, uuid [16]byte, network, target string) (*ClientConn, error) {
atyp, addr, port, err := ParseAddr(target)
if err != nil {
return nil, err
@ -45,7 +67,7 @@ func ClientConn(c net.Conn, uuid [16]byte, network, target string) (*Conn, error
if network == "udp" {
cmd = CmdUDP
}
buf.WriteByte(cmd) // cmd
buf.WriteByte(byte(cmd)) // cmd
// target
err = binary.Write(buf, binary.BigEndian, uint16(port)) // port
@ -56,10 +78,10 @@ func ClientConn(c net.Conn, uuid [16]byte, network, target string) (*Conn, error
buf.Write(addr) //addr
_, err = c.Write(buf.Bytes())
return &Conn{Conn: c}, err
return &ClientConn{Conn: c}, err
}
func (c *Conn) Read(b []byte) (n int, err error) {
func (c *ClientConn) Read(b []byte) (n int, err error) {
if !c.rcved {
buf := pool.GetBuffer(2)
defer pool.PutBuffer(buf)
@ -81,14 +103,3 @@ func (c *Conn) Read(b []byte) (n int, err error) {
return c.Conn.Read(b)
}
// StrToUUID converts string to uuid.
// s fomat: "6ba7b810-9dad-11d1-80b4-00c04fd430c8"
func StrToUUID(s string) (uuid [16]byte, err error) {
b := []byte(strings.Replace(s, "-", "", -1))
if len(b) != 32 {
return uuid, errors.New("invalid UUID: " + s)
}
_, err = hex.Decode(uuid[:], b)
return
}

View File

@ -9,15 +9,11 @@ import (
"github.com/nadoo/glider/pool"
)
// PktConn .
type PktConn struct {
net.Conn
}
// PktConn is a udp Packet.Conn.
type PktConn struct{ net.Conn }
// NewPktConn returns a PktConn.
func NewPktConn(c net.Conn) *PktConn {
return &PktConn{Conn: c}
}
func NewPktConn(c net.Conn) *PktConn { return &PktConn{Conn: c} }
// ReadFrom implements the necessary function of net.PacketConn.
// TODO: we know that we use it in proxy.RelayUDP and the length of b is enough, check it later.
@ -35,7 +31,7 @@ func (pc *PktConn) ReadFrom(b []byte) (int, net.Addr, error) {
// Payload
n, err := io.ReadFull(pc.Conn, b[:length])
if err != nil {
return 0, nil, err
return n, nil, err
}
return n, nil, nil

150
proxy/vless/server.go Normal file
View File

@ -0,0 +1,150 @@
package vless
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"net"
"strings"
"github.com/nadoo/glider/log"
"github.com/nadoo/glider/pool"
"github.com/nadoo/glider/proxy"
)
// NewVLessServer returns a vless proxy server.
func NewVLessServer(s string, p proxy.Proxy) (proxy.Server, error) {
return NewVLess(s, nil, p)
}
// ListenAndServe listen and serves connections.
func (s *VLess) ListenAndServe() {
l, err := net.Listen("tcp", s.addr)
if err != nil {
log.F("[vless] failed to listen on %s: %v", s.addr, err)
return
}
defer l.Close()
log.F("[vless] listening TCP on %s", s.addr)
for {
c, err := l.Accept()
if err != nil {
log.F("[vless] failed to accept: %v", err)
continue
}
go s.Serve(c)
}
}
// Serve serves a connection.
func (s *VLess) Serve(c net.Conn) {
defer c.Close()
if c, ok := c.(*net.TCPConn); ok {
c.SetKeepAlive(true)
}
c = NewServerConn(c)
_, err := s.readHeader(c)
if err != nil {
log.F("[vless] verify header error: %v", err)
return
}
tgt, err := ReadAddrString(c)
if err != nil {
log.F("[vless] get target error: %v", err)
return
}
dialer := s.proxy.NextDialer(tgt)
rc, err := dialer.Dial("tcp", tgt)
if err != nil {
log.F("[vless] %s <-> %s via %s, error in dial: %v", c.RemoteAddr(), tgt, dialer.Addr(), err)
return
}
defer rc.Close()
log.F("[vless] %s <-> %s via %s", c.RemoteAddr(), tgt, 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)
// record remote conn failure only
if !strings.Contains(err.Error(), s.addr) {
s.proxy.Record(dialer, false)
}
}
}
func (s *VLess) readHeader(r io.Reader) (CmdType, error) {
buf := pool.GetBuffer(16)
defer pool.PutBuffer(buf)
// ver
if _, err := io.ReadFull(r, buf[:1]); err != nil {
return CmdErr, fmt.Errorf("get version error: %v", err)
}
if buf[0] != Version {
return CmdErr, fmt.Errorf("version %d not supported", buf[0])
}
// uuid
if _, err := io.ReadFull(r, buf[:16]); err != nil {
return CmdErr, fmt.Errorf("get uuid error: %v", err)
}
if !bytes.Equal(s.uuid[:], buf) {
return CmdErr, fmt.Errorf("auth failed, client id: %02x", buf[:16])
}
// addLen
if _, err := io.ReadFull(r, buf[:1]); err != nil {
return CmdErr, fmt.Errorf("get addon length error: %v", err)
}
// ignore addons
if addLen := int64(buf[0]); addLen > 0 {
proxy.CopyN(ioutil.Discard, r, addLen)
}
// cmd
if _, err := io.ReadFull(r, buf[:1]); err != nil {
return CmdErr, fmt.Errorf("get cmd error: %v", err)
}
return CmdType(buf[0]), nil
}
// ServerConn is a vless client connection.
type ServerConn struct {
net.Conn
sent bool
}
// NewServerConn returns a new vless client conn.
func NewServerConn(c net.Conn) *ServerConn {
return &ServerConn{Conn: c}
}
func (c *ServerConn) Write(b []byte) (int, error) {
if !c.sent {
buf := pool.GetWriteBuffer()
defer pool.PutWriteBuffer(buf)
buf.WriteByte(Version) // ver
buf.WriteByte(0) // addonLen
buf.Write(b)
c.sent = true
n, err := c.Conn.Write(buf.Bytes())
return n - 2, err
}
return c.Conn.Write(b)
}

View File

@ -1,25 +1,42 @@
package vless
import (
"net"
"encoding/hex"
"errors"
"net/url"
"strings"
"github.com/nadoo/glider/proxy"
)
// Version of vless protocol.
const Version byte = 0
// CmdType is vless cmd type.
type CmdType byte
// CMD types.
const (
CmdErr CmdType = 0
CmdTCP CmdType = 1
CmdUDP CmdType = 2
)
// VLess struct.
type VLess struct {
dialer proxy.Dialer
proxy proxy.Proxy
addr string
uuid [16]byte
}
func init() {
proxy.RegisterDialer("vless", NewVLessDialer)
proxy.RegisterServer("vless", NewVLessServer)
}
// NewVLess returns a vless proxy.
func NewVLess(s string, d proxy.Dialer) (*VLess, error) {
func NewVLess(s string, d proxy.Dialer, p proxy.Proxy) (*VLess, error) {
u, err := url.Parse(s)
if err != nil {
return nil, err
@ -31,43 +48,23 @@ func NewVLess(s string, d proxy.Dialer) (*VLess, error) {
return nil, err
}
p := &VLess{
v := &VLess{
dialer: d,
proxy: p,
addr: addr,
uuid: uuid,
}
return p, nil
return v, nil
}
// NewVLessDialer returns a vless proxy dialer.
func NewVLessDialer(s string, dialer proxy.Dialer) (proxy.Dialer, error) {
return NewVLess(s, dialer)
}
// Addr returns forwarder's address.
func (s *VLess) Addr() string {
if s.addr == "" {
return s.dialer.Addr()
// StrToUUID converts string to uuid.
// s fomat: "6ba7b810-9dad-11d1-80b4-00c04fd430c8"
func StrToUUID(s string) (uuid [16]byte, err error) {
b := []byte(strings.Replace(s, "-", "", -1))
if len(b) != 32 {
return uuid, errors.New("invalid UUID: " + s)
}
return s.addr
}
// Dial connects to the address addr on the network net via the proxy.
func (s *VLess) Dial(network, addr string) (net.Conn, error) {
rc, err := s.dialer.Dial("tcp", s.addr)
if err != nil {
return nil, err
}
return ClientConn(rc, s.uuid, network, addr)
}
// DialUDP connects to the given address via the proxy.
func (s *VLess) DialUDP(network, addr string) (net.PacketConn, net.Addr, error) {
c, err := s.Dial("udp", addr)
if err != nil {
return nil, nil, err
}
pkc := NewPktConn(c)
return pkc, nil, nil
_, err = hex.Decode(uuid[:], b)
return
}

View File

@ -76,7 +76,7 @@ func handleDHCP(serverIP net.IP, mask net.IPMask, pool *Pool) server4.Handler {
replyIp, err := pool.AssignIP(m.ClientHWAddr)
if err != nil {
log.F("[dpcpd] can not assign IP error %s", err)
log.F("[dpcpd] can not assign IP, error %s", err)
return
}
@ -92,6 +92,10 @@ func handleDHCP(serverIP net.IP, mask net.IPMask, pool *Pool) server4.Handler {
// RFC 2131, Section 4.3.1. IP lease time: MUST
dhcpv4.WithOption(dhcpv4.OptIPAddressLeaseTime(leaseTime)),
)
if err != nil {
log.F("[dpcpd] can not create reply message, error %s", err)
return
}
if val := m.Options.Get(dhcpv4.OptionClientIdentifier); len(val) > 0 {
reply.UpdateOption(dhcpv4.OptGeneric(dhcpv4.OptionClientIdentifier, val))

View File

@ -8,6 +8,7 @@ import (
"time"
)
// Pool is a dhcp pool.
type Pool struct {
items []*item
}
@ -31,6 +32,7 @@ func NewPool(lease time.Duration, start, end net.IP) (*Pool, error) {
return &Pool{items: items}, nil
}
// AssignIP assigns an ip to mac from dhco pool.
func (p *Pool) AssignIP(mac net.HardwareAddr) (net.IP, error) {
var ip net.IP
for _, item := range p.items {