Upd predefined client list

file is monitored an reloaded dynamically
This commit is contained in:
Hannes Tribus 2022-11-24 07:49:46 +01:00
parent 15d08c6549
commit 51e9f199e5
7 changed files with 108 additions and 36 deletions

View file

@ -190,7 +190,7 @@ Configuration options:
* `tlsCrt`: Path to a TLS certificate file, *default:* `server.crt`
* `tlsKey`: Path to a TLS key file, *default:* `server.key`
* `rootCA`: Path to the trusted certificate chian used for client certificate authentication, if empty any client certificate is accepted
* `clients`: Comma-separated list of tunnel client ids, if empty accept all clients
* `clients`: Path to a properties file that contains a list of 'host=tunnelClientId's, if empty accept all clients
* `keepAlive`: the amount of time to wait between sending keepalive packets *default:* `45s`
* `logLevel`: Level of messages to log, 0-3, *default:* 1

View file

@ -63,7 +63,7 @@ func parseArgs() *options {
tlsCrt := flag.String("tlsCrt", "server.crt", "Path to a TLS certificate file")
tlsKey := flag.String("tlsKey", "server.key", "Path to a TLS key file")
rootCA := flag.String("rootCA", "", "Path to the trusted certificate chian used for client certificate authentication, if empty any client certificate is accepted")
clients := flag.String("clients", "", "Comma-separated list of tunnel client ids, if empty accept all clients")
clients := flag.String("clients", "", "Path to a properties file that contains a list of 'host=tunnelClientId's, if empty accept all clients")
keepAlive := flag.String("keepAlive", "45s", "TCP keep alive configuration")
debounceLog := flag.String("debounceLog", "2s", "How long to keep disconnected log message before actually writing it to the log")
logLevel := flag.Int("logLevel", 1, "Level of messages to log, 0-3")

View file

@ -17,9 +17,9 @@ import (
"golang.org/x/net/http2"
"github.com/bep/debounce"
"github.com/fsnotify/fsnotify"
tunnel "github.com/hons82/go-http-tunnel"
"github.com/hons82/go-http-tunnel/connection"
"github.com/hons82/go-http-tunnel/fileutil"
"github.com/hons82/go-http-tunnel/log"
)
@ -70,14 +70,59 @@ func main() {
}
if !autoSubscribe {
clients, err := fileutil.ReadPropertiesFile(opts.clients)
if err != nil {
fatal("failed to load clients: %s", err)
}
// First load immediatly
server.LoadAllowedTunnels(opts.clients)
for host, value := range clients {
if err := server.RegisterTunnel(host, value); err != nil {
fatal("failed to load tunnel: %s with error %s", host, err)
// Watch for the file to change
watcher, err := fsnotify.NewWatcher()
if err != nil {
fatal("NewWatcher failed: %s", err)
logger.Log(
"level", 1,
"action", "could not create file watcher",
"err", err,
)
} else {
defer watcher.Close()
go func() {
for {
select {
case event, ok := <-watcher.Events:
if !ok {
return
}
logger.Log(
"level", 3,
"action", "watched file changed",
"file", event.Name,
"action", event.Op.String(),
)
if event.Op&fsnotify.Write == fsnotify.Write {
server.Clear()
server.LoadAllowedTunnels(event.Name)
}
case err, ok := <-watcher.Errors:
if !ok {
return
}
logger.Log(
"level", 2,
"action", "error watching file",
"err", err,
)
}
}
}()
err = watcher.Add(opts.clients)
if err != nil {
logger.Log(
"level", 1,
"action", "add watch failed",
"file", opts.clients,
"err", err,
)
}
}
}

1
go.mod
View file

@ -6,6 +6,7 @@ require (
github.com/bep/debounce v1.2.0
github.com/calmh/luhn v2.0.0+incompatible
github.com/cenkalti/backoff v2.1.1+incompatible
github.com/fsnotify/fsnotify v1.5.1 // indirect
github.com/golang/mock v1.2.0
github.com/inconshreveable/go-vhost v0.0.0-20160627193104-06d84117953b
golang.org/x/net v0.0.0-20171123081856-c7086645de24

4
go.sum
View file

@ -4,12 +4,16 @@ github.com/calmh/luhn v2.0.0+incompatible h1:xHkbAc8FBgMiGUaKsiYcwtf8xhSXVtRKA2N
github.com/calmh/luhn v2.0.0+incompatible/go.mod h1:70IGmMi0GKRs073gl/oH5/yiJnTt61h35YQhvo/k3Cc=
github.com/cenkalti/backoff v2.1.1+incompatible h1:tKJnvO2kl0zmb/jA5UKAt4VoEVw1qxKWjE/Bpp46npY=
github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI=
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
github.com/golang/mock v1.2.0 h1:28o5sBqPkBsMGnC6b4MvE2TzSr5/AT4c/1fLqVGIwlk=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/inconshreveable/go-vhost v0.0.0-20160627193104-06d84117953b h1:IpLPmn6Re21F0MaV6Zsc5RdSE6KuoFpWmHiUSEs3PrE=
github.com/inconshreveable/go-vhost v0.0.0-20160627193104-06d84117953b/go.mod h1:aA6DnFhALT3zH0y+A39we+zbrdMC2N0X/q21e6FI0LU=
golang.org/x/net v0.0.0-20171123081856-c7086645de24 h1:z0cmn+BVQSCN8exp26jnHqHXHIvTlqIYhjHln4k/UAU=
golang.org/x/net v0.0.0-20171123081856-c7086645de24/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.1.1-0.20171102192421-88f656faf3f3 h1:OxMYHd6bm+jH+TI7NBCb/CaYk6pMJnBC8GIzIi68Hk4=
golang.org/x/text v0.1.1-0.20171102192421-88f656faf3f3/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=

View file

@ -64,7 +64,7 @@ func (r *registry) Subscribe(identifier id.ID) {
}
r.logger.Log(
"level", 1,
"level", 2,
"action", "subscribe",
"identifier", identifier,
)
@ -103,17 +103,17 @@ func (r *registry) HasTunnel(hostPort string, identifier id.ID) bool {
}
// Unsubscribe removes client from registry and returns it's RegistryItem.
func (r *registry) Unsubscribe(identifier id.ID) *RegistryItem {
func (r *registry) Unsubscribe(identifier id.ID, autoSubscribe bool) *RegistryItem {
r.mu.Lock()
defer r.mu.Unlock()
i, ok := r.items[identifier]
if !ok {
if !ok || (autoSubscribe && i == voidRegistryItem) {
return nil
}
r.logger.Log(
"level", 1,
"level", 2,
"action", "unsubscribe",
"identifier", identifier,
)
@ -124,7 +124,11 @@ func (r *registry) Unsubscribe(identifier id.ID) *RegistryItem {
}
}
delete(r.items, identifier)
if autoSubscribe {
delete(r.items, identifier)
} else {
r.items[identifier] = voidRegistryItem
}
return i
}
@ -174,9 +178,10 @@ func (r *registry) RegisterTunnel(host string, client string) error {
identifier := id.New([]byte(client))
r.logger.Log(
"level", 2,
"action", "add tunnel",
"level", 3,
"action", "register tunnel",
"host", host,
"client", client,
"identifier", identifier,
)
@ -199,24 +204,23 @@ func (r *registry) RegisterTunnel(host string, client string) error {
return nil
}
func (r *registry) clear(identifier id.ID) *RegistryItem {
// Clear removes all items from the registry
func (r *registry) Clear() {
r.logger.Log(
"level", 2,
"action", "clear registry item",
"identifier", identifier,
"level", 3,
"action", "clear registry ",
)
r.mu.Lock()
defer r.mu.Unlock()
i, ok := r.items[identifier]
if !ok || i == voidRegistryItem {
return nil
for k := range r.hosts {
delete(r.hosts, k)
}
r.items[identifier] = voidRegistryItem
return i
for i := range r.items {
delete(r.items, i)
}
}
func trimPort(hostPort string) (host string) {

View file

@ -20,6 +20,7 @@ import (
"golang.org/x/net/http2"
"github.com/hons82/go-http-tunnel/connection"
"github.com/hons82/go-http-tunnel/fileutil"
"github.com/hons82/go-http-tunnel/id"
"github.com/hons82/go-http-tunnel/log"
"github.com/hons82/go-http-tunnel/proto"
@ -201,7 +202,7 @@ func (s *Server) disconnected(identifier id.ID) {
)
}
i := s.unsubscribe(identifier)
i := s.registry.Unsubscribe(identifier, s.config.AutoSubscribe)
if i == nil {
return
}
@ -216,13 +217,6 @@ func (s *Server) disconnected(identifier id.ID) {
}
}
func (s *Server) unsubscribe(identifier id.ID) *RegistryItem {
if s.config.AutoSubscribe {
return s.registry.Unsubscribe(identifier)
}
return s.registry.clear(identifier)
}
// Start starts accepting connections form clients. For accepting http traffic
// from end users server must be run as handler on http server.
func (s *Server) Start() {
@ -473,6 +467,30 @@ reject:
conn.Close()
}
// LoadAllowedTunnels registers allowed tunnels from a file
func (s *Server) LoadAllowedTunnels(propertiesFile string) {
clients, err := fileutil.ReadPropertiesFile(propertiesFile)
if err != nil {
s.logger.Log(
"level", 1,
"action", "failed to load clients",
"err", err,
)
return
}
for host, value := range clients {
if err := s.RegisterTunnel(host, value); err != nil {
s.logger.Log(
"level", 2,
"action", "failed to load tunnel",
"host", host,
"err", err,
)
}
}
}
// notifyError tries to send error to client.
func (s *Server) notifyError(serverError error, identifier id.ID) {
if serverError == nil {
@ -592,7 +610,7 @@ func (s *Server) Unsubscribe(identifier id.ID) *RegistryItem {
s.config.SubscriptionListener.Unsubscribed(identifier)
}
s.connPool.DeleteConn(identifier)
return s.registry.Unsubscribe(identifier)
return s.registry.Unsubscribe(identifier, s.config.AutoSubscribe)
}
// Ping measures the RTT response time.