a geicko-2 based round robin ranking system designed to test c++ battleship submissions battleship.dunkirk.sh
1package ssh 2 3import ( 4 "crypto/rand" 5 "crypto/rsa" 6 "encoding/binary" 7 8 "golang.org/x/crypto/ssh" 9) 10 11func generateSigner() (ssh.Signer, error) { 12 key, err := rsa.GenerateKey(rand.Reader, 2048) 13 if err != nil { 14 return nil, err 15 } 16 return ssh.NewSignerFromKey(key) 17} 18 19func parsePtyRequest(payload []byte) (pty Pty, ok bool) { 20 // From https://datatracker.ietf.org/doc/html/rfc4254 21 // 6.2. Requesting a Pseudo-Terminal 22 // A pseudo-terminal can be allocated for the session by sending the 23 // following message. 24 // byte SSH_MSG_CHANNEL_REQUEST 25 // uint32 recipient channel 26 // string "pty-req" 27 // boolean want_reply 28 // string TERM environment variable value (e.g., vt100) 29 // uint32 terminal width, characters (e.g., 80) 30 // uint32 terminal height, rows (e.g., 24) 31 // uint32 terminal width, pixels (e.g., 640) 32 // uint32 terminal height, pixels (e.g., 480) 33 // string encoded terminal modes 34 35 // The payload starts from the TERM variable. 36 term, rem, ok := parseString(payload) 37 if !ok { 38 return 39 } 40 win, rem, ok := parseWindow(rem) 41 if !ok { 42 return 43 } 44 modes, ok := parseTerminalModes(rem) 45 if !ok { 46 return 47 } 48 pty = Pty{ 49 Term: term, 50 Window: win, 51 Modes: modes, 52 } 53 return 54} 55 56func parseTerminalModes(in []byte) (modes ssh.TerminalModes, ok bool) { 57 // From https://datatracker.ietf.org/doc/html/rfc4254 58 // 8. Encoding of Terminal Modes 59 // 60 // All 'encoded terminal modes' (as passed in a pty request) are encoded 61 // into a byte stream. It is intended that the coding be portable 62 // across different environments. The stream consists of opcode- 63 // argument pairs wherein the opcode is a byte value. Opcodes 1 to 159 64 // have a single uint32 argument. Opcodes 160 to 255 are not yet 65 // defined, and cause parsing to stop (they should only be used after 66 // any other data). The stream is terminated by opcode TTY_OP_END 67 // (0x00). 68 // 69 // The client SHOULD put any modes it knows about in the stream, and the 70 // server MAY ignore any modes it does not know about. This allows some 71 // degree of machine-independence, at least between systems that use a 72 // POSIX-like tty interface. The protocol can support other systems as 73 // well, but the client may need to fill reasonable values for a number 74 // of parameters so the server pty gets set to a reasonable mode (the 75 // server leaves all unspecified mode bits in their default values, and 76 // only some combinations make sense). 77 _, rem, ok := parseUint32(in) 78 if !ok { 79 return 80 } 81 const ttyOpEnd = 0 82 for len(rem) > 0 { 83 if modes == nil { 84 modes = make(ssh.TerminalModes) 85 } 86 code := uint8(rem[0]) 87 rem = rem[1:] 88 if code == ttyOpEnd || code > 160 { 89 break 90 } 91 var val uint32 92 val, rem, ok = parseUint32(rem) 93 if !ok { 94 return 95 } 96 modes[code] = val 97 } 98 ok = true 99 return 100} 101 102func parseWindow(s []byte) (win Window, rem []byte, ok bool) { 103 // 6.7. Window Dimension Change Message 104 // When the window (terminal) size changes on the client side, it MAY 105 // send a message to the other side to inform it of the new dimensions. 106 107 // byte SSH_MSG_CHANNEL_REQUEST 108 // uint32 recipient channel 109 // string "window-change" 110 // boolean FALSE 111 // uint32 terminal width, columns 112 // uint32 terminal height, rows 113 // uint32 terminal width, pixels 114 // uint32 terminal height, pixels 115 wCols, rem, ok := parseUint32(s) 116 if !ok { 117 return 118 } 119 hRows, rem, ok := parseUint32(rem) 120 if !ok { 121 return 122 } 123 wPixels, rem, ok := parseUint32(rem) 124 if !ok { 125 return 126 } 127 hPixels, rem, ok := parseUint32(rem) 128 if !ok { 129 return 130 } 131 win = Window{ 132 Width: int(wCols), 133 Height: int(hRows), 134 WidthPixels: int(wPixels), 135 HeightPixels: int(hPixels), 136 } 137 return 138} 139 140func parseString(in []byte) (out string, rem []byte, ok bool) { 141 length, rem, ok := parseUint32(in) 142 if uint32(len(rem)) < length || !ok { 143 ok = false 144 return 145 } 146 out, rem = string(rem[:length]), rem[length:] 147 ok = true 148 return 149} 150 151func parseUint32(in []byte) (uint32, []byte, bool) { 152 if len(in) < 4 { 153 return 0, nil, false 154 } 155 return binary.BigEndian.Uint32(in), in[4:], true 156}