Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/add iOS support #1244

Merged
merged 63 commits into from
Dec 18, 2023
Merged
Show file tree
Hide file tree
Changes from 58 commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
7f7e101
starting engine by passing file descriptor on engine start
pascal-fischer Aug 9, 2023
6743054
inject logger that does not compile
pascal-fischer Aug 17, 2023
8653c32
logger and first client
pascal-fischer Sep 21, 2023
cdbe9c4
Merge branch 'main' into local/engine-restart
pascal-fischer Sep 21, 2023
e733cdc
first working connection
pascal-fischer Sep 25, 2023
8b8e4bb
support for routes and working connection
pascal-fischer Oct 5, 2023
ec8eb76
small refactor for better code quality in swift
pascal-fischer Oct 6, 2023
91b45ea
Merge remote-tracking branch 'origin/main' into local/engine-restart
pascal-fischer Oct 6, 2023
7f958e9
trying to add DNS
pascal-fischer Oct 9, 2023
c4c59ed
fix
pascal-fischer Oct 9, 2023
de46393
updated
pascal-fischer Oct 23, 2023
79f60b8
fix route deletion
pascal-fischer Oct 27, 2023
64084ca
trying to bind the DNS resolver dialer to an interface
pascal-fischer Nov 3, 2023
65052e5
use dns.Client.Exchange
mlsmaycon Nov 3, 2023
e193df3
fix metadata send on startup
pascal-fischer Nov 4, 2023
5632d22
switching between client to query upstream
pascal-fischer Nov 6, 2023
1c23a0e
fix panic on no dns response
pascal-fischer Nov 7, 2023
0e7a67c
merge main
pascal-fischer Nov 7, 2023
2b249ab
fix after merge changes
pascal-fischer Nov 7, 2023
0a8249e
add engine ready listener
pascal-fischer Nov 8, 2023
a37c946
replace engine listener with connection listener
pascal-fischer Nov 9, 2023
b230021
disable relay connection for iOS until proxy is refactored into bind
pascal-fischer Nov 16, 2023
5f96c56
Merge branch 'main' into feature/add-ios-support
pascal-fischer Dec 6, 2023
ad1cf38
Extract private upstream for iOS and fix function headers for other OS
pascal-fischer Dec 6, 2023
e03c07a
Update mock Server
pascal-fischer Dec 6, 2023
975e8e8
Fix dns server and upstream tests
pascal-fischer Dec 6, 2023
71f1cf8
Fix engine null pointer with mobile dependencies for other OS
pascal-fischer Dec 6, 2023
0f7343d
Revert back to disabling upstream on no response
pascal-fischer Dec 6, 2023
5f3f5dc
Fix some of the remarks from the linter
pascal-fischer Dec 6, 2023
d6d2e64
Fix linter
pascal-fischer Dec 6, 2023
f854ec9
re-arrange duration calculation
pascal-fischer Dec 6, 2023
c88e813
revert exported HostDNSConfig
pascal-fischer Dec 6, 2023
148a537
remove unused engine listener
pascal-fischer Dec 6, 2023
ca9ea29
remove development logs
pascal-fischer Dec 6, 2023
52be5de
refactor dns code and interface name propagation
pascal-fischer Dec 8, 2023
ecfac9d
clean dns server test
pascal-fischer Dec 8, 2023
6d9fd4b
disable upstream deactivation for iOS
pascal-fischer Dec 8, 2023
a567d90
Merge branch 'main' into feature/add-ios-support
pascal-fischer Dec 8, 2023
c35c2fb
remove files after merge
pascal-fischer Dec 8, 2023
0103984
fix dns server darwin
pascal-fischer Dec 8, 2023
9f6c3da
fix server mock
pascal-fischer Dec 8, 2023
cbb1f0e
fix build flags
pascal-fischer Dec 8, 2023
6e86dad
move service listen back to initialize
pascal-fischer Dec 8, 2023
d69d4cf
add wgInterface to hostManager initialization on android
pascal-fischer Dec 8, 2023
4d5760c
fix typo and remove unused function
pascal-fischer Dec 8, 2023
ed06c0c
extract upstream exchange for ios and rest
pascal-fischer Dec 8, 2023
fd40be5
remove todo
pascal-fischer Dec 8, 2023
284ec54
separate upstream logic to ios file
pascal-fischer Dec 11, 2023
974e845
Fix upstream test
pascal-fischer Dec 11, 2023
d6b5f05
use interface and embedded struct for upstream
pascal-fischer Dec 11, 2023
3acdf79
set properly upstream client
pascal-fischer Dec 11, 2023
680f21e
remove placeholder
pascal-fischer Dec 11, 2023
e86153a
remove ios specific attributes
pascal-fischer Dec 11, 2023
d91f2e2
fix upstream test
pascal-fischer Dec 11, 2023
1a00ffd
Merge pull request #1375 from netbirdio/upstream-embeded-struct
pascal-fischer Dec 11, 2023
cc15f06
merge ipc parser and wg configurer for mobile
pascal-fischer Dec 11, 2023
bacc322
fix build annotation
pascal-fischer Dec 11, 2023
0df30be
Merge branch 'main' into feature/add-ios-support
pascal-fischer Dec 14, 2023
5b4e847
use json for DNS settings handover through gomobile
pascal-fischer Dec 14, 2023
8827c52
add logs for DNS json string
pascal-fischer Dec 14, 2023
2265515
bring back check on ios for private upstream
pascal-fischer Dec 14, 2023
d08ef29
remove wrong (and unused) line
pascal-fischer Dec 15, 2023
077d0b9
fix wrongly updated comments on DNSSetting export
pascal-fischer Dec 15, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions client/internal/connect.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,15 @@ func RunClientMobile(ctx context.Context, config *Config, statusRecorder *peer.S
return runClient(ctx, config, statusRecorder, mobileDependency)
}

