main
Raw Download raw file
 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}