Skip to content

Commit 67ecdd5

Browse files
authored
Merge pull request #199 from ruby-no-kai/plat-outer-prefix
plat: Accept prefixes for NAT outer addresses
2 parents 3a7c717 + 9bf8ad3 commit 67ecdd5

7 files changed

Lines changed: 57 additions & 17 deletions

File tree

itamae/helpers.rb

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
module TemplateHelpers
2+
# Embed IPv4 address or CIDR in Pref64::/n
3+
def embed_v4(pref64n, v4)
4+
v4addr, v4prefixlen = v4.split(?/, 2)
5+
v6prefixlen = v4prefixlen.to_i + 96 if v4prefixlen
6+
7+
pref64n.sub('::/96', [sprintf(':%02x%02x:%02x%02x', *v4addr.split(?.).map(&:to_i)), *v6prefixlen].join(?/)) or fail 'pref64n is not /96'
8+
end
9+
10+
# Parse the IPv6 string representation into an array of hextets.
11+
def parse_v6addr(str)
12+
head, tail = str.split('::', 2)
13+
hextets = head.split(?:).map {|h| h.to_i(16) }
14+
if tail
15+
tail = tail.split(?:).map {|h| h.to_i(16) }
16+
hextets << Array.new(8 - hextets.count - tail.count, 0) << tail
17+
end
18+
fail 'invalid IPv6 addr' if hextets.size != 8
19+
hextets
20+
end
21+
22+
# Format the array of hextets into IPv6 string representation.
23+
def format_v6addr(addr)
24+
addr.map {|h| h.to_s(16) }.join(?:)
25+
end
26+
27+
# Convert IPv6 CIDR to min-max range
28+
def v6range(v6cidr)
29+
v6addr, v6prefixlen = v6cidr.split(?/, 2)
30+
v6prefixlen = v6prefixlen&.to_i
31+
return "[#{v6addr}]" if !v6prefixlen || v6prefixlen == 128
32+
v6addr = parse_v6addr(v6addr)
33+
34+
hostmask = 8.times.map do |i|
35+
n = (i+1) * 16 - v6prefixlen
36+
n > 0 ? (1 << n) - 1 : 0
37+
end
38+
39+
min = v6addr.zip(hostmask).map {|a, b| a & ~b }
40+
max = v6addr.zip(hostmask).map {|a, b| a | b }
41+
"[#{format_v6addr(min)}]-[#{format_v6addr(max)}]"
42+
end
43+
end
44+
45+
MItamae::ResourceExecutor::Template::RenderContext.include(TemplateHelpers)

itamae/hosts/nat-61.venue.rubykaigi.net/default.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
},
55
plat: {
66
nat64: {
7-
outer_public: '192.50.220.162',
8-
outer_private: '10.33.40.162',
7+
outer_public: '192.50.220.162/32',
8+
outer_private: '10.33.40.162/32',
99
},
1010
interfaces: {
1111
loopback: {

itamae/hosts/nat-62.venue.rubykaigi.net/default.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
},
55
plat: {
66
nat64: {
7-
outer_public: '192.50.220.163',
8-
outer_private: '10.33.40.163',
7+
outer_public: '192.50.220.163/32',
8+
outer_private: '10.33.40.163/32',
99
},
1010
interfaces: {
1111
loopback: {

itamae/hosts/nat-69.tkyk.rubykaigi.net/default.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
node.reverse_merge!(
22
plat: {
33
nat64: {
4-
outer_public: '192.50.220.166',
5-
outer_private: '10.33.40.64',
4+
outer_public: '192.50.220.166/32',
5+
outer_private: '10.33.40.64/29',
66
},
77
interfaces: {
88
loopback: {

itamae/roles/plat/templates/etc/bird/bird.conf.d/plat.conf

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,10 @@ protocol static {
6666
table static4;
6767
};
6868

69-
route <%= node.dig(:plat, :nat64).fetch(:outer_private) %>/32 via "tun-siit" {
69+
route <%= node.dig(:plat, :nat64).fetch(:outer_private) %> via "tun-siit" {
7070
bgp_community.add((C_SELF,C_CTL_ALLOW_OUTSIDE));
7171
};
72-
route <%= node.dig(:plat, :nat64).fetch(:outer_public) %>/32 via "tun-siit" {
72+
route <%= node.dig(:plat, :nat64).fetch(:outer_public) %> via "tun-siit" {
7373
bgp_community.add((C_SELF,C_CTL_ALLOW_OUTSIDE));
7474
};
7575
}

itamae/roles/plat/templates/etc/nftables/plat.conf

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,5 @@
11
# vim: ft=nftables
22
<%-
3-
def embed_v4(v6prefix, v4)
4-
v4addr, v4prefixlen = v4.split(?/, 2)
5-
v6prefixlen = v4prefixlen.to_i + 96 if v4prefixlen
6-
7-
v6prefix.sub('::/96', [sprintf(':%02x%02x:%02x%02x', *v4.split(?.).map(&:to_i)), *v6prefixlen].join(?/)) or fail 'v6prefix is not /96'
8-
end
9-
103
nat64 = node.dig(:plat, :nat64)
114
outer_public = nat64.fetch(:outer_public)
125
outer_private = nat64.fetch(:outer_private)
@@ -59,12 +52,12 @@ table inet plat {
5952
}
6053

6154
chain srcnat_private {
62-
meta l4proto {tcp, udp} counter snat ip6 to <%= embed_v4(internal, outer_private) %>:1024-65535
55+
meta l4proto {tcp, udp} counter snat ip6 to <%= v6range(embed_v4(internal, outer_private)) %>:1024-65535
6356
counter snat ip6 to <%= embed_v4(internal, outer_private) %>
6457
}
6558

6659
chain srcnat_public {
67-
meta l4proto {tcp, udp} counter snat ip6 to <%= embed_v4(internal, outer_public) %>:1024-65535
60+
meta l4proto {tcp, udp} counter snat ip6 to <%= v6range(embed_v4(internal, outer_public)) %>:1024-65535
6861
counter snat ip6 to <%= embed_v4(internal, outer_public) %>
6962
}
7063

itamae/site.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
include_recipe './helpers'
2+
13
execute "apt-get update" do
24
action :nothing
35
end

0 commit comments

Comments
 (0)