mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-18 08:16:39 +00:00
add debug logging for proxy connections and domain resolution
- Log proxy address and cluster info when proxy connects - Log connected proxy URLs when GetConnectedProxyURLs is called - Log proxy allow list when GetDomains is called - Helps debug issues with free domains not appearing in API response
This commit is contained in:
@@ -58,21 +58,31 @@ func NewManager(store store, proxyURLProvider proxyURLProvider) Manager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m Manager) GetDomains(ctx context.Context, accountID string) ([]*Domain, error) {
|
func (m Manager) GetDomains(ctx context.Context, accountID string) ([]*Domain, error) {
|
||||||
account, err := m.store.GetAccount(ctx, accountID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("get account: %w", err)
|
|
||||||
}
|
|
||||||
free, err := m.store.ListFreeDomains(ctx, accountID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("list free domains: %w", err)
|
|
||||||
}
|
|
||||||
domains, err := m.store.ListCustomDomains(ctx, accountID)
|
domains, err := m.store.ListCustomDomains(ctx, accountID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("list custom domains: %w", err)
|
return nil, fmt.Errorf("list custom domains: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var ret []*Domain
|
var ret []*Domain
|
||||||
// Populate all fields correctly for custom domains that are retrieved.
|
|
||||||
|
// Add connected proxy clusters as free domains.
|
||||||
|
// The cluster address itself is the free domain base (e.g., "eu.proxy.netbird.io").
|
||||||
|
allowList := m.proxyURLAllowList()
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"accountID": accountID,
|
||||||
|
"proxyAllowList": allowList,
|
||||||
|
}).Debug("getting domains with proxy allow list")
|
||||||
|
|
||||||
|
for _, cluster := range allowList {
|
||||||
|
ret = append(ret, &Domain{
|
||||||
|
Domain: cluster,
|
||||||
|
AccountID: accountID,
|
||||||
|
Type: TypeFree,
|
||||||
|
Validated: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add custom domains.
|
||||||
for _, domain := range domains {
|
for _, domain := range domains {
|
||||||
ret = append(ret, &Domain{
|
ret = append(ret, &Domain{
|
||||||
ID: domain.ID,
|
ID: domain.ID,
|
||||||
@@ -83,19 +93,6 @@ func (m Manager) GetDomains(ctx context.Context, accountID string) ([]*Domain, e
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepend each free domain with the account nonce and then add it to the domain
|
|
||||||
// array to be returned.
|
|
||||||
// This account nonce is added to free domains to prevent users being able to
|
|
||||||
// query free domain usage across accounts and simplifies tracking free domain
|
|
||||||
// usage across accounts.
|
|
||||||
for _, name := range free {
|
|
||||||
ret = append(ret, &Domain{
|
|
||||||
Domain: account.ReverseProxyFreeDomainNonce + "." + name,
|
|
||||||
AccountID: accountID,
|
|
||||||
Type: TypeFree,
|
|
||||||
Validated: true,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return ret, nil
|
return ret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,8 +237,3 @@ func (m Manager) DeriveClusterFromDomain(ctx context.Context, domain string) (st
|
|||||||
|
|
||||||
return "", fmt.Errorf("domain %s does not match any available proxy cluster", domain)
|
return "", fmt.Errorf("domain %s does not match any available proxy cluster", domain)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAvailableClusters returns a list of available proxy cluster addresses.
|
|
||||||
func (m Manager) GetAvailableClusters() []string {
|
|
||||||
return m.proxyURLAllowList()
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -10,27 +10,20 @@ import (
|
|||||||
"github.com/netbirdio/netbird/management/internals/modules/reverseproxy/accesslogs"
|
"github.com/netbirdio/netbird/management/internals/modules/reverseproxy/accesslogs"
|
||||||
accesslogsmanager "github.com/netbirdio/netbird/management/internals/modules/reverseproxy/accesslogs/manager"
|
accesslogsmanager "github.com/netbirdio/netbird/management/internals/modules/reverseproxy/accesslogs/manager"
|
||||||
"github.com/netbirdio/netbird/management/internals/modules/reverseproxy/domain"
|
"github.com/netbirdio/netbird/management/internals/modules/reverseproxy/domain"
|
||||||
nbgrpc "github.com/netbirdio/netbird/management/internals/shared/grpc"
|
|
||||||
nbcontext "github.com/netbirdio/netbird/management/server/context"
|
nbcontext "github.com/netbirdio/netbird/management/server/context"
|
||||||
"github.com/netbirdio/netbird/shared/management/http/api"
|
"github.com/netbirdio/netbird/shared/management/http/api"
|
||||||
"github.com/netbirdio/netbird/shared/management/http/util"
|
"github.com/netbirdio/netbird/shared/management/http/util"
|
||||||
"github.com/netbirdio/netbird/shared/management/status"
|
"github.com/netbirdio/netbird/shared/management/status"
|
||||||
)
|
)
|
||||||
|
|
||||||
type clusterProvider interface {
|
|
||||||
GetAvailableClusters() []nbgrpc.ClusterInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
type handler struct {
|
type handler struct {
|
||||||
manager reverseproxy.Manager
|
manager reverseproxy.Manager
|
||||||
clusterProvider clusterProvider
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// RegisterEndpoints registers all reverse proxy HTTP endpoints.
|
// RegisterEndpoints registers all reverse proxy HTTP endpoints.
|
||||||
func RegisterEndpoints(manager reverseproxy.Manager, domainManager domain.Manager, accessLogsManager accesslogs.Manager, clusterProvider clusterProvider, router *mux.Router) {
|
func RegisterEndpoints(manager reverseproxy.Manager, domainManager domain.Manager, accessLogsManager accesslogs.Manager, router *mux.Router) {
|
||||||
h := &handler{
|
h := &handler{
|
||||||
manager: manager,
|
manager: manager,
|
||||||
clusterProvider: clusterProvider,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
domainRouter := router.PathPrefix("/reverse-proxies").Subrouter()
|
domainRouter := router.PathPrefix("/reverse-proxies").Subrouter()
|
||||||
@@ -40,7 +33,6 @@ func RegisterEndpoints(manager reverseproxy.Manager, domainManager domain.Manage
|
|||||||
|
|
||||||
router.HandleFunc("/reverse-proxies", h.getAllReverseProxies).Methods("GET", "OPTIONS")
|
router.HandleFunc("/reverse-proxies", h.getAllReverseProxies).Methods("GET", "OPTIONS")
|
||||||
router.HandleFunc("/reverse-proxies", h.createReverseProxy).Methods("POST", "OPTIONS")
|
router.HandleFunc("/reverse-proxies", h.createReverseProxy).Methods("POST", "OPTIONS")
|
||||||
router.HandleFunc("/reverse-proxies/clusters", h.getAvailableClusters).Methods("GET", "OPTIONS")
|
|
||||||
router.HandleFunc("/reverse-proxies/{proxyId}", h.getReverseProxy).Methods("GET", "OPTIONS")
|
router.HandleFunc("/reverse-proxies/{proxyId}", h.getReverseProxy).Methods("GET", "OPTIONS")
|
||||||
router.HandleFunc("/reverse-proxies/{proxyId}", h.updateReverseProxy).Methods("PUT", "OPTIONS")
|
router.HandleFunc("/reverse-proxies/{proxyId}", h.updateReverseProxy).Methods("PUT", "OPTIONS")
|
||||||
router.HandleFunc("/reverse-proxies/{proxyId}", h.deleteReverseProxy).Methods("DELETE", "OPTIONS")
|
router.HandleFunc("/reverse-proxies/{proxyId}", h.deleteReverseProxy).Methods("DELETE", "OPTIONS")
|
||||||
@@ -176,22 +168,3 @@ func (h *handler) deleteReverseProxy(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
util.WriteJSONObject(r.Context(), w, util.EmptyObject{})
|
util.WriteJSONObject(r.Context(), w, util.EmptyObject{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *handler) getAvailableClusters(w http.ResponseWriter, r *http.Request) {
|
|
||||||
_, err := nbcontext.GetUserAuthFromContext(r.Context())
|
|
||||||
if err != nil {
|
|
||||||
util.WriteError(r.Context(), err, w)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
clusters := h.clusterProvider.GetAvailableClusters()
|
|
||||||
apiClusters := make([]api.ProxyCluster, 0, len(clusters))
|
|
||||||
for _, c := range clusters {
|
|
||||||
apiClusters = append(apiClusters, api.ProxyCluster{
|
|
||||||
Address: c.Address,
|
|
||||||
ConnectedProxies: c.ConnectedProxies,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
util.WriteJSONObject(r.Context(), w, apiClusters)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ func (s *BaseServer) EventStore() activity.Store {
|
|||||||
|
|
||||||
func (s *BaseServer) APIHandler() http.Handler {
|
func (s *BaseServer) APIHandler() http.Handler {
|
||||||
return Create(s, func() http.Handler {
|
return Create(s, func() http.Handler {
|
||||||
httpAPIHandler, err := nbhttp.NewAPIHandler(context.Background(), s.AccountManager(), s.NetworksManager(), s.ResourcesManager(), s.RoutesManager(), s.GroupsManager(), s.GeoLocationManager(), s.AuthManager(), s.Metrics(), s.IntegratedValidator(), s.ProxyController(), s.PermissionsManager(), s.PeersManager(), s.SettingsManager(), s.ZonesManager(), s.RecordsManager(), s.NetworkMapController(), s.IdpManager(), s.ReverseProxyManager(), s.ReverseProxyDomainManager(), s.AccessLogsManager(), s.ReverseProxyGRPCServer())
|
httpAPIHandler, err := nbhttp.NewAPIHandler(context.Background(), s.AccountManager(), s.NetworksManager(), s.ResourcesManager(), s.RoutesManager(), s.GroupsManager(), s.GeoLocationManager(), s.AuthManager(), s.Metrics(), s.IntegratedValidator(), s.ProxyController(), s.PermissionsManager(), s.PeersManager(), s.SettingsManager(), s.ZonesManager(), s.RecordsManager(), s.NetworkMapController(), s.IdpManager(), s.ReverseProxyManager(), s.ReverseProxyDomainManager(), s.AccessLogsManager())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("failed to create API handler: %v", err)
|
log.Fatalf("failed to create API handler: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -112,13 +112,18 @@ func (s *ProxyServiceServer) GetMappingUpdate(req *proto.GetMappingUpdateRequest
|
|||||||
return status.Errorf(codes.InvalidArgument, "proxy_id is required")
|
return status.Errorf(codes.InvalidArgument, "proxy_id is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("Proxy %s connected (version: %s, started: %s)",
|
proxyAddress := req.GetAddress()
|
||||||
proxyID, req.GetVersion(), req.GetStartedAt().AsTime())
|
log.WithFields(log.Fields{
|
||||||
|
"proxy_id": proxyID,
|
||||||
|
"address": proxyAddress,
|
||||||
|
"version": req.GetVersion(),
|
||||||
|
"started": req.GetStartedAt().AsTime(),
|
||||||
|
}).Info("Proxy connected")
|
||||||
|
|
||||||
connCtx, cancel := context.WithCancel(ctx)
|
connCtx, cancel := context.WithCancel(ctx)
|
||||||
conn := &proxyConnection{
|
conn := &proxyConnection{
|
||||||
proxyID: proxyID,
|
proxyID: proxyID,
|
||||||
address: req.GetAddress(),
|
address: proxyAddress,
|
||||||
stream: stream,
|
stream: stream,
|
||||||
sendChan: make(chan *proto.ProxyMapping, 100),
|
sendChan: make(chan *proto.ProxyMapping, 100),
|
||||||
ctx: connCtx,
|
ctx: connCtx,
|
||||||
@@ -127,6 +132,12 @@ func (s *ProxyServiceServer) GetMappingUpdate(req *proto.GetMappingUpdateRequest
|
|||||||
|
|
||||||
s.connectedProxies.Store(proxyID, conn)
|
s.connectedProxies.Store(proxyID, conn)
|
||||||
s.addToCluster(conn.address, proxyID)
|
s.addToCluster(conn.address, proxyID)
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"proxy_id": proxyID,
|
||||||
|
"address": proxyAddress,
|
||||||
|
"cluster_addr": extractClusterAddr(proxyAddress),
|
||||||
|
"total_proxies": len(s.GetConnectedProxies()),
|
||||||
|
}).Info("Proxy registered in cluster")
|
||||||
defer func() {
|
defer func() {
|
||||||
s.connectedProxies.Delete(proxyID)
|
s.connectedProxies.Delete(proxyID)
|
||||||
s.removeFromCluster(conn.address, proxyID)
|
s.removeFromCluster(conn.address, proxyID)
|
||||||
@@ -306,14 +317,25 @@ func (s *ProxyServiceServer) GetConnectedProxies() []string {
|
|||||||
func (s *ProxyServiceServer) GetConnectedProxyURLs() []string {
|
func (s *ProxyServiceServer) GetConnectedProxyURLs() []string {
|
||||||
seenUrls := make(map[string]struct{})
|
seenUrls := make(map[string]struct{})
|
||||||
var urls []string
|
var urls []string
|
||||||
|
var proxyCount int
|
||||||
s.connectedProxies.Range(func(key, value interface{}) bool {
|
s.connectedProxies.Range(func(key, value interface{}) bool {
|
||||||
|
proxyCount++
|
||||||
conn := value.(*proxyConnection)
|
conn := value.(*proxyConnection)
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"proxy_id": conn.proxyID,
|
||||||
|
"address": conn.address,
|
||||||
|
}).Debug("checking connected proxy for URL")
|
||||||
if _, seen := seenUrls[conn.address]; conn.address != "" && !seen {
|
if _, seen := seenUrls[conn.address]; conn.address != "" && !seen {
|
||||||
seenUrls[conn.address] = struct{}{}
|
seenUrls[conn.address] = struct{}{}
|
||||||
urls = append(urls, conn.address)
|
urls = append(urls, conn.address)
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"total_proxies": proxyCount,
|
||||||
|
"unique_urls": len(urls),
|
||||||
|
"connected_urls": urls,
|
||||||
|
}).Debug("GetConnectedProxyURLs result")
|
||||||
return urls
|
return urls
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ import (
|
|||||||
"github.com/netbirdio/netbird/management/internals/modules/reverseproxy/accesslogs"
|
"github.com/netbirdio/netbird/management/internals/modules/reverseproxy/accesslogs"
|
||||||
"github.com/netbirdio/netbird/management/internals/modules/reverseproxy/domain"
|
"github.com/netbirdio/netbird/management/internals/modules/reverseproxy/domain"
|
||||||
reverseproxymanager "github.com/netbirdio/netbird/management/internals/modules/reverseproxy/manager"
|
reverseproxymanager "github.com/netbirdio/netbird/management/internals/modules/reverseproxy/manager"
|
||||||
nbgrpc "github.com/netbirdio/netbird/management/internals/shared/grpc"
|
|
||||||
idpmanager "github.com/netbirdio/netbird/management/server/idp"
|
idpmanager "github.com/netbirdio/netbird/management/server/idp"
|
||||||
|
|
||||||
"github.com/netbirdio/management-integrations/integrations"
|
"github.com/netbirdio/management-integrations/integrations"
|
||||||
@@ -64,13 +63,8 @@ const (
|
|||||||
rateLimitingRPMKey = "NB_API_RATE_LIMITING_RPM"
|
rateLimitingRPMKey = "NB_API_RATE_LIMITING_RPM"
|
||||||
)
|
)
|
||||||
|
|
||||||
// clusterProvider provides access to available proxy clusters.
|
|
||||||
type clusterProvider interface {
|
|
||||||
GetAvailableClusters() []nbgrpc.ClusterInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewAPIHandler creates the Management service HTTP API handler registering all the available endpoints.
|
// NewAPIHandler creates the Management service HTTP API handler registering all the available endpoints.
|
||||||
func NewAPIHandler(ctx context.Context, accountManager account.Manager, networksManager nbnetworks.Manager, resourceManager resources.Manager, routerManager routers.Manager, groupsManager nbgroups.Manager, LocationManager geolocation.Geolocation, authManager auth.Manager, appMetrics telemetry.AppMetrics, integratedValidator integrated_validator.IntegratedValidator, proxyController port_forwarding.Controller, permissionsManager permissions.Manager, peersManager nbpeers.Manager, settingsManager settings.Manager, zManager zones.Manager, rManager records.Manager, networkMapController network_map.Controller, idpManager idpmanager.Manager, reverseProxyManager reverseproxy.Manager, reverseProxyDomainManager *domain.Manager, reverseProxyAccessLogsManager accesslogs.Manager, proxyClusterProvider clusterProvider) (http.Handler, error) {
|
func NewAPIHandler(ctx context.Context, accountManager account.Manager, networksManager nbnetworks.Manager, resourceManager resources.Manager, routerManager routers.Manager, groupsManager nbgroups.Manager, LocationManager geolocation.Geolocation, authManager auth.Manager, appMetrics telemetry.AppMetrics, integratedValidator integrated_validator.IntegratedValidator, proxyController port_forwarding.Controller, permissionsManager permissions.Manager, peersManager nbpeers.Manager, settingsManager settings.Manager, zManager zones.Manager, rManager records.Manager, networkMapController network_map.Controller, idpManager idpmanager.Manager, reverseProxyManager reverseproxy.Manager, reverseProxyDomainManager *domain.Manager, reverseProxyAccessLogsManager accesslogs.Manager) (http.Handler, error) {
|
||||||
|
|
||||||
// Register bypass paths for unauthenticated endpoints
|
// Register bypass paths for unauthenticated endpoints
|
||||||
if err := bypass.AddBypassPath("/api/instance"); err != nil {
|
if err := bypass.AddBypassPath("/api/instance"); err != nil {
|
||||||
@@ -167,7 +161,7 @@ func NewAPIHandler(ctx context.Context, accountManager account.Manager, networks
|
|||||||
instance.AddEndpoints(instanceManager, router)
|
instance.AddEndpoints(instanceManager, router)
|
||||||
instance.AddVersionEndpoint(instanceManager, router)
|
instance.AddVersionEndpoint(instanceManager, router)
|
||||||
if reverseProxyManager != nil && reverseProxyDomainManager != nil {
|
if reverseProxyManager != nil && reverseProxyDomainManager != nil {
|
||||||
reverseproxymanager.RegisterEndpoints(reverseProxyManager, *reverseProxyDomainManager, reverseProxyAccessLogsManager, proxyClusterProvider, router)
|
reverseproxymanager.RegisterEndpoints(reverseProxyManager, *reverseProxyDomainManager, reverseProxyAccessLogsManager, router)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mount embedded IdP handler at /oauth2 path if configured
|
// Mount embedded IdP handler at /oauth2 path if configured
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ func BuildApiBlackBoxWithDBState(t testing_tools.TB, sqlFile string, expectedPee
|
|||||||
customZonesManager := zonesManager.NewManager(store, am, permissionsManager, "")
|
customZonesManager := zonesManager.NewManager(store, am, permissionsManager, "")
|
||||||
zoneRecordsManager := recordsManager.NewManager(store, am, permissionsManager)
|
zoneRecordsManager := recordsManager.NewManager(store, am, permissionsManager)
|
||||||
|
|
||||||
apiHandler, err := http2.NewAPIHandler(context.Background(), am, networksManagerMock, resourcesManagerMock, routersManagerMock, groupsManagerMock, geoMock, authManagerMock, metrics, validatorMock, proxyController, permissionsManager, peersManager, settingsManager, customZonesManager, zoneRecordsManager, networkMapController, nil, nil, nil, nil, nil)
|
apiHandler, err := http2.NewAPIHandler(context.Background(), am, networksManagerMock, resourcesManagerMock, routersManagerMock, groupsManagerMock, geoMock, authManagerMock, metrics, validatorMock, proxyController, permissionsManager, peersManager, settingsManager, customZonesManager, zoneRecordsManager, networkMapController, nil, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create API handler: %v", err)
|
t.Fatalf("Failed to create API handler: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user