mirror of
https://github.com/slackhq/nebula.git
synced 2026-08-16 01:27:04 +02:00
crazy multiport stuff
This commit is contained in:
@@ -20,6 +20,19 @@ type Payload struct {
|
||||
ResponderIndex uint32
|
||||
Time uint64
|
||||
CertVersion uint32
|
||||
|
||||
// Multiport lane negotiation; nil when the sender has multiport disabled
|
||||
// (which keeps the encoded payload byte-identical to a vanilla one).
|
||||
InitiatorLanes *LaneDetails
|
||||
ResponderLanes *LaneDetails
|
||||
}
|
||||
|
||||
// LaneDetails advertises multiport lane capability. LaneIndex is zero on base
|
||||
// handshakes and the initiator's lane number (>= 1) on lane handshakes.
|
||||
type LaneDetails struct {
|
||||
PortCount uint32
|
||||
BasePort uint32
|
||||
LaneIndex uint32
|
||||
}
|
||||
|
||||
// Proto field numbers for NebulaHandshakeDetails
|
||||
@@ -28,9 +41,18 @@ const (
|
||||
fieldInitiatorIndex = 2 // uint32
|
||||
fieldResponderIndex = 3 // uint32
|
||||
fieldTime = 5 // uint64
|
||||
fieldInitiatorLanes = 6 // LaneDetails
|
||||
fieldResponderLanes = 7 // LaneDetails
|
||||
fieldCertVersion = 8 // uint32
|
||||
)
|
||||
|
||||
// Proto field numbers for LaneDetails
|
||||
const (
|
||||
fieldLanePortCount = 1 // uint32
|
||||
fieldLaneBasePort = 2 // uint32
|
||||
fieldLaneLaneIndex = 3 // uint32
|
||||
)
|
||||
|
||||
// MarshalPayload encodes a handshake payload in protobuf wire format compatible
|
||||
// with NebulaHandshake{Details: NebulaHandshakeDetails{...}}.
|
||||
// Returns out (which may be nil), with the marshalled Payload appended to it.
|
||||
@@ -53,6 +75,14 @@ func MarshalPayload(out []byte, p Payload) []byte {
|
||||
details = protowire.AppendTag(details, fieldTime, protowire.VarintType)
|
||||
details = protowire.AppendVarint(details, p.Time)
|
||||
}
|
||||
if p.InitiatorLanes != nil {
|
||||
details = protowire.AppendTag(details, fieldInitiatorLanes, protowire.BytesType)
|
||||
details = protowire.AppendBytes(details, p.InitiatorLanes.marshal(nil))
|
||||
}
|
||||
if p.ResponderLanes != nil {
|
||||
details = protowire.AppendTag(details, fieldResponderLanes, protowire.BytesType)
|
||||
details = protowire.AppendBytes(details, p.ResponderLanes.marshal(nil))
|
||||
}
|
||||
if p.CertVersion != 0 {
|
||||
details = protowire.AppendTag(details, fieldCertVersion, protowire.VarintType)
|
||||
details = protowire.AppendVarint(details, uint64(p.CertVersion))
|
||||
@@ -64,6 +94,20 @@ func MarshalPayload(out []byte, p Payload) []byte {
|
||||
return out
|
||||
}
|
||||
|
||||
// marshal appends the LaneDetails submessage fields to out. All fields are
|
||||
// emitted unconditionally: a LaneDetails is only present at all when multiport
|
||||
// is negotiating, and explicit zeros keep the parser's presence semantics
|
||||
// trivial.
|
||||
func (d *LaneDetails) marshal(out []byte) []byte {
|
||||
out = protowire.AppendTag(out, fieldLanePortCount, protowire.VarintType)
|
||||
out = protowire.AppendVarint(out, uint64(d.PortCount))
|
||||
out = protowire.AppendTag(out, fieldLaneBasePort, protowire.VarintType)
|
||||
out = protowire.AppendVarint(out, uint64(d.BasePort))
|
||||
out = protowire.AppendTag(out, fieldLaneLaneIndex, protowire.VarintType)
|
||||
out = protowire.AppendVarint(out, uint64(d.LaneIndex))
|
||||
return out
|
||||
}
|
||||
|
||||
// UnmarshalPayload decodes a protobuf-encoded NebulaHandshake message.
|
||||
func UnmarshalPayload(b []byte) (Payload, error) {
|
||||
var p Payload
|
||||
@@ -161,6 +205,72 @@ func unmarshalPayloadDetails(p *Payload, b []byte) error {
|
||||
}
|
||||
p.CertVersion = uint32(v)
|
||||
b = b[n:]
|
||||
case fieldInitiatorLanes:
|
||||
if typ != protowire.BytesType {
|
||||
return errInvalidHandshakeDetails
|
||||
}
|
||||
v, n := protowire.ConsumeBytes(b)
|
||||
if n < 0 {
|
||||
return errInvalidHandshakeDetails
|
||||
}
|
||||
p.InitiatorLanes = new(LaneDetails)
|
||||
if err := unmarshalLaneDetails(p.InitiatorLanes, v); err != nil {
|
||||
return err
|
||||
}
|
||||
b = b[n:]
|
||||
case fieldResponderLanes:
|
||||
if typ != protowire.BytesType {
|
||||
return errInvalidHandshakeDetails
|
||||
}
|
||||
v, n := protowire.ConsumeBytes(b)
|
||||
if n < 0 {
|
||||
return errInvalidHandshakeDetails
|
||||
}
|
||||
p.ResponderLanes = new(LaneDetails)
|
||||
if err := unmarshalLaneDetails(p.ResponderLanes, v); err != nil {
|
||||
return err
|
||||
}
|
||||
b = b[n:]
|
||||
default:
|
||||
n := protowire.ConsumeFieldValue(num, typ, b)
|
||||
if n < 0 {
|
||||
return errInvalidHandshakeDetails
|
||||
}
|
||||
b = b[n:]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func unmarshalLaneDetails(d *LaneDetails, b []byte) error {
|
||||
for len(b) > 0 {
|
||||
num, typ, n := protowire.ConsumeTag(b)
|
||||
if n < 0 {
|
||||
return errInvalidHandshakeDetails
|
||||
}
|
||||
b = b[n:]
|
||||
|
||||
// Same contract as the details parser: known fields hard-fail on a
|
||||
// wire-type mismatch, unknown fields are skipped, repeated singular
|
||||
// fields follow proto3 last-wins.
|
||||
switch num {
|
||||
case fieldLanePortCount, fieldLaneBasePort, fieldLaneLaneIndex:
|
||||
if typ != protowire.VarintType {
|
||||
return errInvalidHandshakeDetails
|
||||
}
|
||||
v, n := protowire.ConsumeVarint(b)
|
||||
if n < 0 || v > math.MaxUint32 {
|
||||
return errInvalidHandshakeDetails
|
||||
}
|
||||
switch num {
|
||||
case fieldLanePortCount:
|
||||
d.PortCount = uint32(v)
|
||||
case fieldLaneBasePort:
|
||||
d.BasePort = uint32(v)
|
||||
case fieldLaneLaneIndex:
|
||||
d.LaneIndex = uint32(v)
|
||||
}
|
||||
b = b[n:]
|
||||
default:
|
||||
n := protowire.ConsumeFieldValue(num, typ, b)
|
||||
if n < 0 {
|
||||
|
||||
Reference in New Issue
Block a user