Compare commits

...

4 commits

Author SHA1 Message Date
Jonathan Barrow
519e786544
Merge pull request #83 from DaniElectra/stationurl-custom-params
fix(types/station_url): Fix invalid checks for custom parameters
2025-03-15 17:10:12 -04:00
Daniel López Guimaraes
4a55120377
fix(types/station_url): Fix invalid checks for custom parameters
Check for empty string to prevent setting an empty value on the custom
parameters map. Also fix a typo on formatting which was using the
standard parameters as custom parameters.
2025-03-15 18:20:26 +00:00
Daniel López Guimaraes
4cb8b49c51
Merge pull request #81 from DaniElectra/size-checks
fix(prudp): Add missing size checks on PRUDP packets
2025-03-15 16:57:14 +00:00
Daniel López Guimaraes
397ebe4144
fix(prudp): Add missing size checks on PRUDP packets
PRUDPLite and PRUDPv1 were missing some size checks while parsing their
data. We also need one bounds check at the beginning to choose the
proper packet type by the magic.
2025-02-26 23:51:21 +00:00
4 changed files with 62 additions and 22 deletions

View file

@ -4,6 +4,7 @@ import (
"crypto/hmac"
"crypto/md5"
"encoding/binary"
"errors"
"fmt"
"net"
@ -177,6 +178,10 @@ func (p *PRUDPPacketLite) decode() error {
return fmt.Errorf("Failed to decode PRUDPLite options. %s", err.Error())
}
if p.readStream.Remaining() < uint64(payloadLength) {
return errors.New("Failed to read PRUDPLite payload. Not have enough data")
}
p.payload = p.readStream.ReadBytesNext(int64(payloadLength))
return nil
@ -208,6 +213,10 @@ func (p *PRUDPPacketLite) Bytes() []byte {
}
func (p *PRUDPPacketLite) decodeOptions() error {
if p.readStream.Remaining() < uint64(p.optionsLength) {
return errors.New("Not have enough data")
}
data := p.readStream.ReadBytesNext(int64(p.optionsLength))
optionsStream := NewByteStreamIn(data, p.server.LibraryVersions, p.server.ByteStreamSettings)
@ -231,7 +240,11 @@ func (p *PRUDPPacketLite) decodeOptions() error {
}
if optionID == 1 {
p.connectionSignature = optionsStream.ReadBytesNext(int64(optionSize))
if optionsStream.Remaining() < uint64(optionSize) {
err = errors.New("Failed to read connection signature. Not have enough data")
} else {
p.connectionSignature = optionsStream.ReadBytesNext(int64(optionSize))
}
}
if optionID == 4 {
@ -253,7 +266,11 @@ func (p *PRUDPPacketLite) decodeOptions() error {
if p.packetType == constants.ConnectPacket && !p.HasFlag(constants.PacketFlagAck) {
if optionID == 0x80 {
p.liteSignature = optionsStream.ReadBytesNext(int64(optionSize))
if optionsStream.Remaining() < uint64(optionSize) {
err = errors.New("Failed to read lite signature. Not have enough data")
} else {
p.liteSignature = optionsStream.ReadBytesNext(int64(optionSize))
}
}
}

View file

@ -89,6 +89,10 @@ func (p *PRUDPPacketV1) decode() error {
return fmt.Errorf("Failed to decode PRUDPv1 header. %s", err.Error())
}
if p.readStream.Remaining() < 16 {
return errors.New("Failed to read PRUDPv1 signature. Not have enough data")
}
p.signature = p.readStream.ReadBytesNext(16)
err = p.decodeOptions()
@ -96,6 +100,10 @@ func (p *PRUDPPacketV1) decode() error {
return fmt.Errorf("Failed to decode PRUDPv1 options. %s", err.Error())
}
if p.readStream.Remaining() < uint64(p.payloadLength) {
return errors.New("Failed to read PRUDPv1 payload. Not have enough data")
}
p.payload = p.readStream.ReadBytesNext(int64(p.payloadLength))
return nil
@ -211,6 +219,10 @@ func (p *PRUDPPacketV1) encodeHeader() []byte {
}
func (p *PRUDPPacketV1) decodeOptions() error {
if p.readStream.Remaining() < uint64(p.optionsLength) {
return errors.New("Not have enough data")
}
data := p.readStream.ReadBytesNext(int64(p.optionsLength))
optionsStream := NewByteStreamIn(data, p.server.LibraryVersions, p.server.ByteStreamSettings)
@ -234,7 +246,11 @@ func (p *PRUDPPacketV1) decodeOptions() error {
}
if optionID == 1 {
p.connectionSignature = optionsStream.ReadBytesNext(16)
if optionsStream.Remaining() < 16 {
err = errors.New("Not have enough data")
} else {
p.connectionSignature = optionsStream.ReadBytesNext(16)
}
}
if optionID == 4 {

View file

@ -127,6 +127,11 @@ func (ps *PRUDPServer) initPRUDPv1ConnectionSignatureKey() {
}
func (ps *PRUDPServer) handleSocketMessage(packetData []byte, address net.Addr, webSocketConnection *gws.Conn) error {
// * Check that the message is long enough for initial parsing
if len(packetData) < 2 {
return nil
}
readStream := NewByteStreamIn(packetData, ps.LibraryVersions, ps.ByteStreamSettings)
var packets []PRUDPPacketInterface

View file

@ -643,7 +643,7 @@ func (s *StationURL) Parse() {
standardParameters := strings.Split(standardSection, ";")
for i := 0; i < len(standardParameters); i++ {
for i := range standardParameters {
key, value, _ := strings.Cut(standardParameters[i], "=")
if key == "address" && len(value) > 256 {
@ -662,12 +662,14 @@ func (s *StationURL) Parse() {
s.Set(key, value, false)
}
customParameters := strings.Split(customSection, ";")
if len(customSection) != 0 {
customParameters := strings.Split(customSection, ";")
for i := 0; i < len(customParameters); i++ {
key, value, _ := strings.Cut(customParameters[i], "=")
for i := range customParameters {
key, value, _ := strings.Cut(customParameters[i], "=")
s.Set(key, value, true)
s.Set(key, value, true)
}
}
if flags, ok := s.uint8ParamValue("type"); ok {
@ -692,6 +694,19 @@ func (s *StationURL) Format() {
fields := make([]string, 0)
for key, value := range s.standardParams {
if key == "address" && len(value) > 256 {
// * The client can only hold a host name of up to 256 characters
// TODO - Should we return an error here?
return
}
if key == "port" {
if port, err := strconv.Atoi(value); err != nil || (port < 0 || port > 65535) {
// TODO - Should we return an error here?
return
}
}
fields = append(fields, fmt.Sprintf("%s=%s", key, value))
}
@ -700,20 +715,7 @@ func (s *StationURL) Format() {
if len(s.customParams) != 0 {
customFields := make([]string, 0)
for key, value := range s.standardParams {
if key == "address" && len(value) > 256 {
// * The client can only hold a host name of up to 256 characters
// TODO - Should we return an error here?
return
}
if key == "port" {
if port, err := strconv.Atoi(value); err != nil || (port < 0 || port > 65535) {
// TODO - Should we return an error here?
return
}
}
for key, value := range s.customParams {
customFields = append(customFields, fmt.Sprintf("%s=%s", key, value))
}