The sub 'for_all_corosync_addresses' iterates through all nodes in a passed corosync config and calls a specified function for every ringX_addr on every node it finds (provided the IP-version matches the specified one or undef was specified).
All ringX_addr entries that cannot be parsed as an IP address will be best-effort resolved as hostnames. This has to happen in the exact same way as corosync does internally, to ensure consistency with firewall rules. Signed-off-by: Stefan Reiter <s.rei...@proxmox.com> --- v2: * resolve_hostname_like_corosync now returns IP addresses if passed (this simplifies the iterator function) * Use existing nodelist() function * Use PVE::Tools::* instead of exporting getaddrinfo-related functions * Move IP-version check into iterator function data/PVE/Corosync.pm | 89 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/data/PVE/Corosync.pm b/data/PVE/Corosync.pm index e73e51d..3028e26 100644 --- a/data/PVE/Corosync.pm +++ b/data/PVE/Corosync.pm @@ -5,9 +5,12 @@ use warnings; use Digest::SHA; use Clone 'clone'; +use Socket qw(AF_INET AF_INET6 inet_ntop); use Net::IP qw(ip_is_ipv6); use PVE::Cluster; +use PVE::Tools; +use PVE::Tools qw($IPV4RE $IPV6RE); my $basedir = "/etc/pve"; @@ -256,4 +259,90 @@ sub create_conf { return { main => $conf }; } +sub for_all_corosync_addresses { + my ($corosync_conf, $ip_version, $func) = @_; + + my $nodelist = nodelist($corosync_conf); + return if !defined($nodelist); + + # iterate sorted to make rules deterministic (for change detection) + foreach my $node_name (sort keys %$nodelist) { + my $node_config = $nodelist->{$node_name}; + foreach my $node_key (sort keys %$node_config) { + if ($node_key =~ /^(ring|link)\d+_addr$/) { + my $node_address = $node_config->{$node_key}; + + my($ip, $version) = resolve_hostname_like_corosync($node_address, $corosync_conf); + next if defined($version) && defined($ip_version) && $version != $ip_version; + + $func->($node_name, $ip, $version, $node_key) + if defined($ip); + } + } + } +} + +# NOTE: Corosync actually only resolves on startup or config change, but we +# currently do not have an easy way to synchronize our behaviour to that. +sub resolve_hostname_like_corosync { + my ($hostname, $corosync_conf) = @_; + + my $corosync_strategy = $corosync_conf->{main}->{totem}->{ip_version}; + if (defined($corosync_strategy)) { + $corosync_strategy = lc $corosync_strategy; + } else { + $corosync_strategy = "ipv6-4"; # corosync default + } + + my $resolved_ip4; + my $resolved_ip6; + + my @resolved_raw; + eval { @resolved_raw = PVE::Tools::getaddrinfo_all($hostname); }; + + # ignore resolving error, check if an IP was passed instead + if ($@ || !@resolved_raw) { + if ($hostname =~ m/^(?:$IPV4RE)$/) { + return ($hostname, 4); + } elsif ($hostname =~ m/^(?:$IPV6RE)$/) { + return ($hostname, 6); + } + + return (undef, undef); + } + + foreach my $socket_info (@resolved_raw) { + next if !$socket_info->{addr}; + + my ($family, undef, $host) = PVE::Tools::unpack_sockaddr_in46($socket_info->{addr}); + + if ($family == AF_INET && !defined($resolved_ip4)) { + $resolved_ip4 = inet_ntop(AF_INET, $host); + } elsif ($family == AF_INET6 && !defined($resolved_ip6)) { + $resolved_ip6 = inet_ntop(AF_INET6, $host); + } + + last if defined($resolved_ip4) && defined($resolved_ip6); + } + + # corosync_strategy specifies the order in which IP addresses are resolved + # by corosync. We need to match that order, to ensure we create firewall + # rules for the correct address family. + my $resolved_ip; + if ($corosync_strategy eq "ipv4") { + $resolved_ip = $resolved_ip4; + } elsif ($corosync_strategy eq "ipv6") { + $resolved_ip = $resolved_ip6; + } elsif ($corosync_strategy eq "ipv6-4") { + $resolved_ip = $resolved_ip6 // $resolved_ip4; + } elsif ($corosync_strategy eq "ipv4-6") { + $resolved_ip = $resolved_ip4 // $resolved_ip6; + } + + return (undef, undef) if !defined($resolved_ip); + + my $ip_version = defined($resolved_ip4) && $resolved_ip eq $resolved_ip4 ? 4 : 6; + return ($resolved_ip, $ip_version); +} + 1; -- 2.20.1 _______________________________________________ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel