|
15 | 15 | package ipam |
16 | 16 |
|
17 | 17 | import ( |
| 18 | + "encoding/binary" |
18 | 19 | "fmt" |
19 | | - |
20 | | - "github.com/google/nftables" |
| 20 | + "net" |
21 | 21 |
|
22 | 22 | ipamv1alpha1 "github.com/liqotech/liqo/apis/ipam/v1alpha1" |
23 | 23 | networkingv1beta1 "github.com/liqotech/liqo/apis/networking/v1beta1" |
@@ -46,9 +46,53 @@ func GetUnknownSourceIP(extCIDR string) (string, error) { |
46 | 46 | if extCIDR == "" { |
47 | 47 | return "", fmt.Errorf("ExternalCIDR not set") |
48 | 48 | } |
49 | | - firstExtCIDRip, _, err := nftables.NetFirstAndLastIP(extCIDR) |
| 49 | + firstExtCIDRip, _, err := NetFirstAndLastIP(extCIDR) |
50 | 50 | if err != nil { |
51 | 51 | return "", fmt.Errorf("cannot get first IP of ExternalCIDR") |
52 | 52 | } |
53 | 53 | return firstExtCIDRip.String(), nil |
54 | 54 | } |
| 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