"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "go/pkg/pass1/routes.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.

routes.go  (Netspoc-6.026):routes.go  (Netspoc-6.027)
package pass1 package pass1
import ( import (
"fmt" "fmt"
"sort" "sort"
"strings"
) )
//############################################################################ //############################################################################
// Purpose : Generate and store routing information for all managed interfaces. // Purpose : Generate and store routing information for all managed interfaces.
func (c *spoc) findActiveRoutes() { func (c *spoc) findActiveRoutes() {
c.progress("Finding routes") c.progress("Finding routes")
// Mark interfaces of unmanaged routers such that no routes are collected . // Mark interfaces of unmanaged routers such that no routes are collected .
for _, r := range c.allRouters { for _, r := range c.allRouters {
if r.semiManaged && !r.routingOnly { if r.semiManaged && !r.routingOnly {
for _, intf := range r.interfaces { for _, intf := range r.interfaces {
intf.routing = routingInfo["dynamic"] intf.routing = routingInfo["dynamic"]
} }
} }
} }
// Generate navigation information for routing inside zones. // Generate navigation information for routing inside zones.
for _, z := range c.allZones { for _, z := range c.allZones {
setRoutesInZone(z) c.setRoutesInZone(z)
} }
// Generate pseudo rule set with all src dst pairs to determine routes fo r. // Generate pseudo rule set with all src dst pairs to determine routes fo r.
tree := c.generateRoutingTree() tree := c.generateRoutingTree()
// Generate routing info for every pseudo rule and store it in interfaces . // Generate routing info for every pseudo rule and store it in interfaces .
c.generateRoutingInfo(tree) c.generateRoutingInfo(tree)
c.addRoutingOnlyNetworks()
c.checkAndConvertRoutes() c.checkAndConvertRoutes()
} }
type netMap map[*network]bool type netMap map[*network]bool
//############################################################################# //#############################################################################
// Get networks for routing. // Get networks for routing.
// Add largest supernet inside the zone, if available. // Add largest supernet inside the zone, if available.
// This is needed, because we use the supernet in // This is needed, because we use the supernet in
// secondary optimization too. // secondary optimization too.
// Moreover this reduces the number of routing entries. // Moreover this reduces the number of routing entries.
// It isn't sufficient to solely use the supernet because network and supernet // It isn't sufficient to solely use the supernet because network and supernet
// can have different next hops at end of path. // can have different next hops at end of path.
// For an aggregate, take all matching networks inside the zone. // For an aggregate, take all matching networks inside the zone.
// These are supernets by design. // These are supernets by design.
func getRouteNetworks(list []someObj) netMap { func getRouteNetworks(l []someObj) netMap {
m := make(netMap) m := make(netMap)
LIST: LIST:
for _, obj := range list { for _, obj := range l {
var net *network var n *network
switch x := obj.(type) { switch x := obj.(type) {
case *network: case *network:
if x.isAggregate { if x.isAggregate {
for _, net := range x.networks { for _, n := range x.networks {
m[net] = true m[n] = true
} }
continue LIST continue LIST
} }
net = x n = x
case *subnet: case *subnet:
net = x.network n = x.network
case *routerIntf: case *routerIntf:
net = x.network n = x.network
} }
if max := net.maxRoutingNet; max != nil { if max := n.maxRoutingNet; max != nil {
m[max] = true m[max] = true
} }
m[net] = true m[n] = true
} }
return m return m
} }
//############################################################################# //#############################################################################
// Purpose : Provide routing information inside a security zone. // Purpose : Provide routing information inside a security zone.
// Parameters : zone - a zone object. // Parameters : zone - a zone object.
// Results : Every zone border interface I contains a map // Results : Every zone border interface I contains a map
// routeInZone, keeping the zones networks N reachable from I as // routeInZone, keeping the zones networks N reachable from I as
// keys and the next hop interface H towards N as values. // keys and the next hop interface H towards N as values.
// Comments : A cluster is a maximal set of connected networks of the security // Comments : A cluster is a maximal set of connected networks of the security
// zone surrounded by hop interfaces. Clusters can be empty. // zone surrounded by hop interfaces. Clusters can be empty.
// Optimization: a default route I.routeInZone[network00] = [H] // Optimization: a default route I.routeInZone[network00] = H
// is stored for those border interfaces, that reach networks in // is stored for those border interfaces, that reach networks in
// zone via a single hop. // zone via a single hop.
func setRoutesInZone(zone *zone) { func (c *spoc) setRoutesInZone(zone *zone) {
// Collect networks at zone border and next hop interfaces in lookup hash // Check if zone needs static routing at all.
es. needRoutes := false
// Collect networks at zone border and next hop interfaces in lookup maps
.
borderNetworks := make(netMap) borderNetworks := make(netMap)
hopInterfaces := make(map[*routerIntf]bool) hopInterfaces := make(map[*routerIntf]bool)
// Collect networks at zones interfaces as border networks.
// Collect networks at the zones interfaces as border networks. for _, in := range zone.interfaces {
for _, inIntf := range zone.interfaces { if in.mainIntf != nil {
if inIntf.mainIntf != nil {
continue continue
} }
network := inIntf.network n := in.network
if borderNetworks[network] { if borderNetworks[n] {
continue continue
} }
borderNetworks[network] = true
// Collect non border interfaces of the networks as next hop inte rfaces. // Collect non border interfaces of the networks as next hop inte rfaces.
for _, outIntf := range network.interfaces { for _, out := range n.interfaces {
if outIntf.zone != nil { if out.zone == nil && out.mainIntf == nil {
continue hopInterfaces[out] = true
} }
if outIntf.mainIntf != nil { }
continue // Border network is only needed later, if static routes are gene
} rated.
hopInterfaces[outIntf] = true if in.routing == nil {
borderNetworks[n] = true
needRoutes = true
} }
} }
if len(hopInterfaces) == 0 { if len(hopInterfaces) == 0 || !needRoutes {
return return
} }
// Zone preprocessing: define set of networks surrounded by hop // Zone preprocessing: define set of networks surrounded by hop
// intf (cluster) via depth first search to accelerate later DFS // intf (cluster) via depth first search to accelerate later DFS
// runs starting at hop intfs. // runs starting at hop intfs.
// Store hop intfs as key && reached clusters as values. // Store hop interfaces as key and reached clusters as values.
type cluster netMap type cluster netMap
hop2cluster := make(map[*routerIntf]*cluster) hop2cluster := make(map[*routerIntf]*cluster)
// Store directly linked border networks for clusters. // Store directly linked border networks for clusters.
cluster2borders := make(map[*cluster]netMap) cluster2borders := make(map[*cluster]netMap)
var setCluster func(*router, *routerIntf, *cluster) var setCluster func(*router, *routerIntf, *cluster)
setCluster = func(router *router, inIntf *routerIntf, clust *cluster) {
if router.activePath { setCluster = func(r *router, in *routerIntf, cl *cluster) {
if r.activePath {
return return
} }
router.activePath = true r.activePath = true
defer func() { router.activePath = false }() defer func() { r.activePath = false }()
// Process every interface. // Process every interface.
for _, intf := range router.interfaces { for _, intf := range r.interfaces {
if intf.mainIntf != nil { if intf.mainIntf != nil {
continue continue
} }
// Found hop interface. Add its entries on the fly and sk ip. // Found hop interface. Add its entries on the fly and sk ip.
if hopInterfaces[intf] { if hopInterfaces[intf] {
hop2cluster[intf] = clust hop2cluster[intf] = cl
network := intf.network n := intf.network
cluster2borders[clust][network] = true cluster2borders[cl][n] = true
continue continue
} }
if intf == inIntf { if intf == in {
continue continue
} }
// Add network behind interface to cluster. // Add network behind interface to cluster.
network := intf.network n := intf.network
if (*clust)[network] { if (*cl)[n] {
continue continue
} }
(*clust)[network] = true (*cl)[n] = true
// Recursively proceed with adjacent routers. // Recursively proceed with adjacent routers.
for _, outIntf := range network.interfaces { for _, out := range n.interfaces {
if outIntf == intf { if out != intf && out.mainIntf == nil {
continue setCluster(out.router, out, cl)
} }
if outIntf.mainIntf != nil {
continue
}
setCluster(outIntf.router, outIntf, clust)
} }
} }
} }
// Identify network cluster for every hop interface. // Identify network cluster for every hop interface.
for intf, _ := range hopInterfaces { for intf, _ := range hopInterfaces {
// Hop interface was processed before. // Hop interface was processed before.
if hop2cluster[intf] != nil { if hop2cluster[intf] != nil {
continue continue
} }
clust := make(cluster) cl := make(cluster)
cluster2borders[&clust] = make(netMap) cluster2borders[&cl] = make(netMap)
setCluster(intf.router, intf, &clust) setCluster(intf.router, intf, &cl)
// debug("Cluster: intf->{name} ", // debug("Cluster: intf->{name} ",
// join ',', map {$_->{name}} values %clust); // join ',', map {$_->{name}} values %clust);
} }
// Perform depth first search to collect all networks behind a hop interf // Perform depth first search to collect all networks behind a hop
ace. // interface.
// Map to store the collected sets. // Map to store the collected sets.
hop2netMap := make(map[*routerIntf]netMap) hop2netMap := make(map[*routerIntf]netMap)
var setNetworksBehind func(*routerIntf, *network) var setNetworksBehind func(*routerIntf, *network)
setNetworksBehind = func(hop *routerIntf, inBorder *network) { setNetworksBehind = func(hop *routerIntf, inBorder *network) {
// Hop intf network set is known already. // Hop intf network set is known already.
if hop2netMap[hop] != nil { if hop2netMap[hop] != nil {
return return
} }
nMap := make(netMap) nMap := make(netMap)
// Optimization: add networks of directly attached cluster. // Optimization: add networks of directly attached cluster.
clust := hop2cluster[hop] cl := hop2cluster[hop]
for net, _ := range *clust { for n, _ := range *cl {
nMap[net] = true nMap[n] = true
} }
// Add preliminary result to stop deep recursion. // Add preliminary result to stop deep recursion.
hop2netMap[hop] = nMap hop2netMap[hop] = nMap
// Proceed depth first search with adjacent border networks. // Proceed depth first search with adjacent border networks.
for border, _ := range cluster2borders[clust] { for border, _ := range cluster2borders[cl] {
if border == inBorder { if border == inBorder {
continue continue
} }
// Add reachable border networks to set. // Add reachable border networks to set.
nMap[border] = true nMap[border] = true
// Add cluster members of clusters reachable via border n etworks: // Add cluster members of clusters reachable via border n etworks:
for _, outHop := range border.interfaces { for _, outHop := range border.interfaces {
if !hopInterfaces[outHop] { if !hopInterfaces[outHop] {
continue continue
} }
if hop2cluster[outHop] == clust { if hop2cluster[outHop] == cl {
continue continue
} }
// Create hop2netMap entry for reachable hops and add networks // Create hop2netMap entry for reachable hops and add networks
setNetworksBehind(outHop, border) setNetworksBehind(outHop, border)
for net, _ := range hop2netMap[outHop] { for n, _ := range hop2netMap[outHop] {
nMap[net] = true nMap[n] = true
} }
} }
} }
hop2netMap[hop] = nMap hop2netMap[hop] = nMap
// debug("Hop: hop->{name} ", join ',', map {$_->{name}} res ult); // debug("Hop: hop->{name} ", join ',', map {$_->{name}} res ult);
} }
// In every border interfaces, store reachable networks and // For all border interfaces, store reachable networks and
// corresponding hop interface. Process every border network. // corresponding hop interface. Process every border network.
for border, _ := range borderNetworks { for border, _ := range borderNetworks {
var borderIntf intfList var borderIntf intfList
var hopIntf intfList var hopIntf intfList
// Collect border and hop interfaces of the current border networ k. // Collect border and hop interfaces of current border network.
for _, intf := range border.interfaces { for _, intf := range border.interfaces {
if intf.mainIntf != nil { if intf.mainIntf != nil {
continue continue
} }
if intf.zone != nil { if intf.zone == nil {
borderIntf.push(intf)
intf.routeInZone = make(map[*network]intfList)
} else {
hopIntf.push(intf) hopIntf.push(intf)
} else if intf.routing == nil {
borderIntf.push(intf)
intf.routeInZone = make(map[*network]*routerIntf)
} }
} }
// Optimization: All networks in zone are located behind single h op. // Optimization: All networks in zone are located behind single h op.
if 1 == len(hopIntf) || isRedundanyGroup(hopIntf) { if len(hopIntf) == 1 {
for _, intf := range borderIntf { for _, intf := range borderIntf {
// Spare reachable network specification. // Spare reachable network specification.
// debug("Default hop intf->{name} ", // debug("Default hop intf->{name} ",
// join(',', map {$_->{name}} hop_intf)); // join(',', map {$_->{name}} hop_intf));
intf.routeInZone[network00] = hopIntf intf.routeInZone[network00] = hopIntf[0]
} }
// Proceed with next border network. // Proceed with next border network.
continue continue
} }
// For every hop interfaces of current network, gather reachable // For all hop interfaces of current border network, gather
// network set. // reachable network set.
for _, hop := range hopIntf { // Collect single virtual hops to change them later to physical i
setNetworksBehind(hop, border) nterface.
singleVirtualHops := make(map[*routerIntf]bool)
for _, h := range hopIntf {
setNetworksBehind(h, border)
group := h.redundancyIntfs
if group != nil {
singleVirtualHops[h] = true
}
// In border interface of current network, store reachabl // In border interface of current border network, store
e // reachable networks and hops
// networks and hops
for _, intf := range borderIntf { for _, intf := range borderIntf {
for network, _ := range hop2netMap[hop] { for n, _ := range hop2netMap[h] {
// Border will be found accidently, if cl usters form a // Border will be found accidently, if cl usters form a
// loop inside zone. // loop inside zone.
if network == border { if n == border {
continue continue
} }
intf.routeInZone[network] = if other := intf.routeInZone[n]; other !=
append(intf.routeInZone[network], nil {
hop) // Ignore other redundancy interf
aces.
if group != nil && redundancyEq(g
roup, other.redundancyIntfs) {
delete(singleVirtualHops,
h)
delete(singleVirtualHops,
other)
} else {
c.err("Two static routes
for %s\n at %s via %s and %s",
n, intf, h, other
)
}
} else {
intf.routeInZone[n] = h
}
}
}
}
// Change virtual to physical interface, if not used grouped.
for hop := range singleVirtualHops {
phys := hop.origMain
for _, intf := range borderIntf {
for n, h := range intf.routeInZone {
if h == hop {
intf.routeInZone[n] = phys
}
} }
} }
} }
} }
} }
func getHopInZone(in *routerIntf, n *network) *routerIntf {
routeInZone := in.routeInZone
h := routeInZone[network00]
if h == nil {
h = routeInZone[n]
}
return h
}
//############################################################################# //#############################################################################
// Purpose : Gather rule specific routing information at zone border // Purpose : Gather rule specific routing information at zone border
// interfaces: For a pair (inIntf,outIntf) of zone border // interfaces: For a pair (inIntf,outIntf) of zone border
// interfaces that lies on a path from src to dst, the next hop // interfaces that lies on a path from src to dst, the next hop
// interfaces H to reach outIntf from in_intf are determined // interfaces H to reach outIntf from in_intf are determined
// and stored. // and stored.
// Parameters : inIntf - interface zone is entered from. // Parameters : inIntf - interface zone is entered from.
// outIntf - interface zone is left at. // outIntf - interface zone is left at.
// dstNetMap - destination networks of associated pseudo rule. // dstNetMap - destination networks of associated pseudo rule.
// Results : inIntf holds routing information that dstNetworks are // Results : inIntf holds routing information that dstNetworks are
skipping to change at line 311 skipping to change at line 343
// Comment : dstNetworks are converted to natNets, before storing as // Comment : dstNetworks are converted to natNets, before storing as
// routing information, because NAT addresses are used in // routing information, because NAT addresses are used in
// static routes. // static routes.
func addPathRoutes(in, out *routerIntf, dstNetMap netMap) { func addPathRoutes(in, out *routerIntf, dstNetMap netMap) {
// Interface with manual or dynamic routing. // Interface with manual or dynamic routing.
if in.routing != nil { if in.routing != nil {
return return
} }
inNet := in.network // Identify hop interface.
outNet := out.network var hop *routerIntf
natSet := in.natSet if in.network == out.network {
natNets := make([]*network, 0, len(dstNetMap)) hop = out
for n, _ := range dstNetMap { } else {
natNets = append(natNets, getNatNetwork(n, natSet)) hop = getHopInZone(in, out.network)
} }
// Add hop interface and routing information to in.routes
rMap := in.routes rMap := in.routes
if rMap == nil { if rMap == nil {
rMap = make(map[*routerIntf]netMap) rMap = make(map[*network]intfList)
in.routes = rMap in.routes = rMap
} }
natMap := in.natMap
// Identify hop interface(s). for n, _ := range dstNetMap {
// Store hop interfaces and routing information within inIntf. natNet := getNatNetwork(n, natMap)
if inNet == outNet { // debug("%s -> %s: %s", in, hop, n)
nMap := rMap[out] rMap[natNet] = append(rMap[natNet], hop)
if nMap == nil {
nMap = make(netMap)
rMap[out] = nMap
}
for _, n := range natNets {
// debug("%s -> %s: %s", in, out, n)
nMap[n] = true
}
} else {
routeInZone := in.routeInZone
hops := routeInZone[network00]
if hops == nil {
hops = routeInZone[outNet]
}
for _, hop := range hops {
nMap := rMap[hop]
if nMap == nil {
nMap = make(netMap)
rMap[hop] = nMap
}
for _, n := range natNets {
// debug("%s -> %s: %s", in, hop, n)
nMap[n] = true
}
}
} }
} }
//############################################################################ //############################################################################
// Purpose : Generate routing information for a single interface at zone // Purpose : Generate routing information for a single interface at zone
// border. Store next hop interface to every destination network // border. Store next hop interface to every destination network
// inside zone within the given interface object. // inside zone within the given interface object.
// Parameters : interface - border interface of a zone. // Parameters : interface - border interface of a zone.
// dstNetMap - destination networks inside the same zone. // dstNetMap - destination networks inside the same zone.
// Results : interface holds routing entries about which hops to use to // Results : interface holds routing entries about which hops to use to
skipping to change at line 375 skipping to change at line 383
// routing information, because NAT addresses are used in // routing information, because NAT addresses are used in
// static routes. // static routes.
func addEndRoutes(intf *routerIntf, dstNetMap netMap) { func addEndRoutes(intf *routerIntf, dstNetMap netMap) {
// Interface with manual or dynamic routing. // Interface with manual or dynamic routing.
if intf.routing != nil { if intf.routing != nil {
return return
} }
intfNet := intf.network intfNet := intf.network
routeInZone := intf.routeInZone natMap := intf.natMap
natSet := intf.natSet
rMap := intf.routes rMap := intf.routes
if rMap == nil { if rMap == nil {
rMap = make(map[*routerIntf]netMap) rMap = make(map[*network]intfList)
intf.routes = rMap intf.routes = rMap
} }
// For every dst network, check the hops that can be used to get there. // For every dst network, get the hop that can be used to get there.
for n, _ := range dstNetMap { for n, _ := range dstNetMap {
if n == intfNet { if n == intfNet {
continue continue
} }
natNet := getNatNetwork(n, natSet) natNet := getNatNetwork(n, natMap)
hops := routeInZone[network00] h := getHopInZone(intf, n)
if hops == nil {
hops = routeInZone[n]
}
// Store the used hops and routes within the interface object. // Store the used hop and routes within the interface object.
for _, hop := range hops { // debug("%s -> %s: %s", intf, h, natNet)
nMap := rMap[hop] rMap[natNet] = append(rMap[natNet], h)
if nMap == nil {
nMap = make(netMap)
rMap[hop] = nMap
}
// debug("%s -> %s: %s", intf, hop, natNet)
nMap[natNet] = true
}
} }
} }
type pseudoRule struct { type pseudoRule struct {
groupedRule groupedRule
srcNetworks netMap srcNetworks netMap
dstNetworks netMap dstNetworks netMap
srcIntf2nets map[*routerIntf]netMap srcIntf2nets map[*routerIntf]netMap
dstIntf2nets map[*routerIntf]netMap dstIntf2nets map[*routerIntf]netMap
} }
type zonePair [2]*zone type zonePair [2]*zone
type routingTree map[zonePair]*pseudoRule type routingTree map[zonePair]*pseudoRule
const (
noIntf = iota
srcIntf
dstIntf
bothIntf
)
//############################################################################# //#############################################################################
// Purpose : Add information from single grouped rule to routing tree. // Purpose : Add information from single grouped rule to routing tree.
// Parameters : rule - to be added grouped rule. // Parameters : rule - to be added grouped rule.
// isIntf - marker: which of src and/or dst is an interface. // isIntf - marker: which of src and/or dst is an interface.
// tree - the routing tree. // tree - the routing tree.
func generateRoutingTree1(rule *groupedRule, isIntf string, tree routingTree) { func generateRoutingTree1(rule *groupedRule, isIntf int, t routingTree) {
src, dst := rule.src, rule.dst src, dst := rule.src, rule.dst
srcZone, dstZone := rule.srcPath.(*zone), rule.dstPath.(*zone) srcZone, dstZone := rule.srcPath.(*zone), rule.dstPath.(*zone)
// Check, whether // Check, whether
// - source interface is located in security zone of destination or // - source interface is located in security zone of destination or
// - destination interface is located in security zone of source. // - destination interface is located in security zone of source.
// In this case, pathWalk will do nothing. // In this case, pathWalk will do nothing.
if srcZone == dstZone && isIntf != "" { if srcZone == dstZone {
addRoutes := func(from, to []someObj) {
// Detect next hop interfaces if src/dst are zone border interfac intf := from[0].(*routerIntf)
es. intf = getMainInterface(intf)
for _, what := range strings.Split(isIntf, ",") {
var from *routerIntf
var to []someObj
if what == "src" {
from = rule.src[0].(*routerIntf)
to = dst
} else {
from = rule.dst[0].(*routerIntf)
to = src
}
from = getMainInterface(from)
nMap := getRouteNetworks(to) nMap := getRouteNetworks(to)
addEndRoutes(from, nMap) addEndRoutes(intf, nMap)
}
// Detect next hop interfaces if src/dst are zone border interfac
es.
switch isIntf {
case srcIntf:
addRoutes(src, dst)
case dstIntf:
addRoutes(dst, src)
case bothIntf:
addRoutes(src, dst)
addRoutes(dst, src)
} }
return return
} }
// Construct a pseudo rule with zones as src and dst and store it. // Construct a pseudo rule with zones as src and dst and store it.
var pRule *pseudoRule var p *pseudoRule
// Check whether pseudo rule for src and dst pair is stored already. // Check whether pseudo rule for src and dst pair is stored already.
pRule = tree[zonePair{srcZone, dstZone}] p = t[zonePair{srcZone, dstZone}]
if pRule == nil { if p == nil {
pRule = tree[zonePair{dstZone, srcZone}] p = t[zonePair{dstZone, srcZone}]
if pRule != nil { if p != nil {
src, dst = dst, src src, dst = dst, src
srcZone, dstZone = dstZone, srcZone srcZone, dstZone = dstZone, srcZone
// Change only if set: // Change only if set:
// 'src' -> 'dst, 'dst' -> 'src', 'src,dst' unchanged. // 'src' -> 'dst, 'dst' -> 'src', 'src,dst' unchanged.
if isIntf != "" { switch isIntf {
if isIntf == "src" { case srcIntf:
isIntf = "dst" isIntf = dstIntf
} else if isIntf == "dst" { case dstIntf:
isIntf = "src" isIntf = srcIntf
}
} }
} else { } else {
// Generate new pseudo rule otherwise. // Generate new pseudo rule otherwise.
pRule = &pseudoRule{ p = &pseudoRule{
groupedRule: groupedRule{ groupedRule: groupedRule{
serviceRule: &serviceRule{ serviceRule: &serviceRule{
prt: rule.prt, prt: rule.prt,
rule: rule.rule, rule: rule.rule,
}, },
src: src, src: src,
dst: dst, dst: dst,
srcPath: srcZone, srcPath: srcZone,
dstPath: dstZone, dstPath: dstZone,
}, },
srcIntf2nets: make(map[*routerIntf]netMap), srcIntf2nets: make(map[*routerIntf]netMap),
dstIntf2nets: make(map[*routerIntf]netMap), dstIntf2nets: make(map[*routerIntf]netMap),
srcNetworks: make(netMap), srcNetworks: make(netMap),
dstNetworks: make(netMap), dstNetworks: make(netMap),
} }
tree[zonePair{srcZone, dstZone}] = pRule t[zonePair{srcZone, dstZone}] = p
} }
} }
// Store src and dst networks of grouped rule within pseudo rule. // Store src and dst networks of grouped rule within pseudo rule.
add := func(to, from netMap) { add := func(to, from netMap) {
for net, _ := range from { for net, _ := range from {
to[net] = true to[net] = true
} }
} }
srcNetworks := getRouteNetworks(src) srcNetworks := getRouteNetworks(src)
add(pRule.srcNetworks, srcNetworks) add(p.srcNetworks, srcNetworks)
dstNetworks := getRouteNetworks(dst) dstNetworks := getRouteNetworks(dst)
add(pRule.dstNetworks, dstNetworks) add(p.dstNetworks, dstNetworks)
// If src/dst is interface of managed routers, add this info to // If src/dst is interface of managed routers, add this info to
// pseudo rule. // pseudo rule.
if isIntf != "" { addI2N := func(i2n *map[*routerIntf]netMap, ob []someObj, nets netMap) {
for _, what := range strings.Split(isIntf, ",") { intf := ob[0].(*routerIntf)
var intf *routerIntf r := intf.router
if what == "src" { if r.managed != "" || r.routingOnly {
intf = src[0].(*routerIntf) intf = getMainInterface(intf)
} else { m := (*i2n)[intf]
intf = dst[0].(*routerIntf) if m == nil {
} m = make(netMap)
// debug("%s: %s", what, intf) (*i2n)[intf] = m
r := intf.router }
if r.managed != "" || r.routingOnly { add(m, nets)
if main := intf.mainIntf; main != nil { }
intf = main }
} switch isIntf {
if what == "src" { case srcIntf:
m := pRule.srcIntf2nets[intf] addI2N(&p.srcIntf2nets, src, dstNetworks)
if m == nil { case dstIntf:
m = make(netMap) addI2N(&p.dstIntf2nets, dst, srcNetworks)
pRule.srcIntf2nets[intf] = m case bothIntf:
} addI2N(&p.srcIntf2nets, src, dstNetworks)
for net, _ := range dstNetworks { addI2N(&p.dstIntf2nets, dst, srcNetworks)
m[net] = true
}
} else {
m := pRule.dstIntf2nets[intf]
if m == nil {
m = make(netMap)
pRule.dstIntf2nets[intf] = m
}
for net, _ := range srcNetworks {
m[net] = true
}
}
}
}
} }
} }
//############################################################################ //############################################################################
// Purpose : Generate the routing tree, holding pseudo rules that represent // Purpose : Generate the routing tree, holding pseudo rules that represent
// the whole grouped rule set. As the pseudo rules are // the whole grouped rule set. As the pseudo rules are
// generated to determine routes, ports are omitted, and rules // generated to determine routes, ports are omitted, and rules
// refering to the same src and dst zones are summarized. // refering to the same src and dst zones are summarized.
func (c *spoc) generateRoutingTree() routingTree { func (c *spoc) generateRoutingTree() routingTree {
tree := make(routingTree) t := make(routingTree)
// Special handling needed for rules grouped not at zone pairs but // Special handling needed for rules grouped not at zone pairs but
// grouped at routers. // grouped at routers.
for _, rule := range c.allPathRules.permit { for _, ru := range c.allPathRules.permit {
// debug(rule.print()) // debug(rule.print())
if _, ok := rule.srcPath.(*zone); ok { if _, ok := ru.srcPath.(*zone); ok {
if _, ok := rule.dstPath.(*zone); ok { if _, ok := ru.dstPath.(*zone); ok {
// Common case, process directly. // Common case, process directly.
generateRoutingTree1(rule, "", tree) generateRoutingTree1(ru, noIntf, t)
} else { } else {
// Split group of destination interfaces, one for each zone. // Split group of destination interfaces, one for each zone.
for _, obj := range rule.dst { for _, ob := range ru.dst {
intf := obj.(*routerIntf) intf := ob.(*routerIntf)
copy := *rule cp := *ru
copy.dst = []someObj{obj} cp.dst = []someObj{ob}
copy.dstPath = intf.zone cp.dstPath = intf.zone
generateRoutingTree1(&copy, "dst", tree) generateRoutingTree1(&cp, dstIntf, t)
} }
} }
} else if _, ok := rule.dstPath.(*zone); ok { } else if _, ok := ru.dstPath.(*zone); ok {
for _, obj := range rule.src { for _, ob := range ru.src {
intf := obj.(*routerIntf) intf := ob.(*routerIntf)
copy := *rule cp := *ru
copy.src = []someObj{obj} cp.src = []someObj{ob}
copy.srcPath = intf.zone cp.srcPath = intf.zone
generateRoutingTree1(&copy, "src", tree) generateRoutingTree1(&cp, srcIntf, t)
} }
} else { } else {
for _, srcObj := range rule.src { for _, srcOb := range ru.src {
srcIntf := srcObj.(*routerIntf) srcIntf := srcOb.(*routerIntf)
for _, dstObj := range rule.dst { for _, dstOb := range ru.dst {
dstIntf := dstObj.(*routerIntf) dstIntf := dstOb.(*routerIntf)
copy := *rule cp := *ru
copy.src = []someObj{srcObj} cp.src = []someObj{srcOb}
copy.dst = []someObj{dstObj} cp.dst = []someObj{dstOb}
copy.srcPath = srcIntf.zone cp.srcPath = srcIntf.zone
copy.dstPath = dstIntf.zone cp.dstPath = dstIntf.zone
generateRoutingTree1(&copy, "src,dst", tr generateRoutingTree1(&cp, bothIntf, t)
ee)
} }
} }
} }
} }
return tree return t
} }
//############################################################################# //#############################################################################
// Purpose : Generate routing information for every (source,destination) // Purpose : Generate routing information for every (source,destination)
// pair of the ruleset and store it in the affected interfaces. // pair of the ruleset and store it in the affected interfaces.
// Parameters : routing_tree - a pseudo rule set. // Parameters : routing_tree - a pseudo rule set.
// Results : Every interface object holds next hop routing information // Results : Every interface object holds next hop routing information
// for the rules of original ruleset requiring a path passing the // for the rules of original ruleset requiring a path passing the
// interface. // interface.
func (c *spoc) generateRoutingInfo(tree routingTree) { func (c *spoc) generateRoutingInfo(t routingTree) {
// Process every pseudo rule. Within its {path} attribute....
for _, pRule := range tree {
// Collect data for every passed zone.
var path [][2]*routerIntf
var pathEntries []*routerIntf
var pathExits []*routerIntf
getRoutePath := func(r *groupedRule, in, out *routerIntf) {
/* debug("collect: %s -> %s", r.srcPath, r.dstPath)
info := ""
if in != nil {
info += in.name
}
info += " -> "
if out != nil {
info += out.name
}
debug(info)
*/
if in != nil && out != nil {
// Packets traverse the zone.
path = append(path, [2]*routerIntf{in, out})
} else if in == nil {
// Zone contains rule source.
pathEntries = append(pathEntries, out)
} else {
// Zone contains rule destination.
pathExits = append(pathExits, in)
}
}
c.pathWalk(&pRule.groupedRule, getRoutePath, "Zone")
// Determine routing information for every interface pair.
for _, tuple := range path {
in, out := tuple[0], tuple[1]
// debug("%s => %s", in, out)
addPathRoutes(in, out, pRule.dstNetworks)
addPathRoutes(out, in, pRule.srcNetworks)
}
// Determine routing information for intf of first zone on path. // Process every pseudo rule.
for _, entry := range pathEntries { for _, p := range t {
// For src interfaces at managed routers, generate routes // Add routing information for entry/exit interfaces at
in // start/end zone on path.
// both interfaces. add := func(intf *routerIntf, i2n map[*routerIntf]netMap, nets ne
SRC: tMap) {
for srcIntf, netMap := range pRule.srcIntf2nets {
// For src/dst interfaces at managed routers, generate
// Do not generate routes for src interfaces at p // routes in both interfaces.
ath entry I2N:
// routers. for intf2, netMap := range i2n {
if srcIntf.router == entry.router {
// Do not generate routes for src/dst interfaces
at
// path entry/exit routers.
if intf2.router == intf.router {
continue continue
} }
for _, intf := range srcIntf.redundancyIntfs { for _, intf3 := range intf2.redundancyIntfs {
if intf.router == entry.router { if intf3.router == intf.router {
continue SRC continue I2N
} }
} }
addPathRoutes(srcIntf, entry, netMap) addPathRoutes(intf2, intf, netMap)
} }
// For src networks, generate routes for zone interface o // For src/dst networks, generate routes for zone interfa
nly. ce only.
addEndRoutes(entry, pRule.srcNetworks) addEndRoutes(intf, nets)
} }
// Determine routing information for interface of last zone on pa // Traverse path from src to dst and
th. // collect routes for every passed zone.
for _, exit := range pathExits { getRoutePath := func(r *groupedRule, in, out *routerIntf) {
// debug("collect: %s -> %s", r.srcPath, r.dstPath)
// For dst interfaces at managed routers, generate routes // debug("%s -> %s", in, out)
in if in != nil && out != nil {
// both interfaces. // Packets traverse the zone.
DST: // debug("%s => %s", in, out)
for dstIntf, netMap := range pRule.dstIntf2nets { addPathRoutes(in, out, p.dstNetworks)
addPathRoutes(out, in, p.srcNetworks)
// Do not generate routes for dst interfaces at p } else if in == nil {
ath exit routers. // Zone contains rule source.
if dstIntf.router == exit.router { add(out, p.srcIntf2nets, p.srcNetworks)
continue } else {
} // Zone contains rule destination.
for _, intf := range dstIntf.redundancyIntfs { add(in, p.dstIntf2nets, p.dstNetworks)
if intf.router == exit.router {
continue DST
}
}
addPathRoutes(dstIntf, exit, netMap)
} }
}
c.pathWalk(&p.groupedRule, getRoutePath, "Zone")
}
}
// For dst networks, generate routes for zone interface o func (c *spoc) checkAndConvertRoutes() {
nly. for _, r := range c.managedRouters {
addEndRoutes(exit, pRule.dstNetworks) fixBridgedRoutes(r)
}
for _, r := range c.managedRouters {
if r.routingOnly {
c.addRoutingOnlyNetworks(r)
} }
c.adjustVPNRoutes(r)
c.checkDuplicateRoutes(r)
} }
} }
// Add networks of locally attached zone to routing_only devices. // Add networks of locally attached zone to routing_only devices.
// This is needed because routes between networks inside zone can't be // This is needed because routes between networks inside zone can't be
// derived from packet filter rules. // derived from packet filter rules.
func (c *spoc) addRoutingOnlyNetworks() { func (c *spoc) addRoutingOnlyNetworks(r *router) {
for _, r := range c.routingOnlyRouters { directly := make(netMap)
directly := make(netMap) for _, intf := range r.interfaces {
for _, intf := range r.interfaces { directly[intf.network] = true
directly[intf.network] = true }
for _, intf := range r.interfaces {
if intf.mainIntf != nil {
continue
} }
for _, intf := range r.interfaces { if intf.routing != nil {
if intf.routing != nil { continue
continue }
switch intf.ipType {
case hasIP, unnumberedIP, negotiatedIP:
// debug("intf %s", intf)
z := intf.zone
nMap := make(netMap)
for _, n := range z.networks {
if !directly[n] {
// debug("add1 %s", n)
nMap[n] = true
}
} }
switch intf.ipType { addEndRoutes(intf, nMap)
case hasIP, unnumberedIP, negotiatedIP: // Process other zones of cluster
// debug("intf %s", intf) for _, z2 := range z.cluster {
z := intf.zone if z2 == z {
nMap := make(netMap) continue
for _, n := range z.networks {
if !directly[n] {
// debug("add1 %s", n)
nMap[n] = true
}
} }
addEndRoutes(intf, nMap) for _, n := range z2.networks {
// Process other zones of cluster if !directly[n] {
for _, z2 := range z.cluster { c.singlePathWalk(intf, n,
if z2 == z { func(_ *groupedRule, in,
continue out *routerIntf) {
} // debug("walk %s
for _, n := range z2.networks { : %s %s", n, in, out)
if !directly[n] { if in == intf {
c.singlePathWalk(intf, n, addPathRo
func(_ *groupedRu utes(in, out, netMap{n: true})
le, in, out *routerIntf) { }
// debug( }, "Zone")
"walk %s: %s %s", n, in, out)
if in ==
intf {
a
ddPathRoutes(in, out, netMap{n: true})
}
}, "Zone")
}
} }
} }
} }
} }
} }
} }
func (c *spoc) checkAndConvertRoutes() {
l := append(c.managedRouters, c.routingOnlyRouters...)
for _, r := range l {
fixBridgedRoutes(r)
}
for _, r := range l {
c.adjustVPNRoutes(r)
c.checkDuplicateRoutes(r)
}
}
// Fix routes where bridged interface without IP address is used as // Fix routes where bridged interface without IP address is used as
// next hop. // next hop.
func fixBridgedRoutes(r *router) { func fixBridgedRoutes(r *router) {
for _, intf := range r.interfaces { for _, intf := range r.interfaces {
if intf.routing != nil { if intf.routing != nil {
continue continue
} }
if intf.network.ipType != bridgedIP { if intf.network.ipType != bridgedIP {
continue continue
} }
addRoutes := make(map[*routerIntf][]*network) for natNet, hopList := range intf.routes {
for hop, netMap := range intf.routes { subst := make(map[*routerIntf]intfList)
if hop.ipType != bridgedIP { for _, hop := range hopList {
continue if hop.ipType != bridgedIP {
} continue
for network, _ := range netMap {
realHops := fixBridgedHops(hop, network)
// Add real hops and networks later, after loop o
ver
// routes has been finished.
for _, rHop := range realHops {
addRoutes[rHop] = append(addRoutes[rHop],
network)
} }
realHops := fixBridgedHops(hop, natNet)
// Substite real hops later, after loop over hops
is finished.
subst[hop] = realHops
} }
delete(intf.routes, hop) if len(subst) > 0 {
} var new intfList
for rHop, networks := range addRoutes { for _, hop := range hopList {
nMap := intf.routes[rHop] if real := subst[hop]; real != nil {
if nMap == nil { new = append(new, real...)
nMap = make(netMap) } else {
} new.push(hop)
for _, n := range networks { }
nMap[n] = true }
intf.routes[natNet] = new
} }
intf.routes[rHop] = nMap
} }
} }
} }
// Parameters: // Parameters:
// - a bridged interface without an IP address, not usable as hop. // - a bridged interface without an IP address, not usable as hop.
// - the network for which the hop was found. // - the network for which the hop was found.
// Result: // Result:
// - one or more layer 3 interfaces, usable as hop. // - one or more layer 3 interfaces, usable as hop.
// Non optimized version. // Non optimized version.
// Doesn't matter as long we have only a few bridged networks // Doesn't matter as long we have only a few bridged networks
// or don't use static routing at the border of bridged networks. // or don't use static routing at the border of bridged networks.
func fixBridgedHops(hop *routerIntf, n *network) intfList { func fixBridgedHops(hop *routerIntf, n *network) intfList {
var result intfList var result intfList
r := hop.router r := hop.router
for _, intf := range r.interfaces { for _, intf := range r.interfaces {
if intf == hop { if intf == hop {
continue continue
} }
HOP: for n2, hopList := range intf.routes {
for hop2, netMap := range intf.routes { if n == n2 {
for n2, _ := range netMap { for _, hop2 := range hopList {
if n == n2 {
if hop2.ipType == bridgedIP { if hop2.ipType == bridgedIP {
result = append(result, fixBridge dHops(hop2, n)...) result = append(result, fixBridge dHops(hop2, n)...)
} else { } else {
result.push(hop2) result.push(hop2)
} }
continue HOP
} }
} }
} }
} }
return result return result
} }
// Adjust routes through VPN tunnel to cleartext interface. // Adjust routes through VPN tunnel to cleartext interface.
func (c *spoc) adjustVPNRoutes(r *router) { func (c *spoc) adjustVPNRoutes(r *router) {
for _, intf := range r.interfaces { for _, intf := range r.interfaces {
skipping to change at line 846 skipping to change at line 793
continue continue
} }
tunnelRoutes := intf.routes tunnelRoutes := intf.routes
intf.routes = nil intf.routes = nil
realNet := realIntf.network realNet := realIntf.network
peer := intf.peer peer := intf.peer
realPeer := peer.realIntf realPeer := peer.realIntf
peerNet := realPeer.network peerNet := realPeer.network
// Find hop to peer network and add tunneled networks to this hop . // Find hop to peer network and add tunneled networks to this hop .
var hops intfList var hop *routerIntf
// Peer network is directly connected. // Peer network is directly connected.
if realNet == peerNet { if realNet == peerNet {
if realPeer.ipType == hasIP { if realPeer.ipType == hasIP {
hops.push(realPeer) hop = realPeer
} else { } else {
c.err("%s used to reach software clients\n"+ c.err("%s used to reach software clients\n"+
" must not be directly connected to %s\n" + " must not be directly connected to %s\n" +
" Connect it to some network behind next hop", " Connect it to some network behind next hop",
realPeer, realIntf) realPeer, realIntf)
continue continue
} }
} else if realNet.zone == peerNet.zone { } else if realNet.zone == peerNet.zone {
// Peer network is located in directly connected zone. // Peer network is located in directly connected zone.
routeInZone := realIntf.routeInZone hop = getHopInZone(realIntf, peerNet)
h := routeInZone[network00]
if h == nil {
h = routeInZone[peerNet]
}
hops = append(hops, h...)
} else { } else {
// Find path to peer network to determine available hops. // Find path to peer network to determine available hops.
var zoneHops intfList var hops intfList
walk := func(_ *groupedRule, inIntf, outIntf *routerIntf) { walk := func(_ *groupedRule, inIntf, outIntf *routerIntf) {
if inIntf == realIntf { if inIntf == realIntf {
zoneHops.push(outIntf) hopNet := outIntf.network
} if hopNet == realNet {
} hops.push(outIntf)
c.singlePathWalk(realIntf, peerNet, walk, "Zone") } else {
routeInZone := realIntf.routeInZone h := getHopInZone(realIntf, hopNe
for _, hop := range zoneHops { t)
hopNet := hop.network hops.push(h)
if hopNet == realNet {
hops.push(hop)
} else {
h := routeInZone[network00]
if h == nil {
h = routeInZone[hopNet]
} }
hops = append(hops, h...)
} }
} }
} c.singlePathWalk(realIntf, peerNet, walk, "Zone")
intfEq := func(list intfList) bool { intfEq := func(l intfList) bool {
i0 := list[0] i0 := l[0]
rest := list[1:] rest := l[1:]
for _, i := range rest { for _, i := range rest {
if i != i0 { if i != i0 {
return false return false
} }
}
return true
}
if !intfEq(hops) && !isRedundanyGroup(hops) {
// This can only happen for vpn software clients.
// For hardware clients the route is known
// for the encrypted traffic which is allowed
// by genTunnelRules (even for negotiated interfa
ce).
count := len(hops)
c.err("Can't determine next hop to reach %s"+
" while moving routes\n"+
" of %s to %s.\n"+
" Exactly one route is needed,"+
" but %d candidates were found:\n%s",
peerNet, intf, realIntf, count, hops.name
List())
} }
return true hop = hops[0]
} }
redundEq := func(list intfList) bool {
r0 := list[0].redundancyIntfs
if len(r0) == 0 {
return false
}
rest := list[1:]
for _, i := range rest {
if !intfListEq(i.redundancyIntfs, r0) {
return false
}
}
return true
}
if !intfEq(hops) && !redundEq(hops) {
// This can only happen for vpn software clients.
// For hardware clients the route is known
// for the encrypted traffic which is allowed
// by genTunnelRules (even for negotiated interface).
count := len(hops)
c.err("Can't determine next hop to reach %s"+
" while moving routes\n"+
" of %s to %s.\n"+
" Exactly one route is needed,"+
" but %d candidates were found:\n%s",
peerNet, intf, realIntf, count, hops.nameList())
}
hop := hops[0]
routes := realIntf.routes routes := realIntf.routes
if routes == nil { if routes == nil {
routes = make(map[*routerIntf]netMap) routes = make(map[*network]intfList)
} realIntf.routes = routes
hopRoutes := routes[hop]
if hopRoutes == nil {
hopRoutes = make(netMap)
routes[hop] = hopRoutes
} }
// debug("Use %s as hop for %s", hop, realPeer) // debug("Use %s as hop for %s", hop, realPeer)
// Use found hop to reach tunneled networks in tunnel_routes. // Use found hop to reach tunneled networks in tunnelRoutes.
for _, tunnelNetHash := range tunnelRoutes { for tunnelNet := range tunnelRoutes {
for tunnelNet, _ := range tunnelNetHash { routes[tunnelNet] = append(routes[tunnelNet], hop)
hopRoutes[tunnelNet] = true
}
} }
// Add route to reach peer interface. // Add route to reach peer interface.
if peerNet != realNet { if peerNet != realNet {
natSet := realIntf.natSet natMap := realIntf.natMap
natNet := getNatNetwork(peerNet, natSet) natNet := getNatNetwork(peerNet, natMap)
hopRoutes[natNet] = true routes[natNet] = append(routes[natNet], hop)
} }
realIntf.routes = routes
} }
} }
func (c *spoc) checkDuplicateRoutes(r *router) { func (c *spoc) checkDuplicateRoutes(r *router) {
if r.origRouter != nil { if r.origRouter != nil {
return return
} }
// Remember, via which local interface a network is reached. // Remember, via which local interface a network is reached.
net2intf := make(map[*network]*routerIntf) net2intf := make(map[*network]*routerIntf)
for _, intf := range getIntf(r) { for _, intf := range getIntf(r) {
// Collect error messages for sorted / deterministic output.
var errors stringList
// Routing info not needed, because dynamic routing is in use. // Routing info not needed, because dynamic routing is in use.
if intf.routing != nil || intf.ipType == bridgedIP { if intf.routing != nil || intf.ipType == bridgedIP {
intf.routes = nil intf.routes = nil
continue continue
} }
// Remember, via which remote interface a network is reached. // Collect error messages for sorted / deterministic output.
net2hop := make(map[*network]*routerIntf) var errors stringList
// Remember, via which extra remote redundancy interfaces network
s
// are reached. We use this to check, that all members of a group
// of redundancy interfaces are used to reach a network.
// Otherwise it would be wrong to route to virtual interface.
var netBehindVirtHop []*network
net2extraHops := make(map[*network]intfList)
// Abort, if more than one static route exists per network. // Abort, if more than one static route exists per network.
// Sort interfaces for deterministic output. for n, hopList := range intf.routes {
sorted := make([]*routerIntf, 0, len(intf.routes))
for hop, _ := range intf.routes { // Check if network is reached via two different
sorted = append(sorted, hop) // local interfaces.
} if intf2, ok := net2intf[n]; ok {
sort.Slice(sorted, func(i, j int) bool { if intf2 != intf {
return sorted[i].name < sorted[j].name errors.push(
}) fmt.Sprintf(
for _, hop := range sorted { "Two static routes for %s
for n, _ := range intf.routes[hop] { \n via %s and %s",
// debug("%s -> %s -> %s", intf, hop, n) n, intf, intf2))
// Check if network is reached via two different
// local interfaces.
if intf2, ok := net2intf[n]; ok {
if intf2 != intf {
errors.push(
fmt.Sprintf(
"Two static route
s for %s\n via %s and %s",
n, intf, intf2))
}
} else {
net2intf[n] = intf
} }
} else {
net2intf[n] = intf
}
// Check whether network is reached via different // Sort for finding duplicates and for deterministic erro
hops. r messages.
// Abort, if these do not belong to same redundan sort.Slice(hopList, func(i, j int) bool {
cy group. return hopList[i].name < hopList[j].name
group := hop.redundancyIntfs })
if hop2, ok := net2hop[n]; ok { j := 0
var prev *routerIntf
// If next hop belongs to same redundancy for _, hop := range hopList {
group, if hop != prev {
// collect hops for detailed check below. hopList[j] = hop
group2 := hop2.redundancyIntfs j++
if group != nil && intfListEq(group, grou prev = hop
p2) {
delete(intf.routes[hop], n)
net2extraHops[n] =
append(net2extraHops[n],
hop)
} else {
errors.push(
fmt.Sprintf(
"Two static route
s for %s\n at %s via %s and %s",
n, intf, hop, hop
2))
}
} else {
net2hop[n] = hop
if group != nil {
netBehindVirtHop = append(netBehi
ndVirtHop, n)
}
} }
} }
} hopList = hopList[:j]
// Simple case: one hop
if len(hopList) == 1 {
hop := hopList[0]
// Ensure correct routing at virtual interfaces. // If dst network is reached via exactly one inte
// Check whether dst network is reached via all rface,
// redundancy interfaces. // move hop from virtual to physical interface.
for _, n := range netBehindVirtHop { // Destination is probably a loopback interface o
hop1 := net2hop[n] f same
extraHops := net2extraHops[n] // device.
missing := len(hop1.redundancyIntfs) - len(extraHops) - 1 // Ignore completly unmanaged virtual interface,
if missing == 0 { which has
// been checked already.
if hop.zone != nil {
if physHop := hop.origMain; physHop != ni
l {
hopList[0] = physHop
}
}
intf.routes[n] = hopList
continue continue
} }
// If dst network is reached via exactly one interface, // Network is reached via different hops.
// move hop from virtual to physical interface. // Abort, if these do not belong to same redundancy group
// Destination is probably a loopback interface of same .
// device. if isRedundanyGroup(hopList) {
physHop := hop1.origMain missing := len(hopList[0].redundancyIntfs) - len(
if len(extraHops) == 0 && physHop != nil { hopList)
delete(intf.routes[hop1], n) if missing == 0 {
if intf.routes[physHop] == nil { intf.routes[n] = hopList[:1]
intf.routes[physHop] = make(netMap) continue
} }
intf.routes[physHop][n] = true
// Network is reached by more than one but not by
all
// redundancy interfaces.
errors.push(
fmt.Sprintf(
"Pathrestriction ambiguously affe
cts generation"+
" of static routes\n"+
" to interfaces wit
h virtual IP %s:\n"+
" %s is reached via\n"+
"%s\n"+
" But %d interface(s) of
group are missing.\n"+
" Remaining paths must tr
averse\n"+
" - all interfaces or\n"+
" - exactly one interface
\n"+
" of this group.",
hopList[0].ip, n, hopList.nameLis
t(), missing))
continue continue
} }
// Show error message if dst network is reached by
// more than one but not by all redundancy interfaces.
nameList := stringList{hop1.name}
for _, hop := range extraHops {
nameList.push(hop.name)
}
sort.Strings(nameList)
names := strings.Join(nameList, "\n - ")
errors.push( errors.push(
fmt.Sprintf( fmt.Sprintf("Ambiguous static routes for %s at %s
"Pathrestriction ambiguously affects gene via\n%s",
ration"+ n, intf, hopList.nameList()))
" of static routes\n"+
" to interfaces with virtua
l IP %s:\n"+
" %s is reached via\n"+
" - %s\n"+
" But %d interface(s) of group ar
e missing.\n"+
" Remaining paths must traverse\n
"+
" - all interfaces or\n"+
" - exactly one interface\n"+
" of this group.",
hop1.ip.String(), n.name, names, missing)
)
} }
// Show error messages of both tests above. // Show collected error messages.
sort.Strings(errors) sort.Strings(errors)
for _, e := range errors { for _, e := range errors {
c.err(e) c.err(e)
} }
} }
} }
func intfListEq(l1, l2 []*routerIntf) bool { // Check, whether input interfaces belong to same redundancy group.
if len(l1) != len(l2) { // Each member is known to use the same list in redundancyIntfs
// and each interface can only be member in one redundancy group,
// hence it is sufficient to check only first element.
func isRedundanyGroup(intfs intfList) bool {
l1 := intfs[0].redundancyIntfs
if len(l1) == 0 {
return false return false
} }
for i, e := range l1 { for _, intf := range intfs[1:] {
if e != l2[i] { if !redundancyEq(intf.redundancyIntfs, l1) {
return false return false
} }
} }
return true return true
} }
func getIpv4Ipv6Routers() []*router { func redundancyEq(l1, l2 intfList) bool {
result := make([]*router, 0, len(symTable.router)+len(symTable.router6)) if len(l1) != len(l2) {
for _, r := range symTable.router {
result = append(result, r)
}
for _, r := range symTable.router6 {
result = append(result, r)
}
return result
}
// Check, whether input interfaces belong to same redundancy group.
func isRedundanyGroup(intfs []*routerIntf) bool {
list1 := intfs[0].redundancyIntfs
if len(list1) == 0 {
return false return false
} }
// Check for equality of lists. if l1[0] != l2[0] {
for _, intf := range intfs[1:] { return false
list2 := intf.redundancyIntfs
if len(list2) != len(list1) {
return false
}
for i, obj := range list1 {
if obj != list2[i] {
return false
}
}
} }
return true return true
} }
func getMainInterface(intf *routerIntf) *routerIntf { func getMainInterface(intf *routerIntf) *routerIntf {
if m := intf.mainIntf; m != nil { if m := intf.mainIntf; m != nil {
return m return m
} }
return intf return intf
} }
 End of changes. 129 change blocks. 
620 lines changed or deleted 490 lines changed or added

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