client: prevent downgrading from RTSPS to RTSP during redirect (#816)

This commit is contained in:
Alessandro Ros
2025-06-30 16:03:05 +02:00
committed by GitHub
parent 6cf27aac05
commit bf3ce11479
3 changed files with 93 additions and 20 deletions

View File

@@ -1256,6 +1256,10 @@ func (c *Client) doDescribe(u *base.URL) (*description.Session, *base.Response,
return nil, nil, err return nil, nil, err
} }
if c.connURL.Scheme == "rtsps" && ru.Scheme != "rtsps" {
return nil, nil, fmt.Errorf("connection cannot be downgraded from RTSPS to RTSP")
}
if u.User != nil { if u.User != nil {
ru.User = u.User ru.User = u.User
} }

View File

@@ -252,9 +252,8 @@ func TestClientPlay(t *testing.T) {
packetRecv := make(chan struct{}) packetRecv := make(chan struct{})
listenIP := multicastCapableIP(t) listenIP := multicastCapableIP(t)
l, err := net.Listen("tcp", listenIP+":8554") var l net.Listener
require.NoError(t, err) var err error
defer l.Close()
var scheme string var scheme string
if transport == "tls" { if transport == "tls" {
@@ -264,9 +263,15 @@ func TestClientPlay(t *testing.T) {
cert, err = tls.X509KeyPair(serverCert, serverKey) cert, err = tls.X509KeyPair(serverCert, serverKey)
require.NoError(t, err) require.NoError(t, err)
l = tls.NewListener(l, &tls.Config{Certificates: []tls.Certificate{cert}}) l, err = tls.Listen("tcp", listenIP+":8554", &tls.Config{Certificates: []tls.Certificate{cert}})
require.NoError(t, err)
defer l.Close()
} else { } else {
scheme = "rtsp" scheme = "rtsp"
l, err = net.Listen("tcp", listenIP+":8554")
require.NoError(t, err)
defer l.Close()
} }
serverDone := make(chan struct{}) serverDone := make(chan struct{})
@@ -1650,12 +1655,11 @@ func TestClientPlayDifferentInterleavedIDs(t *testing.T) {
} }
func TestClientPlayRedirect(t *testing.T) { func TestClientPlayRedirect(t *testing.T) {
for _, withCredentials := range []bool{false, true} { for _, ca := range []string{
runName := "WithoutCredentials" "without credentials",
if withCredentials { "with credentials",
runName = "WithCredentials" } {
} t.Run(ca, func(t *testing.T) {
t.Run(runName, func(t *testing.T) {
l, err := net.Listen("tcp", "localhost:8554") l, err := net.Listen("tcp", "localhost:8554")
require.NoError(t, err) require.NoError(t, err)
defer l.Close() defer l.Close()
@@ -1728,7 +1732,7 @@ func TestClientPlayRedirect(t *testing.T) {
require.NoError(t, err2) require.NoError(t, err2)
require.Equal(t, base.Describe, req.Method) require.Equal(t, base.Describe, req.Method)
if withCredentials { if ca == "with credentials" {
if _, exists := req.Header["Authorization"]; !exists { if _, exists := req.Header["Authorization"]; !exists {
authRealm := "example@localhost" authRealm := "example@localhost"
authNonce := "exampleNonce" authNonce := "exampleNonce"
@@ -1823,7 +1827,7 @@ func TestClientPlayRedirect(t *testing.T) {
c := Client{} c := Client{}
ru := "rtsp://localhost:8554/path1" ru := "rtsp://localhost:8554/path1"
if withCredentials { if ca == "with credentials" {
ru = "rtsp://testusr:testpwd@localhost:8554/path1" ru = "rtsp://testusr:testpwd@localhost:8554/path1"
} }
err = readAll(&c, ru, err = readAll(&c, ru,
@@ -1838,6 +1842,61 @@ func TestClientPlayRedirect(t *testing.T) {
} }
} }
func TestClientPlayRedirectPreventDecrypt(t *testing.T) {
cert, err := tls.X509KeyPair(serverCert, serverKey)
require.NoError(t, err)
l, err := tls.Listen("tcp", "localhost:8554", &tls.Config{Certificates: []tls.Certificate{cert}})
require.NoError(t, err)
defer l.Close()
serverDone := make(chan struct{})
defer func() { <-serverDone }()
go func() {
defer close(serverDone)
var nconn net.Conn
nconn, err = l.Accept()
require.NoError(t, err)
defer nconn.Close()
conn := conn.NewConn(nconn)
req, err2 := conn.ReadRequest()
require.NoError(t, err2)
require.Equal(t, base.Options, req.Method)
err2 = conn.WriteResponse(&base.Response{
StatusCode: base.StatusOK,
Header: base.Header{
"Public": base.HeaderValue{strings.Join([]string{
string(base.Describe),
string(base.Setup),
string(base.Play),
}, ", ")},
},
})
require.NoError(t, err2)
req, err2 = conn.ReadRequest()
require.NoError(t, err2)
require.Equal(t, base.Describe, req.Method)
err2 = conn.WriteResponse(&base.Response{
StatusCode: base.StatusMovedPermanently,
Header: base.Header{
"Location": base.HeaderValue{"rtsp://localhost:8554/test"},
},
})
require.NoError(t, err2)
}()
c := Client{TLSConfig: &tls.Config{InsecureSkipVerify: true}}
err = readAll(&c, "rtsps://localhost:8554/test", nil)
require.EqualError(t, err, "connection cannot be downgraded from RTSPS to RTSP")
defer c.Close()
}
func TestClientPlayPausePlay(t *testing.T) { func TestClientPlayPausePlay(t *testing.T) {
writeFrames := func(inTH *headers.Transport, conn *conn.Conn) (chan struct{}, chan struct{}) { writeFrames := func(inTH *headers.Transport, conn *conn.Conn) (chan struct{}, chan struct{}) {
writerTerminate := make(chan struct{}) writerTerminate := make(chan struct{})

View File

@@ -132,9 +132,8 @@ func TestClientRecord(t *testing.T) {
"tls", "tls",
} { } {
t.Run(transport, func(t *testing.T) { t.Run(transport, func(t *testing.T) {
l, err := net.Listen("tcp", "localhost:8554") var l net.Listener
require.NoError(t, err) var err error
defer l.Close()
var scheme string var scheme string
if transport == "tls" { if transport == "tls" {
@@ -144,9 +143,15 @@ func TestClientRecord(t *testing.T) {
cert, err = tls.X509KeyPair(serverCert, serverKey) cert, err = tls.X509KeyPair(serverCert, serverKey)
require.NoError(t, err) require.NoError(t, err)
l = tls.NewListener(l, &tls.Config{Certificates: []tls.Certificate{cert}}) l, err = tls.Listen("tcp", "localhost:8554", &tls.Config{Certificates: []tls.Certificate{cert}})
require.NoError(t, err)
defer l.Close()
} else { } else {
scheme = "rtsp" scheme = "rtsp"
l, err = net.Listen("tcp", "localhost:8554")
require.NoError(t, err)
defer l.Close()
} }
serverDone := make(chan struct{}) serverDone := make(chan struct{})
@@ -380,9 +385,8 @@ func TestClientRecordSocketError(t *testing.T) {
"tls", "tls",
} { } {
t.Run(transport, func(t *testing.T) { t.Run(transport, func(t *testing.T) {
l, err := net.Listen("tcp", "localhost:8554") var l net.Listener
require.NoError(t, err) var err error
defer l.Close()
var scheme string var scheme string
if transport == "tls" { if transport == "tls" {
@@ -392,9 +396,15 @@ func TestClientRecordSocketError(t *testing.T) {
cert, err = tls.X509KeyPair(serverCert, serverKey) cert, err = tls.X509KeyPair(serverCert, serverKey)
require.NoError(t, err) require.NoError(t, err)
l = tls.NewListener(l, &tls.Config{Certificates: []tls.Certificate{cert}}) l, err = tls.Listen("tcp", "localhost:8554", &tls.Config{Certificates: []tls.Certificate{cert}})
require.NoError(t, err)
defer l.Close()
} else { } else {
scheme = "rtsp" scheme = "rtsp"
l, err = net.Listen("tcp", "localhost:8554")
require.NoError(t, err)
defer l.Close()
} }
serverDone := make(chan struct{}) serverDone := make(chan struct{})