diff --git a/README.md b/README.md index 942bed6..39b7b1b 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,16 @@ These depend on which features you want to use and on whether you use homer5 or ![image](https://user-images.githubusercontent.com/20154956/54483281-ef3f5700-4850-11e9-8da1-9b8bed6186e3.png) +#### HEP input listeners +Configure the bind address for each listener in your config (flags/env/file/web): + +* `HEPAddr` - UDP HEP listener (default `0.0.0.0:9060`) +* `HEPTCPAddr` - TCP HEP listener (disabled when empty) +* `HEPTLSAddr` - TLS HEP listener (disabled when empty) +* `HEPWSAddr` - WebSocket HEP listener (disabled when empty) + +When enabling TLS, also set `TLSCertFile` and `TLSKeyFile` (and optional `TLSClientCAFile`, `TLSRequireClientCert`, `TLSMinVersion`) in the same configuration source. + To set up a systemd service, use the sample [service file](https://github.com/sipcapture/heplify-server/blob/master/example/) and follow the instructions found at the top of the file. diff --git a/config/config.go b/config/config.go index 1276069..5239afd 100644 --- a/config/config.go +++ b/config/config.go @@ -80,6 +80,9 @@ type HeplifyServer struct { ScriptEngine string `default:"lua"` ScriptFolder string `default:""` ScriptHEPFilter []int `default:"1,5,100"` - TLSCertFolder string `default:"."` - TLSMinVersion string `default:"1.2"` + TLSCertFile string `default:""` + TLSKeyFile string `default:""` + TLSClientCAFile string `default:""` + TLSRequireClientCert bool `default:"false"` + TLSMinVersion string `default:"1.2"` } diff --git a/go.mod b/go.mod index b29a6d3..c33edf8 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,6 @@ require ( github.com/golang/snappy v0.0.4 github.com/lib/pq v1.10.9 github.com/mailru/easyjson v0.7.1 // indirect - github.com/negbie/cert v0.0.0-20190324145947-d1018a8fb00f github.com/negbie/logp v0.0.0-20190313141056-04cebff7f846 github.com/negbie/multiconfig v1.0.0 github.com/olivere/elastic v6.2.33+incompatible diff --git a/go.sum b/go.sum index 1f35bd7..76aff71 100644 --- a/go.sum +++ b/go.sum @@ -878,8 +878,6 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/negbie/cert v0.0.0-20190324145947-d1018a8fb00f h1:M55iH2PERd3rI05upU5PUVeKIRHaNkjJgFtrIE0G2gU= -github.com/negbie/cert v0.0.0-20190324145947-d1018a8fb00f/go.mod h1:gu8czYryxJq/ecHYWjTXLbVSiAkxUwSNgzfPTrKEJ2k= github.com/negbie/logp v0.0.0-20190313141056-04cebff7f846 h1:PAr5hcOgvc2m71W4SlbUsAbUnea5lNjB5/DfIHW9f8Q= github.com/negbie/logp v0.0.0-20190313141056-04cebff7f846/go.mod h1:xTKf9aKLuVL0r9wxWouR+/4ctK2ywm0rTPFY2klrnOg= github.com/negbie/multiconfig v1.0.0 h1:JXrB+RYMhGS/xlXGJab/4g7AoAIo3tFrwHr8LN3i0fg= diff --git a/server/tls.go b/server/tls.go index 36c6fdf..76baa9f 100644 --- a/server/tls.go +++ b/server/tls.go @@ -2,13 +2,14 @@ package input import ( "crypto/tls" + "crypto/x509" + "fmt" "net" - "path/filepath" + "os" "sync" "sync/atomic" "time" - "github.com/negbie/cert" "github.com/negbie/logp" "github.com/sipcapture/heplify-server/config" ) @@ -46,13 +47,11 @@ func (h *HEPInput) serveTLS(addr string) { return } - // get path for certificate/key storage - cPath := config.Setting.TLSCertFolder minTLSVersion := parseTLSVersion(config.Setting.TLSMinVersion) - // load any existing certs, otherwise generate a new one - ca, err := cert.NewCertificateAuthority(filepath.Join(cPath, "heplify-server")) + + tlsConfig, err := loadTLSConfig(minTLSVersion) if err != nil { - logp.Err("%v", err) + logp.Err("TLS configuration error: %v", err) return } @@ -81,7 +80,7 @@ func (h *HEPInput) serveTLS(addr string) { logp.Info("new TLS connection %s -> %s", conn.RemoteAddr(), conn.LocalAddr()) wg.Add(1) go func() { - h.handleTLS(tls.Server(conn, &tls.Config{GetCertificate: ca.GetCertificate, MinVersion: minTLSVersion})) + h.handleTLS(tls.Server(conn, tlsConfig)) wg.Done() }() } @@ -90,3 +89,42 @@ func (h *HEPInput) serveTLS(addr string) { func (h *HEPInput) handleTLS(c net.Conn) { h.handleStream(c, "TLS") } + +func loadTLSConfig(minTLSVersion uint16) (*tls.Config, error) { + certFile := config.Setting.TLSCertFile + keyFile := config.Setting.TLSKeyFile + if certFile == "" || keyFile == "" { + return nil, fmt.Errorf("TLSCertFile and TLSKeyFile must be set for TLS termination") + } + + cert, err := tls.LoadX509KeyPair(certFile, keyFile) + if err != nil { + return nil, fmt.Errorf("load TLS certificate/key: %w", err) + } + + tlsConfig := &tls.Config{ + Certificates: []tls.Certificate{cert}, + MinVersion: minTLSVersion, + } + + if config.Setting.TLSClientCAFile != "" { + caPEM, err := os.ReadFile(config.Setting.TLSClientCAFile) + if err != nil { + return nil, fmt.Errorf("read TLSClientCAFile: %w", err) + } + caPool := x509.NewCertPool() + if ok := caPool.AppendCertsFromPEM(caPEM); !ok { + return nil, fmt.Errorf("TLSClientCAFile did not contain any valid certificates") + } + tlsConfig.ClientCAs = caPool + if config.Setting.TLSRequireClientCert { + tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert + } else { + tlsConfig.ClientAuth = tls.VerifyClientCertIfGiven + } + } else if config.Setting.TLSRequireClientCert { + return nil, fmt.Errorf("TLSClientCAFile must be set when TLSRequireClientCert is enabled") + } + + return tlsConfig, nil +}