Skip to content

Commit c117f15

Browse files
Merge pull request #117 from step-security/feature-28
Pass ctx to netmon
2 parents 00e9b19 + 92fe455 commit c117f15

File tree

5 files changed

+80
-21
lines changed

5 files changed

+80
-21
lines changed

agent.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ func Run(ctx context.Context, configFilePath string, hostDNSServer DNSServer,
143143
}
144144

145145
// Start network monitor
146-
go netMonitor.MonitorNetwork(nflog, errc) // listens for NFLOG messages
146+
go netMonitor.MonitorNetwork(ctx, nflog, errc) // listens for NFLOG messages
147147

148148
WriteLog("before audit rules")
149149

@@ -167,7 +167,7 @@ func Run(ctx context.Context, configFilePath string, hostDNSServer DNSServer,
167167
}
168168

169169
// Start network monitor
170-
go netMonitor.MonitorNetwork(nflog, errc) // listens for NFLOG messages
170+
go netMonitor.MonitorNetwork(ctx, nflog, errc) // listens for NFLOG messages
171171

172172
if err := addBlockRulesForGitHubHostedRunner(iptables, ipAddressEndpoints); err != nil {
173173
WriteLog(fmt.Sprintf("Error setting firewall for allowed domains %v", err))

agent_test.go

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package main
33
import (
44
"context"
55
"fmt"
6+
"net/http"
67
"os"
78
"path"
89
"testing"
@@ -124,7 +125,15 @@ func TestRun(t *testing.T) {
124125
httpmock.NewStringResponder(200, `{"Status":0,"TC":false,"RD":true,"RA":true,"AD":false,"CD":false,"Question":[{"name":"domain1.com.","type":1}],"Answer":[{"name":"domain1.com.","type":1,"TTL":30,"data":"67.67.67.67"}]}`))
125126

126127
httpmock.RegisterResponder("GET", "https://dns.google/resolve?name=domain2.com.&type=a",
127-
httpmock.NewStringResponder(200, `{"Status":0,"TC":false,"RD":true,"RA":true,"AD":false,"CD":false,"Question":[{"name":"domain2.com.","type":1}],"Answer":[{"name":"domain2.com.","type":1,"TTL":30,"data":"68.68.68.68"}]}`))
128+
httpmock.ResponderFromMultipleResponses(
129+
[]*http.Response{
130+
httpmock.NewStringResponse(200, `{"Status":0,"TC":false,"RD":true,"RA":true,"AD":false,"CD":false,"Question":[{"name":"domain2.com.","type":1}],"Answer":[{"name":"domain2.com.","type":1,"TTL":30,"data":"68.68.68.68"}]}`),
131+
httpmock.NewStringResponse(200, `{"Status":0,"TC":false,"RD":true,"RA":true,"AD":false,"CD":false,"Question":[{"name":"domain2.com.","type":1}],"Answer":[{"name":"domain2.com.","type":1,"TTL":30,"data":"68.68.68.68"}]}`),
132+
httpmock.NewStringResponse(200, `{"Status":0,"TC":false,"RD":true,"RA":true,"AD":false,"CD":false,"Question":[{"name":"domain2.com.","type":1}],"Answer":[{"name":"domain2.com.","type":1,"TTL":30,"data":"70.70.70.70"}]}`),
133+
httpmock.NewStringResponse(200, `{"Status":0,"TC":false,"RD":true,"RA":true,"AD":false,"CD":false,"Question":[{"name":"domain2.com.","type":1}],"Answer":[{"name":"domain2.com.","type":1,"TTL":30,"data":"68.68.68.68"}]}`),
134+
httpmock.NewStringResponse(200, `{"Status":0,"TC":false,"RD":true,"RA":true,"AD":false,"CD":false,"Question":[{"name":"domain2.com.","type":1}],"Answer":[{"name":"domain2.com.","type":1,"TTL":30,"data":"70.70.70.70"}]}`),
135+
},
136+
t.Log))
128137

129138
httpmock.RegisterResponder("GET", "https://dns.google/resolve", // no query params to match all other requests
130139
httpmock.NewStringResponder(200, `{"Status":0,"TC":false,"RD":true,"RA":true,"AD":false,"CD":false,"Question":[{"name":"requesteddomain.com.","type":1}],"Answer":[{"name":"requesteddomain.com.","type":1,"TTL":300,"data":"69.69.69.69"}]}`))
@@ -134,28 +143,21 @@ func TestRun(t *testing.T) {
134143
args args
135144
wantErr bool
136145
}{
137-
{name: "success", args: args{ctxCancelDuration: 2, configFilePath: "./testfiles/agent.json", hostDNSServer: &mockDNSServer{}, dockerDNSServer: &mockDNSServer{},
146+
{name: "success egress audit", args: args{ctxCancelDuration: 2, configFilePath: "./testfiles/agent.json", hostDNSServer: &mockDNSServer{}, dockerDNSServer: &mockDNSServer{},
138147
iptables: &Firewall{&MockIPTables{}}, nflog: &MockAgentNflogger{}, cmd: &MockCommand{}, resolvdConfigPath: createTempFileWithContents(""),
139148
dockerDaemonConfigPath: createTempFileWithContents("{}")}, wantErr: false},
140149

141-
{name: "success monitor process", args: args{ctxCancelDuration: 2, configFilePath: "./testfiles/agent.json", hostDNSServer: &mockDNSServer{}, dockerDNSServer: &mockDNSServer{},
142-
iptables: &Firewall{&MockIPTables{}}, nflog: &MockAgentNflogger{}, cmd: nil, resolvdConfigPath: createTempFileWithContents(""),
143-
dockerDaemonConfigPath: createTempFileWithContents("{}"), ciTestOnly: true}, wantErr: false},
144-
145-
{name: "success allowed endpoints", args: args{ctxCancelDuration: 2, configFilePath: "./testfiles/agent-allowed-endpoints.json",
150+
{name: "success egress blocked", args: args{ctxCancelDuration: 2, configFilePath: "./testfiles/agent-allowed-endpoints.json",
146151
hostDNSServer: &mockDNSServer{}, dockerDNSServer: &mockDNSServer{},
147152
iptables: &Firewall{&MockIPTables{}}, nflog: &MockAgentNflogger{}, cmd: &MockCommand{}, resolvdConfigPath: createTempFileWithContents(""),
148153
dockerDaemonConfigPath: createTempFileWithContents("{}")}, wantErr: false},
149154

150-
{name: "success allowed endpoints CI Test", args: args{ctxCancelDuration: 2, configFilePath: "./testfiles/agent-allowed-endpoints.json",
155+
// ctx will cancel after 35 seconds
156+
// DNS refresh will be done after 30 seconds
157+
{name: "success egress blocked DNS refresh", args: args{ctxCancelDuration: 35, configFilePath: "./testfiles/agent-allowed-endpoints.json",
151158
hostDNSServer: &mockDNSServer{}, dockerDNSServer: &mockDNSServer{},
152-
iptables: nil, nflog: &MockAgentNflogger{}, cmd: &MockCommand{}, resolvdConfigPath: createTempFileWithContents(""),
153-
dockerDaemonConfigPath: createTempFileWithContents("{}"), ciTestOnly: true}, wantErr: false},
154-
155-
{name: "success allowed endpoints DNS refresh CI Test", args: args{ctxCancelDuration: 60, configFilePath: "./testfiles/agent-allowed-endpoints.json",
156-
hostDNSServer: &mockDNSServer{}, dockerDNSServer: &mockDNSServer{},
157-
iptables: nil, nflog: &MockAgentNflogger{}, cmd: &MockCommand{}, resolvdConfigPath: createTempFileWithContents(""),
158-
dockerDaemonConfigPath: createTempFileWithContents("{}"), ciTestOnly: true}, wantErr: false},
159+
iptables: &Firewall{&MockIPTables{}}, nflog: &MockAgentNflogger{}, cmd: &MockCommand{}, resolvdConfigPath: createTempFileWithContents(""),
160+
dockerDaemonConfigPath: createTempFileWithContents("{}")}, wantErr: false},
159161

160162
{name: "dns failure", args: args{ctxCancelDuration: 5, configFilePath: "./testfiles/agent.json", hostDNSServer: &mockDNSServer{}, dockerDNSServer: &mockDNSServerWithError{},
161163
iptables: &Firewall{&MockIPTables{}}, nflog: &MockAgentNflogger{}, cmd: &MockCommand{}, resolvdConfigPath: createTempFileWithContents(""),
@@ -168,6 +170,21 @@ func TestRun(t *testing.T) {
168170
{name: "nflog failure", args: args{ctxCancelDuration: 5, configFilePath: "./testfiles/agent.json", hostDNSServer: &mockDNSServer{}, dockerDNSServer: &mockDNSServer{},
169171
iptables: &Firewall{&MockIPTables{}}, nflog: &MockAgentNfloggerWithErr{}, cmd: &MockCommand{}, resolvdConfigPath: createTempFileWithContents(""),
170172
dockerDaemonConfigPath: createTempFileWithContents("{}")}, wantErr: true},
173+
174+
// CI only tests
175+
{name: "success monitor process CI Test", args: args{ctxCancelDuration: 2, configFilePath: "./testfiles/agent.json", hostDNSServer: &mockDNSServer{}, dockerDNSServer: &mockDNSServer{},
176+
iptables: &Firewall{&MockIPTables{}}, nflog: &MockAgentNflogger{}, cmd: nil, resolvdConfigPath: createTempFileWithContents(""),
177+
dockerDaemonConfigPath: createTempFileWithContents("{}"), ciTestOnly: true}, wantErr: false},
178+
179+
{name: "success allowed endpoints CI Test", args: args{ctxCancelDuration: 2, configFilePath: "./testfiles/agent-allowed-endpoints.json",
180+
hostDNSServer: &mockDNSServer{}, dockerDNSServer: &mockDNSServer{},
181+
iptables: nil, nflog: &MockAgentNflogger{}, cmd: &MockCommand{}, resolvdConfigPath: createTempFileWithContents(""),
182+
dockerDaemonConfigPath: createTempFileWithContents("{}"), ciTestOnly: true}, wantErr: false},
183+
184+
{name: "success allowed endpoints DNS refresh CI Test", args: args{ctxCancelDuration: 60, configFilePath: "./testfiles/agent-allowed-endpoints.json",
185+
hostDNSServer: &mockDNSServer{}, dockerDNSServer: &mockDNSServer{},
186+
iptables: nil, nflog: &MockAgentNflogger{}, cmd: &MockCommand{}, resolvdConfigPath: createTempFileWithContents(""),
187+
dockerDaemonConfigPath: createTempFileWithContents("{}"), ciTestOnly: true}, wantErr: false},
171188
}
172189
_, ciTest := os.LookupEnv("CI")
173190
fmt.Printf("ci-test: %t\n", ciTest)

dnsproxy.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,9 @@ func (proxy *DNSProxy) ResolveDomain(domain string) (*Answer, error) {
113113

114114
for _, answer := range dnsReponse.Answer {
115115
if answer.Type == 1 {
116+
if answer.TTL < 30 {
117+
answer.TTL = 30 // less than 30 will cause too frequent DNS requests in audit scenario
118+
}
116119
return &answer, nil
117120
}
118121
}

dnsproxy_test.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"net/http"
66
"reflect"
77
"testing"
8+
"time"
89

910
"github.com/jarcoal/httpmock"
1011
"github.com/miekg/dns"
@@ -113,3 +114,44 @@ func TestDNSProxy_getResponse(t *testing.T) {
113114
})
114115
}
115116
}
117+
118+
func TestDNSProxy_auditCacheTTL(t *testing.T) {
119+
apiclient := &ApiClient{Client: &http.Client{}, APIURL: agentApiBaseUrl}
120+
121+
httpmock.ActivateNonDefault(apiclient.Client)
122+
123+
httpmock.RegisterResponder("GET", "https://dns.google/resolve?name=domain12345.com.&type=a",
124+
httpmock.ResponderFromMultipleResponses(
125+
[]*http.Response{
126+
httpmock.NewStringResponse(200, `{"Status":0,"TC":false,"RD":true,"RA":true,"AD":false,"CD":false,"Question":[{"name":"domain12345.com.","type":1}],"Answer":[{"name":"domain12345.com.","type":1,"TTL":30,"data":"68.68.68.68"}]}`),
127+
httpmock.NewStringResponse(200, `{"Status":0,"TC":false,"RD":true,"RA":true,"AD":false,"CD":false,"Question":[{"name":"domain12345.com.","type":1}],"Answer":[{"name":"domain12345.com.","type":1,"TTL":30,"data":"68.68.68.68"}]}`),
128+
},
129+
t.Log))
130+
131+
cache := InitCache(EgressPolicyAudit)
132+
133+
proxy := &DNSProxy{
134+
Cache: &cache,
135+
ApiClient: apiclient,
136+
EgressPolicy: EgressPolicyAudit,
137+
}
138+
139+
// should call httpmock
140+
proxy.getResponse(&dns.Msg{Question: []dns.Question{{Name: "domain12345.com.", Qtype: dns.TypeA}}})
141+
142+
time.Sleep(2 * time.Second)
143+
144+
// should get from cache
145+
proxy.getResponse(&dns.Msg{Question: []dns.Question{{Name: "domain12345.com.", Qtype: dns.TypeA}}})
146+
147+
time.Sleep(30 * time.Second)
148+
149+
// should call httpmock
150+
proxy.getResponse(&dns.Msg{Question: []dns.Question{{Name: "domain12345.com.", Qtype: dns.TypeA}}})
151+
152+
info := httpmock.GetCallCountInfo()
153+
count := info["GET https://dns.google/resolve?name=domain12345.com.&type=a"]
154+
if count != 2 {
155+
t.Errorf("incorrect call count %d, expected 2, %v", count, info)
156+
}
157+
}

netmon.go

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ type NetworkMonitor struct {
2424

2525
var ipAddresses = make(map[string]int)
2626

27-
func (netMonitor *NetworkMonitor) MonitorNetwork(nflogger AgentNflogger, errc chan error) []string {
27+
func (netMonitor *NetworkMonitor) MonitorNetwork(ctx context.Context, nflogger AgentNflogger, errc chan error) []string {
2828

2929
//sysLogger, err := syslog.NewLogger(syslog.LOG_INFO|syslog.LOG_USER, 1)
3030
var err error
@@ -48,9 +48,6 @@ func (netMonitor *NetworkMonitor) MonitorNetwork(nflogger AgentNflogger, errc ch
4848
}
4949
defer nf.Close()
5050

51-
ctx, cancel := context.WithCancel(context.Background()) // TODO: Pass context from the top
52-
defer cancel()
53-
5451
fn := func(attrs nflog.Attribute) int {
5552
go netMonitor.handlePacket(attrs)
5653
return 0

0 commit comments

Comments
 (0)