d0e6d6d93b6d1293ab006937a1a988abc72ee5a5
[sks-keyservers-pool.git] / sks-keyservers.net / status-srv / sks.inc.php
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
11   *  
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.
16   *
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.
21   *
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/>.
24   */
25   error_reporting(E_ALL);
26   
27   date_default_timezone_set("UTC");
28   function event_serverreturn($fd, $flag, $arg)
29   {
30     $serverobj = $arg[2];    
31       if($fd !== false)
32      {
33          $json = "";
34         
35              while(($buf = fgets($fd, 1024)) !== false)
36              {
37                  $json .= $buf; 
38              }
39              
40              if (!feof($fd)) 
41              {
42                 echo "Error: popen never ended\n";
43             }
44             
45             $sadd = new sks_peer($serverobj, null, $json);
46              $serverobj->add_server($sadd);
47             
48             pclose($fd);
49         }
50         
51         unset($serverobj->fh[$sadd->get_hostname()]);
52         event_free($arg[0]); 
53   } 
54     
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
60
61         $dns = gethostbynamel6($host, $try_a);
62         if ($dns == false) { return false; }
63         else { return $dns[0]; }
64     }
65
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
71
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);
76         }
77         else { $dns = $dns6; }
78         $ip6 = array();
79         $ip4 = array();
80         foreach ($dns as $record) {
81             if ($record["type"] == "A") {
82                 $ip4[] = $record["ip"];
83             }
84             if ($record["type"] == "AAAA") {
85                 $ip6[] = $record["ipv6"];
86             }
87         }
88         if (count($ip6) < 1) {
89             if ($try_a == true) {
90                 if (count($ip4) < 1) {
91                     return false;
92                 }
93                 else {
94                     return $ip4;
95                 }
96             }
97             else {
98                 return false;
99             }
100         }
101         else {
102             return $ip6;
103         }
104     }
105  
106  class sks_servercollection
107  {
108   private $servers = array();
109   private $servers_queue = array();
110   public $created;
111   private $events = array(); 
112   public $event_base; 
113   public $fh = array(); 
114   
115   public function sks_servercollection()
116   {
117    $this->created = time();
118    $this->event_base = event_base_new(); 
119   }
120   
121   // Queue handling
122   
123   public function add_server_to_queue($server)
124   {
125    if($this->do_add($server) && !isset($this->events[$server]))
126    {
127            $this->servers_queue[$server] = true; 
128                
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], 50000);
134        }
135   }
136   
137   public function get_queue_count()
138   {
139       return count($this->fh);
140   }
141      
142   public function add_server($obj)
143   {
144    if($obj != null && $obj->get_hostname() != "")
145    {     
146        if(!isset($this->servers[$obj->get_hostname()]))
147            $this->servers[$obj->get_hostname()] = $obj;
148    }
149   }
150   
151   public function get_servers()
152   {
153    return $this->servers;
154   }
155   
156   public function include_ipv6()
157   {
158       $should_include_ipv6 = true;
159     $count_ipv6 = 0; 
160     $kfwebs_included = false; 
161           
162     foreach($this->servers as $server)
163     {
164         if($server->get_ipv6())
165             $count_ipv6++; 
166         
167         if($server->get_hostname() == "keys.kfwebs.net")
168             $kfwebs_included = true; 
169     }
170     
171     if($kfwebs_included && $count_ipv6 == 1)
172         return false; 
173     else
174         return true; 
175   }
176   
177   public function get_server_by_name($name)
178   {
179       foreach($this->servers as $id=>$server)
180       {
181           if($server->get_hostname() == $name || $server->get_called_hostname() == $name)
182               return $this->servers[$id];
183       }
184       return false; 
185   }
186   
187   public function get_time()
188   {
189    return $this->created;
190   }
191   
192   public function do_add($n)
193   {
194    if(isset($this->servers[$n]) || isset($this->servers_queue[$n])) 
195            return false;
196    else 
197            return true;
198   }
199  }
200  
201  class sks_peer
202  {
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 = "";
225   
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", " " => ""));
232   }
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;}
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)
252   {
253       /*
254        * Convert version string into array with
255        * (major, minor, release)
256        */
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);
263        
264        // Check major
265        if((int)($version_tuple[0]) > (int)($min_version_tuple[0]))
266            return true; 
267        
268        // Check minor
269        if(
270            ((int)($version_tuple[0]) == (int)($min_version_tuple[0])) 
271            && ((int)($version_tuple[1]) > (int)($min_version_tuple[1]))
272            )
273            return true; 
274        
275        // Check release
276        if(
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)
281            )
282            return true;
283        
284        // If not true by now, return false
285            return false; 
286   }
287   
288   public function sks_get_peer_data()
289   {
290       // Open handle
291    $fp = popen("/usr/bin/php -f /webs/sks-keyservers.net/status/sks_get_peer_data.php {$this->hostname}", "r");
292    
293    // Read back handle
294    $fp_rb = "";
295    
296    while(($buf = fgets($fp, 1024)) !== false)
297    {
298          $fp_rb .= $buf; 
299    } 
300    
301    pclose($fp);
302    return $fp_rb;
303   }
304   
305   public function sks_peer(&$servers, $hostname=false, $jinp=false)
306   {
307    if($jinp===false)
308    {
309        $this->hostname = $hostname; 
310        $jinp = $this->sks_get_peer_data(); 
311    }
312      
313    // Convert back from json
314    $fp_rb_dec = json_decode($jinp, true);
315    
316    $this->hostname = strtolower($fp_rb_dec['hostname']);
317    $this->called_hostname = strtolower($fp_rb_dec['called_hostname']);
318    
319    $this->port = $fp_rb_dec['port'];
320    
321    $this->statusok = $fp_rb_dec['statusok'];
322    if($this->statusok)
323    {
324      $this->responsetime = $fp_rb_dec['responsetime'];
325      $this->http_response_server = $fp_rb_dec['http_response_server'];
326      $this->http_response_via = $fp_rb_dec['http_response_via'];
327      $this->numkeys = $fp_rb_dec['numkeys'];
328      $this->software = $fp_rb_dec['software'];
329      $this->version = $fp_rb_dec['version'];
330      $this->server_contact = $fp_rb_dec['server_contact'];
331
332      if(isset($fp_rb_dec['recon_port']))
333              $this->recon_port = $fp_rb_dec['recon_port'];
334
335      $this->http_post_expect_error = $fp_rb_dec['postExpect'];     
336     
337      if(isset($fp_rb_dec['peers']) && is_array($fp_rb_dec['peers']))
338         $this->peers = $fp_rb_dec['peers'];
339      else
340         $this->peers = array(); 
341     
342      $this->statusipv6ok = $fp_rb_dec['statusipv6ok'];
343      $this->port80 = $fp_rb_dec['port80'];
344      $this->has_hkps = $fp_rb_dec['has_hkps'];
345      $this->hkps_port = $fp_rb_dec['hkps_port'];
346      $this->tor_addresse = $fp_rb_dec['tor_addresse'];
347      $this->affected_cve2014_3207 = $fp_rb_dec['cve-2014-3207'];
348    }
349    
350    if(is_array($this->peers) && count($this->peers) > 0)
351    {
352            foreach($this->peers as $peer)
353            {
354                $servers->add_server_to_queue($peer);    
355            }
356    }
357        
358    } // End function sks_peer
359
360    private function is_loadbalanced()
361    {
362         $loadbalanced = array(
363                 "keys2.kfwebs.net",
364                 "sks.undergrid.net",
365                 "sks.fidocon.de", 
366                 "keyserver.searchy.nl",
367                 "keyserver.codinginfinity.com",
368                 "pgp.key-server.io",
369                 "sks.mj2.uk"
370                 ); 
371         return $this->is_accepted_server_response() && in_array($this->hostname, $loadbalanced); 
372    }
373    
374    private function is_accepted_server_response()
375    {
376     $is_accepted_server = false;
377     
378     // Check if Server: header contain a valid response
379     $accepted_http_server_list = array("nginx", "apache");
380     foreach($accepted_http_server_list as $revprox)
381     {
382           if(strstr(strtolower($this->http_response_server), $revprox) !== false) 
383               $is_accepted_server = true; 
384       }
385     
386     // Check if Via: header is set, presume proxy if it is
387     if($this->http_response_via)
388         $is_accepted_server = true; 
389         
390       return     $is_accepted_server;    
391    } // end is_accepted_server_response
392   
393  } // End class
394  
395  class sks_stats
396  {
397   public function sks_stats()
398   {
399    $servers = new sks_servercollection;
400    
401    $initial_servers = array("keys2.kfwebs.net", "zimmermann.mayfirst.org", "keyserver.ubuntu.com", "sks.undergrid.net", "sks.b4ckbone.de");
402
403          foreach($initial_servers as $s)
404    {
405       $sadd = new sks_peer($servers, $s);
406       $servers->add_server($sadd);
407    }
408    
409    echo "Done adding primaries\n";
410    event_base_loop($servers->event_base);
411    
412    echo "Done looping\n";
413    echo ""; 
414    
415    if(!file_exists(dirname(__FILE__)."/sks_cache_status_collection.serialized"))
416            $status_collection = new sks_status_collection();
417    else
418            $status_collection = unserialize(file_get_contents(dirname(__FILE__)."/sks_cache_status_collection.serialized"));
419            
420    $status_collection->run($servers);
421    $nk = $status_collection->get_statistics_data(); 
422    echo "Numkey set to:\t".$nk['numkeys']; 
423    
424    file_put_contents(dirname(__FILE__)."/sks_cache.serialized",serialize($servers));
425    file_put_contents(dirname(__FILE__)."/sks_cache_status_collection.serialized",serialize($status_collection));
426   }
427  }
428 ?>