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 }