Files
ubicloud/prog/learn_network.rb
Furkan Sahin 6f786b0801 Increase the IPv6 prefix min length to 112 bits
We were expecting the prefix to be shorter than 68 bits but the latest
leaseweb hosts came with ipv6 blocks like:
2607:f5b7:1:64:1::_112/64
2607:f5b7:1:64:2::_112/64
2607:f5b7:1:64:3::_112/64

As you can see, they give /64 but the address space is not actually as
big as /64. Because, the :1, :2, :3 at the end of the prefix is actually
to 80th bit. We must see them like the following for it to make sense;
2607:f5b7:1:64:0001::/64
2607:f5b7:1:64:0002::/64

Here, the differentiating bit is in the residue part of a /64 network.
So, if we use them as they are, we need to actually map them to
2607:f5b7:1:64::/64 which would not work because then we would have
multiple hosts with the same prefix and we cannot assign ipv6 addresses
to the VMs correctly.

To solve this issue, we assign the prefixes correctly using /80. So, the
hosts become
2607:f5b7:1:64:0001::/80
2607:f5b7:1:64:0002::/80

This requires modification in learn_network prog because it was
previously expecting at least /68. We increase the condition to 112
bits.

The main idea of /68 was that so that we can deleget prefixes at the
size of /80 which doesn't really work because dnsmasq cannot delegate
the prefixes anyway. So, in any case, we simply give /128 to anyone.
However, we still keep it at least 112 bits because we need 2 bytes of
entropy.
2024-09-27 11:21:33 +02:00

51 lines
1.6 KiB
Ruby

# frozen_string_literal: true
require "json"
class Prog::LearnNetwork < Prog::Base
subject_is :sshable, :vm_host
label def start
ip6 = parse_ip_addr_j(sshable.cmd("/usr/sbin/ip -j -6 addr show scope global"))
# While it would be ideal for NetAddr's IPv6 support to convey
# both address and prefix information together as `ip` does, it's
# designed in a more IPv4-centric way where IP addresses and CIDRs
# tend to be disaggregated.
#
# Postgres's "inet" does support this IPv6-style mixture of
# addresses and prefixlens, the "cidr" type requires masked-out
# bits to be zero. NetAddr's IPv6Net type clears low bits beyond
# the prefix.
#
# Maybe we can improve support for inet in a fork later, NetAddr
# is not a fast moving project, there is room to improve it, but
# some would be backwards-incompatible.
vm_host.update(
ip6: ip6.addr,
net6: NetAddr::IPv6Net.new(NetAddr.parse_ip(ip6.addr), NetAddr::Mask128.new(ip6.prefixlen)).to_s
)
pop "learned network information"
end
Ip6 = Struct.new(:addr, :prefixlen)
def parse_ip_addr_j(s)
case JSON.parse(s)
in [iface]
case iface.fetch("addr_info").filter_map { |info|
if (local = info["local"]) && (prefixlen = info["prefixlen"]) && prefixlen <= 112
Ip6.new(local, prefixlen)
end
}
in [net6]
net6
else
fail "only one global unique address prefix supported on interface"
end
else
fail "only one one interface supported"
end
end
end