We recently got an e-mail from Hetzner saying our hosts produce a routing loop with their gateway when receiving packets for IPs not yet allocated to a VM. In this case, the host will forward the packet to the default route, which is the gateway, which in turn, forwards it back to the host, until TTL is decremented, with much resource expenditure by both parties. To address this, I introduce a new nftables definition at the host level, with the intention of dropping packets to IP addresses with no VM allocating them. I add a new table of nftables that has two sets and two rules: 1. The first rule is to accept packets if the daddr is part of the first set. 2. The second rule is to drop packets if the daddr is part of the second set. This commit simply sets up the hosts with necessary path creations and some changes in the /etc/nftables.conf file to accommodate that. A small note regarding IPv6: We don't need to implement a similar mechanism for IPv6, because the behavior is different there. When an IPv4 packet reaches us and we don't know what to do, we simply send it back to the network from the default route. In IPv6 on the other hand, we send a neighbor solicitation message to the local network, if there is a match, they would respond with a link local address, if there is not, we don't get that response and send back to the client a destination unreachable message.
26 lines
1.1 KiB
Ruby
26 lines
1.1 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require_relative "../model/spec_helper"
|
|
|
|
RSpec.describe Prog::SetupNftables do
|
|
subject(:sn) {
|
|
described_class.new(Strand.new(prog: "SetupNftables"))
|
|
}
|
|
|
|
describe "#start" do
|
|
it "Sets it up and pops" do
|
|
sshable = instance_double(Sshable, host: "1.1.1.1")
|
|
vm_host = instance_double(VmHost, ubid: "vmhostubid", assigned_subnets: [
|
|
instance_double(Address, cidr: instance_double(NetAddr::IPv4Net, version: 4, network: "1.1.1.1", to_s: "1.1.1.1")),
|
|
instance_double(Address, cidr: instance_double(NetAddr::IPv4Net, version: 6, network: "::", to_s: "::")),
|
|
instance_double(Address, cidr: instance_double(NetAddr::IPv4Net, version: 4, network: "123.123.123.0/24", to_s: "123.123.123.0/24"))
|
|
], sshable: sshable)
|
|
expect(sshable).to receive(:cmd).with("sudo host/bin/setup-nftables.rb \\[\\\"123.123.123.0/24\\\"\\]")
|
|
expect(sn).to receive(:sshable).and_return(sshable)
|
|
expect(sn).to receive(:vm_host).and_return(vm_host).at_least(:once)
|
|
|
|
expect { sn.start }.to exit({"msg" => "nftables was setup"})
|
|
end
|
|
end
|
|
end
|