diff --git a/net/stun/stun.go b/net/stun/stun.go index cba098502..e6077c306 100644 --- a/net/stun/stun.go +++ b/net/stun/stun.go @@ -137,15 +137,15 @@ func foreachAttr(b []byte, fn func(attrType uint16, a []byte) error) error { } attrType := binary.BigEndian.Uint16(b[:2]) attrLen := int(binary.BigEndian.Uint16(b[2:4])) - attrLenPad := attrLen % 4 + attrLenWithPad := (attrLen + 3) &^ 3 b = b[4:] - if attrLen+attrLenPad > len(b) { + if attrLenWithPad > len(b) { return ErrMalformedAttrs } if err := fn(attrType, b[:attrLen]); err != nil { return err } - b = b[attrLen+attrLenPad:] + b = b[attrLenWithPad:] } return nil } diff --git a/net/stun/stun_test.go b/net/stun/stun_test.go index 09ea900c1..81b5a8244 100644 --- a/net/stun/stun_test.go +++ b/net/stun/stun_test.go @@ -140,6 +140,41 @@ var responseTests = []struct { wantAddr: net.ParseIP("2602:d1:b4cf:c100:38b2:31ff:feef:96f6"), wantPort: 37070, }, + + // Testing STUN attribute padding rules using STUN software attribute + // with values of 1 & 3 length respectively before the XorMappedAddress attribute + { + name: "software-a", + data: []byte{ + 0x01, 0x01, 0x00, 0x14, 0x21, 0x12, 0xa4, 0x42, + 0xeb, 0xc2, 0xd3, 0x6e, 0xf4, 0x71, 0x21, 0x7c, + 0x4f, 0x3e, 0x30, 0x8e, 0x80, 0x22, 0x00, 0x01, + 0x61, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, + 0x00, 0x01, 0xce, 0x66, 0x5e, 0x12, 0xa4, 0x43, + }, + wantTID: []byte{ + 0xeb, 0xc2, 0xd3, 0x6e, 0xf4, 0x71, 0x21, 0x7c, + 0x4f, 0x3e, 0x30, 0x8e, + }, + wantAddr: []byte{127, 0, 0, 1}, + wantPort: 61300, + }, + { + name: "software-abc", + data: []byte{ + 0x01, 0x01, 0x00, 0x14, 0x21, 0x12, 0xa4, 0x42, + 0xeb, 0xc2, 0xd3, 0x6e, 0xf4, 0x71, 0x21, 0x7c, + 0x4f, 0x3e, 0x30, 0x8e, 0x80, 0x22, 0x00, 0x03, + 0x61, 0x62, 0x63, 0x00, 0x00, 0x20, 0x00, 0x08, + 0x00, 0x01, 0xce, 0x66, 0x5e, 0x12, 0xa4, 0x43, + }, + wantTID: []byte{ + 0xeb, 0xc2, 0xd3, 0x6e, 0xf4, 0x71, 0x21, 0x7c, + 0x4f, 0x3e, 0x30, 0x8e, + }, + wantAddr: []byte{127, 0, 0, 1}, + wantPort: 61300, + }, } func TestParseResponse(t *testing.T) {