diff --git a/Makefile b/Makefile index a73a3c9..f6bf95f 100644 --- a/Makefile +++ b/Makefile @@ -71,4 +71,6 @@ test-integration: @cd e2e && bash ./test.sh prepush: test lint test-integration check-api: - @api -c api/stun1.txt,api/stun1.12.txt github.com/gortc/stun + @api -c api/stun1.txt github.com/gortc/stun +write-api: + @api github.com/gortc/stun > api/stun1.txt diff --git a/api/stun1.12.txt b/api/stun1.12.txt deleted file mode 100644 index 7515f16..0000000 --- a/api/stun1.12.txt +++ /dev/null @@ -1 +0,0 @@ -pkg github.com/gortc/stun, method (*Message) ForEach(AttrType, func(*Message) error) error diff --git a/api/stun1.txt b/api/stun1.txt index 0bd4a88..0e40b31 100644 --- a/api/stun1.txt +++ b/api/stun1.txt @@ -103,11 +103,13 @@ pkg github.com/gortc/stun, const MethodSend Method pkg github.com/gortc/stun, const TransactionIDSize = 12 pkg github.com/gortc/stun, const TransactionIDSize ideal-int pkg github.com/gortc/stun, func Build(...Setter) (*Message, error) +pkg github.com/gortc/stun, func CheckOverflow(AttrType, int, int) error pkg github.com/gortc/stun, func CheckSize(AttrType, int, int) error pkg github.com/gortc/stun, func Decode([]uint8, *Message) error pkg github.com/gortc/stun, func Dial(string, string) (*Client, error) pkg github.com/gortc/stun, func FingerprintValue([]uint8) uint32 pkg github.com/gortc/stun, func IsAttrSizeInvalid(error) bool +pkg github.com/gortc/stun, func IsAttrSizeOverflow(error) bool pkg github.com/gortc/stun, func IsMessage([]uint8) bool pkg github.com/gortc/stun, func MustBuild(...Setter) *Message pkg github.com/gortc/stun, func New() *Message @@ -146,6 +148,7 @@ pkg github.com/gortc/stun, method (*Message) Contains(AttrType) bool pkg github.com/gortc/stun, method (*Message) Decode() error pkg github.com/gortc/stun, method (*Message) Encode() pkg github.com/gortc/stun, method (*Message) Equal(*Message) bool +pkg github.com/gortc/stun, method (*Message) ForEach(AttrType, func(*Message) error) error pkg github.com/gortc/stun, method (*Message) Get(AttrType) ([]uint8, error) pkg github.com/gortc/stun, method (*Message) NewTransactionID() error pkg github.com/gortc/stun, method (*Message) Parse(...Getter) error @@ -169,8 +172,6 @@ pkg github.com/gortc/stun, method (*UnknownAttributes) GetFrom(*Message) error pkg github.com/gortc/stun, method (*Username) GetFrom(*Message) error pkg github.com/gortc/stun, method (*XORMappedAddress) GetFrom(*Message) error pkg github.com/gortc/stun, method (*XORMappedAddress) GetFromAs(*Message, AttrType) error -pkg github.com/gortc/stun, method (AttrLengthErr) Error() string -pkg github.com/gortc/stun, method (AttrOverflowErr) Error() string pkg github.com/gortc/stun, method (AttrType) Optional() bool pkg github.com/gortc/stun, method (AttrType) Required() bool pkg github.com/gortc/stun, method (AttrType) String() string @@ -221,14 +222,6 @@ pkg github.com/gortc/stun, type AgentOptions struct, Handler Handler pkg github.com/gortc/stun, type AlternateServer struct pkg github.com/gortc/stun, type AlternateServer struct, IP net.IP pkg github.com/gortc/stun, type AlternateServer struct, Port int -pkg github.com/gortc/stun, type AttrLengthErr struct -pkg github.com/gortc/stun, type AttrLengthErr struct, Attr AttrType -pkg github.com/gortc/stun, type AttrLengthErr struct, Expected int -pkg github.com/gortc/stun, type AttrLengthErr struct, Got int -pkg github.com/gortc/stun, type AttrOverflowErr struct -pkg github.com/gortc/stun, type AttrOverflowErr struct, Got int -pkg github.com/gortc/stun, type AttrOverflowErr struct, Max int -pkg github.com/gortc/stun, type AttrOverflowErr struct, Type AttrType pkg github.com/gortc/stun, type AttrType uint16 pkg github.com/gortc/stun, type Attributes []RawAttribute pkg github.com/gortc/stun, type Checker interface { Check } @@ -309,6 +302,8 @@ pkg github.com/gortc/stun, var BindingSuccess MessageType pkg github.com/gortc/stun, var ErrAgentClosed error pkg github.com/gortc/stun, var ErrAttrSizeInvalid error pkg github.com/gortc/stun, var ErrAttributeNotFound error +pkg github.com/gortc/stun, var ErrAttributeSizeInvalid error +pkg github.com/gortc/stun, var ErrAttributeSizeOverflow error pkg github.com/gortc/stun, var ErrBadIPLength error pkg github.com/gortc/stun, var ErrBadUnknownAttrsSize error pkg github.com/gortc/stun, var ErrClientClosed error diff --git a/attributes.go b/attributes.go index da48f50..e9aa390 100644 --- a/attributes.go +++ b/attributes.go @@ -172,34 +172,6 @@ func (m *Message) Get(t AttrType) ([]byte, error) { return v.Value, nil } -// AttrOverflowErr occurs when len(v) > Max. -type AttrOverflowErr struct { - Type AttrType - Max int - Got int -} - -func (e AttrOverflowErr) Error() string { - return fmt.Sprintf("incorrect length of %s attribute: %d exceeds maximum %d", - e.Type, e.Got, e.Max, - ) -} - -// AttrLengthErr means that length for attribute is invalid. -type AttrLengthErr struct { - Attr AttrType - Got int - Expected int -} - -func (e AttrLengthErr) Error() string { - return fmt.Sprintf("incorrect length of %s attribute: got %d, expected %d", - e.Attr, - e.Got, - e.Expected, - ) -} - // STUN aligns attributes on 32-bit boundaries, attributes whose content // is not a multiple of 4 bytes are padded with 1, 2, or 3 bytes of // padding so that its value contains a multiple of 4 bytes. The diff --git a/attributes_debug.go b/attributes_debug.go new file mode 100644 index 0000000..7bf09af --- /dev/null +++ b/attributes_debug.go @@ -0,0 +1,33 @@ +// +build debug + +package stun + +import "fmt" + +// AttrOverflowErr occurs when len(v) > Max. +type AttrOverflowErr struct { + Type AttrType + Max int + Got int +} + +func (e AttrOverflowErr) Error() string { + return fmt.Sprintf("incorrect length of %s attribute: %d exceeds maximum %d", + e.Type, e.Got, e.Max, + ) +} + +// AttrLengthErr means that length for attribute is invalid. +type AttrLengthErr struct { + Attr AttrType + Got int + Expected int +} + +func (e AttrLengthErr) Error() string { + return fmt.Sprintf("incorrect length of %s attribute: got %d, expected %d", + e.Attr, + e.Got, + e.Expected, + ) +} diff --git a/attributes_debug_test.go b/attributes_debug_test.go new file mode 100644 index 0000000..9e03303 --- /dev/null +++ b/attributes_debug_test.go @@ -0,0 +1,27 @@ +// +build debug + +package stun + +import "testing" + +func TestAttrOverflowErr_Error(t *testing.T) { + err := AttrOverflowErr{ + Got: 100, + Max: 50, + Type: AttrLifetime, + } + if err.Error() != "incorrect length of LIFETIME attribute: 100 exceeds maximum 50" { + t.Error("bad error string", err) + } +} + +func TestAttrLengthErr_Error(t *testing.T) { + err := AttrLengthErr{ + Attr: AttrErrorCode, + Expected: 15, + Got: 99, + } + if err.Error() != "incorrect length of ERROR-CODE attribute: got 99, expected 15" { + t.Errorf("bad error string: %s", err) + } +} diff --git a/attributes_test.go b/attributes_test.go index 6dacbd4..d74d3ac 100644 --- a/attributes_test.go +++ b/attributes_test.go @@ -69,28 +69,6 @@ func TestPadding(t *testing.T) { } } -func TestAttrLengthError_Error(t *testing.T) { - err := AttrOverflowErr{ - Got: 100, - Max: 50, - Type: AttrLifetime, - } - if err.Error() != "incorrect length of LIFETIME attribute: 100 exceeds maximum 50" { - t.Error("bad error string", err) - } -} - -func TestAttrLengthErr_Error(t *testing.T) { - err := AttrLengthErr{ - Attr: AttrErrorCode, - Expected: 15, - Got: 99, - } - if err.Error() != "incorrect length of ERROR-CODE attribute: got 99, expected 15" { - t.Errorf("bad error string: %s", err) - } -} - func TestAttrTypeRange(t *testing.T) { for _, a := range []AttrType{ AttrPriority, diff --git a/checks.go b/checks.go index 6c1b60c..ca58525 100644 --- a/checks.go +++ b/checks.go @@ -9,7 +9,7 @@ func CheckSize(_ AttrType, got, expected int) error { if got == expected { return nil } - return ErrAttrSizeInvalid + return ErrAttributeSizeInvalid } func checkHMAC(got, expected []byte) error { @@ -28,5 +28,18 @@ func checkFingerprint(got, expected uint32) error { // IsAttrSizeInvalid returns true if error means that attribute size is invalid. func IsAttrSizeInvalid(err error) bool { - return err == ErrAttrSizeInvalid + return err == ErrAttributeSizeInvalid +} + +// CheckOverflow returns ErrAttributeSizeOverflow if got is bigger that max. +func CheckOverflow(_ AttrType, got, max int) error { + if got <= max { + return nil + } + return ErrAttributeSizeOverflow +} + +// IsAttrSizeOverflow returns true if error means that attribute size is too big. +func IsAttrSizeOverflow(err error) bool { + return err == ErrAttributeSizeOverflow } diff --git a/checks_debug.go b/checks_debug.go index 1ca503a..1b0b9c3 100644 --- a/checks_debug.go +++ b/checks_debug.go @@ -41,3 +41,21 @@ func IsAttrSizeInvalid(err error) bool { _, ok := err.(*AttrLengthErr) return ok } + +// CheckOverflow returns *AttrOverflowErr if got is bigger that max. +func CheckOverflow(t AttrType, got, max int) error { + if got <= max { + return nil + } + return &AttrOverflowErr{ + Type: t, + Got: got, + Max: max, + } +} + +// IsAttrSizeOverflow returns true if error means that attribute size is too big. +func IsAttrSizeOverflow(err error) bool { + _, ok := err.(*AttrOverflowErr) + return ok +} diff --git a/errorcode.go b/errorcode.go index 9b43f00..6b42b7f 100644 --- a/errorcode.go +++ b/errorcode.go @@ -30,12 +30,11 @@ const ( // AddTo adds ERROR-CODE to m. func (c ErrorCodeAttribute) AddTo(m *Message) error { value := make([]byte, 0, errorCodeReasonMaxB) - if len(c.Reason) > errorCodeReasonMaxB { - return &AttrOverflowErr{ - Got: len(c.Reason) + errorCodeReasonStart, - Max: errorCodeReasonMaxB + errorCodeReasonStart, - Type: AttrErrorCode, - } + if err := CheckOverflow(AttrErrorCode, + len(c.Reason)+errorCodeReasonStart, + errorCodeReasonMaxB+errorCodeReasonStart, + ); err != nil { + return err } value = value[:errorCodeReasonStart+len(c.Reason)] number := byte(c.Code % errorCodeModulo) // error code modulo 100 diff --git a/errors.go b/errors.go index e121dab..7802ce4 100644 --- a/errors.go +++ b/errors.go @@ -56,4 +56,12 @@ func newAttrDecodeErr(children, message string) *DecodeErr { } // ErrAttrSizeInvalid means that decoded attribute size is invalid. +// +// DEPRECATED: use ErrAttributeSizeInvalid. var ErrAttrSizeInvalid = errors.New("attribute size is invalid") + +// ErrAttributeSizeInvalid means that decoded attribute size is invalid. +var ErrAttributeSizeInvalid = ErrAttrSizeInvalid + +// ErrAttributeSizeOverflow means that decoded attribute size is too big. +var ErrAttributeSizeOverflow = errors.New("attribute size overflow") diff --git a/textattrs.go b/textattrs.go index c2e75f0..69ca58a 100644 --- a/textattrs.go +++ b/textattrs.go @@ -111,12 +111,8 @@ type TextAttribute []byte // AddToAs adds attribute with type t to m, checking maximum length. If maxLen // is less than 0, no check is performed. func (v TextAttribute) AddToAs(m *Message, t AttrType, maxLen int) error { - if maxLen > 0 && len(v) > maxLen { - return &AttrOverflowErr{ - Max: maxLen, - Got: len(v), - Type: t, - } + if err := CheckOverflow(t, len(v), maxLen); err != nil { + return err } m.Add(t, v) return nil diff --git a/textattrs_test.go b/textattrs_test.go index e06366d..d6e932d 100644 --- a/textattrs_test.go +++ b/textattrs_test.go @@ -38,7 +38,7 @@ func TestSoftware_GetFrom(t *testing.T) { func TestSoftware_AddTo_Invalid(t *testing.T) { m := New() s := make(Software, 1024) - if err, ok := s.AddTo(m).(*AttrOverflowErr); !ok { + if err := s.AddTo(m); !IsAttrSizeOverflow(err) { t.Errorf("AddTo should return *AttrOverflowErr, got: %v", err) } if err := s.GetFrom(m); err != ErrAttributeNotFound { @@ -88,8 +88,8 @@ func TestUsername(t *testing.T) { m.WriteHeader() t.Run("Bad length", func(t *testing.T) { badU := make(Username, 600) - if err, ok := badU.AddTo(m).(*AttrOverflowErr); !ok { - t.Errorf("expected length error, got %v", err) + if err := badU.AddTo(m); !IsAttrSizeOverflow(err) { + t.Errorf("AddTo should return *AttrOverflowErr, got: %v", err) } }) t.Run("AddTo", func(t *testing.T) { @@ -164,7 +164,7 @@ func TestRealm_GetFrom(t *testing.T) { func TestRealm_AddTo_Invalid(t *testing.T) { m := New() r := make(Realm, 1024) - if err, ok := r.AddTo(m).(*AttrOverflowErr); !ok || err.Type != AttrRealm { + if err := r.AddTo(m); !IsAttrSizeOverflow(err) { t.Errorf("AddTo should return *AttrOverflowErr, got: %v", err) } if err := r.GetFrom(m); err != ErrAttributeNotFound { @@ -205,7 +205,7 @@ func TestNonce_GetFrom(t *testing.T) { func TestNonce_AddTo_Invalid(t *testing.T) { m := New() n := make(Nonce, 1024) - if err, ok := n.AddTo(m).(*AttrOverflowErr); !ok || err.Type != AttrNonce { + if err := n.AddTo(m); !IsAttrSizeOverflow(err) { t.Errorf("AddTo should return *AttrOverflowErr, got: %v", err) } if err := n.GetFrom(m); err != ErrAttributeNotFound { diff --git a/xoraddr.go b/xoraddr.go index 78d1693..23f7777 100644 --- a/xoraddr.go +++ b/xoraddr.go @@ -108,12 +108,8 @@ func (a *XORMappedAddress) GetFromAs(m *Message, t AttrType) error { if len(v) <= 4 { return io.ErrUnexpectedEOF } - if len(v[4:]) > len(a.IP) { - return &AttrOverflowErr{ - Got: len(v[4:]), - Type: AttrXORMappedAddress, - Max: len(a.IP), - } + if err := CheckOverflow(t, len(v[4:]), len(a.IP)); err != nil { + return err } a.Port = int(bin.Uint16(v[2:4])) ^ (magicCookie >> 16) xorValue := make([]byte, 4+TransactionIDSize) diff --git a/xoraddr_test.go b/xoraddr_test.go index a3d92f5..f78a286 100644 --- a/xoraddr_test.go +++ b/xoraddr_test.go @@ -80,11 +80,8 @@ func TestXORMappedAddress_GetFrom(t *testing.T) { // {0, 1} is correct addr family. m.Add(AttrXORMappedAddress, []byte{0, 1, 3, 4, 5, 6, 7, 8, 9, 1, 1, 1, 1, 1, 2, 3, 4}) addr := new(XORMappedAddress) - err := addr.GetFrom(m) - if _, ok := err.(*AttrOverflowErr); !ok { - t.Errorf("should render AttrOverflowErr error, got <%s> (%T)", - err, err, - ) + if err := addr.GetFrom(m); !IsAttrSizeOverflow(err) { + t.Errorf("AddTo should return *AttrOverflowErr, got: %v", err) } }) }