fix(portal): Restrict creating Resources with addresses in our reserved ranges (#5844)

In the Clients, we need to prioritize DNS Resource traffic before CIDR
traffic in order to ensure DNS resources take priority over full-route
ones.

Because of this, any CIDR Resources defined within our reserved DNS
range will never be routable. This PR updates the portal validations to
reflect that.

refs #5840 
refs #2667
This commit is contained in:
Jamil
2024-07-11 20:57:50 -07:00
committed by GitHub
parent 71f8b86b78
commit 2c1e6f12ef
3 changed files with 23 additions and 7 deletions

View File

@@ -2,20 +2,28 @@ defmodule Domain.Network do
alias Domain.Repo
alias Domain.Network.Address
@cidrs %{
# Notice: those are also part of "resources_account_id_cidr_address_index" DB constraint
# Encompasses all of CGNAT and our reserved IPv6 unique local prefix
@reserved_cidrs %{
ipv4: %Postgrex.INET{address: {100, 64, 0, 0}, netmask: 10},
ipv6: %Postgrex.INET{address: {64_768, 8_225, 4_369, 0, 0, 0, 0, 0}, netmask: 48}
}
# For generating new IPs for CIDR/IP Resources
@resource_cidrs %{
ipv4: %Postgrex.INET{address: {100, 64, 0, 0}, netmask: 11},
ipv6: %Postgrex.INET{address: {64_768, 8_225, 4_369, 0, 0, 0, 0, 0}, netmask: 107}
}
def cidrs, do: @cidrs
def resource_cidrs, do: @resource_cidrs
def reserved_cidrs, do: @reserved_cidrs
def fetch_next_available_address!(account_id, type, opts \\ []) do
unless Repo.in_transaction?() do
raise "fetch_next_available_address/1 must be called inside a transaction"
end
cidrs = Keyword.get(opts, :cidrs, @cidrs)
cidrs = Keyword.get(opts, :cidrs, @resource_cidrs)
cidr = Map.fetch!(cidrs, type)
hosts = Domain.Types.CIDR.count_hosts(cidr)
offset = Enum.random(2..max(2, hosts - 2))

View File

@@ -130,7 +130,7 @@ defmodule Domain.Resources.Resource.Changeset do
changeset
true ->
Network.cidrs()
Network.reserved_cidrs()
|> Enum.reduce(changeset, fn {_type, cidr}, changeset ->
validate_not_in_cidr(changeset, :address, cidr)
end)

View File

@@ -938,11 +938,19 @@ defmodule Domain.ResourcesTest do
attrs = %{"address" => "100.64.0.0/8", "type" => "cidr"}
assert {:error, changeset} = create_resource(attrs, subject)
assert "cannot be in the CIDR 100.64.0.0/11" in errors_on(changeset).address
assert "cannot be in the CIDR 100.64.0.0/10" in errors_on(changeset).address
attrs = %{"address" => "100.96.0.0/11", "type" => "cidr"}
assert {:error, changeset} = create_resource(attrs, subject)
assert "cannot be in the CIDR 100.64.0.0/10" in errors_on(changeset).address
attrs = %{"address" => "fd00:2021:1111::/102", "type" => "cidr"}
assert {:error, changeset} = create_resource(attrs, subject)
assert "cannot be in the CIDR fd00:2021:1111::/107" in errors_on(changeset).address
assert "cannot be in the CIDR fd00:2021:1111::/48" in errors_on(changeset).address
attrs = %{"address" => "fd00:2021:1111:8000::/96", "type" => "cidr"}
assert {:error, changeset} = create_resource(attrs, subject)
assert "cannot be in the CIDR fd00:2021:1111::/48" in errors_on(changeset).address
attrs = %{"address" => "::/0", "type" => "cidr"}
assert {:error, changeset} = create_resource(attrs, subject)