Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 0 additions & 59 deletions common/libnetwork/internal/util/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import (
"errors"
"fmt"
"net"
"strings"
"unicode"

"go.podman.io/common/libnetwork/types"
"go.podman.io/common/libnetwork/util"
Expand Down Expand Up @@ -98,43 +96,6 @@ func ValidateSubnets(network *types.Network, addGateway bool, usedNetworks []*ne
return nil
}

func ValidateRoutes(routes []types.Route) error {
for _, route := range routes {
err := ValidateRoute(route)
if err != nil {
return err
}
}
return nil
}

func ValidateRoute(route types.Route) error {
if route.Destination.IP == nil {
return errors.New("route destination ip nil")
}

if route.Destination.Mask == nil {
return errors.New("route destination mask nil")
}

if route.Gateway == nil {
return errors.New("route gateway nil")
}

// Reparse to ensure destination is valid.
ip, ipNet, err := net.ParseCIDR(route.Destination.String())
if err != nil {
return fmt.Errorf("route destination invalid: %w", err)
}

// check that destination is a network and not an address
if !ip.Equal(ipNet.IP) {
return errors.New("route destination invalid")
}

return nil
}

func ValidateSetupOptions(n NetUtil, namespacePath string, options types.SetupOptions) error {
if namespacePath == "" {
return errors.New("namespacePath is empty")
Expand Down Expand Up @@ -176,23 +137,3 @@ func validatePerNetworkOpts(network *types.Network, netOpts *types.PerNetworkOpt
}
return nil
}

// ValidateInterfaceName validates the interface name based on the following rules:
// 1. The name must be less than MaxInterfaceNameLength characters
// 2. The name must not be "." or ".."
// 3. The name must not contain / or : or any whitespace characters
// ref to https://github.com/torvalds/linux/blob/81e4f8d68c66da301bb881862735bd74c6241a19/include/uapi/linux/if.h#L33C18-L33C20
func ValidateInterfaceName(ifName string) error {
if len(ifName) > types.MaxInterfaceNameLength {
return fmt.Errorf("interface name is too long: interface names must be %d characters or less: %w", types.MaxInterfaceNameLength, types.ErrInvalidArg)
}
if ifName == "." || ifName == ".." {
return fmt.Errorf("interface name is . or ..: %w", types.ErrInvalidArg)
}
if strings.ContainsFunc(ifName, func(r rune) bool {
return r == '/' || r == ':' || unicode.IsSpace(r)
}) {
return fmt.Errorf("interface name contains / or : or whitespace characters: %w", types.ErrInvalidArg)
}
return nil
}
83 changes: 30 additions & 53 deletions common/libnetwork/netavark/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1817,59 +1817,6 @@ var _ = Describe("Config", func() {
Expect(err.Error()).To(ContainSubstring("failed to load network create: IO error: invalid IP address syntax"))
})

It("create bridge config with invalid static route (gw = \"foo\")", func() {
dest := "10.1.0.0/24"
gw := "foo"
d, _ := types.ParseCIDR(dest)
g := net.ParseIP(gw)
network := types.Network{
Driver: "bridge",
Routes: []types.Route{
{Destination: d, Gateway: g},
},
}
_, err := libpodNet.NetworkCreate(network, nil)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("invalid IP address syntax"))
})

It("create macvlan config with invalid static route (gw = \"foo\")", func() {
dest := "10.1.0.0/24"
gw := "foo"
d, _ := types.ParseCIDR(dest)
g := net.ParseIP(gw)
network := types.Network{
Driver: "macvlan",
Routes: []types.Route{
{Destination: d, Gateway: g},
},
}
_, err := libpodNet.NetworkCreate(network, nil)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("invalid IP address syntax"))
})

It("create ipvlan config with invalid static route (gw = \"foo\")", func() {
subnet := "10.1.0.0/24"
n, _ := types.ParseCIDR(subnet)
dest := "10.1.0.0/24"
gw := "foo"
d, _ := types.ParseCIDR(dest)
g := net.ParseIP(gw)
network := types.Network{
Driver: "ipvlan",
Subnets: []types.Subnet{
{Subnet: n},
},
Routes: []types.Route{
{Destination: d, Gateway: g},
},
}
_, err := libpodNet.NetworkCreate(network, nil)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("invalid IP address syntax"))
})

It("create macvlan config with metric option", func() {
network := types.Network{
Driver: "macvlan",
Expand Down Expand Up @@ -1968,6 +1915,36 @@ var _ = Describe("Config", func() {
Expect(err.Error()).To(ContainSubstring("unable to parse \"no_default_route\""))
})

It("create bridge custom route type route", func() {
dest := "10.1.0.0/24"
d, _ := types.ParseCIDR(dest)
for _, routeType := range []types.RouteType{types.RouteTypeBlackhole, types.RouteTypeProhibit, types.RouteTypeUnreachable} {
network := types.Network{
Driver: "bridge",
Routes: []types.Route{
{Destination: d, RouteType: routeType},
},
}
network1, err := libpodNet.NetworkCreate(network, nil)
Expect(err).ToNot(HaveOccurred())
Expect(network1.Name).ToNot(BeEmpty())
Expect(network1.Routes).To(HaveLen(1))
Expect(network1.Routes[0].Destination.String()).To(Equal(dest))
Expect(network1.Routes[0].RouteType).To(Equal(routeType))
}

// without gateway a unicast route should fail
network := types.Network{
Driver: "bridge",
Routes: []types.Route{
{Destination: d, RouteType: types.RouteTypeUnicast},
},
}
_, err := libpodNet.NetworkCreate(network, nil)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("route 10.1.0.0/24 requires a gateway for type unicast"))
})

Context("network load valid existing ones", func() {
BeforeEach(func() {
dir := "testfiles/valid"
Expand Down
20 changes: 18 additions & 2 deletions common/libnetwork/types/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,15 +201,31 @@ type Subnet struct {
LeaseRange *LeaseRange `json:"lease_range,omitempty"`
}

// RouteType represents the type of a route.
type RouteType string

const (
// RouteTypeUnicast is a regular route with a gateway (default).
RouteTypeUnicast RouteType = "unicast"
// RouteTypeBlackhole silently discards packets.
RouteTypeBlackhole RouteType = "blackhole"
// RouteTypeUnreachable rejects with "destination unreachable".
RouteTypeUnreachable RouteType = "unreachable"
// RouteTypeProhibit rejects with "administratively prohibited".
RouteTypeProhibit RouteType = "prohibit"
)

type Route struct {
// Destination for this route in CIDR form.
// swagger:strfmt string
Destination IPNet `json:"destination"`
// Gateway IP for this route.
// Gateway IP for this route. Required for unicast routes, must be empty for blackhole/unreachable/prohibit.
// swagger:strfmt string
Gateway net.IP `json:"gateway"`
Gateway net.IP `json:"gateway,omitempty"`
// Metric for this route. Optional.
Metric *uint32 `json:"metric,omitempty"`
// RouteType is the type of route: unicast (default), blackhole, unreachable, prohibit.
RouteType RouteType `json:"route_type,omitempty"`
}

// LeaseRange contains the range where IP are leased.
Expand Down
Loading