Fixed UDP Client PortRange RTP port bounds & validation - enforced 16Bit uint for ports

This commit is contained in:
Bjørn Steen Saethre 2026-01-19 17:14:55 +01:00
parent e80958699d
commit 70a027c721
9 changed files with 33 additions and 33 deletions

View file

@ -216,8 +216,8 @@ type Conf struct {
PlaybackAllowOrigins AllowedOrigins `json:"playbackAllowOrigins"`
PlaybackTrustedProxies IPNetworks `json:"playbackTrustedProxies"`
// RTSP Client (Streams IN)
UDPClientPortRange []uint `json:"udpClientPortRange"`
// RTSP Source (Streams IN)
UDPClientPortRange *[]uint16 `json:"udpClientPortRange,omitempty"`
// RTSP server
RTSP bool `json:"rtsp"`
@ -370,7 +370,7 @@ func (conf *Conf) setDefaults() {
conf.PlaybackAllowOrigins = []string{"*"}
// RTSP Client
conf.UDPClientPortRange = []uint{10000, 65535}
conf.UDPClientPortRange = &([]uint16{10000, 65535})
// RTSP server
conf.RTSP = true
@ -657,22 +657,23 @@ func (conf *Conf) Validate(l logger.Writer) error {
// RTSP Client
if len(conf.UDPClientPortRange) != 2 {
if len(*conf.UDPClientPortRange) != 2 {
return fmt.Errorf("parameter 'udpClientPortRange' does not have two port range limits - min and max")
}
udpCportmin := conf.UDPClientPortRange[0]
udpCportmax := conf.UDPClientPortRange[1]
//udpCportmin, err := strconv.ParseUint(conf.UDPClientPortRange[0], 10, 16)
//if err != nil {
// return fmt.Errorf("minimum bound of 'udpClientPortRange' must be a positive integer in valid range")
//}
//udpCportmax, err := strconv.ParseUint(conf.UDPClientPortRange[1], 10, 16)
//if err != nil {
// return fmt.Errorf("maximum bound of 'udpClientPortRange' must be a positive integer in valid range")
//}
if udpCportmin >= udpCportmax-1 {
return fmt.Errorf("'udpClientPortRange' lower bound should be at least 2 less than the upper bound")
udpCportmin := (*conf.UDPClientPortRange)[0]
udpCportmax := (*conf.UDPClientPortRange)[1]
if udpCportmin < 10000 || udpCportmax > 65534 {
return fmt.Errorf("'udpClientPortRange' lower bound should not be < 10000 and upper bound should not be > 65534")
}
if (udpCportmax%2 != 0) || (udpCportmin%2 != 0) {
return fmt.Errorf("'udpClientPortRange' lower bound and upper bound should be even numbers")
}
if udpCportmax-udpCportmin < 10 {
return fmt.Errorf("'udpClientPortRange' range should be at least 10 ports")
}
// RTSP server

View file

@ -226,7 +226,7 @@ func loadEnvInternal(env map[string]string, prefix string, prv reflect.Value) er
vals := make([]uint, len(raw))
for i, v := range raw {
tmp, err := strconv.ParseUint(v, 10, 16)
tmp, err := strconv.ParseUint(v, 10, 32)
if err != nil {
return err
}

View file

@ -160,7 +160,6 @@ type Path struct {
// RTP source
RTPSDP string `json:"rtpSDP"`
RTPUDPReadBufferSize *uint `json:"rtpUDPReadBufferSize,omitempty"` // deprecated
UDPClientPortRange []uint `json:"udpClientPortRange,omitempty"`
// Redirect source
SourceRedirect string `json:"sourceRedirect"`

View file

@ -401,7 +401,7 @@ func (p *Core) createResources(initial bool) error {
writeTimeout: p.conf.WriteTimeout,
writeQueueSize: p.conf.WriteQueueSize,
udpReadBufferSize: p.conf.UDPReadBufferSize,
udpClientPortRange: p.conf.UDPClientPortRange,
udpClientPortRange: *p.conf.UDPClientPortRange,
rtpMaxPayloadSize: rtpMaxPayloadSize,
pathConfs: p.conf.Paths,
externalCmdPool: p.externalCmdPool,
@ -764,8 +764,8 @@ func (p *Core) closeResources(newConf *conf.Conf, calledByAPI bool) {
newConf.WriteTimeout != p.conf.WriteTimeout ||
newConf.WriteQueueSize != p.conf.WriteQueueSize ||
newConf.UDPReadBufferSize != p.conf.UDPReadBufferSize ||
newConf.UDPClientPortRange[0] != p.conf.UDPClientPortRange[0] ||
newConf.UDPClientPortRange[1] != p.conf.UDPClientPortRange[1] ||
(*newConf.UDPClientPortRange)[0] != (*p.conf.UDPClientPortRange)[0] ||
(*newConf.UDPClientPortRange)[1] != (*p.conf.UDPClientPortRange)[1] ||
newConf.UDPMaxPayloadSize != p.conf.UDPMaxPayloadSize ||
newConf.RTSPEncryption != p.conf.RTSPEncryption ||
closeMetrics ||
@ -782,8 +782,6 @@ func (p *Core) closeResources(newConf *conf.Conf, calledByAPI bool) {
!reflect.DeepEqual(newConf.RTSPAuthMethods, p.conf.RTSPAuthMethods) ||
newConf.RTSPUDPReadBufferSize != p.conf.RTSPUDPReadBufferSize ||
newConf.UDPReadBufferSize != p.conf.UDPReadBufferSize ||
newConf.UDPClientPortRange[0] != p.conf.UDPClientPortRange[0] ||
newConf.UDPClientPortRange[1] != p.conf.UDPClientPortRange[1] ||
newConf.ReadTimeout != p.conf.ReadTimeout ||
newConf.WriteTimeout != p.conf.WriteTimeout ||
newConf.WriteQueueSize != p.conf.WriteQueueSize ||
@ -808,8 +806,6 @@ func (p *Core) closeResources(newConf *conf.Conf, calledByAPI bool) {
!reflect.DeepEqual(newConf.RTSPAuthMethods, p.conf.RTSPAuthMethods) ||
newConf.RTSPUDPReadBufferSize != p.conf.RTSPUDPReadBufferSize ||
newConf.UDPReadBufferSize != p.conf.UDPReadBufferSize ||
newConf.UDPClientPortRange[0] != p.conf.UDPClientPortRange[0] ||
newConf.UDPClientPortRange[1] != p.conf.UDPClientPortRange[1] ||
newConf.ReadTimeout != p.conf.ReadTimeout ||
newConf.WriteTimeout != p.conf.WriteTimeout ||
newConf.WriteQueueSize != p.conf.WriteQueueSize ||

View file

@ -71,7 +71,7 @@ type path struct {
writeTimeout conf.Duration
writeQueueSize int
udpReadBufferSize uint
udpClientPortRange []uint
udpClientPortRange []uint16
rtpMaxPayloadSize int
conf *conf.Path
name string

View file

@ -77,7 +77,7 @@ type pathManager struct {
writeTimeout conf.Duration
writeQueueSize int
udpReadBufferSize uint
udpClientPortRange []uint
udpClientPortRange []uint16
rtpMaxPayloadSize int
pathConfs map[string]*conf.Path
externalCmdPool *externalcmd.Pool

View file

@ -68,7 +68,7 @@ type Handler struct {
WriteTimeout conf.Duration
WriteQueueSize int
UDPReadBufferSize uint
UDPClientPortRange []uint
UDPClientPortRange []uint16
RTPMaxPayloadSize int
Matches []string
PathManager handlerPathManager

View file

@ -76,7 +76,7 @@ type Source struct {
WriteTimeout conf.Duration
WriteQueueSize int
UDPReadBufferSize uint
UDPClientPortRange []uint
UDPClientPortRange []uint16
Parent parent
}
@ -157,7 +157,7 @@ func (s *Source) Run(params defs.StaticSourceRunParams) error {
var udpMaxPort uint16 = 65535
if s.UDPClientPortRange != nil && len(s.UDPClientPortRange) == 2 {
if s.UDPClientPortRange[0] < 655536 && s.UDPClientPortRange[1] < 65536 {
if s.UDPClientPortRange[0] < 65535 && s.UDPClientPortRange[1] < 65535 {
udpMinPort = uint16(s.UDPClientPortRange[0])
udpMaxPort = uint16(s.UDPClientPortRange[1])
} else {

View file

@ -29,10 +29,12 @@ udpMaxPayloadSize: 1472
# This can be increased to decrease packet losses.
# It defaults to the default value of the operating system.
udpReadBufferSize: 0
# UDP Client Port range
# UDP RTP Client Port range
# This can be used to control UDP client port ranges for use inside Kubernetes clusters
# It defaults to the range [10000,65535]
udpClientPortRange: [10000,65535]
# Starting and ending ports (interval bounds) should be EVEN numbers
# It defaults to the range [10000,65534]
udpClientPortRange: [ 10000,65534 ]
# Command to run when a client connects to the server.
# This is terminated with SIGINT when a client disconnects from the server.
@ -547,6 +549,8 @@ pathDefaults:
# * smpte: duration such as "300ms", "1.5m" or "2h45m", valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h"
rtspRangeStart:
###############################################
# Default path settings -> RTP source (when source is RTP)