Skip to content

Commit

Permalink
Use typed errors for aliased and reserved inserts
Browse files Browse the repository at this point in the history
These are two errors that it may make sense to handle on the
application side.
  • Loading branch information
oschwald committed Oct 5, 2023
1 parent 5199b97 commit 4876c99
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 13 deletions.
124 changes: 124 additions & 0 deletions errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package mmdbwriter

import (
"errors"
"fmt"
"net"
"net/netip"
)

// AliasedNetworkError is returned when inserting a aliased network into
// a Tree where DisableIPv4Aliasing in Options is false.
type AliasedNetworkError struct {
// AliasedNetwork is the aliased network being inserted into.
AliasedNetwork netip.Prefix
// InsertedNetwork is the network being inserted into the Tree.
InsertedNetwork netip.Prefix
}

func newAliasedNetworkError(netIP net.IP, curPrefixLen, recPrefixLen int) error {
anErr := &AliasedNetworkError{}
ip, ok := netip.AddrFromSlice(netIP)
if !ok {
return errors.Join(
fmt.Errorf("creating netip.Addr from %s", netIP),
anErr,
)
}
var err error
// We are using netip here despite using net.IP/net.IPNet internally as
// it seems quite likely that we will switch to netip throughout.
anErr.InsertedNetwork, err = ip.Prefix(recPrefixLen)
if err != nil {
return errors.Join(
fmt.Errorf(
"creating prefix from addr %s and prefix length %d: %w",
ip,
recPrefixLen,
err,
),
anErr,
)
}

anErr.AliasedNetwork, err = ip.Prefix(curPrefixLen)
if err != nil {
return errors.Join(
fmt.Errorf(
"creating prefix from addr %s and prefix length %d: %w",
ip,
curPrefixLen,
err,
),
anErr,
)
}
return anErr
}

func (r *AliasedNetworkError) Error() string {
return fmt.Sprintf(
"attempt to insert %s into %s, which is an aliased network",
r.InsertedNetwork,
r.AliasedNetwork,
)
}

// ReservedNetworkError is returned when inserting a reserved network into
// a Tree where IncludeReservedNetworks in Options is false.
type ReservedNetworkError struct {
// InsertedNetwork is the network being inserted into the Tree.
InsertedNetwork netip.Prefix
// ReservedNetwork is the reserved network being inserted into.
ReservedNetwork netip.Prefix
}

var _ error = &ReservedNetworkError{}

func newReservedNetworkError(netIP net.IP, curPrefixLen, recPrefixLen int) error {
rnErr := &ReservedNetworkError{}
ip, ok := netip.AddrFromSlice(netIP)
if !ok {
return errors.Join(
fmt.Errorf("creating netip.Addr from %s", netIP),
rnErr,
)
}
var err error
// We are using netip here despite using net.IP/net.IPNet internally as
// it seems quite likely that we will switch to netip throughout.
rnErr.InsertedNetwork, err = ip.Prefix(recPrefixLen)
if err != nil {
return errors.Join(
fmt.Errorf(
"creating prefix from addr %s and prefix length %d: %w",
ip,
recPrefixLen,
err,
),
rnErr,
)
}

rnErr.ReservedNetwork, err = ip.Prefix(curPrefixLen)
if err != nil {
return errors.Join(
fmt.Errorf(
"creating prefix from addr %s and prefix length %d: %w",
ip,
curPrefixLen,
err,
),
rnErr,
)
}
return rnErr
}

func (r *ReservedNetworkError) Error() string {
return fmt.Sprintf(
"attempt to insert %s into %s, which is a reserved network",
r.InsertedNetwork,
r.ReservedNetwork,
)
}
12 changes: 2 additions & 10 deletions node.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,11 +117,7 @@ func (r *record) insert(
return r.maybeMergeChildren(iRec)
case recordTypeReserved:
if iRec.prefixLen >= newDepth {
return fmt.Errorf(
"attempt to insert %s/%d, which is in a reserved network",
iRec.ip,
iRec.prefixLen,
)
return newReservedNetworkError(iRec.ip, newDepth, iRec.prefixLen)
}
// If we are inserting a network that contains a reserved network,
// we silently remove the reserved network.
Expand All @@ -133,11 +129,7 @@ func (r *record) insert(
return nil
}
// attempting to insert _into_ an aliased network
return fmt.Errorf(
"attempt to insert %s/%d, which is in an aliased network",
iRec.ip,
iRec.prefixLen,
)
return newAliasedNetworkError(iRec.ip, newDepth, iRec.prefixLen)
default:
return fmt.Errorf("inserting into record type %d is not implemented", r.recordType)
}
Expand Down
6 changes: 3 additions & 3 deletions tree_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -341,19 +341,19 @@ func TestTreeInsertAndGet(t *testing.T) {
network: "10.0.0.0/8",
start: "10.0.0.0",
end: "10.255.255.255",
expectedErrorMsg: "attempt to insert ::a00:0/104, which is in a reserved network",
expectedErrorMsg: "attempt to insert ::a00:0/104 into ::a00:0/104, which is a reserved network",
},
{
network: "10.0.0.1/32",
start: "10.0.0.1",
end: "10.0.0.1",
expectedErrorMsg: "attempt to insert ::a00:1/128, which is in a reserved network",
expectedErrorMsg: "attempt to insert ::a00:1/128 into ::a00:0/104, which is a reserved network",
},
{
network: "2002:100::/24",
start: "2002:100::",
end: "2002:1ff:ffff:ffff:ffff:ffff:ffff:ffff",
expectedErrorMsg: "attempt to insert 2002:100::/24, which is in an aliased network",
expectedErrorMsg: "attempt to insert 2002:100::/24 into 2002::/16, which is an aliased network",
},
},
gets: []testGet{
Expand Down

0 comments on commit 4876c99

Please sign in to comment.