diff --git a/README.md b/README.md index 2136bb1d..1d134387 100644 --- a/README.md +++ b/README.md @@ -377,6 +377,7 @@ A built-in HTTP server listens on port `8000` to modify the state of the contain - `http://:8000/openvpn/actions/restart` restarts the openvpn process - `http://:8000/unbound/actions/restart` re-downloads the DNS files (crypto and block lists) and restarts the unbound process +- `http://:8000/openvpn/portforwarded` to get your port forwarded as JSON. You can use **jq** to parse JSON on linux. ## Development and contributing diff --git a/cmd/gluetun/main.go b/cmd/gluetun/main.go index 01934fa2..b7b189cf 100644 --- a/cmd/gluetun/main.go +++ b/cmd/gluetun/main.go @@ -129,6 +129,7 @@ func _main(background context.Context, args []string) int { ovpnConf, firewallConf, logger, client, fileManager, streamMerger, fatalOnError) restartOpenvpn := openvpnLooper.Restart portForward := openvpnLooper.PortForward + getPortForwarded := openvpnLooper.GetPortForwarded // wait for restartOpenvpn go openvpnLooper.Run(ctx, wg) @@ -176,7 +177,7 @@ func _main(background context.Context, args []string) int { } }() - httpServer := server.New("0.0.0.0:8000", logger, restartOpenvpn, restartUnbound) + httpServer := server.New("0.0.0.0:8000", logger, restartOpenvpn, restartUnbound, getPortForwarded) go httpServer.Run(ctx, wg) // Start openvpn for the first time diff --git a/internal/openvpn/loop.go b/internal/openvpn/loop.go index 648578b5..8185141d 100644 --- a/internal/openvpn/loop.go +++ b/internal/openvpn/loop.go @@ -23,13 +23,16 @@ type Looper interface { PortForward() GetSettings() (settings settings.OpenVPN) SetSettings(settings settings.OpenVPN) + GetPortForwarded() (portForwarded uint16) } type looper struct { // Variable parameters - provider models.VPNProvider - settings settings.OpenVPN - settingsMutex sync.RWMutex + provider models.VPNProvider + settings settings.OpenVPN + settingsMutex sync.RWMutex + portForwarded uint16 + portForwardedMutex sync.RWMutex // Fixed parameters uid int gid int @@ -187,11 +190,14 @@ func (l *looper) portForward(ctx context.Context, providerConf provider.Provider port, err = providerConf.GetPortForward(client) if err != nil { l.logAndWait(ctx, err) - continue } - l.logger.Info("port forwarded is %d", port) } + l.logger.Info("port forwarded is %d", port) + l.portForwardedMutex.Lock() + l.portForwarded = port + l.portForwardedMutex.Unlock() + filepath := settings.Provider.PortForwarding.Filepath l.logger.Info("writing forwarded port to %s", filepath) err = l.fileManager.WriteLinesToFile( @@ -206,3 +212,9 @@ func (l *looper) portForward(ctx context.Context, providerConf provider.Provider l.logger.Error(err) } } + +func (l *looper) GetPortForwarded() (portForwarded uint16) { + l.portForwardedMutex.RLock() + defer l.portForwardedMutex.RUnlock() + return l.portForwarded +} diff --git a/internal/server/openvpn.go b/internal/server/openvpn.go new file mode 100644 index 00000000..0f28e194 --- /dev/null +++ b/internal/server/openvpn.go @@ -0,0 +1,23 @@ +package server + +import ( + "encoding/json" + "net/http" +) + +func (s *server) handleGetPortForwarded(w http.ResponseWriter) { + port := s.getPortForwarded() + data, err := json.Marshal(struct { + Port uint16 `json:"port"` + }{port}) + if err != nil { + s.logger.Warn(err) + w.WriteHeader(http.StatusInternalServerError) + return + } + if _, err := w.Write(data); err != nil { + s.logger.Warn(err) + w.WriteHeader(http.StatusInternalServerError) + } +} + diff --git a/internal/server/server.go b/internal/server/server.go index 65b055c4..48ab5043 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -15,18 +15,21 @@ type Server interface { } type server struct { - address string - logger logging.Logger - restartOpenvpn func() - restartUnbound func() + address string + logger logging.Logger + restartOpenvpn func() + restartUnbound func() + getPortForwarded func() uint16 } -func New(address string, logger logging.Logger, restartOpenvpn, restartUnbound func()) Server { +func New(address string, logger logging.Logger, restartOpenvpn, restartUnbound func(), + getPortForwarded func() uint16) Server { return &server{ - address: address, - logger: logger.WithPrefix("http server: "), - restartOpenvpn: restartOpenvpn, - restartUnbound: restartUnbound, + address: address, + logger: logger.WithPrefix("http server: "), + restartOpenvpn: restartOpenvpn, + restartUnbound: restartUnbound, + getPortForwarded: getPortForwarded, } } @@ -61,6 +64,8 @@ func (s *server) makeHandler() http.HandlerFunc { s.restartOpenvpn() case "/unbound/actions/restart": s.restartUnbound() + case "/openvpn/portforwarded": + s.handleGetPortForwarded(w) default: routeDoesNotExist(s.logger, w, r) }