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