Skip to content

Commit

Permalink
fix: redirect dns calls by configuring nsswitch config file in linux (#…
Browse files Browse the repository at this point in the history
…1678)

* fix: redirect dns calls by configuring nsswitch config file in linux

linux distros like fedora uses systemd-resolve for dns resolution which makes unix socket with the application due to which keploy is not able to redirect them to proxy in test mode. This results in test failure. This is handled by editing the nsswitch.conf of /etc in linux to not use resolve in test mode

Signed-off-by: re-Tick <jain.ritik.1001@gmail.com>

---------

Signed-off-by: re-Tick <jain.ritik.1001@gmail.com>
  • Loading branch information
re-Tick committed Mar 11, 2024
1 parent 8018b19 commit 7fe9bc0
Showing 1 changed file with 83 additions and 6 deletions.
89 changes: 83 additions & 6 deletions pkg/service/test/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"os/exec"
"os/signal"
"path/filepath"
"runtime"
"sort"
"strconv"
"strings"
Expand All @@ -35,8 +36,9 @@ import (
var Emoji = "\U0001F430" + " Keploy:"

type tester struct {
logger *zap.Logger
mutex sync.Mutex
logger *zap.Logger
mutex sync.Mutex
hostConfigStr string // hosts string in the nsswitch.conf of linux system. To restore the system hosts configuration after completion of test
}
type TestOptions struct {
MongoPassword string
Expand Down Expand Up @@ -73,12 +75,79 @@ func NewTester(logger *zap.Logger) Tester {
}
}

// setting up the dns routing for the linux system
func (t *tester) setupNsswitchConfig() error {
// Check if the nsswitch.conf present for the system
if _, err := os.Stat("/etc/nsswitch.conf"); err == nil {
// Read the current nsswitch.conf
data, err := os.ReadFile("/etc/nsswitch.conf")
if err != nil {
t.logger.Error("failed to read the nsswitch.conf file from system", zap.Error(err))
return err
}

// Replace the hosts field value if it exists
lines := strings.Split(string(data), "\n")
for i, line := range lines {
if strings.HasPrefix(line, "hosts:") {
t.hostConfigStr = lines[i]
lines[i] = "hosts: files dns"
}
}

// Write the modified nsswitch.conf back to the file
err = os.WriteFile("/etc/nsswitch.conf", []byte(strings.Join(lines, "\n")), 0644)
if err != nil {
t.logger.Error("failed to write the configuration to the nsswitch.conf file to redirect the DNS queries to proxy", zap.Error(err))
return err
}

t.logger.Debug("Successfully written to nsswitch config of linux")
}
return nil
}

// resetNsswitchConfig resets the hosts config of nsswitch of the system
func (t *tester) resetNsswitchConfig() {
data, err := os.ReadFile("/etc/nsswitch.conf")
if err != nil {
t.logger.Error("failed to read the nsswitch.conf file from system", zap.Error(err))
return
}

// Replace the hosts field value if it exists with the actual system hosts value
lines := strings.Split(string(data), "\n")
for i, line := range lines {
if strings.HasPrefix(line, "hosts:") {
lines[i] = t.hostConfigStr
}
}

// Write the modified nsswitch.conf back to the file
err = os.WriteFile("/etc/nsswitch.conf", []byte(strings.Join(lines, "\n")), 0644)
if err != nil {
t.logger.Error("failed to write the configuration to the nsswitch.conf file to redirect the DNS queries to proxy", zap.Error(err))
return
}

t.logger.Debug("Successfully reset the nsswitch config of linux")
}

func (t *tester) InitialiseTest(cfg *TestConfig) (TestEnvironmentSetup, error) {
var (
returnVal TestEnvironmentSetup
err error
)
returnVal.Storage = cfg.Storage

// setting up the dns routing for the fedora distro
if runtime.GOOS == "linux" {
err = t.setupNsswitchConfig()
if err != nil {
return returnVal, err
}
}

// capturing the code coverage for go bianries built by go-version 1.20^
if cfg.WithCoverage {

Expand All @@ -102,7 +171,7 @@ func (t *tester) InitialiseTest(cfg *TestConfig) (TestEnvironmentSetup, error) {
return returnVal, err
} else if err == nil && !dirInfo.IsDir() {
t.logger.Error("the goCoverDir is not a directory. Please provide a valid path to a directory for go coverage binaries.")
return returnVal, fmt.Errorf("the goCoverDir is not a directory. Please provide a valid path to a directory for go coverage binaries.")
return returnVal, fmt.Errorf("the goCoverDir is not a directory. Please provide a valid path to a directory for go coverage binaries")
} else if err != nil && os.IsNotExist(err) {
err := makeDirectory(cfg.CoverageReportPath)
if err != nil {
Expand All @@ -124,7 +193,7 @@ func (t *tester) InitialiseTest(cfg *TestConfig) (TestEnvironmentSetup, error) {
}

stopper := make(chan os.Signal, 1)
signal.Notify(stopper, os.Interrupt, os.Kill, syscall.SIGHUP, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGKILL)
signal.Notify(stopper, os.Interrupt, syscall.SIGHUP, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM)

models.SetMode(models.MODE_TEST)

Expand All @@ -140,7 +209,7 @@ func (t *tester) InitialiseTest(cfg *TestConfig) (TestEnvironmentSetup, error) {

select {
case <-stopper:
return returnVal, errors.New("Keploy was interupted by stopper")
return returnVal, errors.New("keploy was interupted by stopper")
default:
// load the ebpf hooks into the kernel
if err := returnVal.LoadedHooks.LoadHooks(cfg.AppCmd, cfg.AppContainer, 0, context.Background(), nil); err != nil {
Expand All @@ -151,7 +220,7 @@ func (t *tester) InitialiseTest(cfg *TestConfig) (TestEnvironmentSetup, error) {
select {
case <-stopper:
returnVal.LoadedHooks.Stop(true)
return returnVal, errors.New("Keploy was interupted by stopper")
return returnVal, errors.New("keploy was interupted by stopper")
default:
// start the proxy
returnVal.ProxySet = proxy.BootProxy(t.logger, proxy.Option{Port: cfg.Proxyport, MongoPassword: cfg.MongoPassword}, cfg.AppCmd, cfg.AppContainer, 0, "", cfg.PassThroughPorts, returnVal.LoadedHooks, context.Background(), cfg.Delay)
Expand Down Expand Up @@ -237,6 +306,14 @@ func (t *tester) Test(path string, testReportPath string, appCmd string, options
return false
}
initialisedValues, err := t.InitialiseTest(cfg)

// reset the hosts config in nsswitch.conf of the system
defer func() {
if t.hostConfigStr != "" {
t.resetNsswitchConfig()
}
}()

// Recover from panic and gracefully shutdown
defer initialisedValues.LoadedHooks.Recover(pkg.GenerateRandomID())
if err != nil {
Expand Down

0 comments on commit 7fe9bc0

Please sign in to comment.