From 2c1e6f12ef1876d05e48eb45fdfe7f4bbbf7786c Mon Sep 17 00:00:00 2001 From: Jamil Date: Thu, 11 Jul 2024 20:57:50 -0700 Subject: [PATCH] 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 --- elixir/apps/domain/lib/domain/network.ex | 16 ++++++++++++---- .../lib/domain/resources/resource/changeset.ex | 2 +- .../apps/domain/test/domain/resources_test.exs | 12 ++++++++++-- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/elixir/apps/domain/lib/domain/network.ex b/elixir/apps/domain/lib/domain/network.ex index 7717dfad0..33c57abf2 100644 --- a/elixir/apps/domain/lib/domain/network.ex +++ b/elixir/apps/domain/lib/domain/network.ex @@ -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)) diff --git a/elixir/apps/domain/lib/domain/resources/resource/changeset.ex b/elixir/apps/domain/lib/domain/resources/resource/changeset.ex index 20b385338..94852068e 100644 --- a/elixir/apps/domain/lib/domain/resources/resource/changeset.ex +++ b/elixir/apps/domain/lib/domain/resources/resource/changeset.ex @@ -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) diff --git a/elixir/apps/domain/test/domain/resources_test.exs b/elixir/apps/domain/test/domain/resources_test.exs index 7842247ed..e871aa351 100644 --- a/elixir/apps/domain/test/domain/resources_test.exs +++ b/elixir/apps/domain/test/domain/resources_test.exs @@ -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)