general: move proxy to separate package

This commit is contained in:
nadoo 2018-06-26 16:15:48 +08:00
parent 3e09aa9ce0
commit fbbae71314
35 changed files with 1127 additions and 932 deletions

View File

@ -1,34 +1,38 @@
package main package conn
import ( import (
"bufio" "bufio"
"io" "io"
"net" "net"
"time" "time"
"github.com/nadoo/glider/common/log"
) )
type conn struct { const UDPBufSize = 65536
type Conn struct {
r *bufio.Reader r *bufio.Reader
net.Conn net.Conn
} }
func newConn(c net.Conn) conn { func NewConn(c net.Conn) Conn {
return conn{bufio.NewReader(c), c} return Conn{bufio.NewReader(c), c}
} }
func newConnSize(c net.Conn, n int) conn { func NewConnSize(c net.Conn, n int) Conn {
return conn{bufio.NewReaderSize(c, n), c} return Conn{bufio.NewReaderSize(c, n), c}
} }
func (c conn) Peek(n int) ([]byte, error) { func (c Conn) Peek(n int) ([]byte, error) {
return c.r.Peek(n) return c.r.Peek(n)
} }
func (c conn) Read(p []byte) (int, error) { func (c Conn) Read(p []byte) (int, error) {
return c.r.Read(p) return c.r.Read(p)
} }
func relay(left, right net.Conn) (int64, int64, error) { func Relay(left, right net.Conn) (int64, int64, error) {
type res struct { type res struct {
N int64 N int64
Err error Err error
@ -53,9 +57,9 @@ 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 // TimedCopy copy from src to dst at target with read timeout
func timedCopy(dst net.PacketConn, target net.Addr, src net.PacketConn, timeout time.Duration) error { func TimedCopy(dst net.PacketConn, target net.Addr, src net.PacketConn, timeout time.Duration) error {
buf := make([]byte, udpBufSize) buf := make([]byte, UDPBufSize)
for { for {
src.SetReadDeadline(time.Now().Add(timeout)) src.SetReadDeadline(time.Now().Add(timeout))
n, _, err := src.ReadFrom(buf) n, _, err := src.ReadFrom(buf)
@ -74,7 +78,7 @@ func timedCopy(dst net.PacketConn, target net.Addr, src net.PacketConn, timeout
func OutboundIP() string { func OutboundIP() string {
conn, err := net.Dial("udp", "8.8.8.8:80") conn, err := net.Dial("udp", "8.8.8.8:80")
if err != nil { if err != nil {
logf("get outbound ip error: %s", err) log.F("get outbound ip error: %s", err)
return "" return ""
} }
defer conn.Close() defer conn.Close()

16
common/log/log.go Normal file
View File

@ -0,0 +1,16 @@
package log
import "log"
// Func defines a simple log function
type Func func(f string, v ...interface{})
var F Func
func Fatal(v ...interface{}) {
log.Fatal(v)
}
func Fatalf(f string, v ...interface{}) {
log.Fatalf(f, v)
}

173
common/socks/socks.go Normal file
View File

@ -0,0 +1,173 @@
package socks
import (
"errors"
"io"
"net"
"strconv"
)
const (
AuthNone = 0
AuthPassword = 2
)
// SOCKS request commands as defined in RFC 1928 section 4.
const (
CmdConnect = 1
CmdBind = 2
CmdUDPAssociate = 3
)
// SOCKS address types as defined in RFC 1928 section 5.
const (
ATypeIP4 = 1
ATypeDomain = 3
ATypeIP6 = 4
)
// MaxAddrLen is the maximum size of SOCKS address in bytes.
const MaxAddrLen = 1 + 1 + 255 + 2
var Errors = []error{
errors.New(""),
errors.New("general failure"),
errors.New("connection forbidden"),
errors.New("network unreachable"),
errors.New("host unreachable"),
errors.New("connection refused"),
errors.New("TTL expired"),
errors.New("command not supported"),
errors.New("address type not supported"),
errors.New("socks5UDPAssociate"),
}
type Addr []byte
// String serializes SOCKS address a to string form.
func (a Addr) String() string {
var host, port string
switch ATYP(a[0]) { // address type
case ATypeDomain:
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]))
case ATypeIP4:
host = net.IP(a[1 : 1+net.IPv4len]).String()
port = strconv.Itoa((int(a[1+net.IPv4len]) << 8) | int(a[1+net.IPv4len+1]))
case ATypeIP6:
host = net.IP(a[1 : 1+net.IPv6len]).String()
port = strconv.Itoa((int(a[1+net.IPv6len]) << 8) | int(a[1+net.IPv6len+1]))
}
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 ReadAddrBuf(r io.Reader, b []byte) (Addr, error) {
if len(b) < MaxAddrLen {
return nil, io.ErrShortBuffer
}
_, err := io.ReadFull(r, b[:1]) // read 1st byte for address type
if err != nil {
return nil, err
}
switch ATYP(b[0]) {
case ATypeDomain:
_, err = io.ReadFull(r, b[1:2]) // read 2nd byte for domain length
if err != nil {
return nil, err
}
_, err = io.ReadFull(r, b[2:2+int(b[1])+2])
return b[:1+1+int(b[1])+2], err
case ATypeIP4:
_, err = io.ReadFull(r, b[1:1+net.IPv4len+2])
return b[:1+net.IPv4len+2], err
case ATypeIP6:
_, err = io.ReadFull(r, b[1:1+net.IPv6len+2])
return b[:1+net.IPv6len+2], err
}
return nil, Errors[8]
}
// ReadAddr reads just enough bytes from r to get a valid Addr.
func ReadAddr(r io.Reader) (Addr, error) {
return ReadAddrBuf(r, make([]byte, MaxAddrLen))
}
// SplitAddr slices a SOCKS address from beginning of b. Returns nil if failed.
func SplitAddr(b []byte) Addr {
addrLen := 1
if len(b) < addrLen {
return nil
}
switch ATYP(b[0]) {
case ATypeDomain:
if len(b) < 2 {
return nil
}
addrLen = 1 + 1 + int(b[1]) + 2
case ATypeIP4:
addrLen = 1 + net.IPv4len + 2
case ATypeIP6:
addrLen = 1 + net.IPv6len + 2
default:
return nil
}
if len(b) < addrLen {
return nil
}
return b[:addrLen]
}
// ParseAddr parses the address in string s. Returns nil if failed.
func ParseAddr(s string) Addr {
var addr Addr
host, port, err := net.SplitHostPort(s)
if err != nil {
return nil
}
if ip := net.ParseIP(host); ip != nil {
if ip4 := ip.To4(); ip4 != nil {
addr = make([]byte, 1+net.IPv4len+2)
addr[0] = ATypeIP4
copy(addr[1:], ip4)
} else {
addr = make([]byte, 1+net.IPv6len+2)
addr[0] = ATypeIP6
copy(addr[1:], ip)
}
} else {
if len(host) > 255 {
return nil
}
addr = make([]byte, 1+1+len(host)+2)
addr[0] = ATypeDomain
addr[1] = byte(len(host))
copy(addr[2:], host)
}
portnum, err := strconv.ParseUint(port, 10, 16)
if err != nil {
return nil
}
addr[len(addr)-2], addr[len(addr)-1] = byte(portnum>>8), byte(portnum)
return addr
}

View File

@ -157,7 +157,7 @@ func usage() {
fmt.Fprintf(os.Stderr, "\n") fmt.Fprintf(os.Stderr, "\n")
fmt.Fprintf(os.Stderr, "Available methods for ss:\n") fmt.Fprintf(os.Stderr, "Available methods for ss:\n")
fmt.Fprintf(os.Stderr, " "+ListCipher()) fmt.Fprintf(os.Stderr, " AEAD_AES_128_GCM AEAD_AES_192_GCM AEAD_AES_256_GCM AEAD_CHACHA20_POLY1305 AES-128-CFB AES-128-CTR AES-192-CFB AES-192-CTR AES-256-CFB AES-256-CTR CHACHA20-IETF XCHACHA20")
fmt.Fprintf(os.Stderr, "\n") fmt.Fprintf(os.Stderr, "\n")
fmt.Fprintf(os.Stderr, " NOTE: chacha20-ietf-poly1305 = AEAD_CHACHA20_POLY1305\n") fmt.Fprintf(os.Stderr, " NOTE: chacha20-ietf-poly1305 = AEAD_CHACHA20_POLY1305\n")
fmt.Fprintf(os.Stderr, "\n") fmt.Fprintf(os.Stderr, "\n")

55
dns.go
View File

@ -8,6 +8,9 @@ import (
"io" "io"
"net" "net"
"strings" "strings"
"github.com/nadoo/glider/common/log"
"github.com/nadoo/glider/proxy"
) )
// DNSHeaderLen is the length of dns msg header // DNSHeaderLen is the length of dns msg header
@ -139,7 +142,7 @@ type DNSAnswerHandler func(Domain, ip string) error
// DNS . // DNS .
type DNS struct { type DNS struct {
dialer Dialer dialer proxy.Dialer
addr string addr string
Tunnel bool Tunnel bool
@ -151,7 +154,7 @@ type DNS struct {
} }
// NewDNS returns a dns forwarder. client[dns.udp] -> glider[tcp] -> forwarder[dns.tcp] -> remote dns addr // NewDNS returns a dns forwarder. client[dns.udp] -> glider[tcp] -> forwarder[dns.tcp] -> remote dns addr
func NewDNS(addr, raddr string, dialer Dialer, tunnel bool) (*DNS, error) { func NewDNS(addr, raddr string, dialer proxy.Dialer, tunnel bool) (*DNS, error) {
s := &DNS{ s := &DNS{
dialer: dialer, dialer: dialer,
addr: addr, addr: addr,
@ -175,25 +178,25 @@ func (s *DNS) ListenAndServe() {
func (s *DNS) ListenAndServeUDP() { func (s *DNS) ListenAndServeUDP() {
c, err := net.ListenPacket("udp", s.addr) c, err := net.ListenPacket("udp", s.addr)
if err != nil { if err != nil {
logf("proxy-dns failed to listen on %s, error: %v", s.addr, err) log.F("proxy-dns failed to listen on %s, error: %v", s.addr, err)
return return
} }
defer c.Close() defer c.Close()
logf("proxy-dns listening UDP on %s", s.addr) log.F("proxy-dns listening UDP on %s", s.addr)
for { for {
b := make([]byte, DNSUDPMaxLen) b := make([]byte, DNSUDPMaxLen)
n, clientAddr, err := c.ReadFrom(b) n, clientAddr, err := c.ReadFrom(b)
if err != nil { if err != nil {
logf("proxy-dns local read error: %v", err) log.F("proxy-dns local read error: %v", err)
continue continue
} }
reqLen := uint16(n) reqLen := uint16(n)
// TODO: check here // TODO: check here
if reqLen <= DNSHeaderLen+2 { if reqLen <= DNSHeaderLen+2 {
logf("proxy-dns not enough data") log.F("proxy-dns not enough data")
continue continue
} }
@ -201,13 +204,13 @@ func (s *DNS) ListenAndServeUDP() {
go func() { go func() {
_, respMsg, err := s.Exchange(reqLen, reqMsg, clientAddr.String()) _, respMsg, err := s.Exchange(reqLen, reqMsg, clientAddr.String())
if err != nil { if err != nil {
logf("proxy-dns error in exchange: %s", err) log.F("proxy-dns error in exchange: %s", err)
return return
} }
_, err = c.WriteTo(respMsg, clientAddr) _, err = c.WriteTo(respMsg, clientAddr)
if err != nil { if err != nil {
logf("proxy-dns error in local write: %s", err) log.F("proxy-dns error in local write: %s", err)
return return
} }
@ -219,16 +222,16 @@ func (s *DNS) ListenAndServeUDP() {
func (s *DNS) ListenAndServeTCP() { func (s *DNS) ListenAndServeTCP() {
l, err := net.Listen("tcp", s.addr) l, err := net.Listen("tcp", s.addr)
if err != nil { if err != nil {
logf("proxy-dns-tcp error: %v", err) log.F("proxy-dns-tcp error: %v", err)
return return
} }
logf("proxy-dns-tcp listening TCP on %s", s.addr) log.F("proxy-dns-tcp listening TCP on %s", s.addr)
for { for {
c, err := l.Accept() c, err := l.Accept()
if err != nil { if err != nil {
logf("proxy-dns-tcp error: failed to accept: %v", err) log.F("proxy-dns-tcp error: failed to accept: %v", err)
continue continue
} }
go s.ServeTCP(c) go s.ServeTCP(c)
@ -245,35 +248,35 @@ func (s *DNS) ServeTCP(c net.Conn) {
var reqLen uint16 var reqLen uint16
if err := binary.Read(c, binary.BigEndian, &reqLen); err != nil { if err := binary.Read(c, binary.BigEndian, &reqLen); err != nil {
logf("proxy-dns-tcp failed to get request length: %v", err) log.F("proxy-dns-tcp failed to get request length: %v", err)
return return
} }
// TODO: check here // TODO: check here
if reqLen <= DNSHeaderLen+2 { if reqLen <= DNSHeaderLen+2 {
logf("proxy-dns-tcp not enough data") log.F("proxy-dns-tcp not enough data")
return return
} }
reqMsg := make([]byte, reqLen) reqMsg := make([]byte, reqLen)
_, err := io.ReadFull(c, reqMsg) _, err := io.ReadFull(c, reqMsg)
if err != nil { if err != nil {
logf("proxy-dns-tcp error in read reqMsg %s", err) log.F("proxy-dns-tcp error in read reqMsg %s", err)
return return
} }
respLen, respMsg, err := s.Exchange(reqLen, reqMsg, c.RemoteAddr().String()) respLen, respMsg, err := s.Exchange(reqLen, reqMsg, c.RemoteAddr().String())
if err != nil { if err != nil {
logf("proxy-dns-tcp error in exchange: %s", err) log.F("proxy-dns-tcp error in exchange: %s", err)
return return
} }
if err := binary.Write(c, binary.BigEndian, respLen); err != nil { if err := binary.Write(c, binary.BigEndian, respLen); err != nil {
logf("proxy-dns-tcp error in local write respLen: %s", err) log.F("proxy-dns-tcp error in local write respLen: %s", err)
return return
} }
if err := binary.Write(c, binary.BigEndian, respMsg); err != nil { if err := binary.Write(c, binary.BigEndian, respMsg); err != nil {
logf("proxy-dns-tcp error in local write respMsg: %s", err) log.F("proxy-dns-tcp error in local write respMsg: %s", err)
return return
} }
} }
@ -284,7 +287,7 @@ func (s *DNS) Exchange(reqLen uint16, reqMsg []byte, addr string) (respLen uint1
// fmt.Printf("\ndns req len %d:\n%s\n", reqLen, hex.Dump(reqMsg[:])) // fmt.Printf("\ndns req len %d:\n%s\n", reqLen, hex.Dump(reqMsg[:]))
query, err := parseQuestion(reqMsg) query, err := parseQuestion(reqMsg)
if err != nil { if err != nil {
logf("proxy-dns error in parseQuestion reqMsg: %s", err) log.F("proxy-dns error in parseQuestion reqMsg: %s", err)
return return
} }
@ -295,29 +298,29 @@ func (s *DNS) Exchange(reqLen uint16, reqMsg []byte, addr string) (respLen uint1
rc, err := s.dialer.NextDialer(query.QNAME+":53").Dial("tcp", dnsServer) rc, err := s.dialer.NextDialer(query.QNAME+":53").Dial("tcp", dnsServer)
if err != nil { if err != nil {
logf("proxy-dns failed to connect to server %v: %v", dnsServer, err) log.F("proxy-dns failed to connect to server %v: %v", dnsServer, err)
return return
} }
defer rc.Close() defer rc.Close()
if err = binary.Write(rc, binary.BigEndian, reqLen); err != nil { if err = binary.Write(rc, binary.BigEndian, reqLen); err != nil {
logf("proxy-dns failed to write req length: %v", err) log.F("proxy-dns failed to write req length: %v", err)
return return
} }
if err = binary.Write(rc, binary.BigEndian, reqMsg); err != nil { if err = binary.Write(rc, binary.BigEndian, reqMsg); err != nil {
logf("proxy-dns failed to write req message: %v", err) log.F("proxy-dns failed to write req message: %v", err)
return return
} }
if err = binary.Read(rc, binary.BigEndian, &respLen); err != nil { if err = binary.Read(rc, binary.BigEndian, &respLen); err != nil {
logf("proxy-dns failed to read response length: %v", err) log.F("proxy-dns failed to read response length: %v", err)
return return
} }
respMsg = make([]byte, respLen) respMsg = make([]byte, respLen)
_, err = io.ReadFull(rc, respMsg) _, err = io.ReadFull(rc, respMsg)
if err != nil { if err != nil {
logf("proxy-dns error in read respMsg %s\n", err) log.F("proxy-dns error in read respMsg %s\n", err)
return return
} }
@ -326,7 +329,7 @@ func (s *DNS) Exchange(reqLen uint16, reqMsg []byte, addr string) (respLen uint1
var ip string var ip string
respReq, err := parseQuestion(respMsg) respReq, err := parseQuestion(respMsg)
if err != nil { if err != nil {
logf("proxy-dns error in parseQuestion respMsg: %s", err) log.F("proxy-dns error in parseQuestion respMsg: %s", err)
return return
} }
@ -336,7 +339,7 @@ func (s *DNS) Exchange(reqLen uint16, reqMsg []byte, addr string) (respLen uint1
var answers []*DNSRR var answers []*DNSRR
answers, err = parseAnswers(respMsg[respReq.Offset:]) answers, err = parseAnswers(respMsg[respReq.Offset:])
if err != nil { if err != nil {
logf("proxy-dns error in parseAnswers: %s", err) log.F("proxy-dns error in parseAnswers: %s", err)
return return
} }
@ -352,7 +355,7 @@ func (s *DNS) Exchange(reqLen uint16, reqMsg []byte, addr string) (respLen uint1
} }
logf("proxy-dns %s <-> %s, type: %d, %s: %s", addr, dnsServer, query.QTYPE, query.QNAME, ip) log.F("proxy-dns %s <-> %s, type: %d, %s: %s", addr, dnsServer, query.QTYPE, query.QNAME, ip)
return return
} }

View File

@ -1,35 +0,0 @@
// https://tools.ietf.org/html/rfc1035
package main
// DNSTun struct
type DNSTun struct {
dialer Dialer
addr string
raddr string
dns *DNS
tcp *TCPTun
}
// NewDNSTun returns a dns tunnel forwarder.
func NewDNSTun(addr, raddr string, dialer Dialer) (*DNSTun, error) {
s := &DNSTun{
dialer: dialer,
addr: addr,
raddr: raddr,
}
s.dns, _ = NewDNS(addr, raddr, dialer, true)
return s, nil
}
// ListenAndServe .
func (s *DNSTun) ListenAndServe() {
if s.dns != nil {
go s.dns.ListenAndServe()
}
}

12
features.go Normal file
View File

@ -0,0 +1,12 @@
package main
import (
_ "github.com/nadoo/glider/proxy/http"
_ "github.com/nadoo/glider/proxy/mixed"
_ "github.com/nadoo/glider/proxy/socks5"
_ "github.com/nadoo/glider/proxy/ss"
_ "github.com/nadoo/glider/proxy/ssr"
_ "github.com/nadoo/glider/proxy/tcptun"
_ "github.com/nadoo/glider/proxy/udptun"
_ "github.com/nadoo/glider/proxy/uottun"
)

5
features_linux.go Normal file
View File

@ -0,0 +1,5 @@
package main
import (
_ "github.com/nadoo/glider/proxy/redir"
)

View File

@ -7,13 +7,14 @@ package main
import ( import (
"bytes" "bytes"
"encoding/binary" "encoding/binary"
"log"
"net" "net"
"strings" "strings"
"sync" "sync"
"sync/atomic" "sync/atomic"
"syscall" "syscall"
"unsafe" "unsafe"
"github.com/nadoo/glider/common/log"
) )
// netfilter netlink message types // netfilter netlink message types
@ -69,7 +70,7 @@ type IPSetManager struct {
func NewIPSetManager(mainSet string, rules []*RuleConf) (*IPSetManager, error) { func NewIPSetManager(mainSet string, rules []*RuleConf) (*IPSetManager, error) {
fd, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW, syscall.NETLINK_NETFILTER) fd, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW, syscall.NETLINK_NETFILTER)
if err != nil { if err != nil {
logf("%s", err) log.F("%s", err)
return nil, err return nil, err
} }
// defer syscall.Close(fd) // defer syscall.Close(fd)
@ -79,7 +80,7 @@ func NewIPSetManager(mainSet string, rules []*RuleConf) (*IPSetManager, error) {
} }
if err = syscall.Bind(fd, &lsa); err != nil { if err = syscall.Bind(fd, &lsa); err != nil {
logf("%s", err) log.F("%s", err)
return nil, err return nil, err
} }
@ -144,7 +145,7 @@ func CreateSet(fd int, lsa syscall.SockaddrNetlink, setName string) {
log.Fatal("ipset: name too long") log.Fatal("ipset: name too long")
} }
logf("ipset create %s hash:net", setName) log.F("ipset create %s hash:net", setName)
req := NewNetlinkRequest(IPSET_CMD_CREATE|(NFNL_SUBSYS_IPSET<<8), syscall.NLM_F_REQUEST) req := NewNetlinkRequest(IPSET_CMD_CREATE|(NFNL_SUBSYS_IPSET<<8), syscall.NLM_F_REQUEST)
@ -172,14 +173,14 @@ func CreateSet(fd int, lsa syscall.SockaddrNetlink, setName string) {
err := syscall.Sendto(fd, req.Serialize(), 0, &lsa) err := syscall.Sendto(fd, req.Serialize(), 0, &lsa)
if err != nil { if err != nil {
logf("%s", err) log.F("%s", err)
} }
FlushSet(fd, lsa, setName) FlushSet(fd, lsa, setName)
} }
func FlushSet(fd int, lsa syscall.SockaddrNetlink, setName string) { func FlushSet(fd int, lsa syscall.SockaddrNetlink, setName string) {
logf("ipset flush %s", setName) log.F("ipset flush %s", setName)
req := NewNetlinkRequest(IPSET_CMD_FLUSH|(NFNL_SUBSYS_IPSET<<8), syscall.NLM_F_REQUEST) req := NewNetlinkRequest(IPSET_CMD_FLUSH|(NFNL_SUBSYS_IPSET<<8), syscall.NLM_F_REQUEST)
@ -190,7 +191,7 @@ func FlushSet(fd int, lsa syscall.SockaddrNetlink, setName string) {
err := syscall.Sendto(fd, req.Serialize(), 0, &lsa) err := syscall.Sendto(fd, req.Serialize(), 0, &lsa)
if err != nil { if err != nil {
logf("%s", err) log.F("%s", err)
} }
} }
@ -201,10 +202,10 @@ func AddToSet(fd int, lsa syscall.SockaddrNetlink, setName, entry string) {
} }
if len(setName) > IPSET_MAXNAMELEN { if len(setName) > IPSET_MAXNAMELEN {
logf("ipset: name too long") log.F("ipset: name too long")
} }
logf("ipset add %s %s", setName, entry) log.F("ipset add %s %s", setName, entry)
var ip net.IP var ip net.IP
var cidr *net.IPNet var cidr *net.IPNet
@ -215,7 +216,7 @@ func AddToSet(fd int, lsa syscall.SockaddrNetlink, setName, entry string) {
} }
if ip == nil { if ip == nil {
logf("ipset: parse %s error", entry) log.F("ipset: parse %s error", entry)
return return
} }
@ -248,7 +249,7 @@ func AddToSet(fd int, lsa syscall.SockaddrNetlink, setName, entry string) {
err = syscall.Sendto(fd, req.Serialize(), 0, &lsa) err = syscall.Sendto(fd, req.Serialize(), 0, &lsa)
if err != nil { if err != nil {
logf("%s", err) log.F("%s", err)
} }
} }

16
log.go
View File

@ -1,16 +0,0 @@
package main
import "log"
// LogFunc defines a simple log function
type LogFunc func(f string, v ...interface{})
var logf LogFunc
func init() {
logf = func(f string, v ...interface{}) {
if conf.Verbose {
log.Printf(f, v...)
}
}
}

26
main.go
View File

@ -1,24 +1,27 @@
package main package main
import ( import (
"log" stdlog "log"
"os" "os"
"os/signal" "os/signal"
"strings" "strings"
"syscall" "syscall"
"github.com/nadoo/glider/common/log"
"github.com/nadoo/glider/proxy"
) )
// VERSION . // VERSION .
const VERSION = "0.5.2" const VERSION = "0.6.0"
func dialerFromConf() Dialer { func dialerFromConf() proxy.Dialer {
// global forwarders in xx.conf // global forwarders in xx.conf
var fwdrs []Dialer var fwdrs []proxy.Dialer
for _, chain := range conf.Forward { for _, chain := range conf.Forward {
var fwdr Dialer var fwdr proxy.Dialer
var err error var err error
for _, url := range strings.Split(chain, ",") { for _, url := range strings.Split(chain, ",") {
fwdr, err = DialerFromURL(url, fwdr) fwdr, err = proxy.DialerFromURL(url, fwdr)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
@ -32,10 +35,17 @@ func dialerFromConf() Dialer {
func main() { func main() {
confInit() confInit()
log.F = func(f string, v ...interface{}) {
if conf.Verbose {
stdlog.Printf(f, v...)
}
}
sDialer := NewRuleDialer(conf.rules, dialerFromConf()) sDialer := NewRuleDialer(conf.rules, dialerFromConf())
for _, listen := range conf.Listen { for _, listen := range conf.Listen {
local, err := ServerFromURL(listen, sDialer) local, err := proxy.ServerFromURL(listen, sDialer)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
@ -45,7 +55,7 @@ func main() {
ipsetM, err := NewIPSetManager(conf.IPSet, conf.rules) ipsetM, err := NewIPSetManager(conf.IPSet, conf.rules)
if err != nil { if err != nil {
logf("create ipset manager error: %s", err) log.F("create ipset manager error: %s", err)
} }
if conf.DNS != "" { if conf.DNS != "" {

105
mixed.go
View File

@ -1,105 +0,0 @@
package main
import (
"bytes"
"net"
)
// https://www.ietf.org/rfc/rfc2616.txt, http methods must be uppercase.
var httpMethods = [...][]byte{
[]byte("GET"),
[]byte("POST"),
[]byte("PUT"),
[]byte("DELETE"),
[]byte("CONNECT"),
[]byte("HEAD"),
[]byte("OPTIONS"),
[]byte("TRACE"),
}
// MixedProxy struct
type MixedProxy struct {
dialer Dialer
addr string
http *HTTP
socks5 *SOCKS5
}
// NewMixedProxy returns a mixed proxy.
func NewMixedProxy(addr, user, pass, rawQuery string, dialer Dialer) (*MixedProxy, error) {
p := &MixedProxy{
dialer: dialer,
addr: addr,
}
p.http, _ = NewHTTP(addr, user, pass, rawQuery, dialer)
p.socks5, _ = NewSOCKS5(addr, user, pass, dialer)
return p, nil
}
// ListenAndServe .
func (p *MixedProxy) ListenAndServe() {
go p.socks5.ListenAndServeUDP()
l, err := net.Listen("tcp", p.addr)
if err != nil {
logf("proxy-mixed failed to listen on %s: %v", p.addr, err)
return
}
logf("proxy-mixed listening TCP on %s", p.addr)
for {
c, err := l.Accept()
if err != nil {
logf("proxy-mixed failed to accept: %v", err)
continue
}
go p.Serve(c)
}
}
// Serve .
func (p *MixedProxy) Serve(conn net.Conn) {
defer conn.Close()
if c, ok := conn.(*net.TCPConn); ok {
c.SetKeepAlive(true)
}
c := newConn(conn)
if p.socks5 != nil {
head, err := c.Peek(1)
if err != nil {
logf("proxy-mixed peek error: %s", err)
return
}
// check socks5, client send socksversion: 5 as the first byte
if head[0] == socks5Version {
p.socks5.ServeTCP(c)
return
}
}
if p.http != nil {
head, err := c.Peek(8)
if err != nil {
logf("proxy-mixed peek error: %s", err)
return
}
for _, method := range httpMethods {
if bytes.HasPrefix(head, method) {
p.http.Serve(c)
return
}
}
}
}

View File

@ -1,12 +1,15 @@
package main package proxy
import ( import (
"errors" "errors"
"net" "net"
"net/url" "net/url"
"strings"
"github.com/nadoo/glider/common/log"
) )
// A Dialer means to establish a connection and relay it. // A proxy.Dialer means to establish a connection and relay it.
type Dialer interface { type Dialer interface {
// Addr() // Addr()
Addr() string Addr() string
@ -21,35 +24,30 @@ type Dialer interface {
NextDialer(dstAddr string) Dialer NextDialer(dstAddr string) Dialer
} }
// DialerFromURL parses url and get a Proxy type DialerCreator func(s string, dialer Dialer) (Dialer, error)
// TODO: table
var (
dialerMap = make(map[string]DialerCreator)
)
func RegisterDialer(name string, c DialerCreator) {
dialerMap[name] = c
}
func DialerFromURL(s string, dialer Dialer) (Dialer, error) { func DialerFromURL(s string, dialer Dialer) (Dialer, error) {
u, err := url.Parse(s) u, err := url.Parse(s)
if err != nil { if err != nil {
logf("parse err: %s", err) log.F("parse err: %s", err)
return nil, err return nil, err
} }
addr := u.Host
var user, pass string
if u.User != nil {
user = u.User.Username()
pass, _ = u.User.Password()
}
if dialer == nil { if dialer == nil {
dialer = Direct dialer = Direct
} }
switch u.Scheme { c, ok := dialerMap[strings.ToLower(u.Scheme)]
case "http": if ok {
return NewHTTP(addr, user, pass, "", dialer) return c(s, dialer)
case "socks5":
return NewSOCKS5(addr, user, pass, dialer)
case "ss":
return NewSS(addr, user, pass, dialer)
case "ssr":
return NewSSR(addr, user, pass, u.RawQuery, dialer)
} }
return nil, errors.New("unknown scheme '" + u.Scheme + "'") return nil, errors.New("unknown scheme '" + u.Scheme + "'")

View File

@ -1,7 +1,9 @@
package main package proxy
import ( import (
"net" "net"
"github.com/nadoo/glider/common/log"
) )
// direct proxy // direct proxy
@ -33,7 +35,7 @@ func (d *direct) Dial(network, addr string) (net.Conn, error) {
func (d *direct) DialUDP(network, addr string) (net.PacketConn, net.Addr, error) { func (d *direct) DialUDP(network, addr string) (net.PacketConn, net.Addr, error) {
pc, err := net.ListenPacket(network, "") pc, err := net.ListenPacket(network, "")
if err != nil { if err != nil {
logf("ListenPacket error: %s", err) log.F("ListenPacket error: %s", err)
return nil, nil, err return nil, nil, err
} }

View File

@ -1,7 +1,7 @@
// http proxy // http proxy
// NOTE: never keep-alive so the implementation can be much easier. // NOTE: never keep-alive so the implementation can be much easier.
package main package http
import ( import (
"bufio" "bufio"
@ -15,61 +15,75 @@ import (
"net/url" "net/url"
"strings" "strings"
"time" "time"
"github.com/nadoo/glider/common/conn"
"github.com/nadoo/glider/common/log"
"github.com/nadoo/glider/proxy"
) )
// HTTP struct // HTTP struct
type HTTP struct { type HTTP struct {
dialer Dialer dialer proxy.Dialer
addr string addr string
user string user string
password string password string
xff bool // X-Forwarded-For }
xsi bool // X-Server-IP
selfip string func init() {
proxy.RegisterDialer("http", NewHTTPDialer)
proxy.RegisterServer("http", NewHTTPServer)
} }
// NewHTTP returns a http proxy. // NewHTTP returns a http proxy.
func NewHTTP(addr, user, pass, rawQuery string, dialer Dialer) (*HTTP, error) { func NewHTTP(s string, dialer proxy.Dialer) (*HTTP, error) {
s := &HTTP{ u, err := url.Parse(s)
if err != nil {
log.F("parse err: %s", err)
return nil, err
}
addr := u.Host
var user, pass string
if u.User != nil {
user = u.User.Username()
pass, _ = u.User.Password()
}
h := &HTTP{
dialer: dialer, dialer: dialer,
addr: addr, addr: addr,
user: user, user: user,
password: pass, password: pass,
xff: false,
selfip: OutboundIP(),
} }
p, _ := url.ParseQuery(rawQuery) return h, nil
if v, ok := p["xff"]; ok { }
if v[0] == "true" {
s.xff = true
}
}
if v, ok := p["xsi"]; ok { // NewHTTPDialer returns a http proxy dialer.
if v[0] == "true" { func NewHTTPDialer(s string, dialer proxy.Dialer) (proxy.Dialer, error) {
s.xsi = true return NewHTTP(s, dialer)
} }
}
return s, nil // NewHTTPServer returns a http proxy server.
func NewHTTPServer(s string, dialer proxy.Dialer) (proxy.Server, error) {
return NewHTTP(s, dialer)
} }
// ListenAndServe . // ListenAndServe .
func (s *HTTP) ListenAndServe() { func (s *HTTP) ListenAndServe() {
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) log.F("failed to listen on %s: %v", s.addr, err)
return return
} }
defer l.Close() defer l.Close()
logf("listening TCP on %s", s.addr) log.F("listening TCP on %s", s.addr)
for { for {
c, err := l.Accept() c, err := l.Accept()
if err != nil { if err != nil {
logf("proxy-http failed to accept: %v", err) log.F("proxy-http failed to accept: %v", err)
continue continue
} }
@ -99,7 +113,7 @@ func (s *HTTP) Serve(c net.Conn) {
reqHeader, err := reqTP.ReadMIMEHeader() reqHeader, err := reqTP.ReadMIMEHeader()
if err != nil { if err != nil {
logf("read header error:%s", err) log.F("read header error:%s", err)
return return
} }
cleanHeaders(reqHeader) cleanHeaders(reqHeader)
@ -107,18 +121,18 @@ func (s *HTTP) Serve(c net.Conn) {
reqHeader.Set("Connection", "close") reqHeader.Set("Connection", "close")
// X-Forwarded-For // X-Forwarded-For
if s.xff { // if s.xff {
if reqHeader.Get("X-Forwarded-For") != "" { // if reqHeader.Get("X-Forwarded-For") != "" {
reqHeader.Add("X-Forwarded-For", ",") // reqHeader.Add("X-Forwarded-For", ",")
} // }
reqHeader.Add("X-Forwarded-For", c.RemoteAddr().(*net.TCPAddr).IP.String()) // reqHeader.Add("X-Forwarded-For", c.RemoteAddr().(*net.TCPAddr).IP.String())
reqHeader.Add("X-Forwarded-For", ",") // reqHeader.Add("X-Forwarded-For", ",")
reqHeader.Add("X-Forwarded-For", s.selfip) // reqHeader.Add("X-Forwarded-For", s.selfip)
} // }
url, err := url.ParseRequestURI(requestURI) url, err := url.ParseRequestURI(requestURI)
if err != nil { if err != nil {
logf("proxy-http parse request url error: %s", err) log.F("proxy-http parse request url error: %s", err)
return return
} }
@ -130,7 +144,7 @@ func (s *HTTP) Serve(c net.Conn) {
rc, err := s.dialer.Dial("tcp", tgt) rc, err := s.dialer.Dial("tcp", tgt)
if err != nil { if err != nil {
fmt.Fprintf(c, "%s 502 ERROR\r\n\r\n", proto) fmt.Fprintf(c, "%s 502 ERROR\r\n\r\n", proto)
logf("proxy-http failed to dial: %v", err) log.F("proxy-http failed to dial: %v", err)
return return
} }
defer rc.Close() defer rc.Close()
@ -166,22 +180,18 @@ func (s *HTTP) Serve(c net.Conn) {
respHeader, err := respTP.ReadMIMEHeader() respHeader, err := respTP.ReadMIMEHeader()
if err != nil { if err != nil {
logf("proxy-http read header error:%s", err) log.F("proxy-http read header error:%s", err)
return return
} }
respHeader.Set("Proxy-Connection", "close") respHeader.Set("Proxy-Connection", "close")
respHeader.Set("Connection", "close") respHeader.Set("Connection", "close")
if s.xsi {
respHeader.Set("X-Server-IP", rc.RemoteAddr().(*net.TCPAddr).IP.String())
}
var respBuf bytes.Buffer var respBuf bytes.Buffer
writeFirstLine(proto, code, status, &respBuf) writeFirstLine(proto, code, status, &respBuf)
writeHeaders(respHeader, &respBuf) writeHeaders(respHeader, &respBuf)
logf("proxy-http %s <-> %s", c.RemoteAddr(), tgt) log.F("proxy-http %s <-> %s", c.RemoteAddr(), tgt)
c.Write(respBuf.Bytes()) c.Write(respBuf.Bytes())
io.Copy(c, respR) io.Copy(c, respR)
@ -193,20 +203,20 @@ func (s *HTTP) servHTTPS(method, requestURI, proto string, c net.Conn) {
if err != nil { if err != nil {
c.Write([]byte(proto)) c.Write([]byte(proto))
c.Write([]byte(" 502 ERROR\r\n\r\n")) c.Write([]byte(" 502 ERROR\r\n\r\n"))
logf("proxy-http failed to dial: %v", err) log.F("proxy-http failed to dial: %v", err)
return return
} }
c.Write([]byte("HTTP/1.0 200 Connection established\r\n\r\n")) c.Write([]byte("HTTP/1.0 200 Connection established\r\n\r\n"))
logf("proxy-http %s <-> %s [c]", c.RemoteAddr(), requestURI) log.F("proxy-http %s <-> %s [c]", c.RemoteAddr(), requestURI)
_, _, err = relay(c, rc) _, _, err = conn.Relay(c, rc)
if err != nil { if err != nil {
if err, ok := err.(net.Error); ok && err.Timeout() { if err, ok := err.(net.Error); ok && err.Timeout() {
return // ignore i/o timeout return // ignore i/o timeout
} }
logf("relay error: %v", err) log.F("relay error: %v", err)
} }
} }
@ -214,13 +224,13 @@ func (s *HTTP) servHTTPS(method, requestURI, proto string, c net.Conn) {
func (s *HTTP) Addr() string { return s.addr } func (s *HTTP) Addr() string { return s.addr }
// NextDialer returns the next dialer // NextDialer returns the next dialer
func (s *HTTP) NextDialer(dstAddr string) Dialer { return s.dialer.NextDialer(dstAddr) } func (s *HTTP) NextDialer(dstAddr string) proxy.Dialer { return s.dialer.NextDialer(dstAddr) }
// 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 *HTTP) Dial(network, addr string) (net.Conn, error) { func (s *HTTP) Dial(network, addr string) (net.Conn, error) {
rc, err := s.dialer.Dial(network, s.addr) rc, err := s.dialer.Dial(network, s.addr)
if err != nil { if err != nil {
logf("proxy-http dial to %s error: %s", s.addr, err) log.F("proxy-http dial to %s error: %s", s.addr, err)
return nil, err return nil, err
} }
@ -245,9 +255,9 @@ func (s *HTTP) Dial(network, addr string) (net.Conn, error) {
if ok && code == "200" { if ok && code == "200" {
return rc, err return rc, err
} else if code == "407" { } else if code == "407" {
logf("proxy-http authencation needed by proxy %s", s.addr) log.F("proxy-http authencation needed by proxy %s", s.addr)
} else if code == "405" { } else if code == "405" {
logf("proxy-http 'CONNECT' method not allowed by proxy %s", s.addr) log.F("proxy-http 'CONNECT' method not allowed by proxy %s", s.addr)
} }
return nil, errors.New("proxy-http cound not connect remote address: " + addr + ". error code: " + code) return nil, errors.New("proxy-http cound not connect remote address: " + addr + ". error code: " + code)
@ -261,9 +271,9 @@ func (s *HTTP) DialUDP(network, addr string) (pc net.PacketConn, writeTo net.Add
// parseFirstLine parses "GET /foo HTTP/1.1" OR "HTTP/1.1 200 OK" into its three parts. // parseFirstLine parses "GET /foo HTTP/1.1" OR "HTTP/1.1 200 OK" into its three parts.
func parseFirstLine(tp *textproto.Reader) (r1, r2, r3 string, ok bool) { func parseFirstLine(tp *textproto.Reader) (r1, r2, r3 string, ok bool) {
line, err := tp.ReadLine() line, err := tp.ReadLine()
// logf("first line: %s", line) // log.F("first line: %s", line)
if err != nil { if err != nil {
logf("proxy-http read first line error:%s", err) log.F("proxy-http read first line error:%s", err)
return return
} }

127
proxy/mixed/mixed.go Normal file
View File

@ -0,0 +1,127 @@
package mixed
import (
"bytes"
"net"
"net/url"
"github.com/nadoo/glider/common/conn"
"github.com/nadoo/glider/common/log"
"github.com/nadoo/glider/proxy"
"github.com/nadoo/glider/proxy/http"
"github.com/nadoo/glider/proxy/socks5"
)
// https://www.ietf.org/rfc/rfc2616.txt, http methods must be uppercase.
var httpMethods = [...][]byte{
[]byte("GET"),
[]byte("POST"),
[]byte("PUT"),
[]byte("DELETE"),
[]byte("CONNECT"),
[]byte("HEAD"),
[]byte("OPTIONS"),
[]byte("TRACE"),
}
// MixedProxy struct
type MixedProxy struct {
dialer proxy.Dialer
addr string
http *http.HTTP
socks5 *socks5.SOCKS5
}
func init() {
proxy.RegisterServer("mixed", NewMixedProxyServer)
}
// NewMixedProxy returns a mixed proxy.
func NewMixedProxy(s string, dialer proxy.Dialer) (*MixedProxy, error) {
u, err := url.Parse(s)
if err != nil {
log.F("parse err: %s", err)
return nil, err
}
p := &MixedProxy{
dialer: dialer,
addr: u.Host,
}
p.http, _ = http.NewHTTP(s, dialer)
p.socks5, _ = socks5.NewSOCKS5(s, dialer)
return p, nil
}
// NewMixedProxyServer returns a mixed proxy server.
func NewMixedProxyServer(s string, dialer proxy.Dialer) (proxy.Server, error) {
return NewMixedProxy(s, dialer)
}
// ListenAndServe .
func (p *MixedProxy) ListenAndServe() {
go p.socks5.ListenAndServeUDP()
l, err := net.Listen("tcp", p.addr)
if err != nil {
log.F("proxy-mixed failed to listen on %s: %v", p.addr, err)
return
}
log.F("proxy-mixed listening TCP on %s", p.addr)
for {
c, err := l.Accept()
if err != nil {
log.F("proxy-mixed failed to accept: %v", err)
continue
}
go p.Serve(c)
}
}
// Serve .
func (p *MixedProxy) Serve(c net.Conn) {
defer c.Close()
if c, ok := c.(*net.TCPConn); ok {
c.SetKeepAlive(true)
}
cc := conn.NewConn(c)
if p.socks5 != nil {
head, err := cc.Peek(1)
if err != nil {
log.F("proxy-mixed peek error: %s", err)
return
}
// check socks5, client send socksversion: 5 as the first byte
if head[0] == socks5.Version {
p.socks5.ServeTCP(cc)
return
}
}
if p.http != nil {
head, err := cc.Peek(8)
if err != nil {
log.F("proxy-mixed peek error: %s", err)
return
}
for _, method := range httpMethods {
if bytes.HasPrefix(head, method) {
p.http.Serve(cc)
return
}
}
}
}

View File

@ -1,13 +1,19 @@
// getOrigDst: // getOrigDst:
// https://github.com/shadowsocks/go-shadowsocks2/blob/master/tcp_linux.go#L30 // https://github.com/shadowsocks/go-shadowsocks2/blob/master/tcp_linux.go#L30
package main package redir
import ( import (
"errors" "errors"
"net" "net"
"net/url"
"syscall" "syscall"
"unsafe" "unsafe"
"github.com/nadoo/glider/common/conn"
"github.com/nadoo/glider/common/log"
"github.com/nadoo/glider/common/socks"
"github.com/nadoo/glider/proxy"
) )
const ( const (
@ -19,34 +25,50 @@ const (
// RedirProxy struct // RedirProxy struct
type RedirProxy struct { type RedirProxy struct {
dialer Dialer dialer proxy.Dialer
addr string addr string
} }
func init() {
proxy.RegisterServer("redir", NewRedirServer)
}
// NewRedirProxy returns a redirect proxy. // NewRedirProxy returns a redirect proxy.
func NewRedirProxy(addr string, dialer Dialer) (*RedirProxy, error) { func NewRedirProxy(s string, dialer proxy.Dialer) (*RedirProxy, error) {
s := &RedirProxy{ u, err := url.Parse(s)
if err != nil {
log.F("parse err: %s", err)
return nil, err
}
addr := u.Host
r := &RedirProxy{
dialer: dialer, dialer: dialer,
addr: addr, addr: addr,
} }
return s, nil return r, nil
}
// NewRedirServer returns a redir server.
func NewRedirServer(s string, dialer proxy.Dialer) (proxy.Server, error) {
return NewRedirProxy(s, dialer)
} }
// ListenAndServe . // ListenAndServe .
func (s *RedirProxy) ListenAndServe() { func (s *RedirProxy) ListenAndServe() {
l, err := net.Listen("tcp", s.addr) l, err := net.Listen("tcp", s.addr)
if err != nil { if err != nil {
logf("proxy-redir failed to listen on %s: %v", s.addr, err) log.F("proxy-redir failed to listen on %s: %v", s.addr, err)
return return
} }
logf("proxy-redir listening TCP on %s", s.addr) log.F("proxy-redir listening TCP on %s", s.addr)
for { for {
c, err := l.Accept() c, err := l.Accept()
if err != nil { if err != nil {
logf("proxy-redir failed to accept: %v", err) log.F("proxy-redir failed to accept: %v", err)
continue continue
} }
@ -59,25 +81,25 @@ func (s *RedirProxy) ListenAndServe() {
tgt, err := getOrigDst(c, false) tgt, err := getOrigDst(c, false)
if err != nil { if err != nil {
logf("proxy-redir failed to get target address: %v", err) log.F("proxy-redir failed to get target address: %v", err)
return return
} }
rc, err := s.dialer.Dial("tcp", tgt.String()) rc, err := s.dialer.Dial("tcp", tgt.String())
if err != nil { if err != nil {
logf("proxy-redir failed to connect to target: %v", err) log.F("proxy-redir failed to connect to target: %v", err)
return return
} }
defer rc.Close() defer rc.Close()
logf("proxy-redir %s <-> %s", c.RemoteAddr(), tgt) log.F("proxy-redir %s <-> %s", c.RemoteAddr(), tgt)
_, _, err = relay(c, rc) _, _, err = conn.Relay(c, rc)
if err != nil { if err != nil {
if err, ok := err.(net.Error); ok && err.Timeout() { if err, ok := err.(net.Error); ok && err.Timeout() {
return // ignore i/o timeout return // ignore i/o timeout
} }
logf("proxy-redir relay error: %v", err) log.F("proxy-redir relay error: %v", err)
} }
}() }()
@ -85,7 +107,7 @@ func (s *RedirProxy) ListenAndServe() {
} }
// Get the original destination of a TCP connection. // Get the original destination of a TCP connection.
func getOrigDst(conn net.Conn, ipv6 bool) (Addr, error) { func getOrigDst(conn net.Conn, ipv6 bool) (socks.Addr, error) {
c, ok := conn.(*net.TCPConn) c, ok := conn.(*net.TCPConn)
if !ok { if !ok {
return nil, errors.New("only work with TCP connection") return nil, errors.New("only work with TCP connection")
@ -113,7 +135,7 @@ func getOrigDst(conn net.Conn, ipv6 bool) (Addr, error) {
} }
// Call getorigdst() from linux/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c // Call getorigdst() from linux/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
func getorigdst(fd uintptr) (Addr, error) { func getorigdst(fd uintptr) (socks.Addr, error) {
raw := syscall.RawSockaddrInet4{} raw := syscall.RawSockaddrInet4{}
siz := unsafe.Sizeof(raw) siz := unsafe.Sizeof(raw)
if err := socketcall(GETSOCKOPT, fd, syscall.IPPROTO_IP, SO_ORIGINAL_DST, uintptr(unsafe.Pointer(&raw)), uintptr(unsafe.Pointer(&siz)), 0); err != nil { if err := socketcall(GETSOCKOPT, fd, syscall.IPPROTO_IP, SO_ORIGINAL_DST, uintptr(unsafe.Pointer(&raw)), uintptr(unsafe.Pointer(&siz)), 0); err != nil {
@ -121,7 +143,7 @@ func getorigdst(fd uintptr) (Addr, error) {
} }
addr := make([]byte, 1+net.IPv4len+2) addr := make([]byte, 1+net.IPv4len+2)
addr[0] = socks5IP4 addr[0] = socks.ATypeIP4
copy(addr[1:1+net.IPv4len], raw.Addr[:]) copy(addr[1:1+net.IPv4len], raw.Addr[:])
port := (*[2]byte)(unsafe.Pointer(&raw.Port)) // big-endian port := (*[2]byte)(unsafe.Pointer(&raw.Port)) // big-endian
addr[1+net.IPv4len], addr[1+net.IPv4len+1] = port[0], port[1] addr[1+net.IPv4len], addr[1+net.IPv4len+1] = port[0], port[1]
@ -130,7 +152,7 @@ func getorigdst(fd uintptr) (Addr, error) {
// Call ipv6_getorigdst() from linux/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c // Call ipv6_getorigdst() from linux/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
// NOTE: I haven't tried yet but it should work since Linux 3.8. // NOTE: I haven't tried yet but it should work since Linux 3.8.
func getorigdstIPv6(fd uintptr) (Addr, error) { func getorigdstIPv6(fd uintptr) (socks.Addr, error) {
raw := syscall.RawSockaddrInet6{} raw := syscall.RawSockaddrInet6{}
siz := unsafe.Sizeof(raw) siz := unsafe.Sizeof(raw)
if err := socketcall(GETSOCKOPT, fd, syscall.IPPROTO_IPV6, IP6T_SO_ORIGINAL_DST, uintptr(unsafe.Pointer(&raw)), uintptr(unsafe.Pointer(&siz)), 0); err != nil { if err := socketcall(GETSOCKOPT, fd, syscall.IPPROTO_IPV6, IP6T_SO_ORIGINAL_DST, uintptr(unsafe.Pointer(&raw)), uintptr(unsafe.Pointer(&siz)), 0); err != nil {
@ -138,7 +160,7 @@ func getorigdstIPv6(fd uintptr) (Addr, error) {
} }
addr := make([]byte, 1+net.IPv6len+2) addr := make([]byte, 1+net.IPv6len+2)
addr[0] = socks5IP6 addr[0] = socks.ATypeIP6
copy(addr[1:1+net.IPv6len], raw.Addr[:]) copy(addr[1:1+net.IPv6len], raw.Addr[:])
port := (*[2]byte)(unsafe.Pointer(&raw.Port)) // big-endian port := (*[2]byte)(unsafe.Pointer(&raw.Port)) // big-endian
addr[1+net.IPv6len], addr[1+net.IPv6len+1] = port[0], port[1] addr[1+net.IPv6len], addr[1+net.IPv6len+1] = port[0], port[1]

View File

@ -1,4 +1,4 @@
package main package redir
import ( import (
"syscall" "syscall"

View File

@ -1,6 +1,6 @@
// +build linux,!386 // +build linux,!386
package main package redir
import "syscall" import "syscall"

48
proxy/server.go Normal file
View File

@ -0,0 +1,48 @@
package proxy
import (
"errors"
"net/url"
"strings"
"github.com/nadoo/glider/common/log"
)
// Server interface
type Server interface {
// ListenAndServe as proxy server, use only in server mode.
ListenAndServe()
}
type ServerCreator func(s string, dialer Dialer) (Server, error)
var (
serverMap = make(map[string]ServerCreator)
)
func RegisterServer(name string, c ServerCreator) {
serverMap[name] = c
}
func ServerFromURL(s string, dialer Dialer) (Server, error) {
if !strings.Contains(s, "://") {
s = "mixed://" + s
}
u, err := url.Parse(s)
if err != nil {
log.F("parse err: %s", err)
return nil, err
}
if dialer == nil {
dialer = Direct
}
c, ok := serverMap[strings.ToLower(u.Scheme)]
if ok {
return c(s, dialer)
}
return nil, errors.New("unknown scheme '" + u.Scheme + "'")
}

View File

@ -9,76 +9,72 @@
// socks5 server: // socks5 server:
// https://github.com/shadowsocks/go-shadowsocks2/tree/master/socks // https://github.com/shadowsocks/go-shadowsocks2/tree/master/socks
package main package socks5
import ( import (
"errors" "errors"
"io" "io"
"net" "net"
"net/url"
"strconv" "strconv"
"sync" "sync"
"time" "time"
"github.com/nadoo/glider/common/conn"
"github.com/nadoo/glider/common/log"
"github.com/nadoo/glider/common/socks"
"github.com/nadoo/glider/proxy"
) )
const socks5Version = 5 const Version = 5
const (
socks5AuthNone = 0
socks5AuthPassword = 2
)
// SOCKS request commands as defined in RFC 1928 section 4.
const (
socks5Connect = 1
socks5Bind = 2
socks5UDPAssociate = 3
)
// SOCKS address types as defined in RFC 1928 section 5.
const (
socks5IP4 = 1
socks5Domain = 3
socks5IP6 = 4
)
// MaxAddrLen is the maximum size of SOCKS address in bytes.
const MaxAddrLen = 1 + 1 + 255 + 2
// Addr represents a SOCKS address as defined in RFC 1928 section 5.
type Addr []byte
var socks5Errors = []error{
errors.New(""),
errors.New("general failure"),
errors.New("connection forbidden"),
errors.New("network unreachable"),
errors.New("host unreachable"),
errors.New("connection refused"),
errors.New("TTL expired"),
errors.New("command not supported"),
errors.New("address type not supported"),
errors.New("socks5UDPAssociate"),
}
// SOCKS5 struct // SOCKS5 struct
type SOCKS5 struct { type SOCKS5 struct {
dialer Dialer dialer proxy.Dialer
addr string addr string
user string user string
password string password string
} }
// NewSOCKS5 returns a Proxy that makes SOCKSv5 connections to the given address func init() {
proxy.RegisterDialer("socks5", NewSocks5Dialer)
proxy.RegisterServer("socks5", NewSocks5Server)
}
// NewSOCKS5 returns a Proxy that makes SOCKS v5 connections to the given address
// with an optional username and password. See RFC 1928. // with an optional username and password. See RFC 1928.
func NewSOCKS5(addr, user, pass string, dialer Dialer) (*SOCKS5, error) { func NewSOCKS5(s string, dialer proxy.Dialer) (*SOCKS5, error) {
s := &SOCKS5{ u, err := url.Parse(s)
if err != nil {
log.F("parse err: %s", err)
return nil, err
}
addr := u.Host
var user, pass string
if u.User != nil {
user = u.User.Username()
pass, _ = u.User.Password()
}
h := &SOCKS5{
dialer: dialer, dialer: dialer,
addr: addr, addr: addr,
user: user, user: user,
password: pass, password: pass,
} }
return s, nil return h, nil
}
// NewSocks5Dialer returns a socks5 proxy dialer.
func NewSocks5Dialer(s string, dialer proxy.Dialer) (proxy.Dialer, error) {
return NewSOCKS5(s, dialer)
}
// NewSocks5Server returns a socks5 proxy server.
func NewSocks5Server(s string, dialer proxy.Dialer) (proxy.Server, error) {
return NewSOCKS5(s, dialer)
} }
// ListenAndServe serves socks5 requests. // ListenAndServe serves socks5 requests.
@ -91,16 +87,16 @@ func (s *SOCKS5) ListenAndServe() {
func (s *SOCKS5) ListenAndServeTCP() { func (s *SOCKS5) ListenAndServeTCP() {
l, err := net.Listen("tcp", s.addr) l, err := net.Listen("tcp", s.addr)
if err != nil { if err != nil {
logf("proxy-socks5 failed to listen on %s: %v", s.addr, err) log.F("proxy-socks5 failed to listen on %s: %v", s.addr, err)
return return
} }
logf("proxy-socks5 listening TCP on %s", s.addr) log.F("proxy-socks5 listening TCP on %s", s.addr)
for { for {
c, err := l.Accept() c, err := l.Accept()
if err != nil { if err != nil {
logf("proxy-socks5 failed to accept: %v", err) log.F("proxy-socks5 failed to accept: %v", err)
continue continue
} }
@ -119,7 +115,7 @@ func (s *SOCKS5) ServeTCP(c net.Conn) {
tgt, err := s.handshake(c) tgt, err := s.handshake(c)
if err != nil { if err != nil {
// UDP: keep the connection until disconnect then free the UDP socket // UDP: keep the connection until disconnect then free the UDP socket
if err == socks5Errors[9] { if err == socks.Errors[9] {
buf := []byte{} buf := []byte{}
// block here // block here
for { for {
@ -127,30 +123,30 @@ func (s *SOCKS5) ServeTCP(c net.Conn) {
if err, ok := err.(net.Error); ok && err.Timeout() { if err, ok := err.(net.Error); ok && err.Timeout() {
continue continue
} }
// logf("proxy-socks5 servetcp udp associate end") // log.F("proxy-socks5 servetcp udp associate end")
return return
} }
} }
logf("proxy-socks5 failed to get target address: %v", err) log.F("proxy-socks5 failed to get target address: %v", err)
return return
} }
rc, err := s.dialer.Dial("tcp", tgt.String()) rc, err := s.dialer.Dial("tcp", tgt.String())
if err != nil { if err != nil {
logf("proxy-socks5 failed to connect to target: %v", err) log.F("proxy-socks5 failed to connect to target: %v", err)
return return
} }
defer rc.Close() defer rc.Close()
logf("proxy-socks5 %s <-> %s", c.RemoteAddr(), tgt) log.F("proxy-socks5 %s <-> %s", c.RemoteAddr(), tgt)
_, _, err = relay(c, rc) _, _, err = conn.Relay(c, rc)
if err != nil { if err != nil {
if err, ok := err.(net.Error); ok && err.Timeout() { if err, ok := err.(net.Error); ok && err.Timeout() {
return // ignore i/o timeout return // ignore i/o timeout
} }
logf("proxy-socks5 relay error: %v", err) log.F("proxy-socks5 relay error: %v", err)
} }
} }
@ -158,22 +154,22 @@ func (s *SOCKS5) ServeTCP(c net.Conn) {
func (s *SOCKS5) ListenAndServeUDP() { func (s *SOCKS5) ListenAndServeUDP() {
lc, err := net.ListenPacket("udp", s.addr) lc, err := net.ListenPacket("udp", s.addr)
if err != nil { if err != nil {
logf("proxy-socks5-udp failed to listen on %s: %v", s.addr, err) log.F("proxy-socks5-udp failed to listen on %s: %v", s.addr, err)
return return
} }
defer lc.Close() defer lc.Close()
logf("proxy-socks5-udp listening UDP on %s", s.addr) log.F("proxy-socks5-udp listening UDP on %s", s.addr)
var nm sync.Map var nm sync.Map
buf := make([]byte, udpBufSize) buf := make([]byte, conn.UDPBufSize)
for { for {
c := NewSocks5PktConn(lc, nil, nil, true, nil) c := NewSocks5PktConn(lc, nil, nil, true, nil)
n, raddr, err := c.ReadFrom(buf) n, raddr, err := c.ReadFrom(buf)
if err != nil { if err != nil {
logf("proxy-socks5-udp remote read error: %v", err) log.F("proxy-socks5-udp remote read error: %v", err)
continue continue
} }
@ -181,13 +177,13 @@ func (s *SOCKS5) ListenAndServeUDP() {
v, ok := nm.Load(raddr.String()) v, ok := nm.Load(raddr.String())
if !ok && v == nil { if !ok && v == nil {
if c.tgtAddr == nil { if c.tgtAddr == nil {
logf("proxy-socks5-udp can not get target address, not a valid request") log.F("proxy-socks5-udp can not get target address, not a valid request")
continue continue
} }
lpc, nextHop, err := s.dialer.DialUDP("udp", c.tgtAddr.String()) lpc, nextHop, err := s.dialer.DialUDP("udp", c.tgtAddr.String())
if err != nil { if err != nil {
logf("proxy-socks5-udp remote dial error: %v", err) log.F("proxy-socks5-udp remote dial error: %v", err)
continue continue
} }
@ -195,7 +191,7 @@ func (s *SOCKS5) ListenAndServeUDP() {
nm.Store(raddr.String(), pc) nm.Store(raddr.String(), pc)
go func() { go func() {
timedCopy(c, raddr, pc, 2*time.Minute) conn.TimedCopy(c, raddr, pc, 2*time.Minute)
pc.Close() pc.Close()
nm.Delete(raddr.String()) nm.Delete(raddr.String())
}() }()
@ -206,11 +202,11 @@ func (s *SOCKS5) ListenAndServeUDP() {
_, err = pc.WriteTo(buf[:n], pc.writeAddr) _, err = pc.WriteTo(buf[:n], pc.writeAddr)
if err != nil { if err != nil {
logf("proxy-socks5-udp remote write error: %v", err) log.F("proxy-socks5-udp remote write error: %v", err)
continue continue
} }
logf("proxy-socks5-udp %s <-> %s", raddr, c.tgtAddr) log.F("proxy-socks5-udp %s <-> %s", raddr, c.tgtAddr)
} }
} }
@ -219,7 +215,7 @@ func (s *SOCKS5) ListenAndServeUDP() {
func (s *SOCKS5) Addr() string { return s.addr } func (s *SOCKS5) Addr() string { return s.addr }
// NextDialer returns the next dialer // NextDialer returns the next dialer
func (s *SOCKS5) NextDialer(dstAddr string) Dialer { return s.dialer.NextDialer(dstAddr) } func (s *SOCKS5) NextDialer(dstAddr string) proxy.Dialer { return s.dialer.NextDialer(dstAddr) }
// Dial connects to the address addr on the network net via the SOCKS5 proxy. // Dial connects to the address addr on the network net via the SOCKS5 proxy.
func (s *SOCKS5) Dial(network, addr string) (net.Conn, error) { func (s *SOCKS5) Dial(network, addr string) (net.Conn, error) {
@ -231,7 +227,7 @@ func (s *SOCKS5) Dial(network, addr string) (net.Conn, error) {
c, err := s.dialer.Dial(network, s.addr) c, err := s.dialer.Dial(network, s.addr)
if err != nil { if err != nil {
logf("dial to %s error: %s", s.addr, err) log.F("dial to %s error: %s", s.addr, err)
return nil, err return nil, err
} }
@ -251,7 +247,7 @@ func (s *SOCKS5) Dial(network, addr string) (net.Conn, error) {
func (s *SOCKS5) DialUDP(network, addr string) (pc net.PacketConn, writeTo net.Addr, err error) { func (s *SOCKS5) DialUDP(network, addr string) (pc net.PacketConn, writeTo net.Addr, err error) {
c, err := s.dialer.Dial("tcp", s.addr) c, err := s.dialer.Dial("tcp", s.addr)
if err != nil { if err != nil {
logf("proxy-socks5 dialudp dial tcp to %s error: %s", s.addr, err) log.F("proxy-socks5 dialudp dial tcp to %s error: %s", s.addr, err)
return nil, nil, err return nil, nil, err
} }
@ -262,15 +258,15 @@ func (s *SOCKS5) DialUDP(network, addr string) (pc net.PacketConn, writeTo net.A
// send VER, NMETHODS, METHODS // send VER, NMETHODS, METHODS
c.Write([]byte{5, 1, 0}) c.Write([]byte{5, 1, 0})
buf := make([]byte, MaxAddrLen) buf := make([]byte, socks.MaxAddrLen)
// read VER METHOD // read VER METHOD
if _, err := io.ReadFull(c, buf[:2]); err != nil { if _, err := io.ReadFull(c, buf[:2]); err != nil {
return nil, nil, err return nil, nil, err
} }
dstAddr := ParseAddr(addr) dstAddr := socks.ParseAddr(addr)
// write VER CMD RSV ATYP DST.ADDR DST.PORT // write VER CMD RSV ATYP DST.ADDR DST.PORT
c.Write(append([]byte{5, socks5UDPAssociate, 0}, dstAddr...)) c.Write(append([]byte{5, socks.CmdUDPAssociate, 0}, dstAddr...))
// read VER REP RSV ATYP BND.ADDR BND.PORT // read VER REP RSV ATYP BND.ADDR BND.PORT
if _, err := io.ReadFull(c, buf[:3]); err != nil { if _, err := io.ReadFull(c, buf[:3]); err != nil {
@ -279,18 +275,18 @@ func (s *SOCKS5) DialUDP(network, addr string) (pc net.PacketConn, writeTo net.A
rep := buf[1] rep := buf[1]
if rep != 0 { if rep != 0 {
logf("proxy-socks5 server reply: %d, not succeeded", rep) log.F("proxy-socks5 server reply: %d, not succeeded", rep)
return nil, nil, errors.New("server connect failed") return nil, nil, errors.New("server connect failed")
} }
uAddr, err := readAddr(c, buf) uAddr, err := socks.ReadAddrBuf(c, buf)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
pc, nextHop, err := s.dialer.DialUDP(network, uAddr.String()) pc, nextHop, err := s.dialer.DialUDP(network, uAddr.String())
if err != nil { if err != nil {
logf("proxy-socks5 dialudp to %s error: %s", uAddr.String(), err) log.F("proxy-socks5 dialudp to %s error: %s", uAddr.String(), err)
return nil, nil, err return nil, nil, err
} }
@ -318,11 +314,11 @@ func (s *SOCKS5) connect(conn net.Conn, target string) error {
// the size here is just an estimate // the size here is just an estimate
buf := make([]byte, 0, 6+len(host)) buf := make([]byte, 0, 6+len(host))
buf = append(buf, socks5Version) buf = append(buf, Version)
if len(s.user) > 0 && len(s.user) < 256 && len(s.password) < 256 { if len(s.user) > 0 && len(s.user) < 256 && len(s.password) < 256 {
buf = append(buf, 2 /* num auth methods */, socks5AuthNone, socks5AuthPassword) buf = append(buf, 2 /* num auth methods */, socks.AuthNone, socks.AuthPassword)
} else { } else {
buf = append(buf, 1 /* num auth methods */, socks5AuthNone) buf = append(buf, 1 /* num auth methods */, socks.AuthNone)
} }
if _, err := conn.Write(buf); err != nil { if _, err := conn.Write(buf); err != nil {
@ -339,7 +335,7 @@ func (s *SOCKS5) connect(conn net.Conn, target string) error {
return errors.New("proxy: SOCKS5 proxy at " + s.addr + " requires authentication") return errors.New("proxy: SOCKS5 proxy at " + s.addr + " requires authentication")
} }
if buf[1] == socks5AuthPassword { if buf[1] == socks.AuthPassword {
buf = buf[:0] buf = buf[:0]
buf = append(buf, 1 /* password protocol version */) buf = append(buf, 1 /* password protocol version */)
buf = append(buf, uint8(len(s.user))) buf = append(buf, uint8(len(s.user)))
@ -361,21 +357,21 @@ func (s *SOCKS5) connect(conn net.Conn, target string) error {
} }
buf = buf[:0] buf = buf[:0]
buf = append(buf, socks5Version, socks5Connect, 0 /* reserved */) buf = append(buf, Version, socks.CmdConnect, 0 /* reserved */)
if ip := net.ParseIP(host); ip != nil { if ip := net.ParseIP(host); ip != nil {
if ip4 := ip.To4(); ip4 != nil { if ip4 := ip.To4(); ip4 != nil {
buf = append(buf, socks5IP4) buf = append(buf, socks.ATypeIP4)
ip = ip4 ip = ip4
} else { } else {
buf = append(buf, socks5IP6) buf = append(buf, socks.ATypeIP6)
} }
buf = append(buf, ip...) buf = append(buf, ip...)
} else { } else {
if len(host) > 255 { if len(host) > 255 {
return errors.New("proxy: destination hostname too long: " + host) return errors.New("proxy: destination hostname too long: " + host)
} }
buf = append(buf, socks5Domain) buf = append(buf, socks.ATypeDomain)
buf = append(buf, byte(len(host))) buf = append(buf, byte(len(host)))
buf = append(buf, host...) buf = append(buf, host...)
} }
@ -390,8 +386,8 @@ func (s *SOCKS5) connect(conn net.Conn, target string) error {
} }
failure := "unknown error" failure := "unknown error"
if int(buf[1]) < len(socks5Errors) { if int(buf[1]) < len(socks.Errors) {
failure = socks5Errors[buf[1]].Error() failure = socks.Errors[buf[1]].Error()
} }
if len(failure) > 0 { if len(failure) > 0 {
@ -400,11 +396,11 @@ func (s *SOCKS5) connect(conn net.Conn, target string) error {
bytesToDiscard := 0 bytesToDiscard := 0
switch buf[3] { switch buf[3] {
case socks5IP4: case socks.ATypeIP4:
bytesToDiscard = net.IPv4len bytesToDiscard = net.IPv4len
case socks5IP6: case socks.ATypeIP6:
bytesToDiscard = net.IPv6len bytesToDiscard = net.IPv6len
case socks5Domain: case socks.ATypeDomain:
_, err := io.ReadFull(conn, buf[:1]) _, err := io.ReadFull(conn, buf[:1])
if err != nil { if err != nil {
return errors.New("proxy: failed to read domain length from SOCKS5 proxy at " + s.addr + ": " + err.Error()) return errors.New("proxy: failed to read domain length from SOCKS5 proxy at " + s.addr + ": " + err.Error())
@ -432,9 +428,9 @@ func (s *SOCKS5) connect(conn net.Conn, target string) error {
} }
// Handshake fast-tracks SOCKS initialization to get target address to connect. // Handshake fast-tracks SOCKS initialization to get target address to connect.
func (s *SOCKS5) handshake(rw io.ReadWriter) (Addr, error) { func (s *SOCKS5) handshake(rw io.ReadWriter) (socks.Addr, error) {
// Read RFC 1928 for request and reply structure and sizes. // Read RFC 1928 for request and reply structure and sizes.
buf := make([]byte, MaxAddrLen) buf := make([]byte, socks.MaxAddrLen)
// read VER, NMETHODS, METHODS // read VER, NMETHODS, METHODS
if _, err := io.ReadFull(rw, buf[:2]); err != nil { if _, err := io.ReadFull(rw, buf[:2]); err != nil {
return nil, err return nil, err
@ -452,169 +448,41 @@ func (s *SOCKS5) handshake(rw io.ReadWriter) (Addr, error) {
return nil, err return nil, err
} }
cmd := buf[1] cmd := buf[1]
addr, err := readAddr(rw, buf) addr, err := socks.ReadAddrBuf(rw, buf)
if err != nil { if err != nil {
return nil, err return nil, err
} }
switch cmd { switch cmd {
case socks5Connect: case socks.CmdConnect:
_, err = rw.Write([]byte{5, 0, 0, 1, 0, 0, 0, 0, 0, 0}) // SOCKS v5, reply succeeded _, err = rw.Write([]byte{5, 0, 0, 1, 0, 0, 0, 0, 0, 0}) // SOCKS v5, reply succeeded
case socks5UDPAssociate: case socks.CmdUDPAssociate:
listenAddr := ParseAddr(rw.(net.Conn).LocalAddr().String()) listenAddr := socks.ParseAddr(rw.(net.Conn).LocalAddr().String())
_, err = rw.Write(append([]byte{5, 0, 0}, listenAddr...)) // SOCKS v5, reply succeeded _, err = rw.Write(append([]byte{5, 0, 0}, listenAddr...)) // SOCKS v5, reply succeeded
if err != nil { if err != nil {
return nil, socks5Errors[7] return nil, socks.Errors[7]
} }
err = socks5Errors[9] err = socks.Errors[9]
default: default:
return nil, socks5Errors[7] return nil, socks.Errors[7]
} }
return addr, err // skip VER, CMD, RSV fields return addr, err // skip VER, CMD, RSV fields
} }
// String serializes SOCKS address a to string form.
func (a Addr) String() string {
var host, port string
switch ATYP(a[0]) { // address type
case socks5Domain:
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]))
case socks5IP4:
host = net.IP(a[1 : 1+net.IPv4len]).String()
port = strconv.Itoa((int(a[1+net.IPv4len]) << 8) | int(a[1+net.IPv4len+1]))
case socks5IP6:
host = net.IP(a[1 : 1+net.IPv6len]).String()
port = strconv.Itoa((int(a[1+net.IPv6len]) << 8) | int(a[1+net.IPv6len+1]))
}
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) {
if len(b) < MaxAddrLen {
return nil, io.ErrShortBuffer
}
_, err := io.ReadFull(r, b[:1]) // read 1st byte for address type
if err != nil {
return nil, err
}
switch ATYP(b[0]) {
case socks5Domain:
_, err = io.ReadFull(r, b[1:2]) // read 2nd byte for domain length
if err != nil {
return nil, err
}
_, err = io.ReadFull(r, b[2:2+int(b[1])+2])
return b[:1+1+int(b[1])+2], err
case socks5IP4:
_, err = io.ReadFull(r, b[1:1+net.IPv4len+2])
return b[:1+net.IPv4len+2], err
case socks5IP6:
_, err = io.ReadFull(r, b[1:1+net.IPv6len+2])
return b[:1+net.IPv6len+2], err
}
return nil, socks5Errors[8]
}
// ReadAddr reads just enough bytes from r to get a valid Addr.
func ReadAddr(r io.Reader) (Addr, error) {
return readAddr(r, make([]byte, MaxAddrLen))
}
// SplitAddr slices a SOCKS address from beginning of b. Returns nil if failed.
func SplitAddr(b []byte) Addr {
addrLen := 1
if len(b) < addrLen {
return nil
}
switch ATYP(b[0]) {
case socks5Domain:
if len(b) < 2 {
return nil
}
addrLen = 1 + 1 + int(b[1]) + 2
case socks5IP4:
addrLen = 1 + net.IPv4len + 2
case socks5IP6:
addrLen = 1 + net.IPv6len + 2
default:
return nil
}
if len(b) < addrLen {
return nil
}
return b[:addrLen]
}
// ParseAddr parses the address in string s. Returns nil if failed.
func ParseAddr(s string) Addr {
var addr Addr
host, port, err := net.SplitHostPort(s)
if err != nil {
return nil
}
if ip := net.ParseIP(host); ip != nil {
if ip4 := ip.To4(); ip4 != nil {
addr = make([]byte, 1+net.IPv4len+2)
addr[0] = socks5IP4
copy(addr[1:], ip4)
} else {
addr = make([]byte, 1+net.IPv6len+2)
addr[0] = socks5IP6
copy(addr[1:], ip)
}
} else {
if len(host) > 255 {
return nil
}
addr = make([]byte, 1+1+len(host)+2)
addr[0] = socks5Domain
addr[1] = byte(len(host))
copy(addr[2:], host)
}
portnum, err := strconv.ParseUint(port, 10, 16)
if err != nil {
return nil
}
addr[len(addr)-2], addr[len(addr)-1] = byte(portnum>>8), byte(portnum)
return addr
}
// Socks5PktConn . // Socks5PktConn .
type Socks5PktConn struct { type Socks5PktConn struct {
net.PacketConn net.PacketConn
writeAddr net.Addr // write to and read from addr writeAddr net.Addr // write to and read from addr
tgtAddr Addr tgtAddr socks.Addr
tgtHeader bool tgtHeader bool
ctrlConn net.Conn // tcp control conn ctrlConn net.Conn // tcp control conn
} }
// NewSocks5PktConn returns a Socks5PktConn // NewSocks5PktConn returns a Socks5PktConn
func NewSocks5PktConn(c net.PacketConn, writeAddr net.Addr, tgtAddr Addr, tgtHeader bool, ctrlConn net.Conn) *Socks5PktConn { func NewSocks5PktConn(c net.PacketConn, writeAddr net.Addr, tgtAddr socks.Addr, tgtHeader bool, ctrlConn net.Conn) *Socks5PktConn {
pc := &Socks5PktConn{ pc := &Socks5PktConn{
PacketConn: c, PacketConn: c,
writeAddr: writeAddr, writeAddr: writeAddr,
@ -630,7 +498,7 @@ func NewSocks5PktConn(c net.PacketConn, writeAddr net.Addr, tgtAddr Addr, tgtHea
if err, ok := err.(net.Error); ok && err.Timeout() { if err, ok := err.(net.Error); ok && err.Timeout() {
continue continue
} }
logf("proxy-socks5 dialudp udp associate end") log.F("proxy-socks5 dialudp udp associate end")
return return
} }
}() }()
@ -657,7 +525,7 @@ func (pc *Socks5PktConn) ReadFrom(b []byte) (int, net.Addr, error) {
// +----+------+------+----------+----------+----------+ // +----+------+------+----------+----------+----------+
// | 2 | 1 | 1 | Variable | 2 | Variable | // | 2 | 1 | 1 | Variable | 2 | Variable |
// +----+------+------+----------+----------+----------+ // +----+------+------+----------+----------+----------+
tgtAddr := SplitAddr(buf[3:]) tgtAddr := socks.SplitAddr(buf[3:])
copy(b, buf[3+len(tgtAddr):]) copy(b, buf[3+len(tgtAddr):])
//test //test

View File

@ -1,40 +1,73 @@
package main package ss
import ( import (
"errors" "errors"
"log"
"net" "net"
"net/url"
"strings" "strings"
"sync" "sync"
"time" "time"
"github.com/shadowsocks/go-shadowsocks2/core" "github.com/shadowsocks/go-shadowsocks2/core"
"github.com/nadoo/glider/common/conn"
"github.com/nadoo/glider/common/log"
"github.com/nadoo/glider/common/socks"
"github.com/nadoo/glider/proxy"
) )
const udpBufSize = 65536 const udpBufSize = 65536
// SS . // SS .
type SS struct { type SS struct {
dialer Dialer dialer proxy.Dialer
addr string addr string
core.Cipher core.Cipher
} }
func init() {
proxy.RegisterDialer("ss", NewSSDialer)
proxy.RegisterServer("ss", NewSSServer)
}
// NewSS returns a shadowsocks proxy. // NewSS returns a shadowsocks proxy.
func NewSS(addr, method, pass string, dialer Dialer) (*SS, error) { func NewSS(s string, dialer proxy.Dialer) (*SS, error) {
u, err := url.Parse(s)
if err != nil {
log.F("parse err: %s", err)
return nil, err
}
addr := u.Host
var method, pass string
if u.User != nil {
method = u.User.Username()
pass, _ = u.User.Password()
}
ciph, err := core.PickCipher(method, nil, pass) ciph, err := core.PickCipher(method, nil, pass)
if err != nil { if err != nil {
log.Fatalf("proxy-ss PickCipher for '%s', error: %s", method, err) log.Fatalf("proxy-ss PickCipher for '%s', error: %s", method, err)
} }
s := &SS{ p := &SS{
dialer: dialer, dialer: dialer,
addr: addr, addr: addr,
Cipher: ciph, Cipher: ciph,
} }
return s, nil return p, nil
}
// NewSSDialer returns a ss proxy dialer.
func NewSSDialer(s string, dialer proxy.Dialer) (proxy.Dialer, error) {
return NewSS(s, dialer)
}
// NewSSServer returns a ss proxy server.
func NewSSServer(s string, dialer proxy.Dialer) (proxy.Server, error) {
return NewSS(s, dialer)
} }
// ListenAndServe serves ss requests. // ListenAndServe serves ss requests.
@ -47,16 +80,16 @@ func (s *SS) ListenAndServe() {
func (s *SS) ListenAndServeTCP() { 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("proxy-ss failed to listen on %s: %v", s.addr, err) log.F("proxy-ss failed to listen on %s: %v", s.addr, err)
return return
} }
logf("proxy-ss listening TCP on %s", s.addr) log.F("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("proxy-ss failed to accept: %v", err) log.F("proxy-ss failed to accept: %v", err)
continue continue
} }
go s.ServeTCP(c) go s.ServeTCP(c)
@ -73,28 +106,28 @@ func (s *SS) ServeTCP(c net.Conn) {
c = s.StreamConn(c) c = s.StreamConn(c)
tgt, err := ReadAddr(c) tgt, err := socks.ReadAddr(c)
if err != nil { if err != nil {
logf("proxy-ss failed to get target address: %v", err) log.F("proxy-ss failed to get target address: %v", err)
return return
} }
dialer := s.dialer.NextDialer(tgt.String()) dialer := s.dialer.NextDialer(tgt.String())
// udp over tcp? // udp over tcp?
uot := UoT(tgt[0]) uot := socks.UoT(tgt[0])
if uot && dialer.Addr() == "DIRECT" { if uot && dialer.Addr() == "DIRECT" {
rc, err := net.ListenPacket("udp", "") rc, err := net.ListenPacket("udp", "")
if err != nil { if err != nil {
logf("proxy-ss UDP remote listen error: %v", err) log.F("proxy-ss UDP remote listen error: %v", err)
} }
defer rc.Close() defer rc.Close()
req := make([]byte, udpBufSize) req := make([]byte, udpBufSize)
n, err := c.Read(req) n, err := c.Read(req)
if err != nil { if err != nil {
logf("proxy-ss error in ioutil.ReadAll: %s\n", err) log.F("proxy-ss error in ioutil.ReadAll: %s\n", err)
return return
} }
@ -104,12 +137,12 @@ func (s *SS) ServeTCP(c net.Conn) {
buf := make([]byte, udpBufSize) buf := make([]byte, udpBufSize)
n, _, err = rc.ReadFrom(buf) n, _, err = rc.ReadFrom(buf)
if err != nil { if err != nil {
logf("proxy-uottun read error: %v", err) log.F("proxy-uottun read error: %v", err)
} }
c.Write(buf[:n]) c.Write(buf[:n])
logf("proxy-ss %s <-tcp-> %s - %s <-udp-> %s ", c.RemoteAddr(), c.LocalAddr(), rc.LocalAddr(), tgt) log.F("proxy-ss %s <-tcp-> %s - %s <-udp-> %s ", c.RemoteAddr(), c.LocalAddr(), rc.LocalAddr(), tgt)
return return
} }
@ -121,19 +154,19 @@ func (s *SS) ServeTCP(c net.Conn) {
rc, err := dialer.Dial(network, tgt.String()) rc, err := dialer.Dial(network, tgt.String())
if err != nil { if err != nil {
logf("proxy-ss failed to connect to target: %v", err) log.F("proxy-ss failed to connect to target: %v", err)
return return
} }
defer rc.Close() defer rc.Close()
logf("proxy-ss %s <-> %s", c.RemoteAddr(), tgt) log.F("proxy-ss %s <-> %s", c.RemoteAddr(), tgt)
_, _, err = relay(c, rc) _, _, err = conn.Relay(c, rc)
if err != nil { if err != nil {
if err, ok := err.(net.Error); ok && err.Timeout() { if err, ok := err.(net.Error); ok && err.Timeout() {
return // ignore i/o timeout return // ignore i/o timeout
} }
logf("proxy-ss relay error: %v", err) log.F("proxy-ss relay error: %v", err)
} }
} }
@ -142,14 +175,14 @@ func (s *SS) ServeTCP(c net.Conn) {
func (s *SS) ListenAndServeUDP() { func (s *SS) ListenAndServeUDP() {
lc, err := net.ListenPacket("udp", s.addr) lc, err := net.ListenPacket("udp", s.addr)
if err != nil { if err != nil {
logf("proxy-ss-udp failed to listen on %s: %v", s.addr, err) log.F("proxy-ss-udp failed to listen on %s: %v", s.addr, err)
return return
} }
defer lc.Close() defer lc.Close()
lc = s.PacketConn(lc) lc = s.PacketConn(lc)
logf("proxy-ss-udp listening UDP on %s", s.addr) log.F("proxy-ss-udp listening UDP on %s", s.addr)
var nm sync.Map var nm sync.Map
buf := make([]byte, udpBufSize) buf := make([]byte, udpBufSize)
@ -159,7 +192,7 @@ func (s *SS) ListenAndServeUDP() {
n, raddr, err := c.ReadFrom(buf) n, raddr, err := c.ReadFrom(buf)
if err != nil { if err != nil {
logf("proxy-ss-udp remote read error: %v", err) log.F("proxy-ss-udp remote read error: %v", err)
continue continue
} }
@ -168,7 +201,7 @@ func (s *SS) ListenAndServeUDP() {
if !ok && v == nil { if !ok && v == nil {
lpc, nextHop, err := s.dialer.DialUDP("udp", c.tgtAddr.String()) lpc, nextHop, err := s.dialer.DialUDP("udp", c.tgtAddr.String())
if err != nil { if err != nil {
logf("proxy-ss-udp remote dial error: %v", err) log.F("proxy-ss-udp remote dial error: %v", err)
continue continue
} }
@ -176,7 +209,7 @@ func (s *SS) ListenAndServeUDP() {
nm.Store(raddr.String(), pc) nm.Store(raddr.String(), pc)
go func() { go func() {
timedCopy(c, raddr, pc, 2*time.Minute) conn.TimedCopy(c, raddr, pc, 2*time.Minute)
pc.Close() pc.Close()
nm.Delete(raddr.String()) nm.Delete(raddr.String())
}() }()
@ -187,11 +220,11 @@ func (s *SS) ListenAndServeUDP() {
_, err = pc.WriteTo(buf[:n], pc.writeAddr) _, err = pc.WriteTo(buf[:n], pc.writeAddr)
if err != nil { if err != nil {
logf("proxy-ss-udp remote write error: %v", err) log.F("proxy-ss-udp remote write error: %v", err)
continue continue
} }
logf("proxy-ss-udp %s <-> %s", raddr, c.tgtAddr) log.F("proxy-ss-udp %s <-> %s", raddr, c.tgtAddr)
} }
} }
@ -204,11 +237,11 @@ func ListCipher() string {
func (s *SS) Addr() string { return s.addr } func (s *SS) Addr() string { return s.addr }
// NextDialer returns the next dialer // NextDialer returns the next dialer
func (s *SS) NextDialer(dstAddr string) Dialer { return s.dialer.NextDialer(dstAddr) } func (s *SS) NextDialer(dstAddr string) proxy.Dialer { return s.dialer.NextDialer(dstAddr) }
// 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) {
target := ParseAddr(addr) target := socks.ParseAddr(addr)
if target == nil { if target == nil {
return nil, errors.New("proxy-ss unable to parse address: " + addr) return nil, errors.New("proxy-ss unable to parse address: " + addr)
} }
@ -219,7 +252,7 @@ func (s *SS) Dial(network, addr string) (net.Conn, error) {
c, err := s.dialer.Dial("tcp", s.addr) c, err := s.dialer.Dial("tcp", s.addr)
if err != nil { if err != nil {
logf("proxy-ss dial to %s error: %s", s.addr, err) log.F("proxy-ss dial to %s error: %s", s.addr, err)
return nil, err return nil, err
} }
@ -241,11 +274,11 @@ func (s *SS) Dial(network, addr string) (net.Conn, error) {
func (s *SS) DialUDP(network, addr string) (net.PacketConn, net.Addr, error) { func (s *SS) DialUDP(network, addr string) (net.PacketConn, net.Addr, error) {
pc, nextHop, err := s.dialer.DialUDP(network, s.addr) pc, nextHop, err := s.dialer.DialUDP(network, s.addr)
if err != nil { if err != nil {
logf("proxy-ss dialudp to %s error: %s", s.addr, err) log.F("proxy-ss dialudp to %s error: %s", s.addr, err)
return nil, nil, err return nil, nil, err
} }
pkc := NewPktConn(s.PacketConn(pc), nextHop, ParseAddr(addr), true) pkc := NewPktConn(s.PacketConn(pc), nextHop, socks.ParseAddr(addr), true)
return pkc, nextHop, err return pkc, nextHop, err
} }
@ -255,12 +288,12 @@ type PktConn struct {
writeAddr net.Addr // write to and read from addr writeAddr net.Addr // write to and read from addr
tgtAddr Addr tgtAddr socks.Addr
tgtHeader bool tgtHeader bool
} }
// NewPktConn returns a PktConn // NewPktConn returns a PktConn
func NewPktConn(c net.PacketConn, writeAddr net.Addr, tgtAddr Addr, tgtHeader bool) *PktConn { func NewPktConn(c net.PacketConn, writeAddr net.Addr, tgtAddr socks.Addr, tgtHeader bool) *PktConn {
pc := &PktConn{ pc := &PktConn{
PacketConn: c, PacketConn: c,
writeAddr: writeAddr, writeAddr: writeAddr,
@ -281,7 +314,7 @@ func (pc *PktConn) ReadFrom(b []byte) (int, net.Addr, error) {
return n, raddr, err return n, raddr, err
} }
tgtAddr := SplitAddr(buf) tgtAddr := socks.SplitAddr(buf)
copy(b, buf[len(tgtAddr):]) copy(b, buf[len(tgtAddr):])
//test //test

View File

@ -1,4 +1,4 @@
package main package ssr
import ( import (
"errors" "errors"
@ -11,11 +11,15 @@ import (
"github.com/sun8911879/shadowsocksR/obfs" "github.com/sun8911879/shadowsocksR/obfs"
"github.com/sun8911879/shadowsocksR/protocol" "github.com/sun8911879/shadowsocksR/protocol"
"github.com/sun8911879/shadowsocksR/ssr" "github.com/sun8911879/shadowsocksR/ssr"
"github.com/nadoo/glider/common/log"
"github.com/nadoo/glider/common/socks"
"github.com/nadoo/glider/proxy"
) )
// SSR . // SSR .
type SSR struct { type SSR struct {
dialer Dialer dialer proxy.Dialer
addr string addr string
EncryptMethod string EncryptMethod string
@ -28,41 +32,63 @@ type SSR struct {
ProtocolData interface{} ProtocolData interface{}
} }
func init() {
proxy.RegisterDialer("ssr", NewSSRDialer)
}
// NewSSR returns a shadowsocksr proxy, ssr://method:pass@host:port/rawQuery // NewSSR returns a shadowsocksr proxy, ssr://method:pass@host:port/rawQuery
func NewSSR(addr, method, pass, rawQuery string, dialer Dialer) (*SSR, error) { func NewSSR(s string, dialer proxy.Dialer) (*SSR, error) {
s := &SSR{ u, err := url.Parse(s)
if err != nil {
log.F("parse err: %s", err)
return nil, err
}
addr := u.Host
var method, pass string
if u.User != nil {
method = u.User.Username()
pass, _ = u.User.Password()
}
p := &SSR{
dialer: dialer, dialer: dialer,
addr: addr, addr: addr,
EncryptMethod: method, EncryptMethod: method,
EncryptPassword: pass, EncryptPassword: pass,
} }
p, _ := url.ParseQuery(rawQuery) q, _ := url.ParseQuery(u.RawQuery)
if v, ok := p["protocol"]; ok { if v, ok := q["protocol"]; ok {
s.Protocol = v[0] p.Protocol = v[0]
} }
if v, ok := p["protocol_param"]; ok { if v, ok := q["protocol_param"]; ok {
s.ProtocolParam = v[0] p.ProtocolParam = v[0]
} }
if v, ok := p["obfs"]; ok { if v, ok := q["obfs"]; ok {
s.Obfs = v[0] p.Obfs = v[0]
} }
if v, ok := p["obfs_param"]; ok { if v, ok := q["obfs_param"]; ok {
s.ObfsParam = v[0] p.ObfsParam = v[0]
} }
return s, nil return p, nil
}
// NewSSRDialer returns a ssr proxy dialer.
func NewSSRDialer(s string, dialer proxy.Dialer) (proxy.Dialer, error) {
return NewSSR(s, dialer)
} }
// Addr returns forwarder's address // Addr returns forwarder's address
func (s *SSR) Addr() string { return s.addr } func (s *SSR) Addr() string { return s.addr }
// NextDialer returns the next dialer // NextDialer returns the next dialer
func (s *SSR) NextDialer(dstAddr string) Dialer { return s.dialer.NextDialer(dstAddr) } func (s *SSR) NextDialer(dstAddr string) proxy.Dialer { return s.dialer.NextDialer(dstAddr) }
// 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 *SSR) Dial(network, addr string) (net.Conn, error) { func (s *SSR) Dial(network, addr string) (net.Conn, error) {
target := ParseAddr(addr) target := socks.ParseAddr(addr)
if target == nil { if target == nil {
return nil, errors.New("proxy-ssr unable to parse address: " + addr) return nil, errors.New("proxy-ssr unable to parse address: " + addr)
} }
@ -74,7 +100,7 @@ func (s *SSR) Dial(network, addr string) (net.Conn, error) {
c, err := s.dialer.Dial("tcp", s.addr) c, err := s.dialer.Dial("tcp", s.addr)
if err != nil { if err != nil {
logf("proxy-ssr dial to %s error: %s", s.addr, err) log.F("proxy-ssr dial to %s error: %s", s.addr, err)
return nil, err return nil, err
} }

94
proxy/tcptun/tcptun.go Normal file
View File

@ -0,0 +1,94 @@
package tcptun
import (
"net"
"net/url"
"strings"
"github.com/nadoo/glider/common/conn"
"github.com/nadoo/glider/common/log"
"github.com/nadoo/glider/proxy"
)
// TCPTun struct
type TCPTun struct {
dialer proxy.Dialer
addr string
raddr string
}
func init() {
proxy.RegisterServer("tcptun", NewTCPTunServer)
}
// NewTCPTun returns a tcptun proxy.
func NewTCPTun(s string, dialer proxy.Dialer) (*TCPTun, error) {
u, err := url.Parse(s)
if err != nil {
log.F("parse err: %s", err)
return nil, err
}
addr := u.Host
d := strings.Split(addr, "=")
p := &TCPTun{
dialer: dialer,
addr: d[0],
raddr: d[1],
}
return p, nil
}
// NewTCPTunServer returns a udp tunnel server.
func NewTCPTunServer(s string, dialer proxy.Dialer) (proxy.Server, error) {
return NewTCPTun(s, dialer)
}
// ListenAndServe .
func (s *TCPTun) ListenAndServe() {
l, err := net.Listen("tcp", s.addr)
if err != nil {
log.F("failed to listen on %s: %v", s.addr, err)
return
}
log.F("listening TCP on %s", s.addr)
for {
c, err := l.Accept()
if err != nil {
log.F("failed to accept: %v", err)
continue
}
go func() {
defer c.Close()
if c, ok := c.(*net.TCPConn); ok {
c.SetKeepAlive(true)
}
rc, err := s.dialer.Dial("tcp", s.raddr)
if err != nil {
log.F("failed to connect to target: %v", err)
return
}
defer rc.Close()
log.F("proxy-tcptun %s <-> %s", c.RemoteAddr(), s.raddr)
_, _, err = conn.Relay(c, rc)
if err != nil {
if err, ok := err.(net.Error); ok && err.Timeout() {
return // ignore i/o timeout
}
log.F("relay error: %v", err)
}
}()
}
}

106
proxy/udptun/udptun.go Normal file
View File

@ -0,0 +1,106 @@
package udptun
import (
"net"
"net/url"
"strings"
"sync"
"time"
"github.com/nadoo/glider/common/conn"
"github.com/nadoo/glider/common/log"
"github.com/nadoo/glider/proxy"
)
// UDPTun struct
type UDPTun struct {
dialer proxy.Dialer
addr string
raddr string
}
func init() {
proxy.RegisterServer("udptun", NewUDPTunServer)
}
// 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)
return nil, err
}
addr := u.Host
d := strings.Split(addr, "=")
p := &UDPTun{
dialer: dialer,
addr: d[0],
raddr: d[1],
}
return p, nil
}
// NewUDPTunServer returns a udp tunnel server.
func NewUDPTunServer(s string, dialer proxy.Dialer) (proxy.Server, error) {
return NewUDPTun(s, dialer)
}
// ListenAndServe .
func (s *UDPTun) ListenAndServe() {
c, err := net.ListenPacket("udp", s.addr)
if err != nil {
log.F("proxy-udptun failed to listen on %s: %v", s.addr, err)
return
}
defer c.Close()
log.F("proxy-udptun listening UDP on %s", s.addr)
var nm sync.Map
buf := make([]byte, conn.UDPBufSize)
for {
n, raddr, err := c.ReadFrom(buf)
if err != nil {
log.F("proxy-udptun read error: %v", err)
continue
}
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)
if err != nil {
log.F("proxy-udptun remote dial error: %v", err)
continue
}
nm.Store(raddr.String(), pc)
go func() {
conn.TimedCopy(c, raddr, pc, 2*time.Minute)
pc.Close()
nm.Delete(raddr.String())
}()
} else {
pc = v.(net.PacketConn)
}
_, err = pc.WriteTo(buf[:n], writeAddr)
if err != nil {
log.F("proxy-udptun remote write error: %v", err)
continue
}
log.F("proxy-udptun %s <-> %s", raddr, s.raddr)
}
}

104
proxy/uottun/uottun.go Normal file
View File

@ -0,0 +1,104 @@
package uottun
import (
"io/ioutil"
"net"
"net/url"
"strings"
"time"
"github.com/nadoo/glider/common/conn"
"github.com/nadoo/glider/common/log"
"github.com/nadoo/glider/proxy"
)
// UoTTun udp over tcp tunnel
type UoTTun struct {
dialer proxy.Dialer
addr string
raddr string
}
func init() {
proxy.RegisterServer("uottun", NewUoTTunServer)
}
// NewUoTTun returns a UoTTun proxy.
func NewUoTTun(s string, dialer proxy.Dialer) (*UoTTun, error) {
u, err := url.Parse(s)
if err != nil {
log.F("parse err: %s", err)
return nil, err
}
addr := u.Host
d := strings.Split(addr, "=")
p := &UoTTun{
dialer: dialer,
addr: d[0],
raddr: d[1],
}
return p, nil
}
// NewUoTTunServer returns a uot tunnel server.
func NewUoTTunServer(s string, dialer proxy.Dialer) (proxy.Server, error) {
return NewUoTTun(s, dialer)
}
// ListenAndServe .
func (s *UoTTun) ListenAndServe() {
c, err := net.ListenPacket("udp", s.addr)
if err != nil {
log.F("proxy-uottun failed to listen on %s: %v", s.addr, err)
return
}
defer c.Close()
log.F("proxy-uottun listening UDP on %s", s.addr)
buf := make([]byte, conn.UDPBufSize)
for {
n, clientAddr, err := c.ReadFrom(buf)
if err != nil {
log.F("proxy-uottun read error: %v", err)
continue
}
rc, err := s.dialer.Dial("uot", s.raddr)
if err != nil {
log.F("proxy-uottun failed to connect to server %v: %v", s.raddr, err)
continue
}
go func() {
// no remote forwarder, just a local udp forwarder
if urc, ok := rc.(*net.UDPConn); ok {
conn.TimedCopy(c, clientAddr, urc, 2*time.Minute)
urc.Close()
return
}
// remote forwarder, udp over tcp
resp, err := ioutil.ReadAll(rc)
if err != nil {
log.F("error in ioutil.ReadAll: %s\n", err)
return
}
rc.Close()
c.WriteTo(resp, clientAddr)
}()
_, err = rc.Write(buf[:n])
if err != nil {
log.F("proxy-uottun remote write error: %v", err)
continue
}
log.F("proxy-uottun %s <-> %s", clientAddr, s.raddr)
}
}

View File

@ -1,21 +0,0 @@
// +build !linux
package main
import (
"errors"
"log"
)
// RedirProxy struct
type RedirProxy struct{}
// NewRedirProxy returns a redirect proxy.
func NewRedirProxy(addr string, sDialer Dialer) (*RedirProxy, error) {
return nil, errors.New("redir not supported on this os")
}
// ListenAndServe .
func (s *RedirProxy) ListenAndServe() {
log.Fatal("redir not supported on this os")
}

26
rule.go
View File

@ -1,15 +1,17 @@
package main package main
import ( import (
"log"
"net" "net"
"strings" "strings"
"sync" "sync"
"github.com/nadoo/glider/common/log"
"github.com/nadoo/glider/proxy"
) )
// RuleDialer struct // RuleDialer struct
type RuleDialer struct { type RuleDialer struct {
gDialer Dialer gDialer proxy.Dialer
domainMap sync.Map domainMap sync.Map
ipMap sync.Map ipMap sync.Map
@ -17,16 +19,16 @@ type RuleDialer struct {
} }
// NewRuleDialer returns a new rule dialer // NewRuleDialer returns a new rule dialer
func NewRuleDialer(rules []*RuleConf, gDialer Dialer) *RuleDialer { func NewRuleDialer(rules []*RuleConf, gDialer proxy.Dialer) *RuleDialer {
rd := &RuleDialer{gDialer: gDialer} rd := &RuleDialer{gDialer: gDialer}
for _, r := range rules { for _, r := range rules {
var fwdrs []Dialer var fwdrs []proxy.Dialer
for _, chain := range r.Forward { for _, chain := range r.Forward {
var fwdr Dialer var fwdr proxy.Dialer
var err error var err error
for _, url := range strings.Split(chain, ",") { for _, url := range strings.Split(chain, ",") {
fwdr, err = DialerFromURL(url, fwdr) fwdr, err = proxy.DialerFromURL(url, fwdr)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
@ -59,7 +61,7 @@ func NewRuleDialer(rules []*RuleConf, gDialer Dialer) *RuleDialer {
func (rd *RuleDialer) Addr() string { return "RULE DIALER, DEFAULT: " + rd.gDialer.Addr() } func (rd *RuleDialer) Addr() string { return "RULE DIALER, DEFAULT: " + rd.gDialer.Addr() }
// NextDialer return next dialer according to rule // NextDialer return next dialer according to rule
func (rd *RuleDialer) NextDialer(dstAddr string) Dialer { func (rd *RuleDialer) NextDialer(dstAddr string) proxy.Dialer {
host, _, err := net.SplitHostPort(dstAddr) host, _, err := net.SplitHostPort(dstAddr)
if err != nil { if err != nil {
// TODO: check here // TODO: check here
@ -71,15 +73,15 @@ func (rd *RuleDialer) NextDialer(dstAddr string) Dialer {
if ip := net.ParseIP(host); ip != nil { if ip := net.ParseIP(host); ip != nil {
// check ip // check ip
if dialer, ok := rd.ipMap.Load(ip.String()); ok { if dialer, ok := rd.ipMap.Load(ip.String()); ok {
return dialer.(Dialer) return dialer.(proxy.Dialer)
} }
var ret Dialer var ret proxy.Dialer
// check cidr // check cidr
rd.cidrMap.Range(func(key, value interface{}) bool { rd.cidrMap.Range(func(key, value interface{}) bool {
cidr := key.(*net.IPNet) cidr := key.(*net.IPNet)
if cidr.Contains(ip) { if cidr.Contains(ip) {
ret = value.(Dialer) ret = value.(proxy.Dialer)
return false return false
} }
@ -99,7 +101,7 @@ func (rd *RuleDialer) NextDialer(dstAddr string) Dialer {
// find in domainMap // find in domainMap
if dialer, ok := rd.domainMap.Load(domain); ok { if dialer, ok := rd.domainMap.Load(domain); ok {
return dialer.(Dialer) return dialer.(proxy.Dialer)
} }
} }
@ -127,7 +129,7 @@ func (rd *RuleDialer) AddDomainIP(domain, ip string) error {
// find in domainMap // find in domainMap
if dialer, ok := rd.domainMap.Load(pDomain); ok { if dialer, ok := rd.domainMap.Load(pDomain); ok {
rd.ipMap.Store(ip, dialer) rd.ipMap.Store(ip, dialer)
logf("rule add ip=%s, based on rule: domain=%s & domain/ip: %s/%s\n", ip, pDomain, domain, ip) log.F("rule add ip=%s, based on rule: domain=%s & domain/ip: %s/%s\n", ip, pDomain, domain, ip)
} }
} }

View File

@ -1,65 +0,0 @@
package main
import (
"errors"
"net/url"
"strings"
)
// Server interface
type Server interface {
// ListenAndServe as proxy server, use only in server mode.
ListenAndServe()
}
// ServerFromURL parses url and get a Proxy
// TODO: table
func ServerFromURL(s string, dialer Dialer) (Server, error) {
if !strings.Contains(s, "://") {
s = "mixed://" + s
}
u, err := url.Parse(s)
if err != nil {
logf("parse err: %s", err)
return nil, err
}
addr := u.Host
var user, pass string
if u.User != nil {
user = u.User.Username()
pass, _ = u.User.Password()
}
if dialer == nil {
dialer = Direct
}
switch u.Scheme {
case "mixed":
return NewMixedProxy(addr, user, pass, u.RawQuery, dialer)
case "http":
return NewHTTP(addr, user, pass, u.RawQuery, dialer)
case "socks5":
return NewSOCKS5(addr, user, pass, dialer)
case "ss":
return NewSS(addr, user, pass, dialer)
case "redir":
return NewRedirProxy(addr, dialer)
case "tcptun":
d := strings.Split(addr, "=")
return NewTCPTun(d[0], d[1], dialer)
case "udptun":
d := strings.Split(addr, "=")
return NewUDPTun(d[0], d[1], dialer)
case "dnstun":
d := strings.Split(addr, "=")
return NewDNSTun(d[0], d[1], dialer)
case "uottun":
d := strings.Split(addr, "=")
return NewUoTTun(d[0], d[1], dialer)
}
return nil, errors.New("unknown scheme '" + u.Scheme + "'")
}

View File

@ -7,28 +7,31 @@ import (
"strings" "strings"
"sync" "sync"
"time" "time"
"github.com/nadoo/glider/common/log"
"github.com/nadoo/glider/proxy"
) )
// NewStrategyDialer returns a new Strategy Dialer // NewStrategyDialer returns a new Strategy proxy.Dialer
func NewStrategyDialer(strategy string, dialers []Dialer, website string, interval int) Dialer { func NewStrategyDialer(strategy string, dialers []proxy.Dialer, website string, interval int) proxy.Dialer {
if len(dialers) == 0 { if len(dialers) == 0 {
return Direct return proxy.Direct
} }
if len(dialers) == 1 { if len(dialers) == 1 {
return dialers[0] return dialers[0]
} }
var dialer Dialer var dialer proxy.Dialer
switch strategy { switch strategy {
case "rr": case "rr":
dialer = newRRDialer(dialers, website, interval) dialer = newRRDialer(dialers, website, interval)
logf("forward to remote servers in round robin mode.") log.F("forward to remote servers in round robin mode.")
case "ha": case "ha":
dialer = newHADialer(dialers, website, interval) dialer = newHADialer(dialers, website, interval)
logf("forward to remote servers in high availability mode.") log.F("forward to remote servers in high availability mode.")
default: default:
logf("not supported forward mode '%s', just use the first forward server.", conf.Strategy) log.F("not supported forward mode '%s', just use the first forward server.", conf.Strategy)
dialer = dialers[0] dialer = dialers[0]
} }
@ -37,7 +40,7 @@ func NewStrategyDialer(strategy string, dialers []Dialer, website string, interv
// rrDialer is the base struct of strategy dialer // rrDialer is the base struct of strategy dialer
type rrDialer struct { type rrDialer struct {
dialers []Dialer dialers []proxy.Dialer
idx int idx int
status sync.Map status sync.Map
@ -48,7 +51,7 @@ type rrDialer struct {
} }
// newRRDialer returns a new rrDialer // newRRDialer returns a new rrDialer
func newRRDialer(dialers []Dialer, website string, interval int) *rrDialer { func newRRDialer(dialers []proxy.Dialer, website string, interval int) *rrDialer {
rr := &rrDialer{dialers: dialers} rr := &rrDialer{dialers: dialers}
rr.website = website rr.website = website
@ -71,7 +74,7 @@ func (rr *rrDialer) DialUDP(network, addr string) (pc net.PacketConn, writeTo ne
return rr.NextDialer(addr).DialUDP(network, addr) return rr.NextDialer(addr).DialUDP(network, addr)
} }
func (rr *rrDialer) NextDialer(dstAddr string) Dialer { func (rr *rrDialer) NextDialer(dstAddr string) proxy.Dialer {
n := len(rr.dialers) n := len(rr.dialers)
if n == 1 { if n == 1 {
rr.idx = 0 rr.idx = 0
@ -88,7 +91,7 @@ func (rr *rrDialer) NextDialer(dstAddr string) Dialer {
} }
if !found { if !found {
logf("NO AVAILABLE PROXY FOUND! please check your network or proxy server settings.") log.F("NO AVAILABLE PROXY FOUND! please check your network or proxy server settings.")
} }
return rr.dialers[rr.idx] return rr.dialers[rr.idx]
@ -117,7 +120,7 @@ func (rr *rrDialer) checkDialer(idx int) {
c, err := d.Dial("tcp", rr.website) c, err := d.Dial("tcp", rr.website)
if err != nil { if err != nil {
rr.status.Store(idx, false) rr.status.Store(idx, false)
logf("proxy-check %s -> %s, set to DISABLED. error in dial: %s", d.Addr(), rr.website, err) log.F("proxy-check %s -> %s, set to DISABLED. error in dial: %s", d.Addr(), rr.website, err)
continue continue
} }
@ -126,15 +129,15 @@ func (rr *rrDialer) checkDialer(idx int) {
_, err = io.ReadFull(c, buf) _, err = io.ReadFull(c, buf)
if err != nil { if err != nil {
rr.status.Store(idx, false) rr.status.Store(idx, false)
logf("proxy-check %s -> %s, set to DISABLED. error in read: %s", d.Addr(), rr.website, err) log.F("proxy-check %s -> %s, set to DISABLED. error in read: %s", d.Addr(), rr.website, err)
} else if bytes.Equal([]byte("HTTP"), buf) { } else if bytes.Equal([]byte("HTTP"), buf) {
rr.status.Store(idx, true) rr.status.Store(idx, true)
retry = 2 retry = 2
dialTime := time.Since(startTime) dialTime := time.Since(startTime)
logf("proxy-check %s -> %s, set to ENABLED. connect time: %s", d.Addr(), rr.website, dialTime.String()) log.F("proxy-check %s -> %s, set to ENABLED. connect time: %s", d.Addr(), rr.website, dialTime.String())
} else { } else {
rr.status.Store(idx, false) rr.status.Store(idx, false)
logf("proxy-check %s -> %s, set to DISABLED. server response: %s", d.Addr(), rr.website, buf) log.F("proxy-check %s -> %s, set to DISABLED. server response: %s", d.Addr(), rr.website, buf)
} }
c.Close() c.Close()
@ -147,7 +150,7 @@ type haDialer struct {
} }
// newHADialer . // newHADialer .
func newHADialer(dialers []Dialer, webhost string, duration int) Dialer { func newHADialer(dialers []proxy.Dialer, webhost string, duration int) proxy.Dialer {
return &haDialer{rrDialer: newRRDialer(dialers, webhost, duration)} return &haDialer{rrDialer: newRRDialer(dialers, webhost, duration)}
} }

View File

@ -1,68 +0,0 @@
package main
import "net"
// TCPTun struct
type TCPTun struct {
dialer Dialer
addr string
raddr string
}
// NewTCPTun returns a tcptun proxy.
func NewTCPTun(addr, raddr string, dialer Dialer) (*TCPTun, error) {
s := &TCPTun{
dialer: dialer,
addr: addr,
raddr: raddr,
}
return s, nil
}
// ListenAndServe .
func (s *TCPTun) ListenAndServe() {
l, err := net.Listen("tcp", s.addr)
if err != nil {
logf("failed to listen on %s: %v", s.addr, err)
return
}
logf("listening TCP on %s", s.addr)
for {
c, err := l.Accept()
if err != nil {
logf("failed to accept: %v", err)
continue
}
go func() {
defer c.Close()
if c, ok := c.(*net.TCPConn); ok {
c.SetKeepAlive(true)
}
rc, err := s.dialer.Dial("tcp", s.raddr)
if err != nil {
logf("failed to connect to target: %v", err)
return
}
defer rc.Close()
logf("proxy-tcptun %s <-> %s", c.RemoteAddr(), s.raddr)
_, _, err = relay(c, rc)
if err != nil {
if err, ok := err.(net.Error); ok && err.Timeout() {
return // ignore i/o timeout
}
logf("relay error: %v", err)
}
}()
}
}

View File

@ -1,82 +0,0 @@
package main
import (
"net"
"sync"
"time"
)
// UDPTun struct
type UDPTun struct {
dialer Dialer
addr string
raddr string
}
// NewUDPTun returns a UDPTun proxy.
func NewUDPTun(addr, raddr string, dialer Dialer) (*UDPTun, error) {
s := &UDPTun{
dialer: dialer,
addr: addr,
raddr: raddr,
}
return s, nil
}
// ListenAndServe .
func (s *UDPTun) ListenAndServe() {
c, err := net.ListenPacket("udp", s.addr)
if err != nil {
logf("proxy-udptun failed to listen on %s: %v", s.addr, err)
return
}
defer c.Close()
logf("proxy-udptun listening UDP on %s", s.addr)
var nm sync.Map
buf := make([]byte, udpBufSize)
for {
n, raddr, err := c.ReadFrom(buf)
if err != nil {
logf("proxy-udptun read error: %v", err)
continue
}
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)
if err != nil {
logf("proxy-udptun remote dial error: %v", err)
continue
}
nm.Store(raddr.String(), pc)
go func() {
timedCopy(c, raddr, pc, 2*time.Minute)
pc.Close()
nm.Delete(raddr.String())
}()
} else {
pc = v.(net.PacketConn)
}
_, err = pc.WriteTo(buf[:n], writeAddr)
if err != nil {
logf("proxy-udptun remote write error: %v", err)
continue
}
logf("proxy-udptun %s <-> %s", raddr, s.raddr)
}
}

View File

@ -1,80 +0,0 @@
package main
import (
"io/ioutil"
"net"
"time"
)
// UoTTun udp over tcp tunnel
type UoTTun struct {
dialer Dialer
addr string
raddr string
}
// NewUoTTun returns a UoTTun proxy.
func NewUoTTun(addr, raddr string, dialer Dialer) (*UoTTun, error) {
s := &UoTTun{
dialer: dialer,
addr: addr,
raddr: raddr,
}
return s, nil
}
// ListenAndServe .
func (s *UoTTun) ListenAndServe() {
c, err := net.ListenPacket("udp", s.addr)
if err != nil {
logf("proxy-uottun failed to listen on %s: %v", s.addr, err)
return
}
defer c.Close()
logf("proxy-uottun listening UDP on %s", s.addr)
buf := make([]byte, udpBufSize)
for {
n, clientAddr, err := c.ReadFrom(buf)
if err != nil {
logf("proxy-uottun read error: %v", err)
continue
}
rc, err := s.dialer.Dial("uot", s.raddr)
if err != nil {
logf("proxy-uottun failed to connect to server %v: %v", s.raddr, err)
continue
}
go func() {
// no remote forwarder, just a local udp forwarder
if urc, ok := rc.(*net.UDPConn); ok {
timedCopy(c, clientAddr, urc, 2*time.Minute)
urc.Close()
return
}
// remote forwarder, udp over tcp
resp, err := ioutil.ReadAll(rc)
if err != nil {
logf("error in ioutil.ReadAll: %s\n", err)
return
}
rc.Close()
c.WriteTo(resp, clientAddr)
}()
_, err = rc.Write(buf[:n])
if err != nil {
logf("proxy-uottun remote write error: %v", err)
continue
}
logf("proxy-uottun %s <-> %s", clientAddr, s.raddr)
}
}