a geicko-2 based round robin ranking system designed to test c++ battleship submissions
battleship.dunkirk.sh
1package ssh
2
3import (
4 "io"
5 "log"
6 "net"
7 "strconv"
8 "sync"
9
10 gossh "golang.org/x/crypto/ssh"
11)
12
13const (
14 forwardedTCPChannelType = "forwarded-tcpip"
15)
16
17// direct-tcpip data struct as specified in RFC4254, Section 7.2
18type localForwardChannelData struct {
19 DestAddr string
20 DestPort uint32
21
22 OriginAddr string
23 OriginPort uint32
24}
25
26// DirectTCPIPHandler can be enabled by adding it to the server's
27// ChannelHandlers under direct-tcpip.
28func DirectTCPIPHandler(srv *Server, conn *gossh.ServerConn, newChan gossh.NewChannel, ctx Context) {
29 d := localForwardChannelData{}
30 if err := gossh.Unmarshal(newChan.ExtraData(), &d); err != nil {
31 newChan.Reject(gossh.ConnectionFailed, "error parsing forward data: "+err.Error())
32 return
33 }
34
35 if srv.LocalPortForwardingCallback == nil || !srv.LocalPortForwardingCallback(ctx, d.DestAddr, d.DestPort) {
36 newChan.Reject(gossh.Prohibited, "port forwarding is disabled")
37 return
38 }
39
40 dest := net.JoinHostPort(d.DestAddr, strconv.FormatInt(int64(d.DestPort), 10))
41
42 var dialer net.Dialer
43 dconn, err := dialer.DialContext(ctx, "tcp", dest)
44 if err != nil {
45 newChan.Reject(gossh.ConnectionFailed, err.Error())
46 return
47 }
48
49 ch, reqs, err := newChan.Accept()
50 if err != nil {
51 dconn.Close()
52 return
53 }
54 go gossh.DiscardRequests(reqs)
55
56 go func() {
57 defer ch.Close()
58 defer dconn.Close()
59 io.Copy(ch, dconn)
60 }()
61 go func() {
62 defer ch.Close()
63 defer dconn.Close()
64 io.Copy(dconn, ch)
65 }()
66}
67
68type remoteForwardRequest struct {
69 BindAddr string
70 BindPort uint32
71}
72
73type remoteForwardSuccess struct {
74 BindPort uint32
75}
76
77type remoteForwardCancelRequest struct {
78 BindAddr string
79 BindPort uint32
80}
81
82type remoteForwardChannelData struct {
83 DestAddr string
84 DestPort uint32
85 OriginAddr string
86 OriginPort uint32
87}
88
89// ForwardedTCPHandler can be enabled by creating a ForwardedTCPHandler and
90// adding the HandleSSHRequest callback to the server's RequestHandlers under
91// tcpip-forward and cancel-tcpip-forward.
92type ForwardedTCPHandler struct {
93 forwards map[string]net.Listener
94 sync.Mutex
95}
96
97func (h *ForwardedTCPHandler) HandleSSHRequest(ctx Context, srv *Server, req *gossh.Request) (bool, []byte) {
98 h.Lock()
99 if h.forwards == nil {
100 h.forwards = make(map[string]net.Listener)
101 }
102 h.Unlock()
103 conn := ctx.Value(ContextKeyConn).(*gossh.ServerConn)
104 switch req.Type {
105 case "tcpip-forward":
106 var reqPayload remoteForwardRequest
107 if err := gossh.Unmarshal(req.Payload, &reqPayload); err != nil {
108 // TODO: log parse failure
109 return false, []byte{}
110 }
111 if srv.ReversePortForwardingCallback == nil || !srv.ReversePortForwardingCallback(ctx, reqPayload.BindAddr, reqPayload.BindPort) {
112 return false, []byte("port forwarding is disabled")
113 }
114 addr := net.JoinHostPort(reqPayload.BindAddr, strconv.Itoa(int(reqPayload.BindPort)))
115 ln, err := net.Listen("tcp", addr)
116 if err != nil {
117 // TODO: log listen failure
118 return false, []byte{}
119 }
120 _, destPortStr, _ := net.SplitHostPort(ln.Addr().String())
121 destPort, _ := strconv.Atoi(destPortStr)
122 h.Lock()
123 h.forwards[addr] = ln
124 h.Unlock()
125 go func() {
126 <-ctx.Done()
127 h.Lock()
128 ln, ok := h.forwards[addr]
129 h.Unlock()
130 if ok {
131 ln.Close()
132 }
133 }()
134 go func() {
135 for {
136 c, err := ln.Accept()
137 if err != nil {
138 // TODO: log accept failure
139 break
140 }
141 originAddr, orignPortStr, _ := net.SplitHostPort(c.RemoteAddr().String())
142 originPort, _ := strconv.Atoi(orignPortStr)
143 payload := gossh.Marshal(&remoteForwardChannelData{
144 DestAddr: reqPayload.BindAddr,
145 DestPort: uint32(destPort),
146 OriginAddr: originAddr,
147 OriginPort: uint32(originPort),
148 })
149 go func() {
150 ch, reqs, err := conn.OpenChannel(forwardedTCPChannelType, payload)
151 if err != nil {
152 // TODO: log failure to open channel
153 log.Println(err)
154 c.Close()
155 return
156 }
157 go gossh.DiscardRequests(reqs)
158 go func() {
159 defer ch.Close()
160 defer c.Close()
161 io.Copy(ch, c)
162 }()
163 go func() {
164 defer ch.Close()
165 defer c.Close()
166 io.Copy(c, ch)
167 }()
168 }()
169 }
170 h.Lock()
171 delete(h.forwards, addr)
172 h.Unlock()
173 }()
174 return true, gossh.Marshal(&remoteForwardSuccess{uint32(destPort)})
175
176 case "cancel-tcpip-forward":
177 var reqPayload remoteForwardCancelRequest
178 if err := gossh.Unmarshal(req.Payload, &reqPayload); err != nil {
179 // TODO: log parse failure
180 return false, []byte{}
181 }
182 addr := net.JoinHostPort(reqPayload.BindAddr, strconv.Itoa(int(reqPayload.BindPort)))
183 h.Lock()
184 ln, ok := h.forwards[addr]
185 h.Unlock()
186 if ok {
187 ln.Close()
188 }
189 return true, nil
190 default:
191 return false, nil
192 }
193}