dns: Reduce ttls
[sks-keyservers-pool.git] / sks-keyservers.net / status-srv / sks.inc.php
blob17081fbe3130ce53976c4dd83dcfa26e6a9de13a
1 <?
2 /*
3 * status-srv/sks.inc.php
4 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 Kristian Fiskerstrand
5 *
6 * This file is part of SKS Keyserver Pool (http://sks-keyservers.net)
7 *
8 * The Author can be reached by electronic mail at kf@sumptuouscapital.com
9 * Communication using OpenPGP is preferred - a copy of the public key 0x0B7F8B60E3EDFAE3
10 * is available in all the common keyservers or in hkp://pool.sks-keyservers.net
12 * This program is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation, either version 3 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25 error_reporting(E_ALL);
27 date_default_timezone_set("UTC");
28 function event_serverreturn($fd, $flag, $arg)
30 $serverobj = $arg[2];
31 if($fd !== false)
33 $json = "";
35 while(($buf = fgets($fd, 1024)) !== false)
37 $json .= $buf;
40 if (!feof($fd))
42 echo "Error: popen never ended\n";
45 $sadd = new sks_peer($serverobj, null, $json);
46 $serverobj->add_server($sadd);
48 pclose($fd);
51 unset($serverobj->fh[$sadd->get_hostname()]);
52 event_free($arg[0]);
55 function gethostbyname6($host, $try_a = false) {
56 // get AAAA record for $host
57 // if $try_a is true, if AAAA fails, it tries for A
58 // the first match found is returned
59 // otherwise returns false
61 $dns = gethostbynamel6($host, $try_a);
62 if ($dns == false) { return false; }
63 else { return $dns[0]; }
66 function gethostbynamel6($host, $try_a = false) {
67 // get AAAA records for $host,
68 // if $try_a is true, if AAAA fails, it tries for A
69 // results are returned in an array of ips found matching type
70 // otherwise returns false
72 $dns6 = dns_get_record($host, DNS_AAAA);
73 if ($try_a == true) {
74 $dns4 = dns_get_record($host, DNS_A);
75 $dns = array_merge($dns4, $dns6);
77 else { $dns = $dns6; }
78 $ip6 = array();
79 $ip4 = array();
80 foreach ($dns as $record) {
81 if ($record["type"] == "A") {
82 $ip4[] = $record["ip"];
84 if ($record["type"] == "AAAA") {
85 $ip6[] = $record["ipv6"];
88 if (count($ip6) < 1) {
89 if ($try_a == true) {
90 if (count($ip4) < 1) {
91 return false;
93 else {
94 return $ip4;
97 else {
98 return false;
101 else {
102 return $ip6;
106 class sks_servercollection
108 private $servers = array();
109 private $servers_queue = array();
110 public $created;
111 private $events = array();
112 public $event_base;
113 public $fh = array();
115 public function sks_servercollection()
117 $this->created = time();
118 $this->event_base = event_base_new();
121 // Queue handling
123 public function add_server_to_queue($server)
125 if($this->do_add($server) && !isset($this->events[$server]))
127 $this->servers_queue[$server] = true;
129 $this->events[$server] = event_new();
130 $this->fh[$server] = popen("/usr/bin/php -f /webs/sks-keyservers.net/status/sks_get_peer_data.php {$server}", "r");
131 event_set($this->events[$server], $this->fh[$server], EV_TIMEOUT | EV_READ | EV_WRITE | EV_PERSIST, "event_serverreturn", array($this->events[$server], $this->event_base, &$this, $this->created));
132 event_base_set($this->events[$server], $this->event_base);
133 event_add($this->events[$server], 70000);
137 public function get_queue_count()
139 return count($this->fh);
142 public function add_server($obj)
144 if($obj != null && $obj->get_hostname() != "")
146 if(!isset($this->servers[$obj->get_hostname()]))
147 $this->servers[$obj->get_hostname()] = $obj;
151 public function get_servers()
153 return $this->servers;
156 public function include_ipv6()
158 $should_include_ipv6 = true;
159 $count_ipv6 = 0;
160 $kfwebs_included = false;
162 foreach($this->servers as $server)
164 if($server->get_ipv6())
165 $count_ipv6++;
167 if($server->get_hostname() == "keys.kfwebs.net")
168 $kfwebs_included = true;
171 if($kfwebs_included && $count_ipv6 == 1)
172 return false;
173 else
174 return true;
177 public function get_server_by_name($name)
179 foreach($this->servers as $id=>$server)
181 if($server->get_hostname() == $name || $server->get_called_hostname() == $name)
182 return $this->servers[$id];
184 return false;
187 public function get_time()
189 return $this->created;
192 public function do_add($n)
194 if(isset($this->servers[$n]) || isset($this->servers_queue[$n]))
195 return false;
196 else
197 return true;
201 class sks_peer
203 private $hostname;
204 private $called_hostname;
205 private $server_contact;
206 private $port;
207 private $recon_port;
208 private $numkeys;
209 private $software;
210 private $version;
211 private $statusok = true;
212 private $statusipv6ok = false;
213 private $port80 = false;
214 private $has_hkps = false;
215 private $hkps_port = 0;
216 private $statusfaultreason;
217 private $peers = array();
218 private $debug = 0;
219 private $responsetime = -1;
220 private $http_response_server;
221 private $http_response_via;
222 private $http_post_expect_error = false;
223 private $affected_cve2014_3207 = true;
224 private $tor_addresse = "";
226 public function get_numkeys() { return $this->numkeys; }
227 public function get_software() { return $this->software; }
228 public function get_version() { return $this->version; }
229 public function get_hostname() { return $this->hostname; }
230 public function get_server_contact() {
231 return strtr(strtoupper($this->server_contact), array("X" => "x", " " => ""));
233 public function get_called_hostname() { return $this->called_hostname; }
234 public function get_port() { return $this->port; }
235 public function get_recon_port() { return $this->recon_port; }
236 public function get_peers() {return $this->peers;}
237 public function get_statusok() {return $this->statusok;}
238 public function get_serversarr() {return $this->servers;}
239 public function get_ipv6() {return $this->statusipv6ok;}
240 public function get_has_hkps() {return ($this->has_hkps && $this->get_is_loadbalanced());}
241 public function get_hkps_port() {return $this->hkps_port;}
242 public function get_port80() {return $this->port80;}
243 public function get_responsetime() {return $this->responsetime;}
244 public function get_http_response_server(){return $this->http_response_server;}
245 public function get_has_http_response_via(){return $this->http_response_via;}
246 public function get_is_loadbalanced(){return $this->is_loadbalanced();}
247 public function get_is_reverse_proxy() {return $this->is_accepted_server_response();}
248 public function get_http_post_error(){return $this->http_post_expect_error;}
249 public function get_affected_cve2014_3207(){return $this->affected_cve2014_3207;}
250 public function get_tor_addresse(){return $this->tor_addresse;}
251 public function version_satisfy_min($min_version, $development = 0)
254 * Convert version string into array with
255 * (major, minor, release)
257 $min_version_tuple = preg_split("/\./", $min_version);
258 preg_match("/(\d+\.\d+\.\d+)/", $this->version, $matches);
259 if(isset($matches[1]))
260 $version_tuple = preg_split("/\./", $matches[1]);
261 else
262 $version_tuple = preg_split("/\./", $this->version);
264 // Check major
265 if((int)($version_tuple[0]) > (int)($min_version_tuple[0]))
266 return true;
268 // Check minor
270 ((int)($version_tuple[0]) == (int)($min_version_tuple[0]))
271 && ((int)($version_tuple[1]) > (int)($min_version_tuple[1]))
273 return true;
275 // Check release
277 ((int)($version_tuple[0]) == (int)($min_version_tuple[0]))
278 && ((int)($version_tuple[1]) == (int)($min_version_tuple[1]))
279 && ((int)($version_tuple[2]) >= (int)($min_version_tuple[2]))
280 && ($development ? substr($this->version, -1) == "+" : true)
282 return true;
284 // If not true by now, return false
285 return false;
288 public function sks_get_peer_data()
290 // Open handle
291 $fp = popen("/usr/bin/php -f /webs/sks-keyservers.net/status/sks_get_peer_data.php {$this->hostname}", "r");
293 // Read back handle
294 $fp_rb = "";
296 while(($buf = fgets($fp, 1024)) !== false)
298 $fp_rb .= $buf;
301 pclose($fp);
302 return $fp_rb;
305 public function sks_peer(&$servers, $hostname=false, $jinp=false)
307 if($jinp===false)
309 $this->hostname = $hostname;
310 $jinp = $this->sks_get_peer_data();
313 // Convert back from json
314 $fp_rb_dec = json_decode($jinp, true);
316 $this->hostname = strtolower($fp_rb_dec['hostname']);
317 $this->called_hostname = strtolower($fp_rb_dec['called_hostname']);
319 $this->port = $fp_rb_dec['port'];
321 $this->statusok = $fp_rb_dec['statusok'];
323 if($this->debug)
324 echo "Server: {$this->hostname} has status: ".($this->statusok ? "OK" : "Not OK")."\n";
326 if($this->statusok)
328 $this->responsetime = $fp_rb_dec['responsetime'];
329 $this->http_response_server = $fp_rb_dec['http_response_server'];
330 $this->http_response_via = $fp_rb_dec['http_response_via'];
331 $this->numkeys = $fp_rb_dec['numkeys'];
332 $this->software = $fp_rb_dec['software'];
333 $this->version = $fp_rb_dec['version'];
334 $this->server_contact = $fp_rb_dec['server_contact'];
336 if(isset($fp_rb_dec['recon_port']))
337 $this->recon_port = $fp_rb_dec['recon_port'];
339 $this->http_post_expect_error = $fp_rb_dec['postExpect'];
341 if(isset($fp_rb_dec['peers']) && is_array($fp_rb_dec['peers']))
342 $this->peers = $fp_rb_dec['peers'];
343 else
344 $this->peers = array();
346 $this->statusipv6ok = $fp_rb_dec['statusipv6ok'];
347 $this->port80 = $fp_rb_dec['port80'];
348 $this->has_hkps = $fp_rb_dec['has_hkps'];
349 $this->hkps_port = $fp_rb_dec['hkps_port'];
350 $this->tor_addresse = $fp_rb_dec['tor_addresse'];
351 $this->affected_cve2014_3207 = $fp_rb_dec['cve-2014-3207'];
354 if(is_array($this->peers) && count($this->peers) > 0)
356 foreach($this->peers as $peer)
358 $servers->add_server_to_queue($peer);
362 } // End function sks_peer
364 private function is_loadbalanced()
366 $loadbalanced = array(
367 "keys2.kfwebs.net",
368 "sks.undergrid.net",
369 "sks.fidocon.de",
370 "keyserver.searchy.nl",
371 "keyserver.codinginfinity.com",
372 "pgp.key-server.io",
373 "sks.mj2.uk",
374 "pgpkeys.co.uk",
375 "pgpkeys.eu",
376 "fks.pgpkeys.eu",
377 "pgpkeys.uk"
379 return $this->is_accepted_server_response() && in_array($this->hostname, $loadbalanced);
382 private function is_accepted_server_response()
384 $is_accepted_server = false;
386 // Check if Server: header contain a valid response
387 $accepted_http_server_list = array("nginx", "apache");
388 foreach($accepted_http_server_list as $revprox)
390 if(strstr(strtolower($this->http_response_server), $revprox) !== false)
391 $is_accepted_server = true;
394 // Check if Via: header is set, presume proxy if it is
395 if($this->http_response_via)
396 $is_accepted_server = true;
398 return $is_accepted_server;
399 } // end is_accepted_server_response
401 } // End class
403 class sks_stats
405 public function sks_stats()
407 $servers = new sks_servercollection;
409 $initial_servers = array("keys2.kfwebs.net", "zimmermann.mayfirst.org", "keyserver.kim-minh.com", "pgp.circl.lu", "keys.niif.hu", "sks.b4ckbone.de", "keyserver.opensuse.org");
411 foreach($initial_servers as $s)
413 $sadd = new sks_peer($servers, $s);
414 $servers->add_server($sadd);
415 echo "Adding: {$s}\n";
418 echo "Done adding primaries\n";
419 event_base_loop($servers->event_base);
421 echo "Done looping\n";
422 echo "";
424 if(!file_exists(dirname(__FILE__)."/sks_cache_status_collection.serialized"))
425 $status_collection = new sks_status_collection();
426 else
427 $status_collection = unserialize(file_get_contents(dirname(__FILE__)."/sks_cache_status_collection.serialized"));
429 $status_collection->run($servers);
430 $nk = $status_collection->get_statistics_data();
431 echo "Numkey set to:\t".$nk['numkeys'];
433 file_put_contents(dirname(__FILE__)."/sks_cache.serialized",serialize($servers));
434 file_put_contents(dirname(__FILE__)."/sks_cache_status_collection.serialized",serialize($status_collection));