"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "go/pkg/pass1/distribute-rules.go" between
Netspoc-6.026.tar.gz and Netspoc-6.027.tar.gz

About: NetSPoC is a network security policy compiler (using its own description language) to manage all the packet filter devices inside your network topology.

distribute-rules.go  (Netspoc-6.026):distribute-rules.go  (Netspoc-6.027)
package pass1 package pass1
import ( import (
"net" "inet.af/netaddr"
"sort" "sort"
) )
func (l *ruleList) push(r *groupedRule) {
*l = append(*l, r)
}
//############################################################################# //#############################################################################
// Distributing rules to managed devices // Distributing rules to managed devices
//############################################################################# //#############################################################################
func distributeRule(rule *groupedRule, inIntf, outIntf *routerIntf) { func distributeRule(ru *groupedRule, in, out *routerIntf) {
// Traffic from src reaches this router via inIntf // Traffic from ru.src reaches this router via in
// and leaves it via outIntf. // and leaves it via out.
// inIntf is undefined if src is an interface of current router. // in is undefined if src is an interface of current router.
// outIntf is undefined if dst is an interface of current router. // out is undefined if dst is an interface of current router.
// Outgoing packets from a router itself are never filtered. // Outgoing packets from a router itself are never filtered.
if inIntf == nil { if in == nil {
return return
} }
router := inIntf.router r := in.router
if router.managed == "" { if r.managed == "" {
return return
} }
model := router.model model := r.model
// Rules of type stateless must only be processed at // Rules of type stateless must only be processed at
// - stateless routers or // - stateless routers or
// - routers which are stateless for packets destined for // - routers which are stateless for packets destined for
// their own interfaces or // their own interfaces or
// - stateless tunnel interfaces of ASA-VPN. // - stateless tunnel interfaces of ASA-VPN.
if rule.stateless { if ru.stateless {
if !(model.stateless || outIntf == nil && model.statelessSelf) { if !(model.stateless || out == nil && model.statelessSelf) {
return return
} }
} }
// Rules of type statelessIcmp must only be processed at routers // Rules of type statelessIcmp must only be processed at routers
// which don't handle statelessIcmp automatically; // which don't handle statelessIcmp automatically;
if rule.statelessICMP && !model.statelessICMP { if ru.statelessICMP && !model.statelessICMP {
return return
} }
// Apply only matching rules to 'managed=local' router. // Apply only matching rules to 'managed=local' router.
// Filter out non matching elements from srcList and dstList. // Filter out non matching elements from srcList and dstList.
if mark := router.localMark; mark != 0 { if mark := r.localMark; mark != 0 {
filter := func(list []someObj) []someObj { filter := func(list []someObj) []someObj {
var result []someObj var result []someObj
for _, obj := range list { for _, obj := range list {
net := obj.getNetwork() net := obj.getNetwork()
filterAt := net.filterAt filterAt := net.filterAt
if filterAt[mark] { if filterAt[mark] {
result = append(result, obj) result = append(result, obj)
} }
} }
return result return result
} }
// Filter srcList and dstList. Ignore rule if no matching element . // Filter srcList and dstList. Ignore rule if no matching element .
srcList := rule.src srcList := ru.src
matchingSrc := filter(srcList) matchingSrc := filter(srcList)
if matchingSrc == nil { if matchingSrc == nil {
return return
} }
dstList := rule.dst dstList := ru.dst
matchingDst := filter(dstList) matchingDst := filter(dstList)
if matchingDst == nil { if matchingDst == nil {
return return
} }
// Create copy of rule. Try to reuse original srcList / dstList. // Create copy of rule. Try to reuse original srcList / dstList.
copy := *rule cp := *ru
rule = &copy ru = &cp
// Overwrite only if list has changed. // Overwrite only if list has changed.
if len(srcList) != len(matchingSrc) { if len(srcList) != len(matchingSrc) {
rule.src = matchingSrc ru.src = matchingSrc
} }
if len(dstList) != len(matchingDst) { if len(dstList) != len(matchingDst) {
rule.dst = matchingDst ru.dst = matchingDst
} }
} }
intfRules := false intfRules := false
// Packets for the router itself. // Packets for the router itself.
if outIntf == nil { if out == nil {
// No ACL generated for traffic to device itself. // No ACL generated for traffic to device itself.
if model.filter == "ASA" { if model.filter == "ASA" {
return return
} }
intfRules = true intfRules = true
} else { } else {
if outIntf.hardware.needOutAcl { if out.hardware.needOutAcl {
outIntf.hardware.outRules.push(rule) out.hardware.outRules.push(ru)
if inIntf.hardware.noInAcl { if in.hardware.noInAcl {
return return
} }
} }
// Outgoing rules are needed at tunnel for generating // Outgoing rules are needed at tunnel for generating
// detailedCryptoAcl. // detailedCryptoAcl.
if outIntf.ipType == tunnelIP && if out.ipType == tunnelIP &&
outIntf.getCrypto().detailedCryptoAcl && out.getCrypto().detailedCryptoAcl &&
outIntf.idRules == nil { out.idRules == nil {
outIntf.outRules.push(rule)
out.outRules.push(ru)
} }
} }
addRule := func(intf *routerIntf, rule *groupedRule) { addRule := func(intf *routerIntf, ru *groupedRule) {
if intfRules { if intfRules {
intf.intfRules = append(intf.intfRules, rule) intf.intfRules.push(ru)
} else { } else {
intf.rules = append(intf.rules, rule) intf.rules.push(ru)
} }
} }
if inIntf.ipType == tunnelIP { if in.ipType == tunnelIP {
noCryptoFilter := model.noCryptoFilter
// Rules for single software clients are stored individually. // Rules for single software clients are stored individually.
// Consistency checks have already been done at expandCrypto. // Consistency checks have already been done at expandCrypto.
// Rules are needed at tunnel for generating split tunnel ACL // Rules are needed at tunnel for generating split tunnel ACL
// regardless of noCryptoFilter value. // regardless of noCryptoFilter value.
if id2rules := inIntf.idRules; id2rules != nil { if id2rules := in.idRules; id2rules != nil {
srcList := rule.src
var extraHosts []someObj var extraHosts []someObj
for _, src := range srcList { for _, src := range ru.src {
// Check individual ID hosts of network at // Check individual ID hosts of network at
// authenticating router. // authenticating router.
if network, ok := src.(*network); ok { if network, ok := src.(*network); ok {
if network.hasIdHosts { if network.hasIdHosts {
for _, host := range network.subn ets { for _, host := range network.subn ets {
id := host.id id := host.id
newRule := *rule newRule := *ru
newRule.src = []someObj{h ost} newRule.src = []someObj{h ost}
addRule(id2rules[id].rout erIntf, &newRule) addRule(id2rules[id].rout erIntf, &newRule)
extraHosts = append(extra Hosts, host) extraHosts = append(extra Hosts, host)
} }
} }
continue continue
} }
id := src.(*subnet).id id := src.(*subnet).id
newRule := *rule newRule := *ru
newRule.src = []someObj{src} newRule.src = []someObj{src}
addRule(id2rules[id].routerIntf, &newRule) addRule(id2rules[id].routerIntf, &newRule)
} }
if extraHosts != nil && noCryptoFilter { if extraHosts != nil && model.noCryptoFilter {
for _, src := range srcList { for _, src := range ru.src {
if _, ok := src.(*subnet); ok { if _, ok := src.(*subnet); ok {
extraHosts = append(extraHosts, s rc) extraHosts = append(extraHosts, s rc)
} }
} }
copy := *rule cp := *ru
rule = &copy ru = &cp
rule.src = extraHosts ru.src = extraHosts
} }
} }
addRule(inIntf, rule) addRule(in, ru)
} else if !intfRules && model.hasIoACL { } else if !intfRules && model.hasIoACL {
// Remember outgoing interface. // Remember outgoing interface.
m := inIntf.hardware.ioRules m := in.hardware.ioRules
if m == nil { if m == nil {
m = make(map[string]ruleList) m = make(map[string]ruleList)
inIntf.hardware.ioRules = m in.hardware.ioRules = m
} }
n := outIntf.hardware.name n := out.hardware.name
m[n] = append(m[n], rule) m[n] = append(m[n], ru)
} else { } else {
hw := inIntf.hardware hw := in.hardware
if intfRules { if intfRules {
hw.intfRules = append(hw.intfRules, rule) hw.intfRules.push(ru)
} else { } else {
hw.rules = append(hw.rules, rule) hw.rules.push(ru)
} }
} }
} }
func getMulticastObjects(info mcastInfo, ipV6 bool) []someObj { func getMulticastObjects(info *mcastProto, ipV6 bool) []someObj {
var ipList []string var m *multicast
if ipV6 { if ipV6 {
ipList = info.v6 m = &info.v6
} else { } else {
ipList = info.v4 m = &info.v4
} }
result := make([]someObj, len(ipList)) if m.networks == nil {
for i, s := range ipList { l := make([]*network, len(m.ips))
ip := net.ParseIP(s) for i, s := range m.ips {
result[i] = &network{ipObj: ipObj{ip: ip}, mask: getHostMask(ipV6 ip := netaddr.MustParseIP(s)
)} l[i] =
&network{ipp: netaddr.IPPrefix{IP: ip, Bits: getH
ostPrefix(ipV6)}}
}
m.networks = l
}
result := make([]someObj, len(m.networks))
for i, n := range m.networks {
result[i] = n
} }
return result return result
} }
func (c *spoc) addRouterAcls() { func (c *spoc) addRouterAcls() {
for _, router := range c.managedRouters { for _, r := range c.managedRouters {
ipv6 := router.ipV6 ipv6 := r.ipV6
hasIoACL := router.model.hasIoACL hasIoACL := r.model.hasIoACL
hardwareList := router.hardware hardwareList := r.hardware
for _, hardware := range hardwareList { for _, hw := range hardwareList {
// Some managed devices are connected by a crosslink netw ork. // Some managed devices are connected by a crosslink netw ork.
// Permit any traffic at the internal crosslink interface . // Permit any traffic at the internal crosslink interface .
if hardware.crosslink { if hw.crosslink {
permitAny := []*groupedRule{getPermitAnyRule(ipv6 )} permitAny := []*groupedRule{getPermitAnyRule(ipv6 )}
// We can savely change rules at hardware interfa ce // We can savely change rules at hardware interfa ce
// because it has been checked that no other logi cal // because it has been checked that no other logi cal
// networks are attached to the same hardware. // networks are attached to the same hardware.
// //
// Substitute or set rules for each outgoing inte rface. // Substitute or set rules for each outgoing inte rface.
if hasIoACL { if hasIoACL {
for _, outHardware := range hardwareList for _, outHw := range hardwareList {
{ if hw == outHw {
if hardware == outHardware {
continue continue
} }
if hardware.ioRules == nil { if hw.ioRules == nil {
hardware.ioRules = make(m hw.ioRules = make(map[str
ap[string]ruleList) ing]ruleList)
} }
hardware.ioRules[outHardware.name ] = permitAny hw.ioRules[outHw.name] = permitAn y
} }
} else { } else {
hardware.rules = permitAny hw.rules = permitAny
if hardware.needOutAcl { if hw.needOutAcl {
hardware.outRules = permitAny hw.outRules = permitAny
} }
} }
hardware.intfRules = permitAny hw.intfRules = permitAny
continue continue
} }
for _, intf := range hardware.interfaces { for _, intf := range hw.interfaces {
// Current router is used as default router even for // Current router is used as default router even for
// some internal networks. // some internal networks.
if len(intf.reroutePermit) != 0 { if len(intf.reroutePermit) != 0 {
nList := intf.reroutePermit nList := intf.reroutePermit
objList := make([]someObj, len(nList)) objList := make([]someObj, len(nList))
for i, n := range nList { for i, n := range nList {
objList[i] = n objList[i] = n
} }
rule := newRule( rule := newRule(
[]someObj{getNetwork00(ipv6)}, []someObj{getNetwork00(ipv6)},
objList, objList,
[]*proto{c.prt.IP}, []*proto{c.prt.IP},
) )
// Prepend to all other rules. // Prepend to all other rules.
if hasIoACL { if hasIoACL {
// Incoming and outgoing interfac e are equal. // Incoming and outgoing interfac e are equal.
m := hardware.ioRules m := hw.ioRules
if m == nil { if m == nil {
m = make(map[string]ruleL ist) m = make(map[string]ruleL ist)
hardware.ioRules = m hw.ioRules = m
} }
n := hardware.name n := hw.name
m[n] = append([]*groupedRule{rule }, m[n]...) m[n] = append([]*groupedRule{rule }, m[n]...)
} else { } else {
hardware.rules = append([]*groupe dRule{rule}, hardware.rules...) hw.rules = append([]*groupedRule{ rule}, hw.rules...)
} }
} }
// Is dynamic routing used? // Is dynamic routing used?
if routing := intf.routing; routing != nil { if routing := intf.routing; routing != nil {
if prt := routing.prt; prt != nil { if prt := routing.prt; prt != nil {
prtList := []*proto{prt} prtList := []*proto{prt}
netList := []someObj{intf.network } netList := []someObj{intf.network }
// Permit multicast packets from current network. // Permit multicast packets from current network.
mcast := getMulticastObjects(rout mcast := getMulticastObjects(rout
ing.mcast, ipv6) ing, ipv6)
hardware.intfRules.push(newRule(n hw.intfRules.push(newRule(netList
etList, mcast, prtList)) , mcast, prtList))
// Additionally permit unicast pa ckets. // Additionally permit unicast pa ckets.
// We use the network address as destination // We use the network address as destination
// instead of the interface addre ss, // instead of the interface addre ss,
// because we get fewer rules if the interface has // because we get fewer rules if the interface has
// multiple addresses. // multiple addresses.
hardware.intfRules.push(newRule(n etList, netList, prtList)) hw.intfRules.push(newRule(netList , netList, prtList))
} }
} }
// Handle multicast packets of redundancy protoco ls. // Handle multicast packets of redundancy protoco ls.
if typ := intf.redundancyType; typ != "" { if xrrp := intf.redundancyType; xrrp != nil {
netList := []someObj{intf.network} netList := []someObj{intf.network}
xrrp := xxrpInfo[typ] mcast := getMulticastObjects(xrrp, ipv6)
mcast := getMulticastObjects(xrrp.mcast,
ipv6)
prtList := []*proto{xrrp.prt} prtList := []*proto{xrrp.prt}
hardware.intfRules.push(newRule(netList, mcast, prtList)) hw.intfRules.push(newRule(netList, mcast, prtList))
} }
// Handle DHCP requests. // Handle DHCP requests.
if intf.dhcpServer { if intf.dhcpServer {
netList := []someObj{getNetwork00(ipv6)} netList := []someObj{getNetwork00(ipv6)}
prtList := []*proto{c.prt.Bootps} prtList := []*proto{c.prt.Bootps}
hardware.intfRules.push(newRule(netList, netList, prtList)) hw.intfRules.push(newRule(netList, netLis t, prtList))
} }
// Handle DHCP answer. // Handle DHCP answer.
if intf.dhcpClient { if intf.dhcpClient {
netList := []someObj{getNetwork00(ipv6)} netList := []someObj{getNetwork00(ipv6)}
prtList := []*proto{c.prt.Bootpc} prtList := []*proto{c.prt.Bootpc}
hardware.intfRules.push(newRule(netList, netList, prtList)) hw.intfRules.push(newRule(netList, netLis t, prtList))
} }
} }
} }
} }
} }
func (c *spoc) distributeGeneralPermit() { func (c *spoc) distributeGeneralPermit() {
for _, router := range c.managedRouters { for _, r := range c.managedRouters {
generalPermit := router.generalPermit generalPermit := r.generalPermit
if len(generalPermit) == 0 { if len(generalPermit) == 0 {
continue continue
} }
net00List := []someObj{getNetwork00(router.ipV6)} net00List := []someObj{getNetwork00(r.ipV6)}
rule := newRule(net00List, net00List, generalPermit) ru := newRule(net00List, net00List, generalPermit)
needProtect := router.needProtect needProtect := r.needProtect
for _, inIntf := range router.interfaces { for _, in := range r.interfaces {
if inIntf.mainIntf != nil { if in.mainIntf != nil {
continue continue
} }
if inIntf.loopback { if in.loopback {
continue continue
} }
// At VPN hub, don't permit any -> any, but only traffic // At VPN hub, don't permit any -> any, but only traffic
// from each encrypted network. // from each encrypted network.
if inIntf.isHub { if in.isHub {
addRule := func(src someObj) { addRule := func(src someObj) {
copy := *rule copy := *ru
rule = &copy ru = &copy
rule.src = []someObj{src} ru.src = []someObj{src}
for _, outIntf := range router.interfaces for _, out := range r.interfaces {
{ if out != in && out.ipType != tun
if outIntf != inIntf && outIntf.i nelIP {
pType != tunnelIP {
// Traffic traverses the device. Traffic for // Traffic traverses the device. Traffic for
// the device itself isn' t needed at VPN hub. // the device itself isn' t needed at VPN hub.
distributeRule(rule, inIn tf, outIntf) distributeRule(ru, in, ou t)
} }
} }
} }
if idRules := inIntf.idRules; idRules != nil { if idRules := in.idRules; idRules != nil {
var srcList []someObj var srcList []someObj
for _, idIntf := range idRules { for _, idIntf := range idRules {
srcList = append(srcList, idIntf. src) srcList = append(srcList, idIntf. src)
} }
sort.Slice(srcList, func(i, j int) bool { sort.Slice(srcList, func(i, j int) bool {
return srcList[i].String() < srcL ist[j].String() return srcList[i].String() < srcL ist[j].String()
}) })
for _, src := range srcList { for _, src := range srcList {
addRule(src) addRule(src)
} }
} else { } else {
for _, net := range inIntf.peerNetworks { for _, net := range in.peerNetworks {
addRule(net) addRule(net)
} }
} }
} else { } else {
for _, outIntf := range router.interfaces { for _, out := range r.interfaces {
if outIntf == inIntf { if out == in {
continue continue
} }
if outIntf.loopback { if out.loopback {
continue continue
} }
// For IOS and NX-OS print this rule only // For IOS and NX-OS print this rule only
// once at interface filter rules below // once at interface filter rules below
// (for incoming ACL). // (for incoming ACL).
if needProtect { if needProtect {
outHw := outIntf.hardware outHw := out.hardware
// For interface with outgoing AC Ls // For interface with outgoing AC Ls
// we need to add the rule. // we need to add the rule.
// distribute_rule would add rule to incoming, // distribute_rule would add rule to incoming,
// hence we add rule directly to outgoing rules. // hence we add rule directly to outgoing rules.
if outHw.needOutAcl { if outHw.needOutAcl {
outHw.outRules.push(rule) outHw.outRules.push(ru)
} }
continue continue
} }
if outIntf.mainIntf != nil { if out.mainIntf != nil {
continue continue
} }
// Traffic traverses the device. // Traffic traverses the device.
distributeRule(rule, inIntf, outIntf) distributeRule(ru, in, out)
} }
// Traffic for the device itself. // Traffic for the device itself.
if inIntf.ipType != bridgedIP { if in.ipType != bridgedIP {
distributeRule(rule, inIntf, nil) distributeRule(ru, in, nil)
} }
} }
} }
} }
} }
func (c *spoc) rulesDistribution() { func (c *spoc) rulesDistribution() {
c.progress("Distributing rules") c.progress("Distributing rules")
// Deny rules // Deny rules
for _, rule := range c.allPathRules.deny { for _, ru := range c.allPathRules.deny {
c.pathWalk(rule, distributeRule, "Router") c.pathWalk(ru, distributeRule, "Router")
} }
// Handle global permit after deny rules. // Handle global permit after deny rules.
c.distributeGeneralPermit() c.distributeGeneralPermit()
// Permit rules // Permit rules
for _, rule := range c.allPathRules.permit { for _, ru := range c.allPathRules.permit {
c.pathWalk(rule, distributeRule, "Router") c.pathWalk(ru, distributeRule, "Router")
} }
c.addRouterAcls() c.addRouterAcls()
} }
 End of changes. 75 change blocks. 
130 lines changed or deleted 129 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)