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}