gfwproxyshadowsocksdocker-imagegogolanggvisornatnetworksocks4socks5tcpip-stacktortun-devicetun2sockstunneludpwireguard
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
106 lines
2.3 KiB
106 lines
2.3 KiB
4 years ago
|
package proxy
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"net"
|
||
|
|
||
4 years ago
|
"github.com/xjasonlyu/tun2socks/common/adapter"
|
||
|
"github.com/xjasonlyu/tun2socks/component/dialer"
|
||
|
"github.com/xjasonlyu/tun2socks/component/socks5"
|
||
4 years ago
|
|
||
4 years ago
|
"github.com/Dreamacro/go-shadowsocks2/core"
|
||
4 years ago
|
)
|
||
|
|
||
|
type ShadowSocks struct {
|
||
|
*Base
|
||
|
|
||
|
cipher core.Cipher
|
||
|
}
|
||
|
|
||
4 years ago
|
func NewShadowSocks(addr, method, password string) (*ShadowSocks, error) {
|
||
4 years ago
|
cipher, err := core.PickCipher(method, nil, password)
|
||
|
if err != nil {
|
||
|
return nil, fmt.Errorf("ss initialize: %w", err)
|
||
|
}
|
||
|
|
||
|
return &ShadowSocks{
|
||
4 years ago
|
Base: NewBase(addr),
|
||
4 years ago
|
cipher: cipher,
|
||
|
}, nil
|
||
|
}
|
||
|
|
||
|
func (ss *ShadowSocks) DialContext(ctx context.Context, metadata *adapter.Metadata) (c net.Conn, err error) {
|
||
|
c, err = dialer.DialContext(ctx, "tcp", ss.Addr())
|
||
|
if err != nil {
|
||
|
return nil, fmt.Errorf("connect to %s: %w", ss.Addr(), err)
|
||
|
}
|
||
4 years ago
|
setKeepAlive(c)
|
||
4 years ago
|
|
||
|
defer func() {
|
||
4 years ago
|
if err != nil && c != nil {
|
||
4 years ago
|
c.Close()
|
||
|
}
|
||
|
}()
|
||
|
|
||
|
c = ss.cipher.StreamConn(c)
|
||
|
_, err = c.Write(metadata.SerializesSocksAddr())
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func (ss *ShadowSocks) DialUDP(_ *adapter.Metadata) (net.PacketConn, error) {
|
||
|
pc, err := dialer.ListenPacket("udp", "")
|
||
|
if err != nil {
|
||
4 years ago
|
return nil, fmt.Errorf("listen packet: %w", err)
|
||
4 years ago
|
}
|
||
|
|
||
4 years ago
|
udpAddr, err := net.ResolveUDPAddr("udp", ss.Addr())
|
||
4 years ago
|
if err != nil {
|
||
4 years ago
|
return nil, fmt.Errorf("resolve udp address %s: %w", ss.Addr(), err)
|
||
4 years ago
|
}
|
||
|
|
||
|
pc = ss.cipher.PacketConn(pc)
|
||
|
return &ssPacketConn{PacketConn: pc, rAddr: udpAddr}, nil
|
||
|
}
|
||
|
|
||
|
type ssPacketConn struct {
|
||
|
net.PacketConn
|
||
|
|
||
|
rAddr net.Addr
|
||
|
}
|
||
|
|
||
|
func (pc *ssPacketConn) WriteTo(b []byte, addr net.Addr) (n int, err error) {
|
||
|
var packet []byte
|
||
|
if m, ok := addr.(*adapter.Metadata); ok {
|
||
|
packet, err = socks5.EncodeUDPPacket(m.SerializesSocksAddr(), b)
|
||
|
} else {
|
||
|
packet, err = socks5.EncodeUDPPacket(socks5.ParseAddrToSocksAddr(addr), b)
|
||
|
}
|
||
|
|
||
|
if err != nil {
|
||
|
return
|
||
|
}
|
||
|
return pc.PacketConn.WriteTo(packet[3:], pc.rAddr)
|
||
|
}
|
||
|
|
||
|
func (pc *ssPacketConn) ReadFrom(b []byte) (int, net.Addr, error) {
|
||
4 years ago
|
n, _, err := pc.PacketConn.ReadFrom(b)
|
||
|
if err != nil {
|
||
|
return 0, nil, err
|
||
4 years ago
|
}
|
||
|
|
||
|
addr := socks5.SplitAddr(b[:n])
|
||
|
if addr == nil {
|
||
|
return 0, nil, errors.New("parse addr error")
|
||
|
}
|
||
|
|
||
|
udpAddr := addr.UDPAddr()
|
||
|
if udpAddr == nil {
|
||
|
return 0, nil, errors.New("parse addr error")
|
||
|
}
|
||
|
|
||
|
copy(b, b[len(addr):])
|
||
4 years ago
|
return n - len(addr), udpAddr, err
|
||
4 years ago
|
}
|