diff --git a/internal/network/port-receive.go b/internal/network/port-receive.go index fe6ab54e..ee6f28f2 100644 --- a/internal/network/port-receive.go +++ b/internal/network/port-receive.go @@ -213,10 +213,11 @@ func (p *Port) networkLoop(remoteKey []byte, tlscfg *dtls.TLSCfg, b BufferTransp p.sctpAssocations[in.srcAddr.String()] = sctp.NewAssocation(func(pkt *sctp.Packet) { raw, err := pkt.Marshal() if err != nil { - fmt.Println(errors.Wrap(err, "Failed to Unmarshal SCTP packet")) + fmt.Println(errors.Wrap(err, "Failed to Marshal SCTP packet")) return } - fmt.Println(raw) + fmt.Printf("Out: %v\n", raw) + d.Send(raw) }, func(data []byte) { fmt.Printf("Handle data %v \n", data) }) diff --git a/internal/sctp/association.go b/internal/sctp/association.go index 462f7c18..12c19b93 100644 --- a/internal/sctp/association.go +++ b/internal/sctp/association.go @@ -210,8 +210,9 @@ func (a *Association) handleInit(p *Packet, i *Init) (*Packet, error) { initAck.initiateTag = a.myVerificationTag initAck.advertisedReceiverWindowCredit = a.myRreceiverWindowCredit - //initAck.params = append(initAck.params, ) - outbound.Chunks = []Chunk{} + initAck.params = []Param{NewRandomStateCookie(), NewEmptySupportedExtensions()} + + outbound.Chunks = []Chunk{initAck} return outbound, nil diff --git a/internal/sctp/chunk_init_ack.go b/internal/sctp/chunk_init_ack.go index 4ae0a324..85059a29 100644 --- a/internal/sctp/chunk_init_ack.go +++ b/internal/sctp/chunk_init_ack.go @@ -57,6 +57,7 @@ func (i *InitAck) Marshal() ([]byte, error) { return nil, errors.Wrap(err, "Failed marshalling INIT common data") } + i.ChunkHeader.typ = INITACK chunkHeader, err := i.ChunkHeader.Marshal(len(initShared)) if err != nil { return nil, errors.Wrap(err, "Failed marshalling InitAck Chunk Header") diff --git a/internal/sctp/chunk_init_common.go b/internal/sctp/chunk_init_common.go index 9216a3eb..ebabde62 100644 --- a/internal/sctp/chunk_init_common.go +++ b/internal/sctp/chunk_init_common.go @@ -111,6 +111,13 @@ func (i *InitCommon) Marshal() ([]byte, error) { binary.BigEndian.PutUint16(out[8:], i.numOutboundStreams) binary.BigEndian.PutUint16(out[10:], i.numInboundStreams) binary.BigEndian.PutUint32(out[12:], i.initialTSN) + for _, p := range i.params { + pp, err := p.Marshal() + if err != nil { + return nil, errors.Wrap(err, "Unable to marshal parameter for INIT/INITACK") + } + out = append(out, pp...) + } return out, nil } diff --git a/internal/sctp/chunk_test.go b/internal/sctp/chunk_test.go index 8333e75e..c497e22b 100644 --- a/internal/sctp/chunk_test.go +++ b/internal/sctp/chunk_test.go @@ -3,6 +3,7 @@ package sctp import ( "testing" + "fmt" "github.com/pkg/errors" ) @@ -37,3 +38,68 @@ func TestInitChunk(t *testing.T) { t.Error(errors.Errorf("Unmarshal passed for SCTP packet, but got incorrect initialTSN exp: %d act: %d", 3899461680, i.initialTSN)) } } + +func TestInitAck(t *testing.T) { + pkt := &Packet{} + rawPkt := []byte{0x13, 0x88, 0x13, 0x88, 0xce, 0x15, 0x79, 0xa2, 0x96, 0x19, 0xe8, 0xb2, 0x02, 0x00, 0x00, 0x1c, 0xeb, 0x81, 0x4e, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x50, 0xdf, 0x90, 0xd9, 0x00, 0x07, 0x00, 0x08, 0x94, 0x06, 0x2f, 0x93} + err := pkt.Unmarshal(rawPkt) + if err != nil { + t.Error(errors.Wrap(err, "Unmarshal failed, has chunk")) + } + + i, ok := pkt.Chunks[0].(*InitAck) + if !ok { + t.Error("Failed to cast Chunk -> Init") + } + + fmt.Printf("Init ack: %v\n", i) + if err != nil { + t.Error(errors.Wrap(err, "Unmarshal init Chunk failed")) + } +} +func TestInitMarshalUnmarshal(t *testing.T) { + p := &Packet{} + p.DestinationPort = 1 + p.SourcePort = 1 + p.VerificationTag = 123 + + initAck := &InitAck{} + + initAck.initialTSN = 123 + initAck.numOutboundStreams = 1 + initAck.numInboundStreams = 1 + initAck.initiateTag = 123 + initAck.advertisedReceiverWindowCredit = 1024 + initAck.params = []Param{NewRandomStateCookie()} + + p.Chunks = []Chunk{initAck} + rawPkt, err := p.Marshal() + if err != nil { + t.Error(errors.Wrap(err, "Failed to marshal packet")) + } + + pkt := &Packet{} + err = pkt.Unmarshal(rawPkt) + if err != nil { + t.Error(errors.Wrap(err, "Unmarshal failed, has chunk")) + } + + i, ok := pkt.Chunks[0].(*InitAck) + if !ok { + t.Error("Failed to cast Chunk -> InitAck") + } + + if err != nil { + t.Error(errors.Wrap(err, "Unmarshal init ack Chunk failed")) + } else if i.initiateTag != 123 { + t.Error(errors.Errorf("Unmarshal passed for SCTP packet, but got incorrect initiate tag exp: %d act: %d", 123, i.initiateTag)) + } else if i.advertisedReceiverWindowCredit != 1024 { + t.Error(errors.Errorf("Unmarshal passed for SCTP packet, but got incorrect advertisedReceiverWindowCredit exp: %d act: %d", 1024, i.advertisedReceiverWindowCredit)) + } else if i.numOutboundStreams != 1 { + t.Error(errors.Errorf("Unmarshal passed for SCTP packet, but got incorrect numOutboundStreams tag exp: %d act: %d", 1, i.numOutboundStreams)) + } else if i.numInboundStreams != 1 { + t.Error(errors.Errorf("Unmarshal passed for SCTP packet, but got incorrect numInboundStreams exp: %d act: %d", 1, i.numInboundStreams)) + } else if i.initialTSN != 123 { + t.Error(errors.Errorf("Unmarshal passed for SCTP packet, but got incorrect initialTSN exp: %d act: %d", 123, i.initialTSN)) + } +} diff --git a/internal/sctp/packet.go b/internal/sctp/packet.go index 9bfc0f1b..211ee2f9 100644 --- a/internal/sctp/packet.go +++ b/internal/sctp/packet.go @@ -75,6 +75,8 @@ func (p *Packet) Unmarshal(raw []byte) error { switch ChunkType(raw[offset]) { case INIT: c = &Init{} + case INITACK: + c = &InitAck{} default: return errors.Errorf("Failed to unmarshal, contains unknown chunk type %s", ChunkType(raw[offset]).String()) } @@ -82,6 +84,7 @@ func (p *Packet) Unmarshal(raw []byte) error { if err := c.Unmarshal(raw[offset:]); err != nil { return err } + p.Chunks = append(p.Chunks, c) chunkValuePadding := c.valueLength() % 4 offset += chunkHeaderSize + c.valueLength() + chunkValuePadding @@ -113,7 +116,7 @@ func (p *Packet) Marshal() ([]byte, error) { raw = append(raw, chunkRaw...) } - paddingNeeded := len(raw) % 4 + paddingNeeded := getPadding(len(raw), 4) if paddingNeeded != 0 { raw = append(raw, make([]byte, paddingNeeded)...) } diff --git a/internal/sctp/param.go b/internal/sctp/param.go index fa94012e..e3d8276a 100644 --- a/internal/sctp/param.go +++ b/internal/sctp/param.go @@ -10,6 +10,7 @@ type ParamType uint16 // Param interface type Param interface { + Marshal() ([]byte, error) Length() int } @@ -26,6 +27,8 @@ func BuildParam(t ParamType, rawParam []byte) (Param, error) { return (&ParamRequestedHMACAlgorithm{}).Unmarshal(rawParam) case ChunkList: return (&ParamChunkList{}).Unmarshal(rawParam) + case StateCookie: + return (&ParamStateCookie{}).Unmarshal(rawParam) } return nil, errors.Errorf("Unhandled ParamType %v", t) diff --git a/internal/sctp/param_state_cookie.go b/internal/sctp/param_state_cookie.go new file mode 100644 index 00000000..6ef299bc --- /dev/null +++ b/internal/sctp/param_state_cookie.go @@ -0,0 +1,34 @@ +package sctp + +import ( + "encoding/binary" + "math/rand" + "time" +) + +type ParamStateCookie struct { + ParamHeader + Cookie []byte +} + +func NewRandomStateCookie() *ParamStateCookie { + rs := rand.NewSource(time.Now().UnixNano()) + r := rand.New(rs) + randCookie := make([]byte, 4) + binary.BigEndian.PutUint32(randCookie, r.Uint32()) + s := &ParamStateCookie{ + Cookie: randCookie, + } + + return s +} + +func (s *ParamStateCookie) Marshal() ([]byte, error) { + return s.ParamHeader.Marshal(StateCookie, s.Cookie) +} + +func (s *ParamStateCookie) Unmarshal(raw []byte) (Param, error) { + s.ParamHeader.Unmarshal(raw) + s.Cookie = s.raw + return s, nil +} diff --git a/internal/sctp/param_supported_extensions.go b/internal/sctp/param_supported_extensions.go index 058d781b..ddee3d69 100644 --- a/internal/sctp/param_supported_extensions.go +++ b/internal/sctp/param_supported_extensions.go @@ -1,9 +1,5 @@ package sctp -import ( - "fmt" -) - func chunkTypeIntersect(l, r []ChunkType) (c []ChunkType) { m := make(map[ChunkType]bool) @@ -19,9 +15,12 @@ func chunkTypeIntersect(l, r []ChunkType) (c []ChunkType) { return } +func NewEmptySupportedExtensions() *ParamSupportedExtensions { + return &ParamSupportedExtensions{} +} + type ParamSupportedExtensions struct { ParamHeader - Raw []byte ChunkTypes []ChunkType } @@ -40,7 +39,6 @@ func (s *ParamSupportedExtensions) Unmarshal(raw []byte) (Param, error) { for t := range s.raw { s.ChunkTypes = append(s.ChunkTypes, ChunkType(t)) } - fmt.Print(s.ChunkTypes) return s, nil }