Skip to content

Commit

Permalink
新增socks和tcp代理的demo
Browse files Browse the repository at this point in the history
  • Loading branch information
wu committed Jan 14, 2021
1 parent 29a33d7 commit 8882fd5
Show file tree
Hide file tree
Showing 5 changed files with 487 additions and 175 deletions.
214 changes: 214 additions & 0 deletions demo/client/socks/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
package main

import (
"encoding/binary"
"errors"
"flag"
"fmt"
"io"
"log"
"net"
"os"
"strconv"
"sync"
"time"
)

type Addr []byte

const (
AtypIPv4 = 1
AtypDomainName = 3
AtypIPv6 = 4
)

var local = flag.String("local", "127.0.0.1:1080", "please enter local proxy ip")
var server = flag.String("server", "192.168.0.104:8805", "please enter tcp tunnel server ip")

func main() {
flag.Parse()
l, err := net.Listen("tcp", *local)
if err != nil {
fmt.Printf("Listen failed: %v\n", err)
return
}

for {
c, err := l.Accept()
if err != nil {
fmt.Printf("Accept failed: %v", err)
continue
}

go func() {

if err := socks5Auth(c); err != nil {
fmt.Println("auth error:", err)
c.Close()
return
}

targetIP, err := getTargetIP(c)
if err != nil {
log.Fatal("don't get target ip ,err is " + err.Error())
return
}

tgt := ParseAddr(targetIP)

rc, err := net.Dial("tcp", *server)
if err != nil {
log.Fatal("can't connect " + *server)
c.Write([]byte("can't connect " + *server))
c.Close()

}

if _, err = rc.Write(tgt); err != nil {
log.Fatal("failed to send target address: ", err.Error()+"\n")
return
}

log.Println("proxy " + c.RemoteAddr().String() + "<->" + *server + "<->" + targetIP)
if err = relay(rc, c); err != nil {
log.Fatal(err.Error() + "\n")
}
}()
}
}

func socks5Auth(client net.Conn) (err error) {
buf := make([]byte, 256)

// 读取 VER 和 NMETHODS
n, err := io.ReadFull(client, buf[:2])
if n != 2 {
return errors.New("reading header: " + err.Error())
}

ver, nMethods := int(buf[0]), int(buf[1])
if ver != 5 {
return errors.New("invalid version")
}

// 读取 METHODS 列表
n, err = io.ReadFull(client, buf[:nMethods])
if n != nMethods {
return errors.New("reading methods: " + err.Error())
}

n, err = client.Write([]byte{0x05, 0x00})
if n != 2 || err != nil {
return errors.New("write rsp err: " + err.Error())
}

return nil
}

func getTargetIP(client net.Conn) (string, error) {
buf := make([]byte, 256)

n, err := io.ReadFull(client, buf[:4])
if n != 4 {
return "", errors.New("read header: " + err.Error())
}

ver, cmd, _, atyp := buf[0], buf[1], buf[2], buf[3]
if ver != 5 || cmd != 1 {
return "", errors.New("invalid ver/cmd")
}

addr := ""
switch atyp {
case 1:
n, err = io.ReadFull(client, buf[:4])
if n != 4 {
return "", errors.New("invalid IPv4: " + err.Error())
}
addr = fmt.Sprintf("%d.%d.%d.%d", buf[0], buf[1], buf[2], buf[3])
case 3:
n, err = io.ReadFull(client, buf[:1])
if n != 1 {
return "", errors.New("invalid hostname: " + err.Error())
}
addrLen := int(buf[0])
n, err = io.ReadFull(client, buf[:addrLen])
if n != addrLen {
return "", errors.New("invalid hostname: " + err.Error())
}
addr = string(buf[:addrLen])
case 4:
return "", errors.New("IPv6: no supported yet")
default:
return "", errors.New("invalid atyp")
}

n, err = io.ReadFull(client, buf[:2])
if n != 2 {
return "", errors.New("read port: " + err.Error())
}
port := binary.BigEndian.Uint16(buf[:2])

destAddrPort := fmt.Sprintf("%s:%d", addr, port)

return destAddrPort, nil
}

