Example #1
0
// EnsureRule implements Firewall interface. It schedules given rule for
// transition in given state and stores it in firewall store.
func (i *IPTsaveFirewall) EnsureRule(rule FirewallRule, opType RuleState) error {
	log.Infof("In EnsureRule() with firewall rule %s %s", opType.String(), rule.GetBody())

	var ruleExists bool

	// This firewall only manages filtering rules so it only operates
	// on `filter` table.
	table := i.DesiredState.TableByName("filter")
	if table == nil {
		return fmt.Errorf("In EnsureRule() firewall doesn't have filter table")
	}

	// Convert iptables rule from Firewall interface into iptsave.IPrule.
	tempChain := iptsave.ParseRule(bytes.NewReader([]byte(rule.GetBody())))
	ipRule := tempChain.Rules[0]

	// Ensure that base chain of the rule is defined in desired state.
	chain := table.ChainByName(tempChain.Name)
	if chain == nil {
		table.Chains = append(table.Chains, tempChain)
		chain = tempChain

		// we just added a chain with our rule
		// into the filter table so we know that
		// target rule is in the table.
		ruleExists = true
	}

	// If we didn't put that rule in the table ourselves yet then
	// try to find it in existing table.
	if !ruleExists {
		ruleExists = chain.RuleInChain(ipRule)
	}

	if ruleExists {
		switch opType {
		case EnsureAbsent:
			log.Infof("In EnsureRule - rule %s exists in current state, removing", rule.GetBody())
			chain.DeleteRule(ipRule)
		default:
			log.Infof("In EnsureRule - nothing to do %s", rule.GetBody())
		}
	} else {
		log.Infof("In EnsureRule - rule %s doesn't exist is current state, %s", rule.GetBody(), opType.String())
		switch opType {
		case EnsureLast:
			chain.AppendRule(ipRule)
		case EnsureFirst:
			chain.InsertRule(0, ipRule)
		default:
			log.Infof("In EnsureRule - nothing to do %s", rule.GetBody())
		}
	}

	return nil
}
Example #2
0
// makeUndoRule checks if given rule is present in current state and if so it generates
// an undo rule in desired state.
func makeUndoRule(rule FirewallRule, tableCurrent, tableDesired *iptsave.IPtable) {
	// If rule exists in current state then we want to delete it
	// in order to do so we will generate an `undo` rule and schedule
	// the `undo` rule for installation by putting it in desired state.
	// e.g. current rule
	// "-A INPUT -j DROP"
	// `undo` rule in desired state is
	// "-D INPUT -j DROP"

	// convert iptables rule from Firewall interface into iptsave.IPrule
	tempChain := iptsave.ParseRule(bytes.NewReader([]byte(rule.GetBody())))
	ipRule := tempChain.Rules[0]

	// check if chain exists in current iptables config
	chain := tableCurrent.ChainByName(tempChain.Name)
	if chain == nil {
		// if chain isn't in iptables config then none of the rules are
		// just skip them
		return
	}

	// scheduling rule deletion
	if chain.RuleInChain(ipRule) {
		ipRule.RenderState = iptsave.RenderDeleteRule

		// check if base chain exists in DesiredState
		chain = tableDesired.ChainByName(tempChain.Name)
		if chain == nil {
			// if not then create a new one
			chain = &iptsave.IPchain{Name: tempChain.Name, Policy: "-"}
			tableDesired.Chains = append(tableDesired.Chains, chain)
		}

		chain.AppendRule(ipRule)

		// if rule targets a chain that chain must be defined
		// in an iptables table
		// It's hard to tell iptables chain from custom modules
		// in iptables rule action, like `-j RESET` could be a jump
		// to RESET chain or call to custom module with RESET name.
		// Here, strategy is to check current state for chain with
		// name that corresponds to current rule action target,
		// if such chain exist then add it in desired state as well
		// otherwise assume the call to custom module.
		// ipRule.Action.Body is the 'target' of a rule, typically the name of another chain.
		targetChain := tableCurrent.ChainByName(ipRule.Action.Body)
		if targetChain != nil {
			if inDesiredStateAlready := tableDesired.ChainByName(ipRule.Action.Body); inDesiredStateAlready == nil {
				tableDesired.Chains = append(tableDesired.Chains, targetChain)
			}
		}
	}
}