Server initiates a control server handshake, returning the resulting control connection. optionalInit can be the client's initial handshake message as returned by ClientDeferred, or nil in which case the initial message is read from conn. The context deadline, if any, covers the entire handshaking
(ctx context.Context, conn net.Conn, controlKey key.MachinePrivate, optionalInit []byte)
| 199 | // The context deadline, if any, covers the entire handshaking |
| 200 | // process. |
| 201 | func Server(ctx context.Context, conn net.Conn, controlKey key.MachinePrivate, optionalInit []byte) (*Conn, error) { |
| 202 | if deadline, ok := ctx.Deadline(); ok { |
| 203 | if err := conn.SetDeadline(deadline); err != nil { |
| 204 | return nil, fmt.Errorf("setting conn deadline: %w", err) |
| 205 | } |
| 206 | defer func() { |
| 207 | conn.SetDeadline(time.Time{}) |
| 208 | }() |
| 209 | } |
| 210 | |
| 211 | // Deliberately does not support formatting, so that we don't echo |
| 212 | // attacker-controlled input back to them. |
| 213 | sendErr := func(msg string) error { |
| 214 | if len(msg) >= 1<<16 { |
| 215 | msg = msg[:1<<16] |
| 216 | } |
| 217 | var hdr [headerLen]byte |
| 218 | hdr[0] = msgTypeError |
| 219 | binary.BigEndian.PutUint16(hdr[1:3], uint16(len(msg))) |
| 220 | if _, err := conn.Write(hdr[:]); err != nil { |
| 221 | return fmt.Errorf("sending %q error to client: %w", msg, err) |
| 222 | } |
| 223 | if _, err := io.WriteString(conn, msg); err != nil { |
| 224 | return fmt.Errorf("sending %q error to client: %w", msg, err) |
| 225 | } |
| 226 | return fmt.Errorf("refused client handshake: %q", msg) |
| 227 | } |
| 228 | |
| 229 | var s symmetricState |
| 230 | s.Initialize() |
| 231 | |
| 232 | var init initiationMessage |
| 233 | if optionalInit != nil { |
| 234 | if len(optionalInit) != len(init) { |
| 235 | return nil, sendErr("wrong handshake initiation size") |
| 236 | } |
| 237 | copy(init[:], optionalInit) |
| 238 | } else if _, err := io.ReadFull(conn, init.Header()); err != nil { |
| 239 | return nil, err |
| 240 | } |
| 241 | // Just a rename to make it more obvious what the value is. In the |
| 242 | // current implementation we don't need to block any protocol |
| 243 | // versions at this layer, it's safe to let the handshake proceed |
| 244 | // and then let the caller make decisions based on the agreed-upon |
| 245 | // protocol version. |
| 246 | clientVersion := init.Version() |
| 247 | if init.Type() != msgTypeInitiation { |
| 248 | return nil, sendErr("unexpected handshake message type") |
| 249 | } |
| 250 | if init.Length() != len(init.Payload()) { |
| 251 | return nil, sendErr("wrong handshake initiation length") |
| 252 | } |
| 253 | // if optionalInit was provided, we have the payload already. |
| 254 | if optionalInit == nil { |
| 255 | if _, err := io.ReadFull(conn, init.Payload()); err != nil { |
| 256 | return nil, err |
| 257 | } |
| 258 | } |
searching dependent graphs…