// 将string类型的IP地址转换成[]byte类型
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] = AtypIPv4
copy(addr[1:], ip4)
} else {
addr = make([]byte, 1+net.IPv6len+2)
addr[0] = AtypIPv6
copy(addr[1:], ip)
}
} else {
if len(host) > 255 {
return nil
}
addr = make([]byte, 1+1+len(host)+2)
addr[0] = AtypDomainName
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
}

func relay(left, right net.Conn) error {
var err, err1 error
var wg sync.WaitGroup
var wait = 5 * time.Second
wg.Add(1)
go func() {
defer wg.Done()
_, err1 = io.Copy(right, left)
right.SetReadDeadline(time.Now().Add(wait)) // unblock read on right
}()
_, err = io.Copy(left, right)
left.SetReadDeadline(time.Now().Add(wait)) // unblock read on left
wg.Wait()
if err1 != nil && !errors.Is(err1, os.ErrDeadlineExceeded) { // requires Go 1.15+
return err1
}
if err != nil && !errors.Is(err, os.ErrDeadlineExceeded) {
return err
}
return nil
}
131 changes: 131 additions & 0 deletions demo/client/tcp/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
package main

import (
"errors"
"flag"
"fmt"
"io"
"log"
"net"
"os"
"strconv"
"sync"
"time"
)

type Addr []byte

const (
AtypIPv4 = 1
AtypDomainName = 3
AtypIPv6 = 4
)

var local = flag.String("local", "127.0.0.1:1080", "please enter local proxy ip")
var target = flag.String("target", "192.168.1.105:8806", "please enter target server ip")
var server = flag.String("server", "192.168.0.104:8805", "please enter tcp tunnel server ip")

func main() {
flag.Parse()
tgt := ParseAddr(*target)
l, err := net.Listen("tcp", *local)
if err != nil {
log.Fatalf("failed to listen on %s: %v", *local, err)
return
}

log.Println("listening TCP on ", *local)
if err != nil {
fmt.Println(err, err.Error())
os.Exit(0)
}

for {
c, err := l.Accept()
if err != nil {
continue
}

go func() {

rc, err := net.Dial("tcp", *server)
if err != nil {
log.Fatal("can't connect " + *server)
c.Write([]byte("can't connect " + *server))
c.Close()

}

if _, err = rc.Write(tgt); err != nil {
log.Fatal("failed to send target address: ", err.Error()+"\n")
return
}

log.Println("proxy " + c.RemoteAddr().String() + "<->" + *server + "<->" + *target)
if err = relay(rc, c); err != nil {
log.Fatal(err.Error() + "\n")
}
}()

}
}

// 数据流的转发
func relay(left, right net.Conn) error {
var err, err1 error
var wg sync.WaitGroup
var wait = 5 * time.Second
wg.Add(1)
go func() {
defer wg.Done()
_, err1 = io.Copy(right, left)
right.SetReadDeadline(time.Now().Add(wait)) // unblock read on right
}()
_, err = io.Copy(left, right)
left.SetReadDeadline(time.Now().Add(wait)) // unblock read on left
wg.Wait()
if err1 != nil && !errors.Is(err1, os.ErrDeadlineExceeded) { // requires Go 1.15+
return err1
}
if err != nil && !errors.Is(err, os.ErrDeadlineExceeded) {
return err
}
return nil
}

// 将string类型的IP地址转换成[]byte类型
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] = AtypIPv4
copy(addr[1:], ip4)
} else {
addr = make([]byte, 1+net.IPv6len+2)
addr[0] = AtypIPv6
copy(addr[1:], ip)
}
} else {
if len(host) > 255 {
return nil
}
addr = make([]byte, 1+1+len(host)+2)
addr[0] = AtypDomainName
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
}
Loading

0 comments on commit 8882fd5

Please sign in to comment.