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}