Compare commits

...

6 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
Daniel López Guimaraes
f34f86f7b7
fix(prudp): Check for matching user PID and ticket source PID 2025-02-13 21:50:11 +00:00
Ash Logan
6ec50052cd fix(datetime): Have FromTimestamp modify the underlying DateTime
This got lost in the types refactor, and was a rare case of the pointer receiver actually being needed - various apps depended on this function modifying the underlying value.

One could also argue for this being factored out into a NewDateTimeFromTimestamp function or something, but this way is source-compatible with older code.
2025-01-27 19:52:18 +11:00
6 changed files with 67 additions and 23 deletions

View file

@ -509,6 +509,10 @@ func (pep *PRUDPEndPoint) readKerberosTicket(payload []byte) ([]byte, types.PID,
return nil, 0, 0, err
}
if userPID != ticket.SourcePID {
return nil, 0, 0, errors.New("User PID and ticket source PID mismatch")
}
_, err = checkDataStream.ReadUInt32LE() // * CID of secure server station url
if err != nil {
return nil, 0, 0, err

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,8 +240,12 @@ func (p *PRUDPPacketLite) decodeOptions() error {
}
if optionID == 1 {
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 {
p.maximumSubstreamID, err = optionsStream.ReadUInt8()
@ -253,9 +266,13 @@ func (p *PRUDPPacketLite) decodeOptions() error {
if p.packetType == constants.ConnectPacket && !p.HasFlag(constants.PacketFlagAck) {
if optionID == 0x80 {
if optionsStream.Remaining() < uint64(optionSize) {
err = errors.New("Failed to read lite signature. Not have enough data")
} else {
p.liteSignature = optionsStream.ReadBytesNext(int64(optionSize))
}
}
}
// * Only one option is processed at a time, so we can
// * just check for errors here rather than after EVERY

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,8 +246,12 @@ func (p *PRUDPPacketV1) decodeOptions() error {
}
if optionID == 1 {
if optionsStream.Remaining() < 16 {
err = errors.New("Not have enough data")
} else {
p.connectionSignature = optionsStream.ReadBytesNext(16)
}
}
if optionID == 4 {
p.maximumSubstreamID, err = optionsStream.ReadUInt8()

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

@ -63,7 +63,7 @@ func (dt *DateTime) Make(year, month, day, hour, minute, second int) DateTime {
}
// FromTimestamp converts a Time timestamp into a NEX DateTime
func (dt DateTime) FromTimestamp(timestamp time.Time) DateTime {
func (dt *DateTime) FromTimestamp(timestamp time.Time) DateTime {
year := timestamp.Year()
month := int(timestamp.Month())
day := timestamp.Day()

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,13 +662,15 @@ func (s *StationURL) Parse() {
s.Set(key, value, false)
}
if len(customSection) != 0 {
customParameters := strings.Split(customSection, ";")
for i := 0; i < len(customParameters); i++ {
for i := range customParameters {
key, value, _ := strings.Cut(customParameters[i], "=")
s.Set(key, value, true)
}
}
if flags, ok := s.uint8ParamValue("type"); ok {
s.flags = flags
@ -691,15 +693,6 @@ func (s *StationURL) Format() {
fields := make([]string, 0)
for key, value := range s.standardParams {
fields = append(fields, fmt.Sprintf("%s=%s", key, value))
}
url := scheme + strings.Join(fields, ";")
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
@ -714,6 +707,15 @@ func (s *StationURL) Format() {
}
}
fields = append(fields, fmt.Sprintf("%s=%s", key, value))
}
url := scheme + strings.Join(fields, ";")
if len(s.customParams) != 0 {
customFields := make([]string, 0)
for key, value := range s.customParams {
customFields = append(customFields, fmt.Sprintf("%s=%s", key, value))
}