-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmux.go
194 lines (168 loc) · 5.72 KB
/
mux.go
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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
package main
import (
"net"
"strings"
"sync"
)
// match a listen pattern to an address string of the form HOST:PORT
func patternMatches(pattern string, addr net.Addr) bool {
if pattern == "*" {
return true
}
if strings.HasPrefix(pattern, ":") && strings.HasSuffix(addr.String(), pattern) {
return true
}
return false
}
// mux dispatches network connections to listeners according to patterns
type mux struct {
mu sync.Mutex
tcpHandlers []*tcpMuxEntry
udpHandlers []*udpMuxEntry
}
// tcpHandlerFunc is a function that receives TCP connections
type tcpHandlerFunc func(net.Conn)
// tcpHandlerFunc is a function that receives TCP connection requests and can choose
// whether to accept or reject them.
type tcpRequestHandlerFunc func(TCPRequest)
// tcpMuxEntry is a pattern and corresponding handler, for use in the mux table for the tcp stack
type tcpMuxEntry struct {
pattern string
handler tcpRequestHandlerFunc
}
// udpHandlerFunc is a function that receives UDP packets. Each call to w.Write
// will send a UDP packet back to the subprocess that looks as if it comes from
// the destination to which the original packet was sent. No matter what you put in
// the source or destination address, the
type udpHandlerFunc func(w udpResponder, packet *udpPacket)
// udpMuxEntry is a pattern and corresponding handler, for use in the mux table for the udp stack
type udpMuxEntry struct {
handler udpHandlerFunc
pattern string
}
// ListenTCP returns a net.Listener that intercepts connections according to a filter pattern.
//
// Pattern can a hostname, a :port, a hostname:port, or "*" for everything". For example:
// - "example.com"
// - "example.com:80"
// - ":80"
// - "*"
//
// Later this will be like net.ListenTCP
func (s *mux) ListenTCP(pattern string) net.Listener {
s.mu.Lock()
defer s.mu.Unlock()
listener := tcpListener{pattern: pattern, connections: make(chan net.Conn, 64)}
s.HandleTCPRequest(pattern, func(r TCPRequest) {
conn, err := r.Accept()
if err != nil {
return
}
listener.connections <- conn
})
return &listener
}
// HandleTCP register a handler to be called each time a new connection is intercepted matching the
// given filter pattern.
//
// Pattern can a hostname, a :port, a hostname:port, or "*" for everything". For example:
// - "example.com"
// - "example.com:80"
// - ":80"
// - "*"
func (s *mux) HandleTCP(pattern string, handler tcpHandlerFunc) {
s.HandleTCPRequest(pattern, func(r TCPRequest) {
conn, err := r.Accept()
if err != nil {
errorf("error accepting connection: %v", err)
return
}
handler(conn)
})
}
// HandleTCPRequest register a handler to be called each time a new connection is intercepted matching the
// given filter pattern. Unlike HandleTCP, the handler can control whether the connection is accepted or
// rejected, which means replying with a SYN+ACK or SYN+RST respectively.
//
// Pattern can a hostname, a :port, a hostname:port, or "*" for everything". For example:
// - "example.com"
// - "example.com:80"
// - ":80"
// - "*"
func (s *mux) HandleTCPRequest(pattern string, handler tcpRequestHandlerFunc) {
s.mu.Lock()
defer s.mu.Unlock()
s.tcpHandlers = append(s.tcpHandlers, &tcpMuxEntry{pattern: pattern, handler: handler})
}
// HandleUDP registers a handler for UDP packets according to destination IP and/or por
//
// Pattern can a hostname, a port, a hostname:port, or "*" for everything". Ports are prepended
// with colons. Valid patterns are:
// - "example.com"
// - "example.com:80"
// - ":80"
// - "*"
//
// Later this will be like net.Listen
func (s *mux) HandleUDP(pattern string, handler udpHandlerFunc) {
s.mu.Lock()
defer s.mu.Unlock()
s.udpHandlers = append(s.udpHandlers, &udpMuxEntry{pattern: pattern, handler: handler})
}
// notifyTCP is called when a new stream is created. It finds the first listener
// that will accept the given stream. It never blocks.
func (s *mux) notifyTCP(req TCPRequest) {
s.mu.Lock()
defer s.mu.Unlock()
for _, entry := range s.tcpHandlers {
if patternMatches(entry.pattern, req.LocalAddr()) {
go entry.handler(req)
return
}
}
verbosef("nobody listening for tcp to %v, dropping", req.LocalAddr())
}
// notifyUDP is called when a new packet arrives. It finds the first handler
// with a pattern that matches the packet and delivers the packet to it
func (s *mux) notifyUDP(w udpResponder, packet *udpPacket) {
s.mu.Lock()
defer s.mu.Unlock()
for _, entry := range s.udpHandlers {
if patternMatches(entry.pattern, packet.dst) {
go entry.handler(w, packet)
return
}
}
verbosef("nobody listening for udp to %v, dropping!", packet.dst)
}
// udpResponder is the interface for writing back UDP packets
type udpResponder interface {
// write a UDP packet back to the subprocess
Write(payload []byte) (n int, err error)
}
// tcpListener implements net.Listener for connections dispatched by a mux
type tcpListener struct {
pattern string
connections chan net.Conn
}
// Accept accepts an intercepted connection. This implements net.Listener.Accept
func (l *tcpListener) Accept() (net.Conn, error) {
stream := <-l.connections
if stream == nil {
// this means the channel is closed, which means the tcpStack was shut down
return nil, net.ErrClosed
}
return stream, nil
}
// for net.Listener interface
func (l *tcpListener) Close() error {
// TODO: unregister from the stack, then close(l.connections)
verbose("tcpListener.Close() not implemented, ignoring")
return nil
}
// for net.Listener interface, returns our side of the connection
func (l *tcpListener) Addr() net.Addr {
verbose("tcpListener.Addr() was called, returning bogus address 0.0.0.0:0")
// in truth we do not have a real address -- we listen for anything going anywhere
return &net.TCPAddr{IP: net.IPv4(0, 0, 0, 0), Port: 0}
}