udptun: fixed a bug in nat mapping. #91

This commit is contained in:
nadoo 2019-03-12 23:32:23 +08:00
parent 4ece9ece25
commit 47406ce4ce
9 changed files with 84 additions and 65 deletions

View File

@ -175,7 +175,7 @@ Available Schemes:
Available schemes for different modes:
listen: mixed ss socks5 http redir redir6 tcptun udptun uottun tls unix kcp
forward: ss socks5 http ssr vmess tls ws unix kcp simple-bfs
forward: reject ss socks5 http ssr vmess tls ws unix kcp simple-bfs
SS scheme:
ss://method:pass@host:port

View File

@ -128,7 +128,7 @@ func usage() {
fmt.Fprintf(os.Stderr, "Available schemes for different modes:\n")
fmt.Fprintf(os.Stderr, " listen: mixed ss socks5 http redir redir6 tcptun udptun uottun tls unix kcp\n")
fmt.Fprintf(os.Stderr, " forward: ss socks5 http ssr vmess tls ws unix kcp simple-bfs\n")
fmt.Fprintf(os.Stderr, " forward: reject ss socks5 http ssr vmess tls ws unix kcp simple-bfs\n")
fmt.Fprintf(os.Stderr, "\n")
fmt.Fprintf(os.Stderr, "SS scheme:\n")

View File

@ -5,7 +5,7 @@ import (
"time"
)
// LongTTL is 50 years duration in seconds, used for none-expired items
// LongTTL is 50 years duration in seconds, used for none-expired items.
const LongTTL = 50 * 365 * 24 * 3600
type item struct {
@ -13,13 +13,13 @@ type item struct {
expire time.Time
}
// Cache is the struct of cache
// Cache is the struct of cache.
type Cache struct {
m map[string]*item
l sync.RWMutex
}
// NewCache returns a new cache
// NewCache returns a new cache.
func NewCache() (c *Cache) {
c = &Cache{m: make(map[string]*item)}
go func() {
@ -36,12 +36,12 @@ func NewCache() (c *Cache) {
return
}
// Len returns the length of cache
// Len returns the length of cache.
func (c *Cache) Len() int {
return len(c.m)
}
// Put an item into cache, invalid after ttl seconds
// Put an item into cache, invalid after ttl seconds.
func (c *Cache) Put(k string, v []byte, ttl int) {
if len(v) != 0 {
c.l.Lock()
@ -55,7 +55,7 @@ func (c *Cache) Put(k string, v []byte, ttl int) {
}
}
// Get an item from cache
// Get an item from cache.
func (c *Cache) Get(k string) (v []byte) {
c.l.RLock()
if it, ok := c.m[k]; ok {

View File

@ -13,10 +13,10 @@ import (
"github.com/nadoo/glider/proxy"
)
// HandleFunc function handles the dns TypeA or TypeAAAA answer
// HandleFunc function handles the dns TypeA or TypeAAAA answer.
type HandleFunc func(Domain, ip string) error
// Config for dns
// Config for dns.
type Config struct {
Servers []string
Timeout int
@ -26,7 +26,7 @@ type Config struct {
AlwaysTCP bool
}
// Client is a dns client struct
// Client is a dns client struct.
type Client struct {
dialer proxy.Dialer
cache *Cache
@ -36,7 +36,7 @@ type Client struct {
handlers []HandleFunc
}
// NewClient returns a new dns client
// NewClient returns a new dns client.
func NewClient(dialer proxy.Dialer, config *Config) (*Client, error) {
c := &Client{
dialer: dialer,
@ -54,7 +54,7 @@ func NewClient(dialer proxy.Dialer, config *Config) (*Client, error) {
return c, nil
}
// Exchange handles request msg and returns response msg
// Exchange handles request message and returns response message.
// reqBytes = reqLen + reqMsg
func (c *Client) Exchange(reqBytes []byte, clientAddr string, preferTCP bool) ([]byte, error) {
req, err := UnmarshalMessage(reqBytes[2:])
@ -122,7 +122,7 @@ func (c *Client) Exchange(reqBytes []byte, clientAddr string, preferTCP bool) ([
return respBytes, nil
}
// exchange choose a upstream dns server based on qname, communicate with it on the network
// exchange choose a upstream dns server based on qname, communicate with it on the network.
func (c *Client) exchange(qname string, reqBytes []byte, preferTCP bool) (server, network string, respBytes []byte, err error) {
// use tcp to connect upstream server default
network = "tcp"
@ -170,7 +170,7 @@ func (c *Client) exchange(qname string, reqBytes []byte, preferTCP bool) (server
return server, network, respBytes, err
}
// exchangeTCP exchange with server over tcp
// exchangeTCP exchange with server over tcp.
func (c *Client) exchangeTCP(rc net.Conn, reqBytes []byte) ([]byte, error) {
if _, err := rc.Write(reqBytes); err != nil {
log.F("[dns] failed to write req message: %v", err)
@ -195,7 +195,7 @@ func (c *Client) exchangeTCP(rc net.Conn, reqBytes []byte) ([]byte, error) {
return respBytes, nil
}
// exchangeUDP exchange with server over udp
// exchangeUDP exchange with server over udp.
func (c *Client) exchangeUDP(rc net.Conn, reqBytes []byte) ([]byte, error) {
if _, err := rc.Write(reqBytes[2:]); err != nil {
log.F("[dns] failed to write req message: %v", err)
@ -212,7 +212,7 @@ func (c *Client) exchangeUDP(rc net.Conn, reqBytes []byte) ([]byte, error) {
return reqBytes[:2+n], nil
}
// SetServers sets upstream dns servers for the given domain
// SetServers sets upstream dns servers for the given domain.
func (c *Client) SetServers(domain string, servers ...string) {
c.upServerMap[domain] = append(c.upServerMap[domain], servers...)
}
@ -232,7 +232,7 @@ func (c *Client) GetServers(domain string) []string {
return c.upServers
}
// AddHandler adds a custom handler to handle the resolved result (A and AAAA)
// AddHandler adds a custom handler to handle the resolved result (A and AAAA).
func (c *Client) AddHandler(h HandleFunc) {
c.handlers = append(c.handlers, h)
}
@ -258,7 +258,7 @@ func (c *Client) AddRecord(record string) error {
return nil
}
// GenResponse generates a dns response message for the given domani an ip address
// GenResponse generates a dns response message for the given domain and ip address.
func (c *Client) GenResponse(domain string, ip string) (*Message, error) {
ipb := net.ParseIP(ip)
if ipb == nil {

View File

@ -16,7 +16,7 @@ import (
// the header.
const UDPMaxLen = 512
// HeaderLen is the length of dns msg header
// HeaderLen is the length of dns msg header.
const HeaderLen = 12
// Message types
@ -25,7 +25,7 @@ const (
Response = 1
)
// QType .
// Query types
const (
QTypeA uint16 = 1 //ipv4
QTypeAAAA uint16 = 28 ///ipv6
@ -62,7 +62,7 @@ type Message struct {
unMarshaled []byte
}
// NewMessage returns a new message
// NewMessage returns a new message.
func NewMessage(id uint16, msgType int) *Message {
if id == 0 {
id = uint16(rand.Uint32())
@ -74,20 +74,20 @@ func NewMessage(id uint16, msgType int) *Message {
return m
}
// SetQuestion sets a question to dns message,
// SetQuestion sets a question to dns message.
func (m *Message) SetQuestion(q *Question) error {
m.Question = q
m.Header.SetQdcount(1)
return nil
}
// AddAnswer adds an answer to dns message
// AddAnswer adds an answer to dns message.
func (m *Message) AddAnswer(rr *RR) error {
m.Answers = append(m.Answers, rr)
return nil
}
// Marshal marshals message struct to []byte
// Marshal marshals message struct to []byte.
func (m *Message) Marshal() ([]byte, error) {
var buf bytes.Buffer
@ -117,7 +117,7 @@ func (m *Message) Marshal() ([]byte, error) {
return buf.Bytes(), nil
}
// UnmarshalMessage unmarshals []bytes to Message
// UnmarshalMessage unmarshals []bytes to Message.
func UnmarshalMessage(b []byte) (*Message, error) {
if len(b) < HeaderLen {
return nil, errors.New("UnmarshalMessage: not enough data")
@ -183,22 +183,22 @@ type Header struct {
ARCOUNT uint16
}
// SetMsgType .
// SetMsgType sets the message type.
func (h *Header) SetMsgType(qr int) {
h.Bits |= uint16(qr) << 15
}
// SetTC .
// SetTC sets the tc flag.
func (h *Header) SetTC(tc int) {
h.Bits |= uint16(tc) << 9
}
// SetQdcount sets query count, most dns servers only support 1 query per request
// SetQdcount sets query count, most dns servers only support 1 query per request.
func (h *Header) SetQdcount(qdcount int) {
h.QDCOUNT = uint16(qdcount)
}
// SetAncount sets answers count
// SetAncount sets answers count.
func (h *Header) SetAncount(ancount int) {
h.ANCOUNT = uint16(ancount)
}
@ -208,14 +208,14 @@ func (h *Header) setFlag(QR uint16, Opcode uint16, AA uint16,
h.Bits = QR<<15 + Opcode<<11 + AA<<10 + TC<<9 + RD<<8 + RA<<7 + RCODE
}
// Marshal marshals header struct to []byte
// Marshal marshals header struct to []byte.
func (h *Header) Marshal() ([]byte, error) {
var buf bytes.Buffer
err := binary.Write(&buf, binary.BigEndian, h)
return buf.Bytes(), err
}
// UnmarshalHeader unmarshals []bytes to Header
// UnmarshalHeader unmarshals []bytes to Header.
func UnmarshalHeader(b []byte, h *Header) error {
if h == nil {
return errors.New("unmarshal header must not be nil")
@ -258,7 +258,7 @@ type Question struct {
QCLASS uint16
}
// NewQuestion returns a new dns question
// NewQuestion returns a new dns question.
func NewQuestion(qtype uint16, domain string) *Question {
return &Question{
QNAME: domain,
@ -267,7 +267,7 @@ func NewQuestion(qtype uint16, domain string) *Question {
}
}
// Marshal marshals Question struct to []byte
// Marshal marshals Question struct to []byte.
func (q *Question) Marshal() ([]byte, error) {
var buf bytes.Buffer
@ -278,7 +278,7 @@ func (q *Question) Marshal() ([]byte, error) {
return buf.Bytes(), nil
}
// UnmarshalQuestion unmarshals []bytes to Question
// UnmarshalQuestion unmarshals []bytes to Question.
func (m *Message) UnmarshalQuestion(b []byte, q *Question) (n int, err error) {
if q == nil {
return 0, errors.New("unmarshal question must not be nil")
@ -339,13 +339,13 @@ type RR struct {
IP string
}
// NewRR returns a new dns rr
// NewRR returns a new dns rr.
func NewRR() *RR {
rr := &RR{}
return rr
}
// Marshal marshals RR struct to []byte
// Marshal marshals RR struct to []byte.
func (rr *RR) Marshal() ([]byte, error) {
var buf bytes.Buffer
@ -359,7 +359,7 @@ func (rr *RR) Marshal() ([]byte, error) {
return buf.Bytes(), nil
}
// UnmarshalRR unmarshals []bytes to RR
// UnmarshalRR unmarshals []bytes to RR.
func (m *Message) UnmarshalRR(start int, rr *RR) (n int, err error) {
if rr == nil {
return 0, errors.New("unmarshal rr must not be nil")
@ -399,7 +399,7 @@ func (m *Message) UnmarshalRR(start int, rr *RR) (n int, err error) {
return n, nil
}
// MarshalDomain marshals domain string struct to []byte
// MarshalDomain marshals domain string struct to []byte.
func MarshalDomain(domain string) []byte {
var buf bytes.Buffer
@ -412,7 +412,7 @@ func MarshalDomain(domain string) []byte {
return buf.Bytes()
}
// UnmarshalDomain gets domain from bytes
// UnmarshalDomain gets domain from bytes.
func (m *Message) UnmarshalDomain(b []byte) (string, int, error) {
var idx, size int
var labels = []string{}
@ -457,7 +457,7 @@ func (m *Message) UnmarshalDomain(b []byte) (string, int, error) {
return domain, idx, nil
}
// UnmarshalDomainPoint gets domain from offset point
// UnmarshalDomainPoint gets domain from offset point.
func (m *Message) UnmarshalDomainPoint(offset int) (string, error) {
if offset > len(m.unMarshaled) {
return "", errors.New("UnmarshalDomainPoint: offset larger than msg length")

View File

@ -14,14 +14,14 @@ import (
// conn timeout, seconds
const timeout = 30
// Server is a dns server struct
// Server is a dns server struct.
type Server struct {
addr string
// Client is used to communicate with upstream dns servers
*Client
}
// NewServer returns a new dns server
// NewServer returns a new dns server.
func NewServer(addr string, dialer proxy.Dialer, config *Config) (*Server, error) {
c, err := NewClient(dialer, config)
s := &Server{
@ -32,7 +32,7 @@ func NewServer(addr string, dialer proxy.Dialer, config *Config) (*Server, error
return s, err
}
// Start starts the dns forwarding server
// Start starts the dns forwarding server.
// We use WaitGroup here to ensure both udp and tcp serer are completly running,
// so we can start any other services later, since they may rely on dns service.
func (s *Server) Start() {
@ -43,7 +43,7 @@ func (s *Server) Start() {
wg.Wait()
}
// ListenAndServeUDP .
// ListenAndServeUDP listen and serves on udp port.
func (s *Server) ListenAndServeUDP(wg *sync.WaitGroup) {
c, err := net.ListenPacket("udp", s.addr)
wg.Done()
@ -88,7 +88,7 @@ func (s *Server) ListenAndServeUDP(wg *sync.WaitGroup) {
}
// ListenAndServeTCP .
// ListenAndServeTCP listen and serves on tcp port.
func (s *Server) ListenAndServeTCP(wg *sync.WaitGroup) {
l, err := net.Listen("tcp", s.addr)
wg.Done()
@ -110,7 +110,7 @@ func (s *Server) ListenAndServeTCP(wg *sync.WaitGroup) {
}
}
// ServeTCP .
// ServeTCP serves a tcp connection.
func (s *Server) ServeTCP(c net.Conn) {
defer c.Close()

8
go.mod
View File

@ -10,7 +10,7 @@ require (
github.com/dgryski/go-rc2 v0.0.0-20150621095337-8a9021637152 // indirect
github.com/ebfe/rc2 v0.0.0-20131011165748-24b9757f5521 // indirect
github.com/klauspost/cpuid v1.2.0 // indirect
github.com/klauspost/reedsolomon v1.9.0 // indirect
github.com/klauspost/reedsolomon v1.9.1 // indirect
github.com/nadoo/conflag v0.2.0
github.com/nadoo/go-shadowsocks2 v0.1.0
github.com/pkg/errors v0.8.1 // indirect
@ -19,9 +19,9 @@ require (
github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b // indirect
github.com/tjfoc/gmsm v1.0.1 // indirect
github.com/xtaci/kcp-go v5.0.7+incompatible
golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25
golang.org/x/net v0.0.0-20190301231341-16b79f2e4e95 // indirect
golang.org/x/sys v0.0.0-20190306220723-b294cbcfc56d // indirect
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2
golang.org/x/net v0.0.0-20190311183353-d8887717615a // indirect
golang.org/x/sys v0.0.0-20190312061237-fead79001313 // indirect
)
// Replace dependency modules with local developing copy

19
go.sum
View File

@ -14,6 +14,8 @@ github.com/klauspost/cpuid v1.2.0 h1:NMpwD2G9JSFOE1/TJjGSo5zG7Yb2bTe7eq1jH+irmeE
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/reedsolomon v1.9.0 h1:usyTY5K7D2B6WOHn2jmpB7ky8Qom96mShZmmq3OW4JU=
github.com/klauspost/reedsolomon v1.9.0/go.mod h1:CwCi+NUr9pqSVktrkN+Ondf06rkhYZ/pcNv7fu+8Un4=
github.com/klauspost/reedsolomon v1.9.1 h1:kYrT1MlR4JH6PqOpC+okdb9CDTcwEC/BqpzK4WFyXL8=
github.com/klauspost/reedsolomon v1.9.1/go.mod h1:CwCi+NUr9pqSVktrkN+Ondf06rkhYZ/pcNv7fu+8Un4=
github.com/nadoo/conflag v0.1.0 h1:m9xSrL0UILGXPCZW66mhW57V2D2IraVpWLNIr2Op8X8=
github.com/nadoo/conflag v0.1.0/go.mod h1:C3xchp3tIA3J2haACChSHFrlih7w00f31DXfjVUQa+0=
github.com/nadoo/conflag v0.2.0 h1:xao13tYqfD+5bjQ1A/jT2kBL8tUcVpFhq3seuN5kpeM=
@ -34,8 +36,16 @@ github.com/xtaci/kcp-go v5.0.7+incompatible h1:zs9tc8XRID0m+aetu3qPWZFyRt2UIMqbX
github.com/xtaci/kcp-go v5.0.7+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25 h1:jsG6UpNLt9iAsb0S2AGW28DveNzzgmbXR+ENoPjUeIU=
golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20190301231341-16b79f2e4e95 h1:fY7Dsw114eJN4boqzVSbpVHO6rTdhq6/GnXeu+PKnzU=
golang.org/x/net v0.0.0-20190301231341-16b79f2e4e95/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190310074541-c10a0554eabf h1:J7RqX9u0J9ZB37CGaFc2VC+QZZT6E6jnDbrboEFVo0U=
golang.org/x/net v0.0.0-20190310074541-c10a0554eabf/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311031020-56fb01167e7d h1:vQJbQvu6+H699vOmHa20TEBI9nEqroRbMtf/9biIE3A=
golang.org/x/net v0.0.0-20190311031020-56fb01167e7d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190302025703-b6889370fb10 h1:xQJI9OEiErEQ++DoXOHqEpzsGMrAv2Q2jyCpi7DmfpQ=
golang.org/x/sys v0.0.0-20190302025703-b6889370fb10/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -51,3 +61,12 @@ golang.org/x/sys v0.0.0-20190306155319-3e9a981b8ddb h1:xIUJ1YHSR/6NhHkg597Yw0jPK
golang.org/x/sys v0.0.0-20190306155319-3e9a981b8ddb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190306220723-b294cbcfc56d h1:4Ew1XHJYjwX6RiE8SgSymqS1zCRQyGpcAnVfbpEuXfE=
golang.org/x/sys v0.0.0-20190306220723-b294cbcfc56d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190308023053-584f3b12f43e h1:K7CV15oJ823+HLXQ+M7MSMrUg8LjfqY7O3naO+8Pp/I=
golang.org/x/sys v0.0.0-20190308023053-584f3b12f43e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190310054646-10058d7d4faa h1:lqti/xP+yD/6zH5TqEwx2MilNIJY5Vbc6Qr8J3qyPIQ=
golang.org/x/sys v0.0.0-20190310054646-10058d7d4faa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190311152110-c8c8c57fd1e1 h1:FQNj2xvjQ1lgFyzbSybGZr792Y8Dy95D7uuqnZAzNaA=
golang.org/x/sys v0.0.0-20190311152110-c8c8c57fd1e1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190312061237-fead79001313 h1:pczuHS43Cp2ktBEEmLwScxgjWsBSzdaQiKzUyf3DTTc=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

View File

@ -12,23 +12,23 @@ import (
"github.com/nadoo/glider/proxy"
)
// UDPTun struct
// UDPTun is a base udptun struct.
type UDPTun struct {
dialer proxy.Dialer
addr string
raddr string
taddr string // tunnel addr
uaddr *net.UDPAddr // tunnel addr
}
func init() {
proxy.RegisterServer("udptun", NewUDPTunServer)
}
// NewUDPTun returns a UDPTun proxy
// NewUDPTun returns a UDPTun proxy.
func NewUDPTun(s string, dialer proxy.Dialer) (*UDPTun, error) {
u, err := url.Parse(s)
if err != nil {
log.F("parse err: %s", err)
log.F("[udptun] parse err: %s", err)
return nil, err
}
@ -38,18 +38,19 @@ func NewUDPTun(s string, dialer proxy.Dialer) (*UDPTun, error) {
p := &UDPTun{
dialer: dialer,
addr: d[0],
raddr: d[1],
taddr: d[1],
}
return p, nil
p.uaddr, err = net.ResolveUDPAddr("udp", p.taddr)
return p, err
}
// NewUDPTunServer returns a udp tunnel server
// NewUDPTunServer returns a udp tunnel server.
func NewUDPTunServer(s string, dialer proxy.Dialer) (proxy.Server, error) {
return NewUDPTun(s, dialer)
}
// ListenAndServe .
// ListenAndServe listen and serves on the given address.
func (s *UDPTun) ListenAndServe() {
c, err := net.ListenPacket("udp", s.addr)
if err != nil {
@ -71,12 +72,11 @@ func (s *UDPTun) ListenAndServe() {
}
var pc net.PacketConn
var writeAddr net.Addr
v, ok := nm.Load(raddr.String())
if !ok && v == nil {
pc, writeAddr, err = s.dialer.DialUDP("udp", s.raddr)
pc, _, err = s.dialer.DialUDP("udp", s.taddr)
if err != nil {
log.F("[udptun] remote dial error: %v", err)
continue
@ -94,18 +94,18 @@ func (s *UDPTun) ListenAndServe() {
pc = v.(net.PacketConn)
}
_, err = pc.WriteTo(buf[:n], writeAddr)
_, err = pc.WriteTo(buf[:n], s.uaddr)
if err != nil {
log.F("[udptun] remote write error: %v", err)
continue
}
log.F("[udptun] %s <-> %s", raddr, s.raddr)
log.F("[udptun] %s <-> %s", raddr, s.taddr)
}
}
// Serve .
// Serve serves a net.Conn, can not be called directly.
func (s *UDPTun) Serve(c net.Conn) {
log.F("[udptun] func Serve: can not be called directly")
}