Browse Source

fix authenticating with vlc and login prompt

pull/31/head
aler9 5 years ago
parent
commit
4c6f929c02
  1. 2
      go.mod
  2. 4
      go.sum
  3. 26
      main.go
  4. 106
      server-client.go
  5. 12
      server-udpl.go

2
go.mod

@ -5,7 +5,7 @@ go 1.13 @@ -5,7 +5,7 @@ go 1.13
require (
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect
github.com/aler9/gortsplib v0.0.0-20200709205811-04b0a6eabe37
github.com/aler9/gortsplib v0.0.0-20200710091324-fb7d7b008e68
github.com/stretchr/testify v1.4.0
gopkg.in/alecthomas/kingpin.v2 v2.2.6
gopkg.in/yaml.v2 v2.2.2

4
go.sum

@ -2,8 +2,8 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafo @@ -2,8 +2,8 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafo
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/aler9/gortsplib v0.0.0-20200709205811-04b0a6eabe37 h1:O92YFUvPXejUg08pDIQTI8MydvHZBnCnSsOMxP2Q828=
github.com/aler9/gortsplib v0.0.0-20200709205811-04b0a6eabe37/go.mod h1:sL64nUkmrTVhlT/GCaxRXyI2Xk7m8XSdw5Uv8xKGPdc=
github.com/aler9/gortsplib v0.0.0-20200710091324-fb7d7b008e68 h1:apyYugiG/luHl0Xyc2xJtGkL2HbF1umxjCNP2sX9iyw=
github.com/aler9/gortsplib v0.0.0-20200710091324-fb7d7b008e68/go.mod h1:sL64nUkmrTVhlT/GCaxRXyI2Xk7m8XSdw5Uv8xKGPdc=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=

26
main.go

@ -192,16 +192,16 @@ type programEventTerminate struct{} @@ -192,16 +192,16 @@ type programEventTerminate struct{}
func (programEventTerminate) isProgramEvent() {}
type ConfPath struct {
Source string `yaml:"source"`
SourceProtocol string `yaml:"sourceProtocol"`
PublishUser string `yaml:"publishUser"`
PublishPass string `yaml:"publishPass"`
PublishIps []string `yaml:"publishIps"`
publishIps []interface{}
ReadUser string `yaml:"readUser"`
ReadPass string `yaml:"readPass"`
ReadIps []string `yaml:"readIps"`
readIps []interface{}
Source string `yaml:"source"`
SourceProtocol string `yaml:"sourceProtocol"`
PublishUser string `yaml:"publishUser"`
PublishPass string `yaml:"publishPass"`
PublishIps []string `yaml:"publishIps"`
publishIpsParsed []interface{}
ReadUser string `yaml:"readUser"`
ReadPass string `yaml:"readPass"`
ReadIps []string `yaml:"readIps"`
readIpsParsed []interface{}
}
type conf struct {
@ -366,7 +366,7 @@ func newProgram(sargs []string, stdin io.Reader) (*program, error) { @@ -366,7 +366,7 @@ func newProgram(sargs []string, stdin io.Reader) (*program, error) {
return nil, fmt.Errorf("publish password must be alphanumeric")
}
}
pconf.publishIps, err = parseIpCidrList(pconf.PublishIps)
pconf.publishIpsParsed, err = parseIpCidrList(pconf.PublishIps)
if err != nil {
return nil, err
}
@ -387,7 +387,7 @@ func newProgram(sargs []string, stdin io.Reader) (*program, error) { @@ -387,7 +387,7 @@ func newProgram(sargs []string, stdin io.Reader) (*program, error) {
if pconf.ReadUser != "" && pconf.ReadPass == "" || pconf.ReadUser == "" && pconf.ReadPass != "" {
return nil, fmt.Errorf("read username and password must be both filled")
}
pconf.readIps, err = parseIpCidrList(pconf.ReadIps)
pconf.readIpsParsed, err = parseIpCidrList(pconf.ReadIps)
if err != nil {
return nil, err
}
@ -482,7 +482,7 @@ outer: @@ -482,7 +482,7 @@ outer:
// close all other clients that share the same path
if pub.publisherIsReady() {
for oc := range p.clients {
if oc.path == evt.client.path {
if oc != evt.client && oc.path == evt.client.path {
go oc.close()
}
}

106
server-client.go

@ -71,8 +71,10 @@ type serverClient struct { @@ -71,8 +71,10 @@ type serverClient struct {
conn *gortsplib.ConnServer
state clientState
path string
publishAuth *gortsplib.AuthServer
readAuth *gortsplib.AuthServer
authUser string
authPass string
authHelper *gortsplib.AuthServer
authFailures int
streamSdpText []byte // filled only if publisher
streamSdpParsed *sdp.Message // filled only if publisher
streamProtocol streamProtocol
@ -86,8 +88,8 @@ type serverClient struct { @@ -86,8 +88,8 @@ type serverClient struct {
writeBuf2 []byte
writeCurBuf bool
writec chan *gortsplib.InterleavedFrame
done chan struct{}
writeChan chan *gortsplib.InterleavedFrame
done chan struct{}
}
func newServerClient(p *program, nconn net.Conn) *serverClient {
@ -103,7 +105,7 @@ func newServerClient(p *program, nconn net.Conn) *serverClient { @@ -103,7 +105,7 @@ func newServerClient(p *program, nconn net.Conn) *serverClient {
readBuf2: make([]byte, 0, 512*1024),
writeBuf1: make([]byte, 2048),
writeBuf2: make([]byte, 2048),
writec: make(chan *gortsplib.InterleavedFrame),
writeChan: make(chan *gortsplib.InterleavedFrame),
done: make(chan struct{}),
}
@ -164,7 +166,7 @@ func (c *serverClient) run() { @@ -164,7 +166,7 @@ func (c *serverClient) run() {
}
go func() {
for range c.writec {
for range c.writeChan {
}
}()
@ -182,9 +184,10 @@ func (c *serverClient) run() { @@ -182,9 +184,10 @@ func (c *serverClient) run() {
c.p.events <- programEventClientClose{done, c}
<-done
close(c.writec)
close(c.writeChan)
c.conn.NetConn().Close() // close socket in case it has not been closed yet
close(c.done)
close(c.done) // close() never blocks
}
func (c *serverClient) close() {
@ -204,7 +207,7 @@ func (c *serverClient) writeFrame(channel uint8, inbuf []byte) { @@ -204,7 +207,7 @@ func (c *serverClient) writeFrame(channel uint8, inbuf []byte) {
copy(buf, inbuf)
c.writeCurBuf = !c.writeCurBuf
c.writec <- &gortsplib.InterleavedFrame{
c.writeChan <- &gortsplib.InterleavedFrame{
Channel: channel,
Content: buf,
}
@ -224,70 +227,101 @@ func (c *serverClient) writeResError(req *gortsplib.Request, code gortsplib.Stat @@ -224,70 +227,101 @@ func (c *serverClient) writeResError(req *gortsplib.Request, code gortsplib.Stat
})
}
func (c *serverClient) findConfForPath(path string) *ConfPath {
if pconf, ok := c.p.conf.Paths[path]; ok {
return pconf
}
if pconf, ok := c.p.conf.Paths["all"]; ok {
return pconf
}
return nil
}
var errAuthCritical = errors.New("auth critical")
var errAuthNotCritical = errors.New("auth not critical")
func (c *serverClient) validateAuth(req *gortsplib.Request, user string, pass string, auth **gortsplib.AuthServer, ips []interface{}) error {
func (c *serverClient) authenticate(ips []interface{}, user string, pass string, req *gortsplib.Request) error {
// validate ip
err := func() error {
if ips == nil {
return nil
}
connIp := c.conn.NetConn().LocalAddr().(*net.TCPAddr).IP
ip := c.ip()
for _, item := range ips {
switch titem := item.(type) {
case net.IP:
if titem.Equal(connIp) {
if titem.Equal(ip) {
return nil
}
case *net.IPNet:
if titem.Contains(connIp) {
if titem.Contains(ip) {
return nil
}
}
}
c.log("ERR: ip '%s' not allowed", connIp)
c.log("ERR: ip '%s' not allowed", ip)
return errAuthCritical
}()
if err != nil {
return err
}
// validate credentials
err = func() error {
if user == "" {
return nil
}
initialRequest := false
if *auth == nil {
initialRequest = true
*auth = gortsplib.NewAuthServer(user, pass, nil)
// reset authHelper every time the credentials change
if c.authHelper == nil || c.authUser != user || c.authPass != pass {
c.authUser = user
c.authPass = pass
c.authHelper = gortsplib.NewAuthServer(user, pass, nil)
}
err := (*auth).ValidateHeader(req.Header["Authorization"], req.Method, req.Url)
err := c.authHelper.ValidateHeader(req.Header["Authorization"], req.Method, req.Url)
if err != nil {
if !initialRequest {
c.authFailures += 1
// vlc with login prompt sends 4 requests:
// 1) without credentials
// 2) with password but without the username
// 3) without credentials
// 4) with password and username
// hence we must allow up to 3 failures
var retErr error
if c.authFailures > 3 {
c.log("ERR: unauthorized: %s", err)
retErr = errAuthCritical
} else if c.authFailures > 1 {
c.log("WARN: unauthorized: %s", err)
retErr = errAuthNotCritical
} else {
retErr = errAuthNotCritical
}
c.conn.WriteResponse(&gortsplib.Response{
StatusCode: gortsplib.StatusUnauthorized,
Header: gortsplib.Header{
"CSeq": req.Header["CSeq"],
"WWW-Authenticate": (*auth).GenerateHeader(),
"WWW-Authenticate": c.authHelper.GenerateHeader(),
},
})
if !initialRequest {
return errAuthCritical
}
return errAuthNotCritical
return retErr
}
// reset authFailures after a successful login
c.authFailures = 0
return nil
}()
if err != nil {
@ -297,18 +331,6 @@ func (c *serverClient) validateAuth(req *gortsplib.Request, user string, pass st @@ -297,18 +331,6 @@ func (c *serverClient) validateAuth(req *gortsplib.Request, user string, pass st
return nil
}
func (c *serverClient) findConfForPath(path string) *ConfPath {
if pconf, ok := c.p.conf.Paths[path]; ok {
return pconf
}
if pconf, ok := c.p.conf.Paths["all"]; ok {
return pconf
}
return nil
}
func (c *serverClient) handleRequest(req *gortsplib.Request) bool {
c.log(string(req.Method))
@ -370,7 +392,7 @@ func (c *serverClient) handleRequest(req *gortsplib.Request) bool { @@ -370,7 +392,7 @@ func (c *serverClient) handleRequest(req *gortsplib.Request) bool {
return false
}
err := c.validateAuth(req, pconf.ReadUser, pconf.ReadPass, &c.readAuth, pconf.readIps)
err := c.authenticate(pconf.readIpsParsed, pconf.ReadUser, pconf.ReadPass, req)
if err != nil {
if err == errAuthCritical {
return false
@ -411,7 +433,7 @@ func (c *serverClient) handleRequest(req *gortsplib.Request) bool { @@ -411,7 +433,7 @@ func (c *serverClient) handleRequest(req *gortsplib.Request) bool {
return false
}
err := c.validateAuth(req, pconf.PublishUser, pconf.PublishPass, &c.publishAuth, pconf.publishIps)
err := c.authenticate(pconf.publishIpsParsed, pconf.PublishUser, pconf.PublishPass, req)
if err != nil {
if err == errAuthCritical {
return false
@ -484,7 +506,7 @@ func (c *serverClient) handleRequest(req *gortsplib.Request) bool { @@ -484,7 +506,7 @@ func (c *serverClient) handleRequest(req *gortsplib.Request) bool {
return false
}
err := c.validateAuth(req, pconf.ReadUser, pconf.ReadPass, &c.readAuth, pconf.readIps)
err := c.authenticate(pconf.readIpsParsed, pconf.ReadUser, pconf.ReadPass, req)
if err != nil {
if err == errAuthCritical {
return false
@ -772,7 +794,7 @@ func (c *serverClient) handleRequest(req *gortsplib.Request) bool { @@ -772,7 +794,7 @@ func (c *serverClient) handleRequest(req *gortsplib.Request) bool {
if c.streamProtocol == _STREAM_PROTOCOL_TCP {
// write RTP frames sequentially
go func() {
for frame := range c.writec {
for frame := range c.writeChan {
c.conn.WriteInterleavedFrame(frame)
}
}()

12
server-udpl.go

@ -21,8 +21,8 @@ type serverUdpListener struct { @@ -21,8 +21,8 @@ type serverUdpListener struct {
writeBuf2 []byte
writeCurBuf bool
writec chan *udpWrite
done chan struct{}
writeChan chan *udpWrite
done chan struct{}
}
func newServerUdpListener(p *program, port int, trackFlowType trackFlowType) (*serverUdpListener, error) {
@ -41,7 +41,7 @@ func newServerUdpListener(p *program, port int, trackFlowType trackFlowType) (*s @@ -41,7 +41,7 @@ func newServerUdpListener(p *program, port int, trackFlowType trackFlowType) (*s
readBuf2: make([]byte, 2048),
writeBuf1: make([]byte, 2048),
writeBuf2: make([]byte, 2048),
writec: make(chan *udpWrite),
writeChan: make(chan *udpWrite),
done: make(chan struct{}),
}
@ -61,7 +61,7 @@ func (l *serverUdpListener) log(format string, args ...interface{}) { @@ -61,7 +61,7 @@ func (l *serverUdpListener) log(format string, args ...interface{}) {
func (l *serverUdpListener) run() {
go func() {
for w := range l.writec {
for w := range l.writeChan {
l.nconn.SetWriteDeadline(time.Now().Add(l.p.conf.WriteTimeout))
l.nconn.WriteTo(w.buf, w.addr)
}
@ -88,7 +88,7 @@ func (l *serverUdpListener) run() { @@ -88,7 +88,7 @@ func (l *serverUdpListener) run() {
}
}
close(l.writec)
close(l.writeChan)
close(l.done)
}
@ -110,7 +110,7 @@ func (l *serverUdpListener) write(addr *net.UDPAddr, inbuf []byte) { @@ -110,7 +110,7 @@ func (l *serverUdpListener) write(addr *net.UDPAddr, inbuf []byte) {
copy(buf, inbuf)
l.writeCurBuf = !l.writeCurBuf
l.writec <- &udpWrite{
l.writeChan <- &udpWrite{
addr: addr,
buf: buf,
}

Loading…
Cancel
Save