summaryrefslogtreecommitdiff
path: root/pkg/server/socket/listen.go
blob: 910e5debac87be1362cb6bcd70400e5329175b1d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
package socket

import (
	"errors"
	"fmt"
	"log"
	"net"
	"strings"
	"tunnel/pkg/server/env"
	"tunnel/pkg/server/opts"
)

type listenSocket struct {
	proto, addr string
	listen      net.Listener
	redirect    bool
	tproxy      bool
}

func newListenSocket(proto, addr string, opts opts.Opts) (S, error) {
	redirect := opts.Bool("redirect")
	tproxy := opts.Bool("tproxy")

	if proto == "tcp" {
		if !strings.Contains(addr, ":") {
			addr = ":" + addr
		}
	}

	if redirect && proto != "tcp" {
		return nil, errors.New("redirect not supported")
	}

	if tproxy && proto != "tcp" {
		return nil, errors.New("tproxy not supported")
	}

	if redirect && tproxy {
		return nil, errors.New("redirect and tproxy cannot be used together")
	}

	listen, err := net.Listen(proto, addr)
	if err != nil {
		return nil, err
	}

	if tproxy {
		if err := setConnTransparent(listen); err != nil {
			listen.Close()
			return nil, err
		}
	}

	s := &listenSocket{
		proto:    proto,
		addr:     addr,
		listen:   listen,
		redirect: redirect,
		tproxy:   tproxy,
	}

	return s, nil
}

func (s *listenSocket) Open(env env.Env) (Conn, error) {
	var original string

	conn, err := s.listen.Accept()
	if err != nil {
		return nil, err
	}

	la, ra := conn.LocalAddr(), conn.RemoteAddr()
	desc := fmt.Sprintf("%s/%s->%s", la.Network(), ra, la)
	info := fmt.Sprintf("<%s/%s", ra.Network(), ra)

	if s.redirect {
		if err := getConnOriginalAddr(conn, &original); err != nil {
			log.Println("accept", desc, "failed")
			conn.Close()
			return nil, err
		} else {
			env.Set("original", original)
		}
	}

	if s.tproxy {
		env.Set("original", la.String())
	}

	if original == "" {
		log.Println("accept", desc)
	} else {
		log.Println("accept", desc, "original", original)
	}

	return newConn(conn, desc, info), nil
}

func (s *listenSocket) String() string {
	return fmt.Sprintf("%s/%s,listen", s.proto, s.addr)
}

func (s *listenSocket) Close() {
	s.listen.Close()
}