github.com/aporeto-inc/trireme-lib@v10.358.0+incompatible/controller/internal/enforcer/dnsproxy/dns_windows.go (about)

     1  // +build windows
     2  
     3  package dnsproxy
     4  
     5  import (
     6  	"context"
     7  	"errors"
     8  	"net"
     9  	"sync"
    10  	"syscall"
    11  
    12  	"github.com/miekg/dns"
    13  	"go.aporeto.io/enforcerd/trireme-lib/collector"
    14  	"go.aporeto.io/enforcerd/trireme-lib/controller/pkg/flowtracking"
    15  	"go.aporeto.io/enforcerd/trireme-lib/controller/pkg/ipsetmanager"
    16  	"go.aporeto.io/enforcerd/trireme-lib/controller/pkg/pucontext"
    17  	"go.aporeto.io/enforcerd/trireme-lib/policy"
    18  	"go.aporeto.io/enforcerd/trireme-lib/utils/cache"
    19  	"go.uber.org/zap"
    20  )
    21  
    22  var clearWindowsDNSCacheFunc = clearWindowsDNSCache
    23  
    24  // Proxy struct represents the object for dns proxy
    25  type Proxy struct {
    26  	puFromID   cache.DataStore
    27  	collector  collector.EventCollector
    28  	contextIDs map[string]struct{}
    29  	chreports  chan dnsReport
    30  	sync.RWMutex
    31  }
    32  
    33  // New creates an instance of the dns proxy
    34  func New(ctx context.Context, puFromID cache.DataStore, conntrack flowtracking.FlowClient, c collector.EventCollector) *Proxy {
    35  	ch := make(chan dnsReport)
    36  	p := &Proxy{chreports: ch, puFromID: puFromID, collector: c, contextIDs: make(map[string]struct{})}
    37  	go p.reportDNSRequests(ctx, ch)
    38  	return p
    39  }
    40  
    41  // StartDNSServer starts the dns server on the port provided for contextID
    42  func (p *Proxy) StartDNSServer(ctx context.Context, contextID, port string) error {
    43  	p.Lock()
    44  	defer p.Unlock()
    45  	p.contextIDs[contextID] = struct{}{}
    46  	return nil
    47  }
    48  
    49  // ShutdownDNS shuts down the dns server for contextID
    50  func (p *Proxy) ShutdownDNS(contextID string) {
    51  	p.Lock()
    52  	defer p.Unlock()
    53  	delete(p.contextIDs, contextID)
    54  }
    55  
    56  // SyncWithPlatformCache is called on policy change.
    57  // Clear the Windows DNS cache in order to guarantee proxying.
    58  func (p *Proxy) SyncWithPlatformCache(ctx context.Context, pctx *pucontext.PUContext) error {
    59  
    60  	if pctx.UsesFQDN() {
    61  		return clearWindowsDNSCacheFunc()
    62  	}
    63  	return nil
    64  }
    65  
    66  // HandleDNSResponsePacket parses the DNS response and forwards the information to each PU based on policy
    67  func (p *Proxy) HandleDNSResponsePacket(dnsPacketData []byte, sourceIP net.IP, sourcePort uint16, destIP net.IP, destPort uint16, puFromContextID func(string) (*pucontext.PUContext, error)) error {
    68  
    69  	// parse dns
    70  	msg := &dns.Msg{}
    71  	err := msg.Unpack(dnsPacketData)
    72  	if err != nil {
    73  		return err
    74  	}
    75  
    76  	// Make sure we have a question
    77  	if len(msg.Question) <= 0 {
    78  		return nil
    79  	}
    80  
    81  	var ips []string
    82  	for _, ans := range msg.Answer {
    83  		if ans.Header().Rrtype == dns.TypeA {
    84  			t, _ := ans.(*dns.A)
    85  			ips = append(ips, t.A.String())
    86  		}
    87  
    88  		if ans.Header().Rrtype == dns.TypeAAAA {
    89  			t, _ := ans.(*dns.AAAA)
    90  			ips = append(ips, t.AAAA.String())
    91  		}
    92  	}
    93  
    94  	// let each pu handle it
    95  	pus := make([]*pucontext.PUContext, 0, len(p.contextIDs))
    96  	p.Lock()
    97  	for id := range p.contextIDs {
    98  		puCtx, err := puFromContextID(id)
    99  		if err != nil {
   100  			zap.L().Error("dnsproxy: DNS Proxy failed to get PUContext", zap.Error(err))
   101  			continue
   102  		}
   103  		pus = append(pus, puCtx)
   104  	}
   105  	p.Unlock()
   106  
   107  	for _, puCtx := range pus {
   108  		ppps, _, err := puCtx.GetPolicyFromFQDN(msg.Question[0].Name)
   109  		if err == nil {
   110  			for _, ppp := range ppps {
   111  				ipsetmanager.V4().UpdateACLIPsets(ips, ppp.Policy.ServiceID)
   112  				ipsetmanager.V6().UpdateACLIPsets(ips, ppp.Policy.ServiceID)
   113  				if err = puCtx.UpdateApplicationACLs(policy.IPRuleList{{Addresses: ips,
   114  					Ports:     ppp.Ports,
   115  					Protocols: ppp.Protocols,
   116  					Policy:    ppp.Policy,
   117  				}}); err != nil {
   118  					zap.L().Error("dnsproxy: adding IP rule returned error", zap.Error(err))
   119  				}
   120  			}
   121  		}
   122  
   123  		// source and destination is swapped because we are looking at response packet
   124  		p.reportDNSLookup(msg.Question[0].Name, puCtx, destIP, destPort, sourceIP, sourcePort, ips, "")
   125  
   126  		configureDependentServices(puCtx, msg.Question[0].Name, ips)
   127  	}
   128  
   129  	return nil
   130  }
   131  
   132  func clearWindowsDNSCache() error {
   133  	dnsAPIDll := syscall.NewLazyDLL("dnsapi.dll")
   134  	flushDNSCacheProc := dnsAPIDll.NewProc("DnsFlushResolverCache")
   135  	ret, _, err := flushDNSCacheProc.Call()
   136  	if err != syscall.Errno(0) {
   137  		return err
   138  	}
   139  	if ret == 0 {
   140  		return errors.New("DnsFlushResolverCache failed")
   141  	}
   142  	return nil
   143  }
   144  
   145  // Enforce starts enforcing policies for the given policy.PUInfo.
   146  func (p *Proxy) Enforce(ctx context.Context, contextID string, puInfo *policy.PUInfo) error {
   147  	return nil
   148  }
   149  
   150  // Unenforce stops enforcing policy for the given IP.
   151  func (p *Proxy) Unenforce(_ context.Context, contextID string) error {
   152  	return nil
   153  }