chiark / gitweb /
bf17ccac1599e449eeb55a3674440e9dfcf71a28
[adns.git] / client / adnslogres.c
1 /*
2  * adnslogres.c
3  * - a replacement for the Apache logresolve program using adns
4  */
5 /*
6  *  This file is
7  *   Copyright (C) 1999 Tony Finch <fanf@demon.net> <dot@dotat.at>
8  *   Copyright (C) 1999 Ian Jackson <ian@davenant.greenend.org.uk>
9  *  
10  *  This program is free software; you can redistribute it and/or modify
11  *  it under the terms of the GNU General Public License as published by
12  *  the Free Software Foundation; either version 2, or (at your option)
13  *  any later version.
14  *  
15  *  This program is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *  GNU General Public License for more details.
19  *  
20  *  You should have received a copy of the GNU General Public License
21  *  along with this program; if not, write to the Free Software Foundation,
22  *  Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23  *
24  * This version was originally supplied by Tony Finch, but has been
25  * modified by Ian Jackson as it was incorporated into adns.
26  */
27
28 static const char * const cvsid =
29         "$Id$";
30
31 #include <sys/types.h>
32 #include <sys/time.h>
33
34 #include <unistd.h>
35 #include <string.h>
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <ctype.h>
39 #include <errno.h>
40
41 #include "adns.h"
42
43 /* maximum number of concurrent DNS queries */
44 #define MAXPENDING 1000
45
46 /* maximum length of a line */
47 #define MAXLINE 1024
48
49 /* option flags */
50 #define OPT_DEBUG 1
51 #define OPT_POLL 2
52
53 static const char *progname;
54
55 static void aargh(const char *msg) {
56   fprintf(stderr, "%s: %s: %s (%d)\n", progname, msg,
57           strerror(errno) ? strerror(errno) : "Unknown error", errno);
58   exit(1);
59 }
60
61 /*
62  * Parse the IP address and convert to a reverse domain name.
63  */
64 static char *ipaddr2domain(char *start, char **addr, char **rest) {
65   static char buf[30]; /* "123.123.123.123.in-addr.arpa.\0" */
66   char *ptrs[5];
67   int i;
68
69   ptrs[0]= start;
70 retry:
71   while (!isdigit(*ptrs[0]))
72     if (!*ptrs[0]++) {
73       strcpy(buf, "invalid.");
74       *addr= *rest= NULL;
75       return buf;
76     }
77   for (i= 1; i < 5; i ++) {
78     ptrs[i]= strchr(ptrs[i-1], (i == 4) ? ' ' : '.');
79     if (!ptrs[i] || ptrs[i]-ptrs[i-1] > 3) {
80       ptrs[0]++;
81       goto retry;
82     } else
83       ptrs[i]++;
84   }
85   sprintf(buf, "%.*s.%.*s.%.*s.%.*s.in-addr.arpa.",
86           ptrs[4]-ptrs[3]-1, ptrs[3],
87           ptrs[3]-ptrs[2]-1, ptrs[2],
88           ptrs[2]-ptrs[1]-1, ptrs[1],
89           ptrs[1]-ptrs[0]-1, ptrs[0]);
90   *addr= ptrs[0];
91   *rest= ptrs[4]-1;
92   return buf;
93 }
94
95 static void printline(char *start, char *addr, char *rest, char *domain) {
96   if (domain)
97     printf("%.*s%s%s", addr - start, start, domain, rest);
98   else
99     fputs(start, stdout);
100   if (ferror(stdout)) aargh("write output");
101 }
102
103 typedef struct logline {
104   struct logline *next;
105   char *start, *addr, *rest;
106   adns_query query;
107 } logline;
108
109 static logline *readline(adns_state adns, int opts) {
110   static char buf[MAXLINE];
111   char *str;
112   logline *line;
113
114   if (fgets(buf, MAXLINE, stdin)) {
115     str= malloc(sizeof(*line) + strlen(buf) + 1);
116     if (!str) aargh("malloc");
117     line= (logline*)str;
118     line->next= NULL;
119     line->start= str+sizeof(logline);
120     strcpy(line->start, buf);
121     str = ipaddr2domain(line->start, &line->addr, &line->rest);
122     if (opts & OPT_DEBUG)
123         fprintf(stderr, "%s: adns_submit %s\n", progname, str);
124     if (adns_submit(adns, str, adns_r_ptr,
125                     adns_qf_quoteok_cname|adns_qf_cname_loose,
126                     NULL, &line->query))
127       aargh("adns_submit");
128     return line;
129   }
130   if (!feof(stdin))
131     aargh("fgets");
132   return NULL;
133 }
134         
135 static void proclog(int opts) {
136   int eof, err, len;
137   adns_state adns;
138   adns_answer *answer;
139   logline *head, *tail, *line;
140
141   errno= adns_init(&adns, (opts & OPT_DEBUG) ? adns_if_debug : 0, 0);
142   if (errno) aargh("adns_init");
143   head= tail= readline(adns, opts);
144   len= 1; eof= 0;
145   while (head) {
146     if (eof || len > MAXPENDING)
147       if (opts & OPT_POLL)
148         err= adns_wait_poll(adns, &head->query, &answer, NULL);
149       else
150         err= adns_wait(adns, &head->query, &answer, NULL);
151     else
152       err= adns_check(adns, &head->query, &answer, NULL);
153     if (err != EWOULDBLOCK) {
154         printline(head->start, head->addr, head->rest,
155                   answer->status == adns_s_ok ? *answer->rrs.str : NULL);
156         line= head; head= head->next;
157         free(line); free(answer);
158         len--;
159     }
160     if (!eof) {
161       line= readline(adns, opts);
162       if (!line)
163         eof= 1;
164       else {
165         if (!head)
166           head = line;
167         else
168           tail->next = line;
169         tail = line;
170         len++;
171       }
172     }
173   }
174   adns_finish(adns);
175 }
176
177 int main(int argc, char *argv[]) {
178   int c, opts;
179
180   progname= *argv;
181   opts= 0;
182
183   while ((c= getopt(argc, argv, "dp")) != -1) {
184     switch (c) {
185     case 'd':
186       opts |= OPT_DEBUG;
187       break;
188     case 'p':
189       opts |= OPT_POLL;
190       break;
191     default:
192       fprintf(stderr, "usage: %s [-d] < logfile\n", progname);
193       exit(1);
194     }
195     argc-= optind;
196     argv+= optind;
197   }
198
199   proclog(opts);
200
201   if (fclose(stdout)) aargh("finish writing output");
202   return 0;
203 }