github.com/aporeto-inc/trireme-lib@v10.358.0+incompatible/controller/internal/supervisor/iptablesctrl/acls.go (about)

     1  package iptablesctrl
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"os"
     7  	"strconv"
     8  	"strings"
     9  	"text/template"
    10  
    11  	"github.com/kballard/go-shellquote"
    12  	"github.com/mattn/go-shellwords"
    13  	mgrconstants "go.aporeto.io/cns-agent-mgr/pkg/constants"
    14  	"go.aporeto.io/enforcerd/trireme-lib/common"
    15  	"go.aporeto.io/enforcerd/trireme-lib/controller/constants"
    16  	"go.aporeto.io/enforcerd/trireme-lib/policy"
    17  	markconstants "go.aporeto.io/enforcerd/trireme-lib/utils/constants"
    18  	"go.aporeto.io/gaia/protocols"
    19  	"go.uber.org/zap"
    20  )
    21  
    22  const (
    23  	numPackets   = "100"
    24  	initialCount = "99"
    25  )
    26  
    27  var (
    28  	cnsAgentBootPid    int
    29  	cnsAgentMgrPid     int
    30  	getEnforcerPID     = func() int { return os.Getpid() }
    31  	getCnsAgentMgrPID  = func() int { return cnsAgentMgrPid }
    32  	getCnsAgentBootPID = func() int { return cnsAgentBootPid }
    33  )
    34  
    35  func init() {
    36  	cnsAgentBootPid = -1
    37  	if mgrconstants.IsManagedByCnsAgentManager() {
    38  		cnsAgentBootPid = discoverCnsAgentBootPID()
    39  	}
    40  	cnsAgentMgrPid = -1
    41  	if mgrconstants.IsManagedByCnsAgentManager() {
    42  		cnsAgentMgrPid = os.Getppid()
    43  	}
    44  }
    45  
    46  type rulesInfo struct {
    47  	RejectObserveApply    [][]string
    48  	RejectNotObserved     [][]string
    49  	RejectObserveContinue [][]string
    50  
    51  	AcceptObserveApply    [][]string
    52  	AcceptNotObserved     [][]string
    53  	AcceptObserveContinue [][]string
    54  	ReverseRules          [][]string
    55  }
    56  
    57  // cgroupChainRules provides the rules for redirecting to a processing unit
    58  // specific chain based for Linux processed and based on the cgroups and net_cls
    59  // configuration.
    60  func (i *iptables) cgroupChainRules(cfg *ACLInfo) [][]string {
    61  
    62  	if legacyRules, ok := i.legacyPuChainRules(cfg); ok {
    63  		return legacyRules
    64  	}
    65  
    66  	tmpl := template.Must(template.New(cgroupCaptureTemplate).Funcs(template.FuncMap{
    67  		"isUDPPorts": func() bool {
    68  			return cfg.UDPPorts != "0"
    69  		},
    70  		"isTCPPorts": func() bool {
    71  			return cfg.TCPPorts != "0"
    72  		},
    73  		"isHostPU": func() bool {
    74  			return cfg.AppSection == HostModeOutput && cfg.NetSection == HostModeInput
    75  		},
    76  		"isProcessPU": func() bool {
    77  			return cfg.PUType == common.LinuxProcessPU || cfg.PUType == common.WindowsProcessPU
    78  		},
    79  		"isIPV6Enabled": func() bool {
    80  			// icmpv6 rules are needed for ipv6
    81  			return cfg.needICMPRules
    82  		},
    83  	}).Parse(cgroupCaptureTemplate))
    84  
    85  	rules, err := extractRulesFromTemplate(tmpl, cfg)
    86  	if err != nil {
    87  		zap.L().Warn("unable to extract rules", zap.Error(err))
    88  	}
    89  	rules = append(rules, i.proxyRules(cfg)...)
    90  	rules = append(rules, i.proxyDNSRules(cfg)...)
    91  	return rules
    92  }
    93  
    94  // containerChainRules provides the list of rules that are used to send traffic to
    95  // a particular chain
    96  func (i *iptables) containerChainRules(cfg *ACLInfo) [][]string {
    97  	tmpl := template.Must(template.New(containerChainTemplate).Parse(containerChainTemplate))
    98  
    99  	rules, err := extractRulesFromTemplate(tmpl, cfg)
   100  	if err != nil {
   101  		zap.L().Warn("unable to extract rules", zap.Error(err))
   102  	}
   103  	rules = append(rules, i.istioRules(cfg)...)
   104  	if i.serviceMeshType == policy.None {
   105  		rules = append(rules, i.proxyRules(cfg)...)
   106  	}
   107  	rules = append(rules, i.proxyDNSRules(cfg)...)
   108  	return rules
   109  }
   110  
   111  func (i *iptables) istioRules(cfg *ACLInfo) [][]string {
   112  	if i.serviceMeshType == policy.Istio {
   113  		tmpl := template.Must(template.New(istioChainTemplate).Funcs(template.FuncMap{
   114  			"IstioUID": func() string {
   115  				return IstioUID
   116  			},
   117  		}).Parse(istioChainTemplate))
   118  		rules, err := extractRulesFromTemplate(tmpl, cfg)
   119  		if err != nil {
   120  			zap.L().Warn("unable to extract rules", zap.Error(err))
   121  		}
   122  		zap.L().Debug("configured Istio: ", zap.Any(" rules ", rules))
   123  		return rules
   124  	}
   125  	return nil
   126  }
   127  
   128  // proxyRules creates the rules that allow traffic to go through if it is handled
   129  // by the services.
   130  func (i *iptables) proxyRules(cfg *ACLInfo) [][]string {
   131  
   132  	tmpl := template.Must(template.New(proxyChainTemplate).Funcs(template.FuncMap{
   133  		"isCgroupSet": func() bool {
   134  			return cfg.CgroupMark != ""
   135  		},
   136  		"enableDNSProxy": func() bool {
   137  			return cfg.DNSServerIP != ""
   138  		},
   139  	}).Parse(proxyChainTemplate))
   140  
   141  	rules, err := extractRulesFromTemplate(tmpl, cfg)
   142  	if err != nil {
   143  		zap.L().Warn("unable to extract rules", zap.Error(err))
   144  	}
   145  	return rules
   146  }
   147  
   148  func (i *iptables) proxyDNSRules(cfg *ACLInfo) [][]string {
   149  	tmpl := template.Must(template.New(proxyDNSChainTemplate).Funcs(template.FuncMap{
   150  		"isCgroupSet": func() bool {
   151  			return cfg.CgroupMark != ""
   152  		},
   153  		"enableDNSProxy": func() bool {
   154  			return cfg.DNSServerIP != ""
   155  		},
   156  	}).Parse(proxyDNSChainTemplate))
   157  
   158  	rules, err := extractRulesFromTemplate(tmpl, cfg)
   159  	if err != nil {
   160  		zap.L().Warn("proxyDNSRules unable to extract rules", zap.Error(err))
   161  	}
   162  	return rules
   163  }
   164  
   165  // extractPreNetworkACLRules creates the rules that come before ACL rules.
   166  func (i *iptables) extractPreNetworkACLRules(cfg *ACLInfo) [][]string {
   167  
   168  	tmpl := template.Must(template.New(preNetworkACLRuleTemplate).Funcs(template.FuncMap{
   169  		"Increment": func(i int) int {
   170  			return i + 1
   171  		},
   172  	}).Parse(preNetworkACLRuleTemplate))
   173  
   174  	rules, err := extractRulesFromTemplate(tmpl, cfg)
   175  	if err != nil {
   176  		zap.L().Warn("unable to extract rules", zap.Error(err))
   177  	}
   178  	return rules
   179  }
   180  
   181  // trapRules provides the packet capture rules that are defined for each processing unit.
   182  func (i *iptables) trapRules(cfg *ACLInfo, isHostPU bool, appAnyRules, netAnyRules [][]string) [][]string {
   183  
   184  	outputMark, _ := strconv.Atoi(cfg.PacketMark)
   185  	outputMark = outputMark * cfg.NumNFQueues
   186  
   187  	tmpl := template.Must(template.New(packetCaptureTemplate).Funcs(template.FuncMap{
   188  		"windowsAllIpsetName": func() string {
   189  			return i.ipsetmanager.GetIPsetPrefix() + "WindowsAllIPs"
   190  		},
   191  		"packetMark": func() string {
   192  			outputMark, _ := strconv.Atoi(cfg.PacketMark)
   193  			outputMark = outputMark * cfg.NumNFQueues
   194  			return strconv.Itoa(outputMark)
   195  		},
   196  		"getOutputMark": func() string {
   197  			m := strconv.Itoa(outputMark)
   198  			outputMark++
   199  			return m
   200  		},
   201  		"queueBalance": func() string {
   202  			return fmt.Sprintf("0:%d", cfg.NumNFQueues-1)
   203  		},
   204  		"isNotContainerPU": func() bool {
   205  			return cfg.PUType != common.ContainerPU
   206  		},
   207  		"needDnsRules": func() bool {
   208  			return isHostPU
   209  		},
   210  		"needICMP": func() bool {
   211  			return cfg.needICMPRules
   212  		},
   213  		"appAnyRules": func() [][]string {
   214  			return appAnyRules
   215  		},
   216  		"netAnyRules": func() [][]string {
   217  			return netAnyRules
   218  		},
   219  		"joinRule": func(rule []string) string {
   220  			return strings.Join(rule, " ")
   221  		},
   222  		"isBPFEnabled": func() bool {
   223  			return i.bpf != nil
   224  		},
   225  		"isHostPU": func() bool {
   226  			return isHostPU
   227  		},
   228  		"Increment": func(i int) int {
   229  			return i + 1
   230  		},
   231  		"isAppDrop": func() bool {
   232  			return strings.EqualFold(cfg.AppDefaultAction, "DROP")
   233  		},
   234  		"isNetDrop": func() bool {
   235  			return strings.EqualFold(cfg.NetDefaultAction, "DROP")
   236  		},
   237  	}).Parse(packetCaptureTemplate))
   238  
   239  	rules, err := extractRulesFromTemplate(tmpl, cfg)
   240  	if err != nil {
   241  		zap.L().Warn("unable to extract rules", zap.Error(err))
   242  	}
   243  
   244  	return rules
   245  }
   246  
   247  // getProtocolAnyRules returns app any acls and net any acls.
   248  func (i *iptables) getProtocolAnyRules(cfg *ACLInfo, appRules, netRules []aclIPset) ([][]string, [][]string, error) {
   249  
   250  	appAnyRules, _ := extractProtocolAnyRules(appRules)
   251  	netAnyRules, _ := extractProtocolAnyRules(netRules)
   252  
   253  	sortedAppAnyRulesBuckets := i.sortACLsInBuckets(cfg, cfg.AppChain, cfg.NetChain, appAnyRules, true)
   254  	sortedNetAnyRulesBuckets := i.sortACLsInBuckets(cfg, cfg.NetChain, cfg.AppChain, netAnyRules, false)
   255  
   256  	sortedAppAnyRules, err := extractACLsFromTemplate(sortedAppAnyRulesBuckets)
   257  	if err != nil {
   258  		return nil, nil, fmt.Errorf("unable extract app protocol any rules: %v", err)
   259  	}
   260  
   261  	sortedNetAnyRules, err := extractACLsFromTemplate(sortedNetAnyRulesBuckets)
   262  	if err != nil {
   263  		return nil, nil, fmt.Errorf("unable extract net protocol any rules: %v", err)
   264  	}
   265  
   266  	sortedAppAnyRules = transformACLRules(sortedAppAnyRules, cfg, sortedAppAnyRulesBuckets, true)
   267  	sortedNetAnyRules = transformACLRules(sortedNetAnyRules, cfg, sortedNetAnyRulesBuckets, false)
   268  
   269  	return sortedAppAnyRules, sortedNetAnyRules, nil
   270  }
   271  
   272  func extractACLsFromTemplate(rulesBucket *rulesInfo) ([][]string, error) {
   273  
   274  	tmpl := template.Must(template.New(acls).Funcs(template.FuncMap{
   275  		"joinRule": func(rule []string) string {
   276  			return shellquote.Join(rule...)
   277  		},
   278  	}).Parse(acls))
   279  
   280  	aclRules, err := extractRulesFromTemplate(tmpl, *rulesBucket)
   281  	if err != nil {
   282  		return nil, fmt.Errorf("unable to extract rules from template: %s", err)
   283  	}
   284  
   285  	return aclRules, nil
   286  }
   287  
   288  // extractProtocolAnyRules extracts protocol any rules from the set and returns
   289  // protocol any rules and all other rules without any.
   290  func extractProtocolAnyRules(rules []aclIPset) (anyRules []aclIPset, otherRules []aclIPset) {
   291  
   292  	for _, rule := range rules {
   293  		for _, proto := range rule.Protocols {
   294  
   295  			if proto != constants.AllProtoString {
   296  				otherRules = append(otherRules, rule)
   297  				continue
   298  			}
   299  
   300  			anyRules = append(anyRules, rule)
   301  		}
   302  	}
   303  
   304  	return anyRules, otherRules
   305  }
   306  
   307  // processRulesFromList is a generic helper that parses a set of rules and sends the corresponding
   308  // ACL commands.
   309  func (i *iptables) processRulesFromList(rulelist [][]string, methodType string) error {
   310  	var err error
   311  	for _, cr := range rulelist {
   312  		// HACK: Adding a retry loop to avoid iptables error of "invalid argument"
   313  		// Once in a while iptables
   314  	L:
   315  		for retry := 0; retry < 3; retry++ {
   316  			switch methodType {
   317  			case "Append":
   318  				if err = i.impl.Append(cr[0], cr[1], cr[2:]...); err == nil {
   319  					break L
   320  				}
   321  			case "Insert":
   322  				order, err := strconv.Atoi(cr[2])
   323  				if err != nil {
   324  					zap.L().Error("Incorrect format for iptables insert")
   325  					return errors.New("invalid format")
   326  				}
   327  				if err = i.impl.Insert(cr[0], cr[1], order, cr[3:]...); err == nil {
   328  					break L
   329  				}
   330  
   331  			case "Delete":
   332  				if err = i.impl.Delete(cr[0], cr[1], cr[2:]...); err == nil {
   333  					break L
   334  				}
   335  
   336  			default:
   337  				return errors.New("invalid method type")
   338  			}
   339  		}
   340  		if err != nil && methodType != "Delete" {
   341  			return fmt.Errorf("unable to %s rule for table %s and chain %s with error %s", methodType, cr[0], cr[1], err)
   342  		}
   343  	}
   344  
   345  	return nil
   346  }
   347  
   348  // addChainrules implements all the iptable rules that redirect traffic to a chain
   349  func (i *iptables) addChainRules(cfg *ACLInfo) error {
   350  	if i.mode != constants.LocalServer {
   351  		return i.processRulesFromList(i.containerChainRules(cfg), "Append")
   352  	}
   353  
   354  	return i.processRulesFromList(i.cgroupChainRules(cfg), "Append")
   355  }
   356  
   357  // addPacketTrap adds the necessary iptables rules to capture control packets to user space
   358  func (i *iptables) addPacketTrap(cfg *ACLInfo, isHostPU bool, appAnyRules, netAnyRules [][]string) error {
   359  
   360  	return i.processRulesFromList(i.trapRules(cfg, isHostPU, appAnyRules, netAnyRules), "Append")
   361  }
   362  
   363  // programExtensionsRules programs iptable rules for the given extensions
   364  func (i *iptables) programExtensionsRules(contextID string, rule *aclIPset, chain, proto, ipMatchDirection, nfLogGroup string) error {
   365  
   366  	rulesspec := []string{
   367  		"-p", proto,
   368  		"-m", "set", "--match-set", rule.ipset, ipMatchDirection,
   369  	}
   370  
   371  	for _, ext := range rule.Extensions {
   372  		if rule.Policy.Action&policy.Log > 0 {
   373  			if err := i.programNflogExtensionRule(contextID, rule, rulesspec, ext, chain, nfLogGroup); err != nil {
   374  				return fmt.Errorf("unable to program nflog extension: %v", err)
   375  			}
   376  		}
   377  
   378  		args, err := shellwords.Parse(ext)
   379  		if err != nil {
   380  			return fmt.Errorf("unable to parse extension %s: %v", ext, err)
   381  		}
   382  
   383  		extRulesSpec := append(rulesspec, args...)
   384  		if err := i.impl.Append(appPacketIPTableContext, chain, extRulesSpec...); err != nil {
   385  			return fmt.Errorf("unable to program extension rules: %v", err)
   386  		}
   387  	}
   388  
   389  	return nil
   390  }
   391  
   392  // WARNING: The extension should always contain the action at the end else,
   393  // the function returns error.
   394  func (i *iptables) programNflogExtensionRule(contextID string, rule *aclIPset, rulesspec []string, ext string, chain, nfLogGroup string) error {
   395  
   396  	parts := strings.SplitN(ext, " -j ", 2)
   397  	if len(parts) != 2 {
   398  		return fmt.Errorf("invalid extension format: %s", ext)
   399  	}
   400  	filter, target := parts[0], parts[1]
   401  
   402  	if filter == "" || target == "" {
   403  		return fmt.Errorf("filter or target is empty: %s", ext)
   404  	}
   405  
   406  	filterArgs, err := shellwords.Parse(filter)
   407  	if err != nil {
   408  		return fmt.Errorf("unable to parse extension %s: %v", ext, err)
   409  	}
   410  
   411  	action := "3"
   412  	if target == "DROP" {
   413  		action = "6"
   414  	}
   415  
   416  	defaultNflogSuffix := []string{"-m", "state", "--state", "NEW",
   417  		"-j", "NFLOG", "--nflog-group", nfLogGroup, "--nflog-prefix", rule.Policy.LogPrefixAction(contextID, action)}
   418  	filterArgs = append(filterArgs, defaultNflogSuffix...)
   419  
   420  	nflogRulesspec := append(rulesspec, filterArgs...)
   421  	return i.impl.Append(appPacketIPTableContext, chain, nflogRulesspec...)
   422  }
   423  
   424  // sortACLsInBuckets will process all the rules and add them in a list of buckets
   425  // based on their priority. We need an explicit order of these buckets
   426  // in order to support observation only of ACL actions. The parameters
   427  // must provide the chain and whether it is App or Net ACLs so that the rules
   428  // can be created accordingly.
   429  func (i *iptables) sortACLsInBuckets(cfg *ACLInfo, chain string, reverseChain string, rules []aclIPset, isAppACLs bool) *rulesInfo {
   430  
   431  	rulesBucket := &rulesInfo{
   432  		RejectObserveApply:    [][]string{},
   433  		RejectNotObserved:     [][]string{},
   434  		RejectObserveContinue: [][]string{},
   435  		AcceptObserveApply:    [][]string{},
   436  		AcceptNotObserved:     [][]string{},
   437  		AcceptObserveContinue: [][]string{},
   438  		ReverseRules:          [][]string{},
   439  	}
   440  
   441  	direction := "src"
   442  	reverse := "dst"
   443  	nflogGroup := "11"
   444  	if isAppACLs {
   445  		direction = "dst"
   446  		reverse = "src"
   447  		nflogGroup = "10"
   448  	}
   449  
   450  	for _, rule := range rules {
   451  
   452  		for _, proto := range rule.Protocols {
   453  
   454  			if !i.impl.ProtocolAllowed(proto) {
   455  				continue
   456  			}
   457  
   458  			if i.aclSkipProto(proto) {
   459  				continue
   460  			}
   461  
   462  			acls, r := i.generateACLRules(cfg, &rule, chain, reverseChain, nflogGroup, proto, direction, reverse, isAppACLs)
   463  			rulesBucket.ReverseRules = append(rulesBucket.ReverseRules, r...)
   464  
   465  			if testReject(rule.Policy) && testObserveApply(rule.Policy) {
   466  				rulesBucket.RejectObserveApply = append(rulesBucket.RejectObserveApply, acls...)
   467  			}
   468  
   469  			if testReject(rule.Policy) && testNotObserved(rule.Policy) {
   470  				rulesBucket.RejectNotObserved = append(rulesBucket.RejectNotObserved, acls...)
   471  			}
   472  
   473  			if testReject(rule.Policy) && testObserveContinue(rule.Policy) {
   474  				rulesBucket.RejectObserveContinue = append(rulesBucket.RejectObserveContinue, acls...)
   475  			}
   476  
   477  			if testAccept(rule.Policy) && testObserveContinue(rule.Policy) {
   478  				rulesBucket.AcceptObserveContinue = append(rulesBucket.AcceptObserveContinue, acls...)
   479  			}
   480  
   481  			if testAccept(rule.Policy) && testNotObserved(rule.Policy) {
   482  				rulesBucket.AcceptNotObserved = append(rulesBucket.AcceptNotObserved, acls...)
   483  			}
   484  
   485  			if testAccept(rule.Policy) && testObserveApply(rule.Policy) {
   486  				rulesBucket.AcceptObserveApply = append(rulesBucket.AcceptObserveApply, acls...)
   487  			}
   488  		}
   489  	}
   490  
   491  	return rulesBucket
   492  }
   493  
   494  // addExternalACLs adds a set of rules to the external services that are initiated
   495  // by an application. The allow rules are inserted with highest priority.
   496  func (i *iptables) addExternalACLs(cfg *ACLInfo, chain string, reverseChain string, rules []aclIPset, isAppAcls bool) error {
   497  
   498  	_, rules = extractProtocolAnyRules(rules)
   499  
   500  	rulesBucket := i.sortACLsInBuckets(cfg, chain, reverseChain, rules, isAppAcls)
   501  
   502  	aclRules, err := extractACLsFromTemplate(rulesBucket)
   503  	if err != nil {
   504  		return fmt.Errorf("unable to extract rules from template: %s", err)
   505  	}
   506  
   507  	aclRules = transformACLRules(aclRules, cfg, rulesBucket, isAppAcls)
   508  
   509  	if err := i.processRulesFromList(aclRules, "Append"); err != nil {
   510  		return fmt.Errorf("unable to install rules - mode :%s %v", err, isAppAcls)
   511  	}
   512  
   513  	return nil
   514  }
   515  
   516  func (i *iptables) addPreNetworkACLRules(cfg *ACLInfo) error {
   517  
   518  	rules := i.extractPreNetworkACLRules(cfg)
   519  
   520  	if err := i.processRulesFromList(rules, "Append"); err != nil {
   521  		return fmt.Errorf("unable to install networkd SYN rule : %s", err)
   522  	}
   523  
   524  	return nil
   525  }
   526  
   527  // deleteChainRules deletes the rules that send traffic to our chain
   528  func (i *iptables) deleteChainRules(cfg *ACLInfo) error {
   529  
   530  	if i.mode != constants.LocalServer {
   531  		return i.processRulesFromList(i.containerChainRules(cfg), "Delete")
   532  	}
   533  
   534  	return i.processRulesFromList(i.cgroupChainRules(cfg), "Delete")
   535  }
   536  
   537  // setGlobalRules installs the global rules
   538  func (i *iptables) setGlobalRules() error {
   539  	cfg, err := i.newACLInfo(0, "", nil, 0)
   540  	if err != nil {
   541  		return err
   542  	}
   543  
   544  	_, _, excludedNetworkName := i.ipsetmanager.GetIPsetNamesForTargetAndExcludedNetworks()
   545  
   546  	inputMark, _ := strconv.Atoi(cfg.DefaultInputMark) //nolint
   547  	outputMark := 0
   548  
   549  	tmpl := template.Must(template.New(globalRules).Funcs(template.FuncMap{
   550  		"isIstioEnabled": func() bool {
   551  			return i.serviceMeshType == policy.Istio
   552  		},
   553  		"IstioRedirPort": func() string {
   554  			return IstioRedirPort
   555  		},
   556  		"getInputMark": func() string {
   557  			m := strconv.Itoa(inputMark)
   558  			inputMark++
   559  			return m
   560  		},
   561  		"getOutputMark": func() string {
   562  			m := strconv.Itoa(outputMark)
   563  			outputMark++
   564  			return m
   565  		},
   566  		"queueBalance": func() string {
   567  			return fmt.Sprintf("0:%d", cfg.NumNFQueues-1)
   568  		},
   569  		"isLocalServer": func() bool {
   570  			return i.mode == constants.LocalServer
   571  		},
   572  		"isBPFEnabled": func() bool {
   573  			return i.bpf != nil
   574  		},
   575  		"enableDNSProxy": func() bool {
   576  			return cfg.DNSServerIP != ""
   577  		},
   578  		"Increment": func(i int) int {
   579  			return i + 1
   580  		},
   581  		"EnforcerPID": func() string {
   582  			return strconv.Itoa(getEnforcerPID())
   583  		},
   584  		"CnsAgentMgrPID": func() string {
   585  			return strconv.Itoa(getCnsAgentMgrPID())
   586  		},
   587  		"CnsAgentBootPID": func() string {
   588  			return strconv.Itoa(getCnsAgentBootPID())
   589  		},
   590  		"isManagedByCnsAgentManager": func() bool {
   591  			return getCnsAgentBootPID() > 0
   592  		},
   593  		"isIPv4": func() bool {
   594  			return i.impl.IPVersion() == IPV4
   595  		},
   596  		"windowsDNSServerName": func() string {
   597  			return i.ipsetmanager.GetIPsetPrefix() + "WindowsDNSServer"
   598  		},
   599  		"isKubernetesPU": func() bool {
   600  			return cfg.PUType == common.KubernetesPU
   601  		},
   602  		"needICMP": func() bool {
   603  			return cfg.needICMPRules
   604  		},
   605  	}).Parse(globalRules))
   606  
   607  	rules, err := extractRulesFromTemplate(tmpl, cfg)
   608  	if err != nil {
   609  		zap.L().Warn("unable to extract rules", zap.Error(err))
   610  	}
   611  
   612  	if err := i.processRulesFromList(rules, "Append"); err != nil {
   613  		return fmt.Errorf("unable to install global rules:%s", err)
   614  	}
   615  
   616  	// Insert the Istio nat rules into the ISTIO_OUTPUT table
   617  	// the following is done so that there is no loop in the dataPath.
   618  	// basically, the envoy packets which are already processed by us, we should
   619  	// accept the packets.
   620  	if i.serviceMeshType == policy.Istio {
   621  		err = i.impl.Insert(appProxyIPTableContext,
   622  			ipTableSectionOutput, 1,
   623  			"-p", "tcp",
   624  			"-m", "mark", "--mark", strconv.Itoa(markconstants.IstioPacketMark),
   625  			"-j", "ACCEPT")
   626  		if err != nil {
   627  			return fmt.Errorf("unable to add Istio accept for marked packets : %s", err)
   628  		}
   629  	}
   630  
   631  	// nat rules cannot be templated, since they interfere with Docker.
   632  	err = i.impl.Insert(appProxyIPTableContext,
   633  		ipTableSectionPreRouting, 1,
   634  		"-p", "tcp",
   635  		"-m", "addrtype", "--dst-type", "LOCAL",
   636  		"-m", "set", "!", "--match-set", excludedNetworkName, "src",
   637  		"-j", natProxyInputChain)
   638  	if err != nil {
   639  		return fmt.Errorf("unable to add default allow for marked packets at net: %s", err)
   640  	}
   641  
   642  	err = i.impl.Insert(appProxyIPTableContext,
   643  		ipTableSectionOutput, 1,
   644  		"-m", "set", "!", "--match-set", excludedNetworkName, "dst",
   645  		"-j", natProxyOutputChain)
   646  	if err != nil {
   647  		return fmt.Errorf("unable to add default allow for marked packets at net: %s", err)
   648  	}
   649  
   650  	return nil
   651  }
   652  
   653  func (i *iptables) removeGlobalHooks(cfg *ACLInfo) error {
   654  
   655  	tmpl := template.Must(template.New(globalHooks).Funcs(template.FuncMap{
   656  		"isLocalServer": func() bool {
   657  			return i.mode == constants.LocalServer
   658  		},
   659  	}).Parse(globalHooks))
   660  
   661  	rules, err := extractRulesFromTemplate(tmpl, cfg)
   662  	if err != nil {
   663  		return fmt.Errorf("unable to create trireme chains:%s", err)
   664  	}
   665  
   666  	i.processRulesFromList(rules, "Delete") // nolint
   667  	return nil
   668  }
   669  
   670  func (i *iptables) generateACLRules(cfg *ACLInfo, rule *aclIPset, chain string, reverseChain string, nfLogGroup, proto, ipMatchDirection string, reverseDirection string, isAppACLs bool) ([][]string, [][]string) {
   671  
   672  	iptRules := [][]string{}
   673  	reverseRules := [][]string{}
   674  
   675  	targetTCPName, targetUDPName, _ := i.ipsetmanager.GetIPsetNamesForTargetAndExcludedNetworks()
   676  
   677  	observeContinue := rule.Policy.ObserveAction.ObserveContinue()
   678  	contextID := cfg.ContextID
   679  
   680  	baseRule := func(proto string) []string {
   681  
   682  		iptRule := []string{appPacketIPTableContext, chain}
   683  
   684  		if splits := strings.Split(proto, "/"); strings.ToUpper(splits[0]) == protocols.L4ProtocolICMP || strings.ToUpper(splits[0]) == protocols.L4ProtocolICMP6 {
   685  			iptRule = append(iptRule, icmpRule(proto, rule.Ports)...)
   686  
   687  			if strings.ToUpper(splits[0]) == protocols.L4ProtocolICMP6 {
   688  				proto = "icmpv6"
   689  			} else {
   690  				proto = "icmp"
   691  			}
   692  		}
   693  
   694  		iptRule = append(iptRule, []string{
   695  			"-p", proto,
   696  			"-m", "set", "--match-set", rule.ipset, ipMatchDirection,
   697  		}...)
   698  
   699  		if proto == constants.UDPProtoNum || proto == constants.UDPProtoString {
   700  			udpRule := generateUDPACLRule()
   701  			iptRule = append(iptRule, udpRule...)
   702  		}
   703  
   704  		if proto == constants.TCPProtoNum || proto == constants.TCPProtoString {
   705  			stateMatch := []string{"-m", "state", "--state", "NEW"}
   706  			iptRule = append(iptRule, stateMatch...)
   707  		}
   708  
   709  		// add the target network condition if tcp and not a reject action and is the app chain
   710  		if (rule.Policy.Action&policy.Reject == 0 && isAppACLs) && (proto == constants.TCPProtoNum || proto == constants.TCPProtoString) {
   711  			targetNet := []string{"-m", "set", "!", "--match-set", targetTCPName, ipMatchDirection}
   712  			iptRule = append(iptRule, targetNet...)
   713  		}
   714  
   715  		// add the target network condition if tcp and not a reject action and is the app chain
   716  		if (rule.Policy.Action&policy.Reject == 0 && isAppACLs) && (proto == constants.UDPProtoNum || proto == constants.UDPProtoString) {
   717  
   718  			targetUDPClause := targetUDPNetworkClause(rule, targetUDPName, ipMatchDirection)
   719  			if len(targetUDPClause) > 0 {
   720  				iptRule = append(iptRule, targetUDPClause...)
   721  			}
   722  
   723  		}
   724  		// port match is required only for tcp and udp protocols
   725  		if proto == constants.TCPProtoNum || proto == constants.UDPProtoNum || proto == constants.TCPProtoString || proto == constants.UDPProtoString {
   726  
   727  			portMatchSet := []string{"--match", "multiport", "--dports", strings.Join(rule.Ports, ",")}
   728  			iptRule = append(iptRule, portMatchSet...)
   729  		}
   730  
   731  		return iptRule
   732  	}
   733  
   734  	if err := i.programExtensionsRules(contextID, rule, chain, proto, ipMatchDirection, nfLogGroup); err != nil {
   735  		zap.L().Warn("unable to program extension rules",
   736  			zap.Error(err),
   737  		)
   738  	}
   739  
   740  	// If log or observeContinue
   741  	if rule.Policy.Action&policy.Log != 0 || observeContinue {
   742  		state := []string{}
   743  		if proto == constants.TCPProtoNum || proto == constants.UDPProtoNum || proto == constants.TCPProtoString || proto == constants.UDPProtoString {
   744  			state = []string{"-m", "state", "--state", "NEW"}
   745  		}
   746  
   747  		nflog := append(state, []string{"-j", "NFLOG", "--nflog-group", nfLogGroup, "--nflog-prefix", rule.Policy.LogPrefix(contextID)}...)
   748  		nfLogRule := append(baseRule(proto), nflog...)
   749  
   750  		iptRules = append(iptRules, nfLogRule)
   751  	}
   752  
   753  	if !observeContinue {
   754  		if (rule.Policy.Action & policy.Accept) != 0 {
   755  			if proto == constants.UDPProtoNum || proto == constants.UDPProtoString {
   756  				connmarkClause := connmarkUDPConnmarkClause()
   757  				if len(connmarkClause) > 0 {
   758  					connmarkRule := append(baseRule(proto), connmarkClause...)
   759  					iptRules = append(iptRules, connmarkRule)
   760  				}
   761  			}
   762  			acceptRule := append(baseRule(proto), []string{"-j", "ACCEPT"}...)
   763  			iptRules = append(iptRules, acceptRule)
   764  		}
   765  
   766  		if rule.Policy.Action&policy.Reject != 0 {
   767  			reject := []string{"-j", "DROP"}
   768  			rejectRule := append(baseRule(proto), reject...)
   769  			iptRules = append(iptRules, rejectRule)
   770  		}
   771  
   772  		if rule.Policy.Action&policy.Accept != 0 && (proto == constants.UDPProtoNum || proto == constants.UDPProtoString) {
   773  			reverseRules = append(reverseRules, []string{
   774  				appPacketIPTableContext,
   775  				reverseChain,
   776  				"-p", proto,
   777  				"-m", "set", "--match-set", rule.ipset, reverseDirection,
   778  				"-m", "state", "--state", "ESTABLISHED",
   779  				"-m", "connmark", "--mark", strconv.Itoa(int(markconstants.DefaultExternalConnMark)),
   780  				"-j", "ACCEPT",
   781  			})
   782  		}
   783  	}
   784  
   785  	return iptRules, reverseRules
   786  }