mirror of
https://github.com/nadoo/glider.git
synced 2025-02-23 09:25:41 +08:00
general: move proxy to separate package
This commit is contained in:
parent
3e09aa9ce0
commit
fbbae71314
@ -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
16
common/log/log.go
Normal 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
173
common/socks/socks.go
Normal 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
|
||||||
|
}
|
2
conf.go
2
conf.go
@ -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
55
dns.go
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
35
dnstun.go
35
dnstun.go
@ -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
12
features.go
Normal 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
5
features_linux.go
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "github.com/nadoo/glider/proxy/redir"
|
||||||
|
)
|
@ -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
16
log.go
@ -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
26
main.go
@ -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
105
mixed.go
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -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 + "'")
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
@ -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
127
proxy/mixed/mixed.go
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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]
|
@ -1,4 +1,4 @@
|
|||||||
package main
|
package redir
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"syscall"
|
"syscall"
|
@ -1,6 +1,6 @@
|
|||||||
// +build linux,!386
|
// +build linux,!386
|
||||||
|
|
||||||
package main
|
package redir
|
||||||
|
|
||||||
import "syscall"
|
import "syscall"
|
||||||
|
|
48
proxy/server.go
Normal file
48
proxy/server.go
Normal 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 + "'")
|
||||||
|
}
|
@ -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
|
@ -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
|
@ -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
94
proxy/tcptun/tcptun.go
Normal 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
106
proxy/udptun/udptun.go
Normal 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
104
proxy/uottun/uottun.go
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
@ -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
26
rule.go
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
65
server.go
65
server.go
@ -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 + "'")
|
|
||||||
}
|
|
35
strategy.go
35
strategy.go
@ -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)}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
68
tcptun.go
68
tcptun.go
@ -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)
|
|
||||||
}
|
|
||||||
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
}
|
|
82
udptun.go
82
udptun.go
@ -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)
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
80
uottun.go
80
uottun.go
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user