chiark / gitweb /
New internal consistency checking with assert if right options set.
[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 <string.h>
35 #include <stdlib.h>
36 #include <stdio.h>
37 #include <ctype.h>
38 #include <errno.h>
39
40 #include "adns.h"
41
42 /* maximum number of concurrent DNS queries */
43 #define MAXPENDING 1000
44
45 /* maximum length of a line */
46 #define MAXLINE 1024
47
48 static const char *progname;
49
50 static void aargh(const char *msg) {
51   fprintf(stderr, "%s: %s: %s (%d)\n", progname, msg,
52           strerror(errno) ? strerror(errno) : "Unknown error", errno);
53   exit(1);
54 }
55
56 /*
57  * Parse the IP address and convert to a reverse domain name.
58  */
59 static void ipaddr2domain(char *start, char **addr, char **rest, char **domain) {
60   static char buf[30]; /* "123.123.123.123.in-addr.arpa.\0" */
61   char *ptrs[5];
62   int i;
63
64   for (ptrs[0]= start; !isdigit(*ptrs[0]); ptrs[0]++)
65     if (!*ptrs[0])
66       goto invalid;
67   for (i= 1; i < 5; i ++) {
68     ptrs[i]= strchr(ptrs[i-1], (i == 4) ? ' ' : '.');
69     if (!ptrs[i] || ptrs[i]-ptrs[i-1] > 3)
70       goto invalid;
71     else
72       ptrs[i]++;
73   }
74   sprintf(buf, "%.*s.%.*s.%.*s.%.*s.in-addr.arpa.",
75           ptrs[4]-ptrs[3]-1, ptrs[3],
76           ptrs[3]-ptrs[2]-1, ptrs[2],
77           ptrs[2]-ptrs[1]-1, ptrs[1],
78           ptrs[1]-ptrs[0]-1, ptrs[0]);
79   *addr= ptrs[0];
80   *rest= ptrs[4]-1;
81   *domain= buf;
82   return;
83 invalid:
84   strcpy(buf, "invalid.");
85   *addr= *rest= NULL;
86   *domain= buf;
87   return;
88 }
89
90 static void printline(char *start, char *addr, char *rest, char *domain) {
91   if (domain)
92     printf("%.*s%s%s", addr - start, start, domain, rest);
93   else
94     fputs(start, stdout);
95   if (ferror(stdout)) aargh("write output");
96 }
97
98 typedef struct logline {
99   struct logline *next;
100   char *start, *addr, *rest;
101   adns_query query;
102 } logline;
103
104 static logline *readline(adns_state adns) {
105   static char buf[MAXLINE];
106   char *str;
107   logline *line;
108
109   if (fgets(buf, MAXLINE, stdin)) {
110     str= malloc(sizeof(*line) + strlen(buf) + 1);
111     if (!str) aargh("malloc");
112     line= (logline*)str;
113     line->next= NULL;
114     line->start= str+sizeof(logline);
115     strcpy(line->start, buf);
116     ipaddr2domain(line->start, &line->addr, &line->rest, &str);
117     if (adns_submit(adns, str, adns_r_ptr,
118                     adns_qf_quoteok_cname|adns_qf_cname_loose,
119                     NULL, &line->query))
120       aargh("adns_submit");
121     return line;
122   }
123   if (!feof(stdin))
124     aargh("fgets");
125   return NULL;
126 }
127         
128 static void proclog(void) {
129   int eof, err, len;
130   adns_state adns;
131   adns_answer *answer;
132   logline *head, *tail, *line;
133
134   errno= adns_init(&adns, 0, 0);
135   if (errno) aargh("adns_init");
136   head= tail= readline(adns);
137   len= 1; eof= 0;
138   while (head) {
139     if (eof || len > MAXPENDING)
140       err= adns_wait(adns, &head->query, &answer, NULL);
141     else
142       err= adns_check(adns, &head->query, &answer, NULL);
143     if (err != EWOULDBLOCK) {
144         printline(head->start, head->addr, head->rest,
145                   answer->status == adns_s_ok ? *answer->rrs.str : NULL);
146         line= head; head= head->next;
147         free(line); free(answer);
148         len--;
149     }
150     if (!eof) {
151       line= readline(adns);
152       if (!line)
153         eof= 1;
154       else {
155         if (!head)
156           head = line;
157         else
158           tail->next = line;
159         tail = line;
160         len++;
161       }
162     }
163   }
164   adns_finish(adns);
165 }
166
167 int main(int argc, char *argv[]) {
168   progname= *argv;
169   proclog();
170   if (fclose(stdout)) aargh("finish writing output");
171   return 0;
172 }