main
1package main
2
3import (
4 "context"
5 "fmt"
6 "net"
7
8 "github.com/google/uuid"
9 "golang.org/x/sync/errgroup"
10)
11
12type connection struct {
13 id uuid.UUID
14 dAddr AddrRequest
15 sConn, dConn *net.TCPConn
16 ctx context.Context
17 cancel context.CancelFunc
18 errgroup *errgroup.Group
19}
20
21// TODO: Options
22// - higher context
23func NewConnection(
24 sConn *net.TCPConn,
25) (*connection, error) {
26 ctx := context.Background()
27
28 groupCtx, cancel := context.WithCancel(ctx)
29 g, connCtx := errgroup.WithContext(groupCtx)
30
31 c := &connection{
32 id: uuid.New(),
33 sConn: sConn,
34 ctx: connCtx,
35 cancel: cancel,
36 errgroup: g,
37 }
38
39 err := handleClientIdentifier(sConn)
40 if err != nil {
41 return nil, fmt.Errorf("failed to handle socks5 client id: %w", err)
42 }
43
44 c.dAddr, err = ParseClientRequest(sConn)
45 if err != nil {
46 return nil, fmt.Errorf("failed to handle socks5 client request: %w", err)
47 }
48
49 err = c.DialRemote()
50 if err != nil {
51 return nil, fmt.Errorf("failed to dial remote: %w", err)
52 }
53
54 _, err = sConn.Write(replyV4(ReplySucceeded))
55
56 return c, nil
57}
58
59func (c *connection) Id() string { return c.id.String() }
60
61func (c *connection) DialRemote() error {
62
63 var tcpAddr *net.TCPAddr
64 var err error
65
66 if c.dAddr.Domain != nil {
67 tcpAddr, err = net.ResolveTCPAddr("tcp", *c.dAddr.Domain)
68 if err != nil {
69 return err
70 }
71 }
72 if c.dAddr.AddrPort != nil {
73 tcpAddr = net.TCPAddrFromAddrPort(*c.dAddr.AddrPort)
74 }
75
76 conn, err := net.DialTCP("tcp", nil, tcpAddr)
77 if err != nil {
78 return err
79 }
80 err = conn.SetReadBuffer(bufSize)
81 if err != nil {
82 return err
83 }
84 err = conn.SetWriteBuffer(bufSize)
85 if err != nil {
86 return err
87 }
88
89 c.dConn = conn
90 return nil
91}