mirror of
https://github.com/nadoo/glider.git
synced 2025-02-23 17:35:40 +08:00
ss: add udp support as server mode
This commit is contained in:
parent
8bc8ee3876
commit
30f340dc86
27
conn.go
27
conn.go
@ -52,3 +52,30 @@ func relay(left, right net.Conn) (int64, int64, error) {
|
|||||||
}
|
}
|
||||||
return n, rs.N, err
|
return n, rs.N, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// copy from src to dst at target with read timeout
|
||||||
|
func timedCopy(dst net.PacketConn, target net.Addr, src net.PacketConn, timeout time.Duration, srcIncluded bool) error {
|
||||||
|
buf := make([]byte, udpBufSize)
|
||||||
|
|
||||||
|
for {
|
||||||
|
src.SetReadDeadline(time.Now().Add(timeout))
|
||||||
|
n, raddr, err := src.ReadFrom(buf)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if srcIncluded { // server -> client: add original packet source
|
||||||
|
srcAddr := ParseAddr(raddr.String())
|
||||||
|
copy(buf[len(srcAddr):], buf[:n])
|
||||||
|
copy(buf, srcAddr)
|
||||||
|
_, err = dst.WriteTo(buf[:len(srcAddr)+n], target)
|
||||||
|
} else { // client -> user: strip original packet source
|
||||||
|
srcAddr := SplitAddr(buf[:n])
|
||||||
|
_, err = dst.WriteTo(buf[len(srcAddr):n], target)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
16
socks5.go
16
socks5.go
@ -326,7 +326,7 @@ func (s *SOCKS5) handshake(rw io.ReadWriter) (Addr, error) {
|
|||||||
func (a Addr) String() string {
|
func (a Addr) String() string {
|
||||||
var host, port string
|
var host, port string
|
||||||
|
|
||||||
switch a[0] { // address type
|
switch ATYP(a[0]) { // address type
|
||||||
case socks5Domain:
|
case socks5Domain:
|
||||||
host = string(a[2 : 2+int(a[1])])
|
host = string(a[2 : 2+int(a[1])])
|
||||||
port = strconv.Itoa((int(a[2+int(a[1])]) << 8) | int(a[2+int(a[1])+1]))
|
port = strconv.Itoa((int(a[2+int(a[1])]) << 8) | int(a[2+int(a[1])+1]))
|
||||||
@ -341,6 +341,16 @@ func (a Addr) String() string {
|
|||||||
return net.JoinHostPort(host, port)
|
return net.JoinHostPort(host, port)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UoT udp over tcp
|
||||||
|
func UoT(b byte) bool {
|
||||||
|
return b&0x8 == 0x8
|
||||||
|
}
|
||||||
|
|
||||||
|
// ATYP return the address type
|
||||||
|
func ATYP(b byte) int {
|
||||||
|
return int(b &^ 0x8)
|
||||||
|
}
|
||||||
|
|
||||||
func readAddr(r io.Reader, b []byte) (Addr, error) {
|
func readAddr(r io.Reader, b []byte) (Addr, error) {
|
||||||
if len(b) < MaxAddrLen {
|
if len(b) < MaxAddrLen {
|
||||||
return nil, io.ErrShortBuffer
|
return nil, io.ErrShortBuffer
|
||||||
@ -350,7 +360,7 @@ func readAddr(r io.Reader, b []byte) (Addr, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
switch b[0] {
|
switch ATYP(b[0]) {
|
||||||
case socks5Domain:
|
case socks5Domain:
|
||||||
_, err = io.ReadFull(r, b[1:2]) // read 2nd byte for domain length
|
_, err = io.ReadFull(r, b[1:2]) // read 2nd byte for domain length
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -381,7 +391,7 @@ func SplitAddr(b []byte) Addr {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
switch b[0] {
|
switch ATYP(b[0]) {
|
||||||
case socks5Domain:
|
case socks5Domain:
|
||||||
if len(b) < 2 {
|
if len(b) < 2 {
|
||||||
return nil
|
return nil
|
||||||
|
103
ss.go
103
ss.go
@ -5,16 +5,21 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/shadowsocks/go-shadowsocks2/core"
|
"github.com/shadowsocks/go-shadowsocks2/core"
|
||||||
|
"github.com/shadowsocks/go-shadowsocks2/socks"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const udpBufSize = 64 * 1024
|
||||||
|
|
||||||
// SS .
|
// SS .
|
||||||
type SS struct {
|
type SS struct {
|
||||||
*Forwarder
|
*Forwarder
|
||||||
sDialer Dialer
|
sDialer Dialer
|
||||||
|
|
||||||
core.StreamConnCipher
|
core.Cipher
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSS returns a shadowsocks proxy.
|
// NewSS returns a shadowsocks proxy.
|
||||||
@ -25,53 +30,59 @@ func NewSS(addr, method, pass string, cDialer Dialer, sDialer Dialer) (*SS, erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
s := &SS{
|
s := &SS{
|
||||||
Forwarder: NewForwarder(addr, cDialer),
|
Forwarder: NewForwarder(addr, cDialer),
|
||||||
sDialer: sDialer,
|
sDialer: sDialer,
|
||||||
StreamConnCipher: ciph,
|
Cipher: ciph,
|
||||||
}
|
}
|
||||||
|
|
||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListenAndServe shadowsocks requests as a server.
|
// ListenAndServe serves ss requests.
|
||||||
func (s *SS) ListenAndServe() {
|
func (s *SS) ListenAndServe() {
|
||||||
|
go s.ListenAndServeUDP()
|
||||||
|
s.ListenAndServeTCP()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListenAndServeTCP serves tcp ss requests.
|
||||||
|
func (s *SS) ListenAndServeTCP() {
|
||||||
l, err := net.Listen("tcp", s.addr)
|
l, err := net.Listen("tcp", s.addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logf("failed to listen on %s: %v", s.addr, err)
|
logf("proxy-ss failed to listen on %s: %v", s.addr, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
logf("listening TCP on %s", s.addr)
|
logf("proxy-ss listening TCP on %s", s.addr)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
c, err := l.Accept()
|
c, err := l.Accept()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logf("failed to accept: %v", err)
|
logf("proxy-ss failed to accept: %v", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
go s.Serve(c)
|
go s.ServeTCP(c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Serve .
|
// ServeTCP .
|
||||||
func (s *SS) Serve(c net.Conn) {
|
func (s *SS) ServeTCP(c net.Conn) {
|
||||||
defer c.Close()
|
defer c.Close()
|
||||||
|
|
||||||
if c, ok := c.(*net.TCPConn); ok {
|
if c, ok := c.(*net.TCPConn); ok {
|
||||||
c.SetKeepAlive(true)
|
c.SetKeepAlive(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
c = s.StreamConnCipher.StreamConn(c)
|
c = s.StreamConn(c)
|
||||||
|
|
||||||
tgt, err := ReadAddr(c)
|
tgt, err := ReadAddr(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logf("failed to get target address: %v", err)
|
logf("proxy-ss failed to get target address: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
rc, err := s.sDialer.Dial("tcp", tgt.String())
|
rc, err := s.sDialer.Dial("tcp", tgt.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logf("failed to connect to target: %v", err)
|
logf("proxy-ss failed to connect to target: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer rc.Close()
|
defer rc.Close()
|
||||||
@ -88,6 +99,70 @@ func (s *SS) Serve(c net.Conn) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListenAndServeUDP serves udp ss requests.
|
||||||
|
func (s *SS) ListenAndServeUDP() {
|
||||||
|
c, err := net.ListenPacket("udp", s.addr)
|
||||||
|
if err != nil {
|
||||||
|
logf("proxy-ss failed to listen on %s: %v", s.addr, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
|
logf("proxy-ss listening UDP on %s", s.addr)
|
||||||
|
|
||||||
|
c = s.PacketConn(c)
|
||||||
|
|
||||||
|
var nm sync.Map
|
||||||
|
buf := make([]byte, udpBufSize)
|
||||||
|
|
||||||
|
for {
|
||||||
|
n, raddr, err := c.ReadFrom(buf)
|
||||||
|
if err != nil {
|
||||||
|
logf("UDP remote read error: %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
tgtAddr := socks.SplitAddr(buf[:n])
|
||||||
|
if tgtAddr == nil {
|
||||||
|
logf("failed to split target address from packet: %q", buf[:n])
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
tgtUDPAddr, err := net.ResolveUDPAddr("udp", tgtAddr.String())
|
||||||
|
if err != nil {
|
||||||
|
logf("failed to resolve target UDP address: %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
payload := buf[len(tgtAddr):n]
|
||||||
|
|
||||||
|
var pc net.PacketConn
|
||||||
|
v, _ := nm.Load(raddr.String())
|
||||||
|
if v == nil {
|
||||||
|
pc, err = net.ListenPacket("udp", "")
|
||||||
|
if err != nil {
|
||||||
|
logf("UDP remote listen error: %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
nm.Store(raddr.String(), pc)
|
||||||
|
go func() {
|
||||||
|
timedCopy(c, raddr, pc, 5*time.Minute, true)
|
||||||
|
pc.Close()
|
||||||
|
nm.Delete(raddr.String())
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
pc = pc.(net.PacketConn)
|
||||||
|
_, err = pc.WriteTo(payload, tgtUDPAddr) // accept only UDPAddr despite the signature
|
||||||
|
if err != nil {
|
||||||
|
logf("UDP remote write error: %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Dial connects to the address addr on the network net via the proxy.
|
// Dial connects to the address addr on the network net via the proxy.
|
||||||
func (s *SS) Dial(network, addr string) (net.Conn, error) {
|
func (s *SS) Dial(network, addr string) (net.Conn, error) {
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ type TCPTun struct {
|
|||||||
raddr string
|
raddr string
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTCPTun returns a redirect proxy.
|
// NewTCPTun returns a tcptun proxy.
|
||||||
func NewTCPTun(addr, raddr string, sDialer Dialer) (*TCPTun, error) {
|
func NewTCPTun(addr, raddr string, sDialer Dialer) (*TCPTun, error) {
|
||||||
s := &TCPTun{
|
s := &TCPTun{
|
||||||
Forwarder: NewForwarder(addr, nil),
|
Forwarder: NewForwarder(addr, nil),
|
||||||
|
Loading…
Reference in New Issue
Block a user