158 lines
4.1 KiB
Go
158 lines
4.1 KiB
Go
package subnet
|
|
|
|
import (
|
|
"errors"
|
|
"net"
|
|
"testing"
|
|
)
|
|
|
|
func cidr(t *testing.T, s string) *net.IPNet {
|
|
t.Helper()
|
|
_, n, err := net.ParseCIDR(s)
|
|
if err != nil {
|
|
t.Fatalf("ParseCIDR(%q) : %v", s, err)
|
|
}
|
|
return n
|
|
}
|
|
|
|
func baseSubnet(t *testing.T, mode string) subnetData {
|
|
t.Helper()
|
|
return subnetData{
|
|
mode: mode,
|
|
interfaceIP: net.ParseIP("10.1.1.1").To4(),
|
|
cidr: cidr(t, "10.1.0.0/23"),
|
|
vpcCIDR: cidr(t, "192.168.0.0/16"),
|
|
}
|
|
}
|
|
|
|
func deduced(ip string) func() (net.IP, error) {
|
|
return func() (net.IP, error) { return net.ParseIP(ip).To4(), nil }
|
|
}
|
|
|
|
func neverDeduced(t *testing.T) func() (net.IP, error) {
|
|
t.Helper()
|
|
return func() (net.IP, error) {
|
|
t.Error("la gateway de l'host ne doit pas être interrogée dans ce cas")
|
|
return nil, nil
|
|
}
|
|
}
|
|
|
|
// --- next-hop de la route par défaut ---
|
|
|
|
func TestDhcpRouting_DefaultRouteUsesInterfaceIP(t *testing.T) {
|
|
d := baseSubnet(t, ModeVxlan)
|
|
|
|
gw, _, err := dhcpRouting(d, neverDeduced(t))
|
|
if err != nil {
|
|
t.Fatalf("dhcpRouting : %v", err)
|
|
}
|
|
if gw.String() != "10.1.1.1" {
|
|
t.Errorf("sans default_route le next-hop doit être l'interface_ip, obtenu %s", gw)
|
|
}
|
|
}
|
|
|
|
func TestDhcpRouting_DefaultRouteUsesSuppliedGateway(t *testing.T) {
|
|
d := baseSubnet(t, ModeVxlan)
|
|
d.defaultRoute = true
|
|
d.gateway = net.ParseIP("10.1.1.254").To4()
|
|
|
|
gw, _, err := dhcpRouting(d, neverDeduced(t))
|
|
if err != nil {
|
|
t.Fatalf("dhcpRouting : %v", err)
|
|
}
|
|
if gw.String() != "10.1.1.254" {
|
|
t.Errorf("gateway fournie attendue, obtenu %s", gw)
|
|
}
|
|
}
|
|
|
|
func TestDhcpRouting_DefaultRouteFallsBackToDeducedGateway(t *testing.T) {
|
|
d := baseSubnet(t, ModeBridge)
|
|
d.defaultRoute = true
|
|
|
|
gw, _, err := dhcpRouting(d, deduced("192.0.2.1"))
|
|
if err != nil {
|
|
t.Fatalf("dhcpRouting : %v", err)
|
|
}
|
|
if gw.String() != "192.0.2.1" {
|
|
t.Errorf("gateway déduite attendue, obtenu %s", gw)
|
|
}
|
|
}
|
|
|
|
func TestDhcpRouting_SuppliedGatewayIgnoredWithoutDefaultRoute(t *testing.T) {
|
|
d := baseSubnet(t, ModeVxlan)
|
|
d.gateway = net.ParseIP("10.1.1.254").To4()
|
|
|
|
gw, _, err := dhcpRouting(d, neverDeduced(t))
|
|
if err != nil {
|
|
t.Fatalf("dhcpRouting : %v", err)
|
|
}
|
|
if gw.String() != "10.1.1.1" {
|
|
t.Errorf("gateway fournie sans default_route : ignorée en silence, next-hop attendu 10.1.1.1, obtenu %s", gw)
|
|
}
|
|
}
|
|
|
|
func TestDhcpRouting_DeductionFailureIsReported(t *testing.T) {
|
|
d := baseSubnet(t, ModeBridge)
|
|
d.defaultRoute = true
|
|
|
|
_, _, err := dhcpRouting(d, func() (net.IP, error) { return nil, errors.New("pas de route") })
|
|
if err == nil {
|
|
t.Error("l'échec de déduction de la gateway doit remonter, pas produire une route muette")
|
|
}
|
|
}
|
|
|
|
// --- route VPC ---
|
|
|
|
func TestDhcpRouting_VPCRouteKeptInVxlan(t *testing.T) {
|
|
_, route, err := dhcpRouting(baseSubnet(t, ModeVxlan), neverDeduced(t))
|
|
if err != nil {
|
|
t.Fatalf("dhcpRouting : %v", err)
|
|
}
|
|
if route == nil || route.String() != "192.168.0.0/16" {
|
|
t.Errorf("route VPC attendue, obtenu %v", route)
|
|
}
|
|
}
|
|
|
|
func TestDhcpRouting_VPCRouteKeptInPublicIP(t *testing.T) {
|
|
d := baseSubnet(t, ModePublicIP)
|
|
d.defaultRoute = true
|
|
d.gateway = net.ParseIP("203.0.113.1").To4()
|
|
|
|
gw, route, err := dhcpRouting(d, neverDeduced(t))
|
|
if err != nil {
|
|
t.Fatalf("dhcpRouting : %v", err)
|
|
}
|
|
if route == nil || route.String() != "192.168.0.0/16" {
|
|
t.Fatalf("route VPC attendue sur un subnet public, obtenu %v", route)
|
|
}
|
|
if gw.String() != "203.0.113.1" {
|
|
t.Errorf("next-hop par défaut attendu 203.0.113.1, obtenu %s", gw)
|
|
}
|
|
// C'est tout l'intérêt du mode : la route VPC garde interface_ip comme next-hop,
|
|
// donc le trafic interne ne sort jamais par la gateway publique.
|
|
}
|
|
|
|
func TestDhcpRouting_NoVPCRouteInBridge(t *testing.T) {
|
|
_, route, err := dhcpRouting(baseSubnet(t, ModeBridge), neverDeduced(t))
|
|
if err != nil {
|
|
t.Fatalf("dhcpRouting : %v", err)
|
|
}
|
|
if route != nil {
|
|
t.Errorf("le mode bridge n'a pas de route VPC, obtenu %v", route)
|
|
}
|
|
}
|
|
|
|
// --- modes ---
|
|
|
|
func TestValidMode(t *testing.T) {
|
|
for _, m := range []string{ModeVxlan, ModeBridge, ModePublicIP} {
|
|
if !ValidMode(m) {
|
|
t.Errorf("%q devrait être un mode valide", m)
|
|
}
|
|
}
|
|
for _, m := range []string{"", "public", "vxlan ", "VXLAN"} {
|
|
if ValidMode(m) {
|
|
t.Errorf("%q ne devrait pas être un mode valide", m)
|
|
}
|
|
}
|
|
}
|