Skip to content

Commit 6778f21

Browse files
Merge pull request #102 from step-security/feature-99
Add sinkhole IP address
2 parents a051e3d + 330ca1a commit 6778f21

File tree

3 files changed

+32
-9
lines changed

3 files changed

+32
-9
lines changed

dnsproxy.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ type Answer struct {
3939
Data string `json:"data"`
4040
}
4141

42+
const StepSecuritySinkHoleIPAddress = "54.185.253.63"
43+
4244
func (proxy *DNSProxy) getResponse(requestMsg *dns.Msg) (*dns.Msg, error) {
4345

4446
responseMsg := new(dns.Msg)
@@ -51,7 +53,6 @@ func (proxy *DNSProxy) getResponse(requestMsg *dns.Msg) (*dns.Msg, error) {
5153

5254
answer, err := proxy.processTypeA(&question, requestMsg)
5355
if err != nil {
54-
5556
return responseMsg, err
5657
}
5758
responseMsg.Answer = append(responseMsg.Answer, *answer)
@@ -98,7 +99,14 @@ func (proxy *DNSProxy) getIPByDomain(domain string) (string, error) {
9899
if !proxy.isAllowedDomain(domain) {
99100
go WriteLog(fmt.Sprintf("domain not allowed: %s", domain))
100101
go WriteAnnotation(fmt.Sprintf("DNS resolution for domain %s was blocked", domain))
101-
return "", fmt.Errorf("domain not allowed %s", domain)
102+
103+
// return an ip address, so calling process calls the ip address
104+
// the call will be blocked by the firewall
105+
proxy.Cache.Set(domain, StepSecuritySinkHoleIPAddress)
106+
107+
go proxy.ApiClient.sendDNSRecord(proxy.CorrelationId, proxy.Repo, domain, StepSecuritySinkHoleIPAddress)
108+
109+
return StepSecuritySinkHoleIPAddress, nil
102110
}
103111
}
104112

dnsproxy_test.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package main
22

33
import (
4+
"fmt"
45
"net/http"
56
"reflect"
67
"testing"
@@ -21,6 +22,7 @@ func TestDNSProxy_getResponse(t *testing.T) {
2122
Cache := InitCache(60 * 1000000000)
2223
rrDnsGoogle, _ := dns.NewRR("dns.google. IN A 8.8.8.8")
2324
rrDnsTest, _ := dns.NewRR("test.com. IN A 67.225.146.248")
25+
rrDnsNotAllowed, _ := dns.NewRR(fmt.Sprintf("notallowed.com. IN A %s", StepSecuritySinkHoleIPAddress))
2426
rrDnsAllowed, _ := dns.NewRR("allowed.com. IN A 67.225.146.248")
2527

2628
apiclient := &ApiClient{Client: &http.Client{}, APIURL: agentApiBaseUrl}
@@ -33,6 +35,9 @@ func TestDNSProxy_getResponse(t *testing.T) {
3335
httpmock.RegisterResponder("GET", "https://dns.google/resolve?name=allowed.com.&type=a",
3436
httpmock.NewStringResponder(200, `{"Status":0,"TC":false,"RD":true,"RA":true,"AD":false,"CD":false,"Question":[{"name":"allowed.com.","type":1}],"Answer":[{"name":"allowed.com.","type":1,"TTL":3080,"data":"67.225.146.248"}]}`))
3537

38+
httpmock.RegisterResponder("GET", "https://dns.google/resolve?name=notfound.com.&type=a",
39+
httpmock.NewStringResponder(200, `{"Status":3,"TC":false,"RD":true,"RA":true,"AD":false,"CD":false,"Question":[{"name":"notfound.com.","type":1}],"Authority":[{"name":"com.","type":6,"TTL":900,"data":"a.gtld-servers.net. nstld.verisign-grs.com. 1640040308 1800 900 604800 86400"}],"Comment":"Response from 2001:503:231d::2:30."}`))
40+
3641
tests := []struct {
3742
name string
3843
fields fields
@@ -61,8 +66,8 @@ func TestDNSProxy_getResponse(t *testing.T) {
6166
{name: "type A notallowed.com",
6267
fields: fields{Cache: &Cache, EgressPolicy: EgressPolicyBlock, AllowedEndpoints: []Endpoint{{domainName: "allowed.com"}}},
6368
args: args{requestMsg: &dns.Msg{Question: []dns.Question{{Name: "notallowed.com.", Qtype: dns.TypeA}}}},
64-
want: &dns.Msg{},
65-
wantErr: true,
69+
want: &dns.Msg{Answer: []dns.RR{rrDnsNotAllowed}},
70+
wantErr: false,
6671
},
6772
{name: "type A test.com egress policy cached",
6873
fields: fields{Cache: &Cache, EgressPolicy: EgressPolicyBlock, AllowedEndpoints: []Endpoint{{domainName: "test.com"}}},
@@ -76,6 +81,12 @@ func TestDNSProxy_getResponse(t *testing.T) {
7681
want: &dns.Msg{Answer: []dns.RR{rrDnsAllowed}},
7782
wantErr: false,
7883
},
84+
{name: "type A notfound.com",
85+
fields: fields{Cache: &Cache, EgressPolicy: EgressPolicyAudit},
86+
args: args{requestMsg: &dns.Msg{Question: []dns.Question{{Name: "notfound.com.", Qtype: dns.TypeA}}}},
87+
want: &dns.Msg{},
88+
wantErr: true,
89+
},
7990
}
8091
for _, tt := range tests {
8192
t.Run(tt.name, func(t *testing.T) {

netmon.go

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,17 +88,21 @@ func (netMonitor *NetworkMonitor) handlePacket(attrs nflog.Attribute) {
8888
// Get actual TCP data from this layer
8989
ipv4, _ := ipv4Layer.(*layers.IPv4)
9090
netMonitor.netMutex.Lock()
91-
_, found := ipAddresses[ipv4.DstIP.String()]
91+
ipv4Address := ipv4.DstIP.String()
92+
_, found := ipAddresses[ipv4Address]
9293
if !found {
93-
ipAddresses[ipv4.DstIP.String()] = 1
94+
ipAddresses[ipv4Address] = 1
9495

9596
if isSYN {
9697
netMonitor.ApiClient.sendNetConnection(netMonitor.CorrelationId, netMonitor.Repo,
97-
ipv4.DstIP.String(), port, netMonitor.Status, timestamp, Tool{Name: Unknown, SHA256: Unknown})
98+
ipv4Address, port, netMonitor.Status, timestamp, Tool{Name: Unknown, SHA256: Unknown})
9899

99100
if netMonitor.Status == "Dropped" {
100-
go WriteLog(fmt.Sprintf("ip address dropped: %s", ipv4.DstIP.String()))
101-
go WriteAnnotation(fmt.Sprintf("Traffic to IP Address %s was blocked", ipv4.DstIP.String()))
101+
go WriteLog(fmt.Sprintf("ip address dropped: %s", ipv4Address))
102+
103+
if ipv4Address != StepSecuritySinkHoleIPAddress { // Sinkhole IP address will be covered by DNS block
104+
go WriteAnnotation(fmt.Sprintf("Traffic to IP Address %s was blocked", ipv4Address))
105+
}
102106
}
103107
}
104108
}

0 commit comments

Comments
 (0)