Skip to content

Commit

Permalink
chore: Merge branch 'master' of ssh://github.com/mrtc0/bouheki
Browse files Browse the repository at this point in the history
  • Loading branch information
mrtc0 committed Mar 29, 2022
2 parents 6938b0d + 32a7afc commit c7683cb
Show file tree
Hide file tree
Showing 6 changed files with 147 additions and 290 deletions.
74 changes: 50 additions & 24 deletions pkg/audit/network/audit.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package network
import (
"bytes"
"encoding/binary"
"fmt"
"os"
"os/signal"
"time"
Expand Down Expand Up @@ -128,8 +129,6 @@ func RunAudit(conf *config.Config) error {
}
defer mod.Close()

cache := make(map[string][]DomainCache)

dnsConfig, err := dns.ClientConfigFromFile("/etc/resolv.conf")
if err != nil {
return err
Expand All @@ -138,7 +137,6 @@ func RunAudit(conf *config.Config) error {
mgr := Manager{
mod: mod,
config: conf,
cache: cache,
dnsResolver: &DefaultResolver{
config: dnsConfig,
client: new(dns.Client),
Expand All @@ -150,65 +148,93 @@ func RunAudit(conf *config.Config) error {
log.Fatal(err)
}

if err = mgr.Attach(); err != nil {
log.Fatal(err)
}

eventsChannel := make(chan []byte)
mgr.Start(eventsChannel)

for _, domain := range mgr.config.RestrictedNetworkConfig.Domain.Allow {
go func(domain string) {
for _, allowedDomain := range mgr.config.RestrictedNetworkConfig.Domain.Allow {
go func(domainName string) {
for {
answer, err := mgr.updateAllowedDomainList(domain, dns.TypeA)
answer, err := mgr.ResolveAddressv4(domainName)
if err != nil {
log.Debug(fmt.Sprintf("%s (A) resolve failed. %s\n", domainName, err))
time.Sleep(5 * time.Second)
continue
}

err = mgr.updateAllowedFQDNist(answer)
if err != nil {
log.Fatal(err)
}

log.Debug(fmt.Sprintf("%s (A) is %#v, TTL is %d\n", answer.Domain, answer.Addresses, answer.TTL))
time.Sleep(time.Duration(answer.TTL) * time.Second)
}
}(domain)
}(allowedDomain)

go func(domain string) {
go func(domainName string) {
for {
answer, err := mgr.updateAllowedDomainList(domain, dns.TypeAAAA)
answer, err := mgr.ResolveAddressv6(domainName)
if err != nil {
log.Debug(fmt.Sprintf("%s (AAAA) resolve failed. %s\n", domainName, err))
time.Sleep(5 * time.Second)
continue
}

err = mgr.updateAllowedFQDNist(answer)
if err != nil {
log.Fatal(err)
}

log.Debug(fmt.Sprintf("%s (AAAA) is %#v, TTL is %d\n", answer.Domain, answer.Addresses, answer.TTL))
time.Sleep(time.Duration(answer.TTL) * time.Second)
}
}(domain)
}(allowedDomain)
}

for _, domain := range mgr.config.RestrictedNetworkConfig.Domain.Deny {
go func(domain string) {
for _, deniedDomain := range mgr.config.RestrictedNetworkConfig.Domain.Deny {
go func(domainName string) {
for {
answer, err := mgr.updateDeniedDomainList(domain, dns.TypeA)
answer, err := mgr.ResolveAddressv4(domainName)
if err != nil {
log.Debug(fmt.Sprintf("%s (A) resolve failed. %s\n", domainName, err))
time.Sleep(5 * time.Second)
continue
}

err = mgr.updateDeniedFQDNList(answer)
if err != nil {
log.Fatal(err)
}

log.Debug(fmt.Sprintf("%s (A) is %#v, TTL is %d\n", answer.Domain, answer.Addresses, answer.TTL))
time.Sleep(time.Duration(answer.TTL) * time.Second)
}
}(domain)
}(deniedDomain)

go func(domain string) {
go func(domainName string) {
for {
answer, err := mgr.updateDeniedDomainList(domain, dns.TypeAAAA)
answer, err := mgr.ResolveAddressv6(domainName)
if err != nil {
log.Debug(fmt.Sprintf("%s (AAAA) resolve failed. %s\n", domainName, err))
time.Sleep(5 * time.Second)
continue
}

err = mgr.updateDeniedFQDNList(answer)
if err != nil {
log.Fatal(err)
}

log.Debug(fmt.Sprintf("%s (AAAA) is %#v, TTL is %d\n", answer.Domain, answer.Addresses, answer.TTL))
time.Sleep(time.Duration(answer.TTL) * time.Second)
}
}(domain)
}(deniedDomain)
}

if err = mgr.Attach(); err != nil {
log.Fatal(err)
}

eventsChannel := make(chan []byte)
mgr.Start(eventsChannel)

go func() {
for {
eventBytes := <-eventsChannel
Expand Down
6 changes: 3 additions & 3 deletions pkg/audit/network/audit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,17 +175,17 @@ func TestAuditBlockModeV4(t *testing.T) {

type SpyIntegrationDNSResolver struct{}

func (r *SpyIntegrationDNSResolver) Resolve(host string, recordType uint16) (DNSAnswerCache, error) {
func (r *SpyIntegrationDNSResolver) Resolve(host string, recordType uint16) (*DNSAnswer, error) {
// See: testdata/docker-compose.yml
answer := DNSAnswerCache{Domain: host, TTL: 1234}
answer := DNSAnswer{Domain: host, TTL: 1234}
switch host {
case "nginx-1":
answer.Addresses = []net.IP{net.IPv4(10, 254, 249, 3), net.ParseIP("2001:3984:3989::3")}
case "nginx-2":
answer.Addresses = []net.IP{net.IPv4(10, 254, 249, 4), net.ParseIP("2001:3984:3989::4")}
}

return answer, nil
return &answer, nil
}

func TestAuditBlockModeDomainV4(t *testing.T) {
Expand Down
66 changes: 35 additions & 31 deletions pkg/audit/network/fqdn.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,78 +6,82 @@ import (
"net"

"github.com/miekg/dns"
log "github.com/mrtc0/bouheki/pkg/log"
)

type DNSAnswerCache struct {
type DNSAnswer struct {
Domain string
Addresses []net.IP
TTL uint32
}

// Domain Name to FQDN
// To FQDN format
// e.g. example.com -> example.com.
func domainNameToFqdn(domainName string) string {
func toFqdn(domainName string) string {
if domainName[len(domainName)-1:] == "." {
return domainName
}

return domainName + "."
}

func (r *DefaultResolver) Resolve(host string, recordType uint16) (DNSAnswerCache, error) {
answers := DNSAnswerCache{Domain: host}
func (r *DefaultResolver) Resolve(host string, recordType uint16) (*DNSAnswer, error) {
r.mux.Lock()

r.message.SetQuestion(domainNameToFqdn(host), recordType)
r.message.SetQuestion(toFqdn(host), recordType)
r.message.RecursionDesired = true

res, _, err := r.client.Exchange(r.message, r.config.Servers[0]+":"+r.config.Port)
r.mux.Unlock()

if err != nil {
return answers, err
return nil, err
}

if res.Rcode != dns.RcodeSuccess {
return answers, errors.New(fmt.Sprintf("Return code is %d\n", res.Rcode))
return nil, errors.New(fmt.Sprintf("Return code is %d\n", res.Rcode))
}

if len(res.Answer) == 0 {
return nil, errors.New(fmt.Sprintf("%s has not records(type %d)", host, recordType))
}

var addresses []net.IP
for _, answer := range res.Answer {
answer := DNSAnswer{Domain: host}
for _, rr := range res.Answer {
switch recordType {
case dns.TypeA:
if a, ok := answer.(*dns.A); ok {
addresses = append(addresses, a.A)
answers.TTL = a.Hdr.Ttl
if record, ok := rr.(*dns.A); ok {
answer.Addresses = append(answer.Addresses, record.A)
answer.TTL = record.Hdr.Ttl
}
case dns.TypeAAAA:
if aaaa, ok := answer.(*dns.AAAA); ok {
addresses = append(addresses, aaaa.AAAA)
answers.TTL = aaaa.Hdr.Ttl
if record, ok := rr.(*dns.AAAA); ok {
answer.Addresses = append(answer.Addresses, record.AAAA)
answer.TTL = record.Hdr.Ttl
}
}
}
answers.Addresses = addresses

return answers, nil
if answer.Addresses == nil {
return nil, errors.New(fmt.Sprintf("%s has not records(type %d)", host, recordType))
}

return &answer, nil
}

func (mgr *Manager) updateAllowedDomainList(domain string, queryType uint16) (DNSAnswerCache, error) {
answer, err := mgr.dnsResolver.Resolve(domain, queryType)
if err != nil || len(answer.Addresses) == 0 {
return answer, err
func (mgr *Manager) ResolveAddressv4(domain string) (*DNSAnswer, error) {
answer, err := mgr.dnsResolver.Resolve(domain, dns.TypeA)
if err != nil {
return nil, err
}
log.Debug(fmt.Sprintf("%s(queryType=%d) is %s, TTL is %d\n", domain, queryType, answer.Addresses, answer.TTL))
mgr.setAllowedDomainList(domain, answer.Addresses)

return answer, nil
}

func (mgr *Manager) updateDeniedDomainList(domain string, queryType uint16) (DNSAnswerCache, error) {
answer, err := mgr.dnsResolver.Resolve(domain, queryType)
if err != nil || len(answer.Addresses) == 0 {
return answer, err
func (mgr *Manager) ResolveAddressv6(domain string) (*DNSAnswer, error) {
answer, err := mgr.dnsResolver.Resolve(domain, dns.TypeAAAA)
if err != nil {
return nil, err
}
log.Debug(fmt.Sprintf("%s(queryType=%d) is %s, TTL is %d\n", domain, queryType, answer.Addresses, answer.TTL))
mgr.setDeniedDomainList(domain, answer.Addresses)

return answer, nil
}
4 changes: 2 additions & 2 deletions pkg/audit/network/fqdn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"github.com/stretchr/testify/assert"
)

func Test_domainNameToFqdn(t *testing.T) {
func Test_toFqdn(t *testing.T) {
tests := []struct {
name string
domain string
Expand All @@ -26,7 +26,7 @@ func Test_domainNameToFqdn(t *testing.T) {

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
assert.Equal(t, test.expect, domainNameToFqdn(test.domain))
assert.Equal(t, test.expect, toFqdn(test.domain))
})
}
}
Loading

0 comments on commit c7683cb

Please sign in to comment.