Skip to content

Commit

Permalink
udp support
Browse files Browse the repository at this point in the history
  • Loading branch information
txthinking committed Nov 1, 2017
1 parent f84d8cb commit 13e940f
Show file tree
Hide file tree
Showing 14 changed files with 642 additions and 195 deletions.
52 changes: 13 additions & 39 deletions README.md
Expand Up @@ -13,49 +13,23 @@ $ go get github.com/txthinking/socks5
### Example

```
func ExampleServer() {
socks5.Debug = true // enable socks5 debug log
package main
l, err := net.Listen("tcp", ":1980")
import "github.com/txthinking/socks5"
func main() {
socks5.Debug = true
s, err := socks5.NewClassicServer("127.0.0.1:1080", "127.0.0.1:1080", "", "", 0, 0, 0, 60)
if err != nil {
log.Println(err)
return
panic(err)
}
defer l.Close()
for {
c, err := l.Accept()
if err != nil {
log.Println(err)
return
}
go func(c net.Conn) {
defer c.Close()
s5s := socks5.NewClassicServer(c)
if err := s5s.Negotiate(); err != nil {
log.Println(err)
return
}
r, err := s5s.GetRequest()
if err != nil {
log.Println(err)
return
}
rc, err := r.Connect(c)
if err != nil {
log.Println(err)
return
}
defer rc.Close()
go func() {
_, _ = io.Copy(c, rc)
}()
_, _ = io.Copy(rc, c)
}(c)
if err := s.Run(nil); err != nil {
panic(err)
}
}
```
Now you have a socks5 proxy listen on :1980
Test with curl: `curl -x socks5://127.0.0.1:1080 http://httpbin.org/ip`

### Users:

