Skip to content

Commit 7be17a9

Browse files
committed
refactor: avoid importing nftables to get first IP
1 parent 137a743 commit 7be17a9

File tree

1 file changed

+47
-3
lines changed

1 file changed

+47
-3
lines changed

pkg/utils/ipam/ips.go

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@
1515
package ipam
1616

1717
import (
18+
"encoding/binary"
1819
"fmt"
19-
20-
"github.com/google/nftables"
20+
"net"
2121

2222
ipamv1alpha1 "github.com/liqotech/liqo/apis/ipam/v1alpha1"
2323
networkingv1beta1 "github.com/liqotech/liqo/apis/networking/v1beta1"
@@ -46,9 +46,53 @@ func GetUnknownSourceIP(extCIDR string) (string, error) {
4646
if extCIDR == "" {
4747
return "", fmt.Errorf("ExternalCIDR not set")
4848
}
49-
firstExtCIDRip, _, err := nftables.NetFirstAndLastIP(extCIDR)
49+
firstExtCIDRip, _, err := NetFirstAndLastIP(extCIDR)
5050
if err != nil {
5151
return "", fmt.Errorf("cannot get first IP of ExternalCIDR")
5252
}
5353
return firstExtCIDRip.String(), nil
5454
}
55+
56+
// NetFirstAndLastIP takes the beginning address of an entire network in CIDR
57+
// notation (e.g. 192.168.1.0/24) and returns the first and last IP addresses
58+
// within the network (e.g. first 192.168.1.0, last 192.168.1.255).
59+
//
60+
// Note that these are the first and last IP addresses, not the first and last
61+
// *usable* IP addresses (which would be 192.168.1.1 and 192.168.1.254,
62+
// respectively, for 192.168.1.0/24).
63+
// Note: this is copied from github.com/google/nftables, copyright Google LLC,
64+
// licensed under the Apache 2.0 license.
65+
func NetFirstAndLastIP(networkCIDR string) (first, last net.IP, err error) {
66+
_, subnet, err := net.ParseCIDR(networkCIDR)
67+
if err != nil {
68+
return nil, nil, err
69+
}
70+
71+
first = make(net.IP, len(subnet.IP))
72+
last = make(net.IP, len(subnet.IP))
73+
74+
switch len(subnet.IP) {
75+
case net.IPv4len:
76+
mask := binary.BigEndian.Uint32(subnet.Mask)
77+
ip := binary.BigEndian.Uint32(subnet.IP)
78+
// To achieve the first IP address, we need to AND the IP with the mask.
79+
// The AND operation will set all bits in the host part to 0.
80+
binary.BigEndian.PutUint32(first, ip&mask)
81+
// To achieve the last IP address, we need to OR the IP network with the inverted mask.
82+
// The AND between the IP and the mask will set all bits in the host part to 0, keeping the network part.
83+
// The XOR between the mask and 0xffffffff will set all bits in the host part to 1, and the network part to 0.
84+
// The OR operation will keep the host part unchanged, and sets the host part to all 1.
85+
binary.BigEndian.PutUint32(last, (ip&mask)|(mask^0xffffffff))
86+
case net.IPv6len:
87+
mask1 := binary.BigEndian.Uint64(subnet.Mask[:8])
88+
mask2 := binary.BigEndian.Uint64(subnet.Mask[8:])
89+
ip1 := binary.BigEndian.Uint64(subnet.IP[:8])
90+
ip2 := binary.BigEndian.Uint64(subnet.IP[8:])
91+
binary.BigEndian.PutUint64(first[:8], ip1&mask1)
92+
binary.BigEndian.PutUint64(first[8:], ip2&mask2)
93+
binary.BigEndian.PutUint64(last[:8], (ip1&mask1)|(mask1^0xffffffffffffffff))
94+
binary.BigEndian.PutUint64(last[8:], (ip2&mask2)|(mask2^0xffffffffffffffff))
95+
}
96+
97+
return first, last, nil
98+
}

0 commit comments

Comments
 (0)