MCPcopy Index your code
hub / github.com/tailscale/tailscale / Server

Function Server

control/controlbase/handshake.go:201–326  ·  view source on GitHub ↗

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)

Source from the content-addressed store, hash-verified

199// The context deadline, if any, covers the entire handshaking
200// process.
201func 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 }

Callers 8

acceptHTTPFunction · 0.92
acceptWebsocketFunction · 0.92
TestConnStdFunction · 0.70
pairWithConnsFunction · 0.70
TestHandshakeFunction · 0.70
TestNoReuseFunction · 0.70
TestTamperingFunction · 0.70
TestInteropClientFunction · 0.70

Calls 15

InitializeMethod · 0.95
HeaderMethod · 0.95
VersionMethod · 0.95
TypeMethod · 0.95
LengthMethod · 0.95
PayloadMethod · 0.95
MixHashMethod · 0.95
EphemeralPubMethod · 0.95
MixDHMethod · 0.95
DecryptAndHashMethod · 0.95
MachinePubMethod · 0.95
TagMethod · 0.95

Tested by 6

TestConnStdFunction · 0.56
pairWithConnsFunction · 0.56
TestHandshakeFunction · 0.56
TestNoReuseFunction · 0.56
TestTamperingFunction · 0.56
TestInteropClientFunction · 0.56

Used in the wild real call sites across dependent graphs

searching dependent graphs…