]> git.proxmox.com Git - pmg-api.git/blame - PMG/Cluster.pm
remove debug statement
[pmg-api.git] / PMG / Cluster.pm
CommitLineData
0854fb22
DM
1package PMG::Cluster;
2
3use strict;
4use warnings;
5
6use Socket;
7use PVE::Tools;
8use PVE::INotify;
9
9f67f5b3 10use PMG::ClusterConfig;
0854fb22 11
8737f93a
DM
12sub remote_node_ip {
13 my ($nodename, $noerr) = @_;
14
15 my $cinfo = PVE::INotify::read_file("cluster.conf");
16
9f67f5b3 17 foreach my $entry (@{$cinfo->{ids}}) {
8737f93a
DM
18 if ($entry->{name} eq $nodename) {
19 my $ip = $entry->{ip};
20 return $ip if !wantarray;
21 my $family = PVE::Tools::get_host_address_family($ip);
22 return ($ip, $family);
23 }
24 }
25
26 # fallback: try to get IP by other means
9f67f5b3 27 return PMG::Utils::lookup_node_ip($nodename, $noerr);
8737f93a
DM
28}
29
d2e43f9e
DM
30sub get_master_node {
31 my ($cinfo) = @_;
32
9f67f5b3 33 $cinfo = PVE::INotify::read_file("cluster.conf");
d2e43f9e
DM
34
35 return $cinfo->{master}->{name} if defined($cinfo->{master});
36
37 return 'localhost';
38}
39
0854fb22
DM
40# X509 Certificate cache helper
41
42my $cert_cache_nodes = {};
43my $cert_cache_timestamp = time();
44my $cert_cache_fingerprints = {};
45
46sub update_cert_cache {
47 my ($update_node, $clear) = @_;
48
49 syslog('info', "Clearing outdated entries from certificate cache")
50 if $clear;
51
52 $cert_cache_timestamp = time() if !defined($update_node);
53
54 my $node_list = defined($update_node) ?
55 [ $update_node ] : [ keys %$cert_cache_nodes ];
56
57 my $clear_node = sub {
58 my ($node) = @_;
59 if (my $old_fp = $cert_cache_nodes->{$node}) {
60 # distrust old fingerprint
61 delete $cert_cache_fingerprints->{$old_fp};
62 # ensure reload on next proxied request
63 delete $cert_cache_nodes->{$node};
64 }
65 };
66
67 my $nodename = PVE::INotify::nodename();
68
69 foreach my $node (@$node_list) {
70
71 if ($node ne $nodename) {
72 &$clear_node($node) if $clear;
73 next;
74 }
75
76 my $cert_path = "/etc/proxmox/pmg-api.pem";
77
78 my $cert;
79 eval {
80 my $bio = Net::SSLeay::BIO_new_file($cert_path, 'r');
81 $cert = Net::SSLeay::PEM_read_bio_X509($bio);
82 Net::SSLeay::BIO_free($bio);
83 };
84 my $err = $@;
85 if ($err || !defined($cert)) {
86 &$clear_node($node) if $clear;
87 next;
88 }
89
90 my $fp;
91 eval {
92 $fp = Net::SSLeay::X509_get_fingerprint($cert, 'sha256');
93 };
94 $err = $@;
95 if ($err || !defined($fp) || $fp eq '') {
96 &$clear_node($node) if $clear;
97 next;
98 }
99
100 my $old_fp = $cert_cache_nodes->{$node};
101 $cert_cache_fingerprints->{$fp} = 1;
102 $cert_cache_nodes->{$node} = $fp;
103
104 if (defined($old_fp) && $fp ne $old_fp) {
105 delete $cert_cache_fingerprints->{$old_fp};
106 }
107 }
108}
109
110# load and cache cert fingerprint once
111sub initialize_cert_cache {
112 my ($node) = @_;
113
114 update_cert_cache($node)
115 if defined($node) && !defined($cert_cache_nodes->{$node});
116}
117
118sub check_cert_fingerprint {
119 my ($cert) = @_;
120
121 # clear cache every 30 minutes at least
122 update_cert_cache(undef, 1) if time() - $cert_cache_timestamp >= 60*30;
123
124 # get fingerprint of server certificate
125 my $fp;
126 eval {
127 $fp = Net::SSLeay::X509_get_fingerprint($cert, 'sha256');
128 };
129 return 0 if $@ || !defined($fp) || $fp eq ''; # error
130
131 my $check = sub {
132 for my $expected (keys %$cert_cache_fingerprints) {
133 return 1 if $fp eq $expected;
134 }
135 return 0;
136 };
137
138 return 1 if &$check();
139
140 # clear cache and retry at most once every minute
141 if (time() - $cert_cache_timestamp >= 60) {
142 syslog ('info', "Could not verify remote node certificate '$fp' with list of pinned certificates, refreshing cache");
143 update_cert_cache();
144 return &$check();
145 }
146
147 return 0;
148}
149
1501;