wzshiming / shadowsocks

ShadowSocks server and client. Full TCP/UDP and IPv4/IPv6 support
MIT License
19 stars 10 forks source link

Client / Server #1

Closed monok-o closed 2 years ago

monok-o commented 3 years ago

Hey hey, I don't really understand how to connect to a server with this library, I mean I don't understand what to do this "shadowsocks.PacketClient". I'm trying to understand with the documentation but to be honest I'm a bit new with Go and also shadowsocks, it would be really nice if it's possible to give a little example.

What I'm trying to do looks like this: UDP client -> shadowsocks client -> shadowsocks server -> UDP server

Sorry for bothering with this question.

Thank you!

wzshiming commented 3 years ago

I wrote an example of DNS proxy through ss client and server for your reference.

package main

import (
    "context"
    "log"
    "net"
    "os"
    "time"

    "github.com/wzshiming/shadowsocks"
    _ "github.com/wzshiming/shadowsocks/init"
)

func main() {
    ctx := context.Background()

    // Start remote server of Shadowsocks
    ssServer, err := shadowsocks.NewSimplePacketServer("ss://aes-128-cfb:123456@127.0.0.1:0")
    if err != nil {
        log.Println("NewSimplePacketServer", err)
        os.Exit(1)
    }

    // Print remote listening address
    ssServer.ProxyPacket = func(ctx context.Context, network, address string) (net.PacketConn, error) {
        pc, err := net.ListenPacket(network, address)
        if err != nil {
            return nil, err
        }
        log.Println("ss server to target address", pc.LocalAddr())
        return pc, nil
    }
    err = ssServer.Start(ctx)
    if err != nil {
        log.Println("Start", err)
        os.Exit(1)
    }

    // Create local client of Shadowsocks
    ssClient, err := shadowsocks.NewPacketClient(ssServer.ProxyURL())
    if err != nil {
        log.Println("NewPacketClient", err)
        os.Exit(1)
    }
    // Print local listening address
    ssClient.ProxyPacket = func(ctx context.Context, network, address string) (net.PacketConn, error) {
        pc, err := net.ListenPacket(network, address)
        if err != nil {
            return nil, err
        }
        log.Println("ss client to server", pc.LocalAddr())
        return pc, nil
    }

    // Create DNS client
    resolverClient := net.Resolver{
        PreferGo: true,
        Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
            // Use local client of Shadowsocks to connect to remote DNS server
            client, err := ssClient.ListenPacket(context.Background(), "udp", ":0")
            if err != nil {
                return nil, err
            }

            addr, err := net.ResolveUDPAddr("udp", address)
            if err != nil {
                return nil, err
            }

            return &wrap{PacketConn: client, remoteAddr: addr}, nil
        },
    }

    // Send DNS query
    for i := 0; i != 3; i++ {
        time.Sleep(1 * time.Second)
        addresses, err := resolverClient.LookupHost(ctx, "google.com")
        if err != nil {
            log.Println("LookupHost", err)
            os.Exit(1)
        }
        log.Println(addresses)
    }
}

type wrap struct {
    net.PacketConn
    remoteAddr net.Addr
}

func (t wrap) RemoteAddr() net.Addr {
    return t.remoteAddr
}

func (t *wrap) Write(b []byte) (n int, err error) {
    return t.PacketConn.WriteTo(b, t.remoteAddr)
}

func (t *wrap) Read(b []byte) (n int, err error) {
    n, addr, err := t.PacketConn.ReadFrom(b)
    if err != nil {
        return 0, err
    }
    if addr.String() == t.remoteAddr.String() {
        return n, nil
    }
    return t.Read(b)
}