You can test with curl: `curl --socks5-hostname YOUR_SERVER_IP:1980 http://httpbin.org/ip`
* Brook [https://github.com/txthinking/brook](https://github.com/txthinking/brook)
101 changes: 101 additions & 0 deletions client.go
@@ -0,0 +1,101 @@
package socks5

import (
"errors"
"net"
"time"
)

// Client is socks5 client wrapper
type Client struct {
UserName string
Password string
TCPAddr *net.TCPAddr
TCPConn *net.TCPConn
UDPAddr *net.UDPAddr
TCPDeadline int // not refreshed
TCPTimeout int
UDPDeadline int // refreshed
}

func NewClient(addr, username, password string, tcpTimeout, tcpDeadline, udpDeadline int) (*Client, error) {
taddr, err := net.ResolveTCPAddr("tcp", addr)
if err != nil {
return nil, err
}
uaddr, err := net.ResolveUDPAddr("udp", addr)
if err != nil {
return nil, err
}
c := &Client{
UserName: username,
Password: password,
TCPAddr: taddr,
UDPAddr: uaddr,
TCPTimeout: tcpTimeout,
TCPDeadline: tcpDeadline,
UDPDeadline: udpDeadline,
}
return c, nil
}

func (c *Client) Negotiate() error {
con, err := Dial.Dial("tcp", c.TCPAddr.String())
if err != nil {
return err
}
c.TCPConn = con.(*net.TCPConn)
if c.TCPTimeout != 0 {
if err := c.TCPConn.SetKeepAlivePeriod(time.Duration(c.TCPTimeout) * time.Second); err != nil {
return err
}
}
if c.TCPDeadline != 0 {
if err := c.TCPConn.SetDeadline(time.Now().Add(time.Duration(c.TCPTimeout) * time.Second)); err != nil {
return err
}
}
m := MethodNone
if c.UserName != "" && c.Password != "" {
m = MethodUsernamePassword
}
rq := NewNegotiationRequest([]byte{m})
if err := rq.WriteTo(c.TCPConn); err != nil {
return err
}
rp, err := NewNegotiationReplyFrom(c.TCPConn)
if err != nil {
return err
}
if rp.Method != m {
return errors.New("Unsupport method")
}
if m == MethodUsernamePassword {
urq := NewUserPassNegotiationRequest([]byte(c.UserName), []byte(c.Password))
if err := urq.WriteTo(c.TCPConn); err != nil {
return err
}
urp, err := NewUserPassNegotiationReplyFrom(c.TCPConn)
if err != nil {
return err
}
if urp.Status != UserPassStatusSuccess {
return ErrUserPassAuth
}
}
return nil
}

func (c *Client) Request(r *Request) (*Reply, error) {
if err := r.WriteTo(c.TCPConn); err != nil {
return nil, err
}
rp, err := NewReplyFrom(c.TCPConn)
if err != nil {
return nil, err
}
if rp.Rep != RepSuccess {
return nil, errors.New("Host unreachable")
}
return rp, nil
}
13 changes: 7 additions & 6 deletions client_side.go
Expand Up @@ -4,6 +4,7 @@ import (
"errors"
"io"
"log"
"net"
)

var (
Expand All @@ -21,7 +22,7 @@ func NewNegotiationRequest(methods []byte) *NegotiationRequest {
}

// WriteTo write negotiation request packet into server
func (r *NegotiationRequest) WriteTo(w io.Writer) error {
func (r *NegotiationRequest) WriteTo(w *net.TCPConn) error {
if _, err := w.Write([]byte{r.Ver}); err != nil {
return err
}
Expand All @@ -38,7 +39,7 @@ func (r *NegotiationRequest) WriteTo(w io.Writer) error {
}

// NewNegotiationReplyFrom read negotiation reply packet from server
func NewNegotiationReplyFrom(r io.Reader) (*NegotiationReply, error) {
func NewNegotiationReplyFrom(r *net.TCPConn) (*NegotiationReply, error) {
bb := make([]byte, 2)
if _, err := io.ReadFull(r, bb); err != nil {
return nil, err
Expand Down Expand Up @@ -67,7 +68,7 @@ func NewUserPassNegotiationRequest(username []byte, password []byte) *UserPassNe
}

// WriteTo write user password negotiation request packet into server
func (r *UserPassNegotiationRequest) WriteTo(w io.Writer) error {
func (r *UserPassNegotiationRequest) WriteTo(w *net.TCPConn) error {
if _, err := w.Write([]byte{r.Ver, r.Ulen}); err != nil {
return err
}
Expand All @@ -87,7 +88,7 @@ func (r *UserPassNegotiationRequest) WriteTo(w io.Writer) error {
}

// NewUserPassNegotiationReplyFrom read user password negotiation reply packet from server
func NewUserPassNegotiationReplyFrom(r io.Reader) (*UserPassNegotiationReply, error) {
func NewUserPassNegotiationReplyFrom(r *net.TCPConn) (*UserPassNegotiationReply, error) {
bb := make([]byte, 2)
if _, err := io.ReadFull(r, bb); err != nil {
return nil, err
Expand Down Expand Up @@ -120,7 +121,7 @@ func NewRequest(cmd byte, atyp byte, dstaddr []byte, dstport []byte) *Request {
}

// WriteTo write request packet into server
func (r *Request) WriteTo(w io.Writer) error {
func (r *Request) WriteTo(w *net.TCPConn) error {
if _, err := w.Write([]byte{r.Ver, r.Cmd, r.Rsv, r.Atyp}); err != nil {
return err
}
Expand All @@ -137,7 +138,7 @@ func (r *Request) WriteTo(w io.Writer) error {
}

// NewReplyFrom read reply packet from server
func NewReplyFrom(r io.Reader) (*Reply, error) {
func NewReplyFrom(r *net.TCPConn) (*Reply, error) {
bb := make([]byte, 4)
if _, err := io.ReadFull(r, bb); err != nil {
return nil, err
Expand Down
14 changes: 3 additions & 11 deletions connect.go
Expand Up @@ -5,21 +5,13 @@ import (
"net"
)

// Connect remote conn which u want to connect.
// You may should write your method instead of use this method.
func (r *Request) Connect(c net.Conn) (*net.TCPConn, error) {
return r.ConnectWithDial(c, nil)
}

// Connect remote conn which u want to connect with your dialer
func (r *Request) ConnectWithDial(c net.Conn, dial Dialer) (*net.TCPConn, error) {
if dial == nil {
dial = &DefaultDial{}
}
// Error or OK both replied.
func (r *Request) Connect(c *net.TCPConn) (*net.TCPConn, error) {
if Debug {
log.Println("Call:", r.Address())
}
tmp, err := dial.Dial("tcp", r.Address())
tmp, err := Dial.Dial("tcp", r.Address())
if err != nil {
var p *Reply
if r.Atyp == ATYPIPv4 || r.Atyp == ATYPDomain {
Expand Down
21 changes: 0 additions & 21 deletions dial.go

This file was deleted.

51 changes: 0 additions & 51 deletions example_test.go

This file was deleted.

3 changes: 3 additions & 0 deletions init.go
@@ -1,7 +1,10 @@
package socks5

import "github.com/txthinking/ant"

// Debug enable debug log
var Debug bool
var Dial ant.Dialer = ant.DefaultDial

func init() {
}
20 changes: 0 additions & 20 deletions request.go

This file was deleted.

0 comments on commit 13e940f

Please sign in to comment.