Public IP endpoint with GET /ip fixing #319
This commit is contained in:
@@ -267,7 +267,7 @@ func _main(background context.Context, args []string) int { //nolint:gocognit,go
|
|||||||
controlServerAddress := fmt.Sprintf("0.0.0.0:%d", allSettings.ControlServer.Port)
|
controlServerAddress := fmt.Sprintf("0.0.0.0:%d", allSettings.ControlServer.Port)
|
||||||
controlServerLogging := allSettings.ControlServer.Log
|
controlServerLogging := allSettings.ControlServer.Log
|
||||||
httpServer := server.New(controlServerAddress, controlServerLogging,
|
httpServer := server.New(controlServerAddress, controlServerLogging,
|
||||||
logger, buildInfo, openvpnLooper, unboundLooper, updaterLooper)
|
logger, buildInfo, openvpnLooper, unboundLooper, updaterLooper, publicIPLooper)
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go httpServer.Run(ctx, wg)
|
go httpServer.Run(ctx, wg)
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package publicip
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -18,6 +19,7 @@ type Looper interface {
|
|||||||
Stop()
|
Stop()
|
||||||
GetPeriod() (period time.Duration)
|
GetPeriod() (period time.Duration)
|
||||||
SetPeriod(period time.Duration)
|
SetPeriod(period time.Duration)
|
||||||
|
GetPublicIP() (publicIP net.IP)
|
||||||
}
|
}
|
||||||
|
|
||||||
type looper struct {
|
type looper struct {
|
||||||
@@ -26,6 +28,8 @@ type looper struct {
|
|||||||
getter IPGetter
|
getter IPGetter
|
||||||
logger logging.Logger
|
logger logging.Logger
|
||||||
fileManager files.FileManager
|
fileManager files.FileManager
|
||||||
|
ipMutex sync.RWMutex
|
||||||
|
ip net.IP
|
||||||
ipStatusFilepath models.Filepath
|
ipStatusFilepath models.Filepath
|
||||||
uid int
|
uid int
|
||||||
gid int
|
gid int
|
||||||
@@ -115,6 +119,7 @@ func (l *looper) Run(ctx context.Context, wg *sync.WaitGroup) {
|
|||||||
l.logAndWait(ctx, err)
|
l.logAndWait(ctx, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
l.setPublicIP(ip)
|
||||||
l.logger.Info("Public IP address is %s", ip)
|
l.logger.Info("Public IP address is %s", ip)
|
||||||
const userReadWritePermissions = 0600
|
const userReadWritePermissions = 0600
|
||||||
err = l.fileManager.WriteLinesToFile(
|
err = l.fileManager.WriteLinesToFile(
|
||||||
|
|||||||
17
internal/publicip/state.go
Normal file
17
internal/publicip/state.go
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package publicip
|
||||||
|
|
||||||
|
import "net"
|
||||||
|
|
||||||
|
func (l *looper) GetPublicIP() (publicIP net.IP) {
|
||||||
|
l.ipMutex.RLock()
|
||||||
|
defer l.ipMutex.RUnlock()
|
||||||
|
publicIP = make(net.IP, len(l.ip))
|
||||||
|
copy(publicIP, l.ip)
|
||||||
|
return publicIP
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *looper) setPublicIP(publicIP net.IP) {
|
||||||
|
l.ipMutex.Lock()
|
||||||
|
defer l.ipMutex.Unlock()
|
||||||
|
l.ip = publicIP
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/qdm12/gluetun/internal/dns"
|
"github.com/qdm12/gluetun/internal/dns"
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
"github.com/qdm12/gluetun/internal/openvpn"
|
"github.com/qdm12/gluetun/internal/openvpn"
|
||||||
|
"github.com/qdm12/gluetun/internal/publicip"
|
||||||
"github.com/qdm12/gluetun/internal/updater"
|
"github.com/qdm12/gluetun/internal/updater"
|
||||||
"github.com/qdm12/golibs/logging"
|
"github.com/qdm12/golibs/logging"
|
||||||
)
|
)
|
||||||
@@ -16,15 +17,17 @@ func newHandler(logger logging.Logger, logging bool,
|
|||||||
openvpnLooper openvpn.Looper,
|
openvpnLooper openvpn.Looper,
|
||||||
unboundLooper dns.Looper,
|
unboundLooper dns.Looper,
|
||||||
updaterLooper updater.Looper,
|
updaterLooper updater.Looper,
|
||||||
|
publicIPLooper publicip.Looper,
|
||||||
) http.Handler {
|
) http.Handler {
|
||||||
handler := &handler{}
|
handler := &handler{}
|
||||||
|
|
||||||
openvpn := newOpenvpnHandler(openvpnLooper, logger)
|
openvpn := newOpenvpnHandler(openvpnLooper, logger)
|
||||||
dns := newDNSHandler(unboundLooper, logger)
|
dns := newDNSHandler(unboundLooper, logger)
|
||||||
updater := newUpdaterHandler(updaterLooper, logger)
|
updater := newUpdaterHandler(updaterLooper, logger)
|
||||||
|
publicip := newPublicIPHandler(publicIPLooper, logger)
|
||||||
|
|
||||||
handler.v0 = newHandlerV0(logger, openvpnLooper, unboundLooper, updaterLooper)
|
handler.v0 = newHandlerV0(logger, openvpnLooper, unboundLooper, updaterLooper)
|
||||||
handler.v1 = newHandlerV1(logger, buildInfo, openvpn, dns, updater)
|
handler.v1 = newHandlerV1(logger, buildInfo, openvpn, dns, updater, publicip)
|
||||||
|
|
||||||
handlerWithLog := withLogMiddleware(handler, logger, logging)
|
handlerWithLog := withLogMiddleware(handler, logger, logging)
|
||||||
handler.setLogEnabled = handlerWithLog.setEnabled
|
handler.setLogEnabled = handlerWithLog.setEnabled
|
||||||
|
|||||||
@@ -11,13 +11,14 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func newHandlerV1(logger logging.Logger, buildInfo models.BuildInformation,
|
func newHandlerV1(logger logging.Logger, buildInfo models.BuildInformation,
|
||||||
openvpn, dns, updater http.Handler) http.Handler {
|
openvpn, dns, updater, publicip http.Handler) http.Handler {
|
||||||
return &handlerV1{
|
return &handlerV1{
|
||||||
logger: logger,
|
logger: logger,
|
||||||
buildInfo: buildInfo,
|
buildInfo: buildInfo,
|
||||||
openvpn: openvpn,
|
openvpn: openvpn,
|
||||||
dns: dns,
|
dns: dns,
|
||||||
updater: updater,
|
updater: updater,
|
||||||
|
publicip: publicip,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,6 +28,7 @@ type handlerV1 struct {
|
|||||||
openvpn http.Handler
|
openvpn http.Handler
|
||||||
dns http.Handler
|
dns http.Handler
|
||||||
updater http.Handler
|
updater http.Handler
|
||||||
|
publicip http.Handler
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *handlerV1) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
func (h *handlerV1) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -39,6 +41,8 @@ func (h *handlerV1) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
h.dns.ServeHTTP(w, r)
|
h.dns.ServeHTTP(w, r)
|
||||||
case strings.HasPrefix(r.RequestURI, "/updater"):
|
case strings.HasPrefix(r.RequestURI, "/updater"):
|
||||||
h.updater.ServeHTTP(w, r)
|
h.updater.ServeHTTP(w, r)
|
||||||
|
case strings.HasPrefix(r.RequestURI, "/publicip"):
|
||||||
|
h.publicip.ServeHTTP(w, r)
|
||||||
default:
|
default:
|
||||||
errString := fmt.Sprintf("%s %s not found", r.Method, r.RequestURI)
|
errString := fmt.Sprintf("%s %s not found", r.Method, r.RequestURI)
|
||||||
http.Error(w, errString, http.StatusNotFound)
|
http.Error(w, errString, http.StatusNotFound)
|
||||||
|
|||||||
55
internal/server/publicip.go
Normal file
55
internal/server/publicip.go
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
//nolint:dupl
|
||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/publicip"
|
||||||
|
"github.com/qdm12/golibs/logging"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newPublicIPHandler(
|
||||||
|
looper publicip.Looper,
|
||||||
|
logger logging.Logger) http.Handler {
|
||||||
|
return &publicIPHandler{
|
||||||
|
looper: looper,
|
||||||
|
logger: logger,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type publicIPHandler struct {
|
||||||
|
looper publicip.Looper
|
||||||
|
logger logging.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *publicIPHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
r.RequestURI = strings.TrimPrefix(r.RequestURI, "/publicip")
|
||||||
|
switch r.RequestURI {
|
||||||
|
case "/ip":
|
||||||
|
switch r.Method {
|
||||||
|
case http.MethodGet:
|
||||||
|
h.getPublicIP(w)
|
||||||
|
default:
|
||||||
|
http.Error(w, "", http.StatusNotFound)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
http.Error(w, "", http.StatusNotFound)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type publicIPWrapper struct {
|
||||||
|
PublicIP string `json:"public_ip"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *publicIPHandler) getPublicIP(w http.ResponseWriter) {
|
||||||
|
publicIP := h.looper.GetPublicIP()
|
||||||
|
encoder := json.NewEncoder(w)
|
||||||
|
data := publicIPWrapper{PublicIP: publicIP.String()}
|
||||||
|
if err := encoder.Encode(data); err != nil {
|
||||||
|
h.logger.Warn(err)
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/qdm12/gluetun/internal/dns"
|
"github.com/qdm12/gluetun/internal/dns"
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
"github.com/qdm12/gluetun/internal/openvpn"
|
"github.com/qdm12/gluetun/internal/openvpn"
|
||||||
|
"github.com/qdm12/gluetun/internal/publicip"
|
||||||
"github.com/qdm12/gluetun/internal/updater"
|
"github.com/qdm12/gluetun/internal/updater"
|
||||||
"github.com/qdm12/golibs/logging"
|
"github.com/qdm12/golibs/logging"
|
||||||
)
|
)
|
||||||
@@ -25,9 +26,11 @@ type server struct {
|
|||||||
|
|
||||||
func New(address string, logging bool, logger logging.Logger,
|
func New(address string, logging bool, logger logging.Logger,
|
||||||
buildInfo models.BuildInformation,
|
buildInfo models.BuildInformation,
|
||||||
openvpnLooper openvpn.Looper, unboundLooper dns.Looper, updaterLooper updater.Looper) Server {
|
openvpnLooper openvpn.Looper, unboundLooper dns.Looper,
|
||||||
|
updaterLooper updater.Looper, publicIPLooper publicip.Looper) Server {
|
||||||
serverLogger := logger.WithPrefix("http server: ")
|
serverLogger := logger.WithPrefix("http server: ")
|
||||||
handler := newHandler(serverLogger, logging, buildInfo, openvpnLooper, unboundLooper, updaterLooper)
|
handler := newHandler(serverLogger, logging, buildInfo,
|
||||||
|
openvpnLooper, unboundLooper, updaterLooper, publicIPLooper)
|
||||||
return &server{
|
return &server{
|
||||||
address: address,
|
address: address,
|
||||||
logger: serverLogger,
|
logger: serverLogger,
|
||||||
|
|||||||
Reference in New Issue
Block a user