mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-25 11:46:40 +00:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5de61f3081 | ||
|
|
541e258639 | ||
|
|
34042b8171 | ||
|
|
a72ef1af39 | ||
|
|
980a6eca8e |
@@ -9,7 +9,7 @@ RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
|
|||||||
libayatana-appindicator3-dev=0.5.5-2+deb11u2 \
|
libayatana-appindicator3-dev=0.5.5-2+deb11u2 \
|
||||||
&& apt-get clean \
|
&& apt-get clean \
|
||||||
&& rm -rf /var/lib/apt/lists/* \
|
&& rm -rf /var/lib/apt/lists/* \
|
||||||
&& go install -v golang.org/x/tools/gopls@latest
|
&& go install -v golang.org/x/tools/gopls@v0.18.1
|
||||||
|
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import (
|
|||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
|
|
||||||
gstatus "google.golang.org/grpc/status"
|
gstatus "google.golang.org/grpc/status"
|
||||||
"google.golang.org/protobuf/types/known/durationpb"
|
"google.golang.org/protobuf/types/known/durationpb"
|
||||||
|
|
||||||
@@ -242,7 +243,11 @@ func runInDaemonMode(ctx context.Context, cmd *cobra.Command, pm *profilemanager
|
|||||||
// set the new config
|
// set the new config
|
||||||
req := setupSetConfigReq(customDNSAddressConverted, cmd, activeProf.Name, username.Username)
|
req := setupSetConfigReq(customDNSAddressConverted, cmd, activeProf.Name, username.Username)
|
||||||
if _, err := client.SetConfig(ctx, req); err != nil {
|
if _, err := client.SetConfig(ctx, req); err != nil {
|
||||||
return fmt.Errorf("call service set config method: %v", err)
|
if st, ok := gstatus.FromError(err); ok && st.Code() == codes.Unavailable {
|
||||||
|
log.Warnf("setConfig method is not available in the daemon")
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("call service setConfig method: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := doDaemonUp(ctx, cmd, client, pm, activeProf, customDNSAddressConverted, username.Username); err != nil {
|
if err := doDaemonUp(ctx, cmd, client, pm, activeProf, customDNSAddressConverted, username.Username); err != nil {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package dns
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"runtime"
|
"runtime"
|
||||||
@@ -61,6 +62,8 @@ type hostManagerWithOriginalNS interface {
|
|||||||
type DefaultServer struct {
|
type DefaultServer struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
ctxCancel context.CancelFunc
|
ctxCancel context.CancelFunc
|
||||||
|
// disableSys disables system DNS management (e.g., /etc/resolv.conf updates) while keeping the DNS service running.
|
||||||
|
// This is different from ServiceEnable=false from management which completely disables the DNS service.
|
||||||
disableSys bool
|
disableSys bool
|
||||||
mux sync.Mutex
|
mux sync.Mutex
|
||||||
service service
|
service service
|
||||||
@@ -187,6 +190,7 @@ func newDefaultServer(
|
|||||||
statusRecorder: statusRecorder,
|
statusRecorder: statusRecorder,
|
||||||
stateManager: stateManager,
|
stateManager: stateManager,
|
||||||
hostsDNSHolder: newHostsDNSHolder(),
|
hostsDNSHolder: newHostsDNSHolder(),
|
||||||
|
hostManager: &noopHostConfigurator{},
|
||||||
}
|
}
|
||||||
|
|
||||||
// register with root zone, handler chain takes care of the routing
|
// register with root zone, handler chain takes care of the routing
|
||||||
@@ -258,7 +262,8 @@ func (s *DefaultServer) Initialize() (err error) {
|
|||||||
s.mux.Lock()
|
s.mux.Lock()
|
||||||
defer s.mux.Unlock()
|
defer s.mux.Unlock()
|
||||||
|
|
||||||
if s.hostManager != nil {
|
if !s.isUsingNoopHostManager() {
|
||||||
|
// already initialized
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -271,19 +276,19 @@ func (s *DefaultServer) Initialize() (err error) {
|
|||||||
|
|
||||||
s.stateManager.RegisterState(&ShutdownState{})
|
s.stateManager.RegisterState(&ShutdownState{})
|
||||||
|
|
||||||
// use noop host manager if requested or running in netstack mode.
|
// Keep using noop host manager if dns off requested or running in netstack mode.
|
||||||
// Netstack mode currently doesn't have a way to receive DNS requests.
|
// Netstack mode currently doesn't have a way to receive DNS requests.
|
||||||
// TODO: Use listener on localhost in netstack mode when running as root.
|
// TODO: Use listener on localhost in netstack mode when running as root.
|
||||||
if s.disableSys || netstack.IsEnabled() {
|
if s.disableSys || netstack.IsEnabled() {
|
||||||
log.Info("system DNS is disabled, not setting up host manager")
|
log.Info("system DNS is disabled, not setting up host manager")
|
||||||
s.hostManager = &noopHostConfigurator{}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
s.hostManager, err = s.initialize()
|
hostManager, err := s.initialize()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("initialize: %w", err)
|
return fmt.Errorf("initialize: %w", err)
|
||||||
}
|
}
|
||||||
|
s.hostManager = hostManager
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -297,26 +302,40 @@ func (s *DefaultServer) DnsIP() netip.Addr {
|
|||||||
|
|
||||||
// Stop stops the server
|
// Stop stops the server
|
||||||
func (s *DefaultServer) Stop() {
|
func (s *DefaultServer) Stop() {
|
||||||
s.mux.Lock()
|
|
||||||
defer s.mux.Unlock()
|
|
||||||
s.ctxCancel()
|
s.ctxCancel()
|
||||||
|
|
||||||
if s.hostManager != nil {
|
s.mux.Lock()
|
||||||
|
defer s.mux.Unlock()
|
||||||
|
|
||||||
|
if err := s.disableDNS(); err != nil {
|
||||||
|
log.Errorf("failed to disable DNS: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
maps.Clear(s.extraDomains)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *DefaultServer) disableDNS() error {
|
||||||
|
defer s.service.Stop()
|
||||||
|
|
||||||
|
if s.isUsingNoopHostManager() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deregister original nameservers if they were registered as fallback
|
||||||
if srvs, ok := s.hostManager.(hostManagerWithOriginalNS); ok && len(srvs.getOriginalNameservers()) > 0 {
|
if srvs, ok := s.hostManager.(hostManagerWithOriginalNS); ok && len(srvs.getOriginalNameservers()) > 0 {
|
||||||
log.Debugf("deregistering original nameservers as fallback handlers")
|
log.Debugf("deregistering original nameservers as fallback handlers")
|
||||||
s.deregisterHandler([]string{nbdns.RootZone}, PriorityFallback)
|
s.deregisterHandler([]string{nbdns.RootZone}, PriorityFallback)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.hostManager.restoreHostDNS(); err != nil {
|
if err := s.hostManager.restoreHostDNS(); err != nil {
|
||||||
log.Error("failed to restore host DNS settings: ", err)
|
log.Errorf("failed to restore host DNS settings: %v", err)
|
||||||
} else if err := s.stateManager.DeleteState(&ShutdownState{}); err != nil {
|
} else if err := s.stateManager.DeleteState(&ShutdownState{}); err != nil {
|
||||||
log.Errorf("failed to delete shutdown dns state: %v", err)
|
log.Errorf("failed to delete shutdown dns state: %v", err)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
s.service.Stop()
|
s.hostManager = &noopHostConfigurator{}
|
||||||
|
|
||||||
maps.Clear(s.extraDomains)
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnUpdatedHostDNSServer update the DNS servers addresses for root zones
|
// OnUpdatedHostDNSServer update the DNS servers addresses for root zones
|
||||||
@@ -357,10 +376,6 @@ func (s *DefaultServer) UpdateDNSServer(serial uint64, update nbdns.Config) erro
|
|||||||
s.mux.Lock()
|
s.mux.Lock()
|
||||||
defer s.mux.Unlock()
|
defer s.mux.Unlock()
|
||||||
|
|
||||||
if s.hostManager == nil {
|
|
||||||
return fmt.Errorf("dns service is not initialized yet")
|
|
||||||
}
|
|
||||||
|
|
||||||
hash, err := hashstructure.Hash(update, hashstructure.FormatV2, &hashstructure.HashOptions{
|
hash, err := hashstructure.Hash(update, hashstructure.FormatV2, &hashstructure.HashOptions{
|
||||||
ZeroNil: true,
|
ZeroNil: true,
|
||||||
IgnoreZeroValue: true,
|
IgnoreZeroValue: true,
|
||||||
@@ -418,13 +433,14 @@ func (s *DefaultServer) ProbeAvailability() {
|
|||||||
|
|
||||||
func (s *DefaultServer) applyConfiguration(update nbdns.Config) error {
|
func (s *DefaultServer) applyConfiguration(update nbdns.Config) error {
|
||||||
// is the service should be Disabled, we stop the listener or fake resolver
|
// is the service should be Disabled, we stop the listener or fake resolver
|
||||||
// and proceed with a regular update to clean up the handlers and records
|
|
||||||
if update.ServiceEnable {
|
if update.ServiceEnable {
|
||||||
if err := s.service.Listen(); err != nil {
|
if err := s.enableDNS(); err != nil {
|
||||||
log.Errorf("failed to start DNS service: %v", err)
|
log.Errorf("failed to enable DNS: %v", err)
|
||||||
}
|
}
|
||||||
} else if !s.permanent {
|
} else if !s.permanent {
|
||||||
s.service.Stop()
|
if err := s.disableDNS(); err != nil {
|
||||||
|
log.Errorf("failed to disable DNS: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
localMuxUpdates, localRecords, err := s.buildLocalHandlerUpdate(update.CustomZones)
|
localMuxUpdates, localRecords, err := s.buildLocalHandlerUpdate(update.CustomZones)
|
||||||
@@ -469,11 +485,40 @@ func (s *DefaultServer) applyConfiguration(update nbdns.Config) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DefaultServer) applyHostConfig() {
|
func (s *DefaultServer) isUsingNoopHostManager() bool {
|
||||||
if s.hostManager == nil {
|
_, isNoop := s.hostManager.(*noopHostConfigurator)
|
||||||
return
|
return isNoop
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *DefaultServer) enableDNS() error {
|
||||||
|
if err := s.service.Listen(); err != nil {
|
||||||
|
return fmt.Errorf("start DNS service: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !s.isUsingNoopHostManager() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.disableSys || netstack.IsEnabled() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("DNS service re-enabled, initializing host manager")
|
||||||
|
|
||||||
|
if !s.service.RuntimeIP().IsValid() {
|
||||||
|
return errors.New("DNS service runtime IP is invalid")
|
||||||
|
}
|
||||||
|
|
||||||
|
hostManager, err := s.initialize()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("initialize host manager: %w", err)
|
||||||
|
}
|
||||||
|
s.hostManager = hostManager
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *DefaultServer) applyHostConfig() {
|
||||||
// prevent reapplying config if we're shutting down
|
// prevent reapplying config if we're shutting down
|
||||||
if s.ctx.Err() != nil {
|
if s.ctx.Err() != nil {
|
||||||
return
|
return
|
||||||
@@ -541,10 +586,7 @@ func (s *DefaultServer) registerFallback(config HostDNSConfig) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
ns = fmt.Sprintf("%s:%d", ns, defaultPort)
|
ns = formatAddr(ns, defaultPort)
|
||||||
if ip, err := netip.ParseAddr(ns); err == nil && ip.Is6() {
|
|
||||||
ns = fmt.Sprintf("[%s]:%d", ns, defaultPort)
|
|
||||||
}
|
|
||||||
|
|
||||||
handler.upstreamServers = append(handler.upstreamServers, ns)
|
handler.upstreamServers = append(handler.upstreamServers, ns)
|
||||||
}
|
}
|
||||||
@@ -729,7 +771,15 @@ func (s *DefaultServer) updateMux(muxUpdates []handlerWrapper) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getNSHostPort(ns nbdns.NameServer) string {
|
func getNSHostPort(ns nbdns.NameServer) string {
|
||||||
return fmt.Sprintf("%s:%d", ns.IP.String(), ns.Port)
|
return formatAddr(ns.IP.String(), ns.Port)
|
||||||
|
}
|
||||||
|
|
||||||
|
// formatAddr formats a nameserver address with port, handling IPv6 addresses properly
|
||||||
|
func formatAddr(address string, port int) string {
|
||||||
|
if ip, err := netip.ParseAddr(address); err == nil && ip.Is6() {
|
||||||
|
return fmt.Sprintf("[%s]:%d", address, port)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s:%d", address, port)
|
||||||
}
|
}
|
||||||
|
|
||||||
// upstreamCallbacks returns two functions, the first one is used to deactivate
|
// upstreamCallbacks returns two functions, the first one is used to deactivate
|
||||||
|
|||||||
@@ -2053,3 +2053,56 @@ func TestLocalResolverPriorityConstants(t *testing.T) {
|
|||||||
assert.Equal(t, PriorityLocal, localMuxUpdates[0].priority, "Local handler should use PriorityLocal")
|
assert.Equal(t, PriorityLocal, localMuxUpdates[0].priority, "Local handler should use PriorityLocal")
|
||||||
assert.Equal(t, "local.example.com", localMuxUpdates[0].domain)
|
assert.Equal(t, "local.example.com", localMuxUpdates[0].domain)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFormatAddr(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
address string
|
||||||
|
port int
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "IPv4 address",
|
||||||
|
address: "8.8.8.8",
|
||||||
|
port: 53,
|
||||||
|
expected: "8.8.8.8:53",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "IPv4 address with custom port",
|
||||||
|
address: "1.1.1.1",
|
||||||
|
port: 5353,
|
||||||
|
expected: "1.1.1.1:5353",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "IPv6 address",
|
||||||
|
address: "fd78:94bf:7df8::1",
|
||||||
|
port: 53,
|
||||||
|
expected: "[fd78:94bf:7df8::1]:53",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "IPv6 address with custom port",
|
||||||
|
address: "2001:db8::1",
|
||||||
|
port: 5353,
|
||||||
|
expected: "[2001:db8::1]:5353",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "IPv6 localhost",
|
||||||
|
address: "::1",
|
||||||
|
port: 53,
|
||||||
|
expected: "[::1]:53",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Invalid address treated as hostname",
|
||||||
|
address: "dns.example.com",
|
||||||
|
port: 53,
|
||||||
|
expected: "dns.example.com:53",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
result := formatAddr(tt.address, tt.port)
|
||||||
|
assert.Equal(t, tt.expected, result)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -452,6 +452,11 @@ func (s *Server) Login(callerCtx context.Context, msg *proto.LoginRequest) (*pro
|
|||||||
}
|
}
|
||||||
|
|
||||||
if *msg.ProfileName != activeProf.Name && username != activeProf.Username {
|
if *msg.ProfileName != activeProf.Name && username != activeProf.Username {
|
||||||
|
if s.checkProfilesDisabled() {
|
||||||
|
log.Errorf("profiles are disabled, you cannot use this feature without profiles enabled")
|
||||||
|
return nil, gstatus.Errorf(codes.Unavailable, errProfilesDisabled)
|
||||||
|
}
|
||||||
|
|
||||||
log.Infof("switching to profile %s for user '%s'", *msg.ProfileName, username)
|
log.Infof("switching to profile %s for user '%s'", *msg.ProfileName, username)
|
||||||
if err := s.profileManager.SetActiveProfileState(&profilemanager.ActiveProfileState{
|
if err := s.profileManager.SetActiveProfileState(&profilemanager.ActiveProfileState{
|
||||||
Name: *msg.ProfileName,
|
Name: *msg.ProfileName,
|
||||||
|
|||||||
@@ -718,6 +718,9 @@ func (am *DefaultAccountManager) DeleteAccount(ctx context.Context, accountID, u
|
|||||||
// cancel peer login expiry job
|
// cancel peer login expiry job
|
||||||
am.peerLoginExpiry.Cancel(ctx, []string{account.Id})
|
am.peerLoginExpiry.Cancel(ctx, []string{account.Id})
|
||||||
|
|
||||||
|
meta := map[string]any{"account_id": account.Id, "domain": account.Domain, "created_at": account.CreatedAt}
|
||||||
|
am.StoreEvent(ctx, userID, accountID, accountID, activity.AccountDeleted, meta)
|
||||||
|
|
||||||
log.WithContext(ctx).Debugf("account %s deleted", accountID)
|
log.WithContext(ctx).Debugf("account %s deleted", accountID)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -174,6 +174,8 @@ const (
|
|||||||
|
|
||||||
AccountLazyConnectionEnabled Activity = 85
|
AccountLazyConnectionEnabled Activity = 85
|
||||||
AccountLazyConnectionDisabled Activity = 86
|
AccountLazyConnectionDisabled Activity = 86
|
||||||
|
|
||||||
|
AccountDeleted Activity = 99999
|
||||||
)
|
)
|
||||||
|
|
||||||
var activityMap = map[Activity]Code{
|
var activityMap = map[Activity]Code{
|
||||||
@@ -182,6 +184,7 @@ var activityMap = map[Activity]Code{
|
|||||||
UserJoined: {"User joined", "user.join"},
|
UserJoined: {"User joined", "user.join"},
|
||||||
UserInvited: {"User invited", "user.invite"},
|
UserInvited: {"User invited", "user.invite"},
|
||||||
AccountCreated: {"Account created", "account.create"},
|
AccountCreated: {"Account created", "account.create"},
|
||||||
|
AccountDeleted: {"Account deleted", "account.delete"},
|
||||||
PeerRemovedByUser: {"Peer deleted", "user.peer.delete"},
|
PeerRemovedByUser: {"Peer deleted", "user.peer.delete"},
|
||||||
RuleAdded: {"Rule added", "rule.add"},
|
RuleAdded: {"Rule added", "rule.add"},
|
||||||
RuleUpdated: {"Rule updated", "rule.update"},
|
RuleUpdated: {"Rule updated", "rule.update"},
|
||||||
|
|||||||
Reference in New Issue
Block a user