func RunClientiOS(ctx context.Context, config *Config, statusRecorder *peer.Status, fileDescriptor int32, networkChangeListener listener.NetworkChangeListener, dnsManager dns.IosDnsManager) error {
mobileDependency := MobileDependency{
FileDescriptor: fileDescriptor,
NetworkChangeListener: networkChangeListener,
DnsManager: dnsManager,
}
return runClient(ctx, config, statusRecorder, mobileDependency)
}

func runClient(ctx context.Context, config *Config, statusRecorder *peer.Status, mobileDependency MobileDependency) error {
log.Infof("starting NetBird client version %s", version.NetbirdVersion())

Expand Down
2 changes: 2 additions & 0 deletions client/internal/dns/host_darwin.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//go:build !ios

package dns

import (
Expand Down
45 changes: 45 additions & 0 deletions client/internal/dns/host_ios.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package dns

import (
"strconv"
"strings"
)

type iosHostManager struct {
dnsManager IosDnsManager
config hostDNSConfig
}

func newHostManager(dnsManager IosDnsManager) (hostManager, error) {
return &iosHostManager{
dnsManager: dnsManager,
}, nil
}

func (a iosHostManager) applyDNSConfig(config hostDNSConfig) error {
var configAsString []string
configAsString = append(configAsString, config.serverIP)
configAsString = append(configAsString, strconv.Itoa(config.serverPort))
configAsString = append(configAsString, strconv.FormatBool(config.routeAll))
var domainConfigAsString []string
for _, domain := range config.domains {
var domainAsString []string
domainAsString = append(domainAsString, strconv.FormatBool(domain.disabled))
domainAsString = append(domainAsString, domain.domain)
domainAsString = append(domainAsString, strconv.FormatBool(domain.matchOnly))
domainConfigAsString = append(domainConfigAsString, strings.Join(domainAsString, "|"))
}
domainConfig := strings.Join(domainConfigAsString, ";")
configAsString = append(configAsString, domainConfig)
outputString := strings.Join(configAsString, ",")
a.dnsManager.ApplyDns(outputString)
return nil
}

func (a iosHostManager) restoreHostDNS() error {
return nil
}

func (a iosHostManager) supportCustomPort() bool {
return false
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func (m *MockServer) DnsIP() string {
}

func (m *MockServer) OnUpdatedHostDNSServer(strings []string) {
//TODO implement me
// TODO implement me
panic("implement me")
}

Expand Down
3 changes: 2 additions & 1 deletion client/internal/dns/network_manager_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ import (
"github.com/godbus/dbus/v5"
"github.com/hashicorp/go-version"
"github.com/miekg/dns"
nbversion "github.com/netbirdio/netbird/version"
log "github.com/sirupsen/logrus"

nbversion "github.com/netbirdio/netbird/version"
)

const (
Expand Down
2 changes: 1 addition & 1 deletion client/internal/dns/notifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,6 @@ func (n *notifier) notify() {
}

go func(l listener.NetworkChangeListener) {
l.OnNetworkChanged()
l.OnNetworkChanged("")
}(n.listener)
}
28 changes: 24 additions & 4 deletions client/internal/dns/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ type ReadyListener interface {
OnReady()
}

// IosDnsManager is a dns manager interface for iOS
type IosDnsManager interface {
ApplyDns(string)
}

// Server is a dns server interface
type Server interface {
Initialize() error
Expand Down Expand Up @@ -52,6 +57,7 @@ type DefaultServer struct {

// make sense on mobile only
searchDomainNotifier *notifier
iosDnsManager IosDnsManager
}

type handlerWithStop interface {
Expand Down Expand Up @@ -99,6 +105,13 @@ func NewDefaultServerPermanentUpstream(ctx context.Context, wgInterface WGIface,
return ds
}

// NewDefaultServerIos returns a new dns server. It optimized for ios
func NewDefaultServerIos(ctx context.Context, wgInterface WGIface, iosDnsManager IosDnsManager) *DefaultServer {
ds := newDefaultServer(ctx, wgInterface, newServiceViaMemory(wgInterface))
ds.iosDnsManager = iosDnsManager
return ds
}

func newDefaultServer(ctx context.Context, wgInterface WGIface, dnsService service) *DefaultServer {
ctx, stop := context.WithCancel(ctx)
defaultServer := &DefaultServer{
Expand Down Expand Up @@ -131,8 +144,8 @@ func (s *DefaultServer) Initialize() (err error) {
}
}

s.hostManager, err = newHostManager(s.wgInterface)
return
s.hostManager, err = s.initialize()
return err
}

// DnsIP returns the DNS resolver server IP address
Expand Down Expand Up @@ -312,7 +325,10 @@ func (s *DefaultServer) buildUpstreamHandlerUpdate(nameServerGroups []*nbdns.Nam
continue
}

handler := newUpstreamResolver(s.ctx)
handler, err := newUpstreamResolver(s.ctx, s.wgInterface.Name(), s.wgInterface.Address().IP)
if err != nil {
return nil, fmt.Errorf("unable to create a new upstream resolver, error: %v", err)
}
for _, ns := range nsGroup.NameServers {
if ns.NSType != nbdns.UDPNameServerType {
log.Warnf("skipping nameserver %s with type %s, this peer supports only %s",
Expand Down Expand Up @@ -485,7 +501,11 @@ func (s *DefaultServer) upstreamCallbacks(
}

func (s *DefaultServer) addHostRootZone() {
handler := newUpstreamResolver(s.ctx)
handler, err := newUpstreamResolver(s.ctx, s.wgInterface.Name(), s.wgInterface.Address().IP)
if err != nil {
log.Errorf("unable to create a new upstream resolver, error: %v", err)
return
}
handler.upstreamServers = make([]string, len(s.hostsDnsList))
for n, ua := range s.hostsDnsList {
a, err := netip.ParseAddr(ua)
Expand Down
5 changes: 5 additions & 0 deletions client/internal/dns/server_android.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package dns

func (s *DefaultServer) initialize() (manager hostManager, err error) {
return newHostManager(s.wgInterface)
}
7 changes: 7 additions & 0 deletions client/internal/dns/server_darwin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
//go:build !ios

package dns

func (s *DefaultServer) initialize() (manager hostManager, err error) {
return newHostManager(s.wgInterface)
}
5 changes: 5 additions & 0 deletions client/internal/dns/server_ios.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package dns

func (s *DefaultServer) initialize() (manager hostManager, err error) {
return newHostManager(s.iosDnsManager)
}
7 changes: 7 additions & 0 deletions client/internal/dns/server_linux.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
//go:build !android

package dns

func (s *DefaultServer) initialize() (manager hostManager, err error) {
return newHostManager(s.wgInterface)
}
5 changes: 5 additions & 0 deletions client/internal/dns/server_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package dns

func (s *DefaultServer) initialize() (manager hostManager, err error) {
return newHostManager(s.wgInterface)
}
58 changes: 37 additions & 21 deletions client/internal/dns/upstream.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"net"
"runtime"
"sync"
"sync/atomic"
"time"
Expand All @@ -21,10 +22,15 @@ const (
)

type upstreamClient interface {
ExchangeContext(ctx context.Context, m *dns.Msg, a string) (r *dns.Msg, rtt time.Duration, err error)
exchange(upstream string, r *dns.Msg) (*dns.Msg, time.Duration, error)
}

type upstreamResolver struct {
type UpstreamResolver interface {
serveDNS(r *dns.Msg) (*dns.Msg, time.Duration, error)
upstreamExchange(upstream string, r *dns.Msg) (*dns.Msg, time.Duration, error)
}

type upstreamResolverBase struct {
ctx context.Context
cancel context.CancelFunc
upstreamClient upstreamClient
Expand All @@ -40,25 +46,25 @@ type upstreamResolver struct {
reactivate func()
}

func newUpstreamResolver(parentCTX context.Context) *upstreamResolver {
func newUpstreamResolverBase(parentCTX context.Context) *upstreamResolverBase {
ctx, cancel := context.WithCancel(parentCTX)
return &upstreamResolver{

return &upstreamResolverBase{
ctx: ctx,
cancel: cancel,
upstreamClient: &dns.Client{},
upstreamTimeout: upstreamTimeout,
reactivatePeriod: reactivatePeriod,
failsTillDeact: failsTillDeact,
}
}

func (u *upstreamResolver) stop() {
func (u *upstreamResolverBase) stop() {
log.Debugf("stopping serving DNS for upstreams %s", u.upstreamServers)
u.cancel()
}

// ServeDNS handles a DNS request
func (u *upstreamResolver) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
func (u *upstreamResolverBase) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
defer u.checkUpstreamFails()

log.WithField("question", r.Question[0]).Trace("received an upstream question")
Expand All @@ -70,10 +76,8 @@ func (u *upstreamResolver) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
}

for _, upstream := range u.upstreamServers {
ctx, cancel := context.WithTimeout(u.ctx, u.upstreamTimeout)
rm, t, err := u.upstreamClient.ExchangeContext(ctx, r, upstream)

cancel()
rm, t, err := u.upstreamClient.exchange(upstream, r)

if err != nil {
if err == context.DeadlineExceeded || isTimeout(err) {
Expand All @@ -83,7 +87,19 @@ func (u *upstreamResolver) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
}
u.failsCount.Add(1)
log.WithError(err).WithField("upstream", upstream).
Error("got an error while querying the upstream")
Error("got other error while querying the upstream")
return
}

if rm == nil {
log.WithError(err).WithField("upstream", upstream).
Warn("no response from upstream")
return
}
// those checks need to be independent of each other due to memory address issues
if !rm.Response {
log.WithError(err).WithField("upstream", upstream).
Warn("no response from upstream")
return
}

Expand All @@ -106,7 +122,7 @@ func (u *upstreamResolver) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
// If fails count is greater that failsTillDeact, upstream resolving
// will be disabled for reactivatePeriod, after that time period fails counter
// will be reset and upstream will be reactivated.
func (u *upstreamResolver) checkUpstreamFails() {
func (u *upstreamResolverBase) checkUpstreamFails() {
u.mutex.Lock()
defer u.mutex.Unlock()

Expand All @@ -118,15 +134,18 @@ func (u *upstreamResolver) checkUpstreamFails() {
case <-u.ctx.Done():
return
default:
log.Warnf("upstream resolving is disabled for %v", reactivatePeriod)
u.deactivate()
u.disabled = true
go u.waitUntilResponse()
// todo test the deactivation logic, it seems to affect the client
if runtime.GOOS != "ios" {
log.Warnf("upstream resolving is disabled for %v", reactivatePeriod)
u.deactivate()
u.disabled = true
go u.waitUntilResponse()
}
}
}

// waitUntilResponse retries, in an exponential interval, querying the upstream servers until it gets a positive response
func (u *upstreamResolver) waitUntilResponse() {
func (u *upstreamResolverBase) waitUntilResponse() {
exponentialBackOff := &backoff.ExponentialBackOff{
InitialInterval: 500 * time.Millisecond,
RandomizationFactor: 0.5,
Expand All @@ -148,10 +167,7 @@ func (u *upstreamResolver) waitUntilResponse() {

var err error
for _, upstream := range u.upstreamServers {
ctx, cancel := context.WithTimeout(u.ctx, u.upstreamTimeout)
_, _, err = u.upstreamClient.ExchangeContext(ctx, r, upstream)

cancel()
_, _, err = u.upstreamClient.exchange(upstream, r)

if err == nil {
return nil
Expand Down
Loading
Loading