addrutil: Re-indent.
[wk-misc.git] / hkpstats.c
1 /* hkpstats.c - Report stats about an HPK keyserver pool
2  *      Copyright (C) 2009 Werner Koch
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 3 of the
7  * License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, see <http://www.gnu.org/licenses/>.
16  */
17
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <stddef.h>
22 #include <string.h>
23 #include <errno.h>
24 #include <stdarg.h>
25 #include <assert.h>
26 #include <sys/socket.h>
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
29 #include <adns.h>
30
31
32 #define PGM           "hkpstats"
33 #define PGM_VERSION   "0.0"
34 #define PGM_BUGREPORT "wk@gnupg.org"
35
36 /* Option flags. */
37 static int verbose;
38 static int debug;
39
40 /* Error counter.  */
41 static int any_error;
42
43 /* An object to keep track of each host. */
44 struct host_s
45 {
46   struct host_s *next;
47
48   const char *poolname;  /* Original poolname (e.g. "keys.gnupg.net") */
49   struct in_addr addr;   /* Its IP address.  */
50   char *addr_str;        /* Ditto but in human readabale format.  */
51
52   struct {
53     adns_query query;    /* Active query.  */
54   } help;
55 };
56 typedef struct host_s *host_t;
57
58
59
60 /* Print diagnostic message and exit with failure. */
61 static void
62 die (const char *format, ...)
63 {
64   va_list arg_ptr;
65
66   fflush (stdout);
67   fprintf (stderr, "%s: ", PGM);
68
69   va_start (arg_ptr, format);
70   vfprintf (stderr, format, arg_ptr);
71   va_end (arg_ptr);
72   putc ('\n', stderr);
73
74   exit (1);
75 }
76
77
78 /* Print diagnostic message. */
79 static void
80 err (const char *format, ...)
81 {
82   va_list arg_ptr;
83
84   any_error = 1;
85
86   fflush (stdout);
87   fprintf (stderr, "%s: ", PGM);
88
89   va_start (arg_ptr, format);
90   vfprintf (stderr, format, arg_ptr);
91   va_end (arg_ptr);
92   putc ('\n', stderr);
93 }
94
95 /* Print a info message message. */
96 static void
97 inf (const char *format, ...)
98 {
99   va_list arg_ptr;
100
101   if (verbose)
102     {
103       fprintf (stderr, "%s: ", PGM);
104       
105       va_start (arg_ptr, format);
106       vfprintf (stderr, format, arg_ptr);
107       va_end (arg_ptr);
108       putc ('\n', stderr);
109     }
110 }
111
112
113
114 static void
115 process_one_pool (adns_state adns_ctx, const char *poolname)
116 {
117   adns_answer *answer = NULL;
118   int rridx;
119   host_t host;
120   host_t hostlist = NULL;
121   in rc;
122
123   inf ("collecting data for `%s'", poolname);
124   
125   if (adns_synchronous (adns_ctx, poolname,
126                         adns_r_a, adns_qf_quoteok_query,
127                         &answer) )
128     {
129       err ("DNS query for `%s' failed: %s", poolname, strerror (errno));
130       return;
131     }
132
133   if (answer->status != adns_s_ok) 
134     {
135       err ("DNS query for `%s' failed: %s (%s)", poolname, 
136            adns_strerror (answer->status),
137            adns_errabbrev (answer->status)); 
138       free (answer); 
139       return;
140     }
141   assert (answer->type == adns_r_a);
142
143   for (rridx=0; rridx < answer->nrrs; rridx++)
144     {
145       struct sockaddr_in sockaddr;
146       struct in_addr addr = answer->rrs.inaddr[rridx];
147       const char *s;
148
149       host = calloc (1, sizeof *host);
150       if (!host)
151         die ("out of core: %s", strerror (errno));
152       host->poolname = poolname;
153       host->addr = addr;
154       s = inet_ntoa (addr);
155       host->addr_str = strdup (s?s:"[none]");
156       if (!host->addr_str)
157         die ("out of core: %s", strerror (errno));
158         
159       inf ("IP=%s", host->addr_str);
160
161       memset (&sockaddr, 0,sizeof sockaddr);
162       sockaddr.sin_family = AF_INET; 
163       memcpy (&sockaddr.sin_addr, &addr, sizeof addr);
164       if (adns_submit_reverse (adns_ctx, (struct sockaddr *)&sockaddr,
165                                adns_r_ptr, 
166                                adns_qf_quoteok_cname | adns_qf_cname_loose,
167                                host, &host->help.query))
168         {
169           err ("DNS reverse lookup of `%s', %s failed: %s (%s)",
170                poolname, host->addr_str,
171                adns_strerror (answer->status),
172                adns_errabbrev (answer->status)); 
173           /*fixme: release_host (host);*/
174         }
175       else
176         {
177           host->next = hostlist;
178           hostlist = host;
179         }
180     }
181   free (answer);
182
183   if (!hostlist)
184     return;
185     
186   /* Wait until all hosts are resolved. */
187   for (;;)
188     {
189       adns_query query = NULL;  
190
191       rc = adns_check(adns_ctx, &query, &answer, &host);
192       if (!rc)
193         {
194
195
196         }
197       else if (err == EAGAIN) break;
198       if (err) {
199         fprintf(stderr, "%s: adns_wait/check: %s", progname, strerror(err));
200         exit(1);
201       }
202
203
204       for (host = hostlist; host; host = host->next)
205     {
206       if (!host->help.query)
207         continue;
208     }
209 }
210
211
212 static int
213 show_usage (int ex)
214 {
215   fputs ("Usage: " PGM " {pool}\n"
216          "Generate a report for all keyservers in the POOLs.\n\n"
217          "  --verbose      enable extra informational output\n"
218          "  --debug        enable additional debug output\n"
219          "  --help         display this help and exit\n\n"
220          "Example:  \"" PGM " keys.gnupg.net http-keys.gnupg.net\"\n\n"
221          "Report bugs to " PGM_BUGREPORT ".\n",
222          ex? stderr:stdout);
223   exit (ex);
224 }
225
226
227 int 
228 main (int argc, char **argv)
229 {
230   int last_argc = -1;
231   adns_state adns_ctx = NULL;
232
233   if (argc)
234     {
235       argc--; argv++;
236     }
237   while (argc && last_argc != argc )
238     {
239       last_argc = argc;
240       if (!strcmp (*argv, "--"))
241         {
242           argc--; argv++;
243           break;
244         }
245       else if (!strcmp (*argv, "--version"))
246         {
247           fputs (PGM " " PGM_VERSION "\n", stdout);
248           exit (0);
249         }
250       else if (!strcmp (*argv, "--help"))
251         {
252           show_usage (0);
253         }
254       else if (!strcmp (*argv, "--verbose"))
255         {
256           verbose = 1;
257           argc--; argv++;
258         }
259       else if (!strcmp (*argv, "--debug"))
260         {
261           verbose = debug = 1;
262           argc--; argv++;
263         }
264       else if (!strncmp (*argv, "--", 2))
265         show_usage (1);
266     }          
267
268   if (argc < 1)
269     show_usage (1);
270
271   if (adns_init (&adns_ctx, adns_if_none, stderr))
272     die ("error initializing ADNS: %s", strerror (errno));
273
274   /* Note: Firther own we keep shallow copies of argv; thus don't
275      modify them. */
276   for (; argc; argc--, argv++)
277     process_one_pool (adns_ctx, *argv);
278   
279   adns_finish (adns_ctx);
280
281
282   return any_error? 1:0;
283 }
284
285
286 /*
287 Local Variables:
288 compile-command: "gcc -Wall -W -O2 -g -o hkpstats -ladns hkpstats.c"
289 End:
290 */