98db6da3 |
1 | /* |
2 | * setup.c |
3 | * - configuration file parsing |
4 | * - management of global state |
5 | */ |
6 | /* |
7 | * This file is part of adns, which is Copyright (C) 1997, 1998 Ian Jackson |
8 | * |
9 | * This program is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU General Public License as published by |
11 | * the Free Software Foundation; either version 2, or (at your option) |
12 | * any later version. |
13 | * |
14 | * This program is distributed in the hope that it will be useful, |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 | * GNU General Public License for more details. |
18 | * |
19 | * You should have received a copy of the GNU General Public License |
20 | * along with this program; if not, write to the Free Software Foundation, |
21 | * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
22 | */ |
6f17710a |
23 | |
d05cc330 |
24 | #include <stdlib.h> |
25 | #include <errno.h> |
26 | #include <string.h> |
27 | #include <unistd.h> |
28 | #include <fcntl.h> |
6f17710a |
29 | |
d05cc330 |
30 | #include <netdb.h> |
31 | #include <arpa/inet.h> |
32 | |
33 | #include "internal.h" |
34 | |
6f17710a |
35 | static void addserver(adns_state ads, struct in_addr addr) { |
36 | int i; |
37 | struct server *ss; |
38 | |
39 | for (i=0; i<ads->nservers; i++) { |
40 | if (ads->servers[i].addr.s_addr == addr.s_addr) { |
11c8bf9b |
41 | adns__debug(ads,-1,0,"duplicate nameserver %s ignored",inet_ntoa(addr)); |
6f17710a |
42 | return; |
43 | } |
44 | } |
45 | |
46 | if (ads->nservers>=MAXSERVERS) { |
11c8bf9b |
47 | adns__diag(ads,-1,0,"too many nameservers, ignoring %s",inet_ntoa(addr)); |
6f17710a |
48 | return; |
49 | } |
50 | |
51 | ss= ads->servers+ads->nservers; |
52 | ss->addr= addr; |
6f17710a |
53 | ads->nservers++; |
54 | } |
55 | |
56 | static void configparseerr(adns_state ads, const char *fn, int lno, |
57 | const char *fmt, ...) { |
58 | va_list al; |
59 | |
60 | if (ads->iflags & adns_if_noerrprint) return; |
61 | if (lno==-1) fprintf(stderr,"adns: %s: ",fn); |
62 | else fprintf(stderr,"adns: %s:%d: ",fn,lno); |
63 | va_start(al,fmt); |
64 | vfprintf(stderr,fmt,al); |
65 | va_end(al); |
66 | fputc('\n',stderr); |
67 | } |
68 | |
69 | static void ccf_nameserver(adns_state ads, const char *fn, int lno, const char *buf) { |
70 | struct in_addr ia; |
71 | |
72 | if (!inet_aton(buf,&ia)) { |
73 | configparseerr(ads,fn,lno,"invalid nameserver address `%s'",buf); |
74 | return; |
75 | } |
11c8bf9b |
76 | adns__debug(ads,-1,0,"using nameserver %s",inet_ntoa(ia)); |
6f17710a |
77 | addserver(ads,ia); |
78 | } |
79 | |
80 | static void ccf_search(adns_state ads, const char *fn, int lno, const char *buf) { |
81 | if (!buf) return; |
11c8bf9b |
82 | adns__diag(ads,-1,0,"warning - `search' ignored fixme"); |
6f17710a |
83 | } |
84 | |
85 | static void ccf_sortlist(adns_state ads, const char *fn, int lno, const char *buf) { |
11c8bf9b |
86 | adns__diag(ads,-1,0,"warning - `sortlist' ignored fixme"); |
6f17710a |
87 | } |
88 | |
89 | static void ccf_options(adns_state ads, const char *fn, int lno, const char *buf) { |
90 | if (!buf) return; |
11c8bf9b |
91 | adns__diag(ads,-1,0,"warning - `options' ignored fixme"); |
6f17710a |
92 | } |
93 | |
94 | static void ccf_clearnss(adns_state ads, const char *fn, int lno, const char *buf) { |
95 | ads->nservers= 0; |
96 | } |
97 | |
98 | static const struct configcommandinfo { |
99 | const char *name; |
100 | void (*fn)(adns_state ads, const char *fn, int lno, const char *buf); |
101 | } configcommandinfos[]= { |
102 | { "nameserver", ccf_nameserver }, |
103 | { "domain", ccf_search }, |
104 | { "search", ccf_search }, |
105 | { "sortlist", ccf_sortlist }, |
106 | { "options", ccf_options }, |
107 | { "clearnameservers", ccf_clearnss }, |
108 | { 0 } |
109 | }; |
110 | |
6f17710a |
111 | static void readconfig(adns_state ads, const char *filename) { |
112 | char linebuf[2000], *p, *q; |
113 | FILE *file; |
114 | int lno, l, c; |
115 | const struct configcommandinfo *ccip; |
116 | |
117 | file= fopen(filename,"r"); |
118 | if (!file) { |
119 | if (errno == ENOENT) { |
11c8bf9b |
120 | adns__debug(ads,-1,0,"configuration file `%s' does not exist",filename); |
6f17710a |
121 | return; |
122 | } |
11c8bf9b |
123 | adns__diag(ads,-1,0,"cannot open configuration file `%s': %s", |
d05cc330 |
124 | filename,strerror(errno)); |
6f17710a |
125 | return; |
126 | } |
127 | |
128 | for (lno=1; fgets(linebuf,sizeof(linebuf),file); lno++) { |
129 | l= strlen(linebuf); |
130 | if (!l) continue; |
131 | if (linebuf[l-1] != '\n' && !feof(file)) { |
11c8bf9b |
132 | adns__diag(ads,-1,0,"%s:%d: line too long",filename,lno); |
6f17710a |
133 | while ((c= getc(file)) != EOF && c != '\n') { } |
134 | if (c == EOF) break; |
135 | continue; |
136 | } |
137 | while (l>0 && ctype_whitespace(linebuf[l-1])) l--; |
138 | linebuf[l]= 0; |
139 | p= linebuf; |
140 | while (ctype_whitespace(*p)) p++; |
141 | if (*p == '#' || *p == '\n') continue; |
142 | q= p; |
143 | while (*q && !ctype_whitespace(*q)) q++; |
144 | for (ccip=configcommandinfos; |
145 | ccip->name && strncmp(ccip->name,p,q-p); |
146 | ccip++); |
147 | if (!ccip->name) { |
11c8bf9b |
148 | adns__diag(ads,-1,0,"%s:%d: unknown configuration directive `%.*s'", |
d05cc330 |
149 | filename,lno,q-p,p); |
6f17710a |
150 | continue; |
151 | } |
152 | while (ctype_whitespace(*q)) q++; |
153 | ccip->fn(ads,filename,lno,q); |
154 | } |
155 | if (ferror(file)) { |
11c8bf9b |
156 | adns__diag(ads,-1,0,"%s:%d: read error: %s",filename,lno,strerror(errno)); |
6f17710a |
157 | } |
158 | fclose(file); |
159 | } |
160 | |
161 | static const char *instrum_getenv(adns_state ads, const char *envvar) { |
162 | const char *value; |
163 | |
164 | value= getenv(envvar); |
11c8bf9b |
165 | if (!value) adns__debug(ads,-1,0,"environment variable %s not set",envvar); |
166 | else adns__debug(ads,-1,0,"environment variable %s set to `%s'",envvar,value); |
6f17710a |
167 | return value; |
168 | } |
169 | |
170 | static void readconfigenv(adns_state ads, const char *envvar) { |
171 | const char *filename; |
172 | |
173 | if (ads->iflags & adns_if_noenv) { |
11c8bf9b |
174 | adns__debug(ads,-1,0,"not checking environment variable `%s'",envvar); |
6f17710a |
175 | return; |
176 | } |
177 | filename= instrum_getenv(ads,envvar); |
178 | if (filename) readconfig(ads,filename); |
179 | } |
d05cc330 |
180 | |
181 | |
182 | int adns__setnonblock(adns_state ads, int fd) { |
183 | int r; |
6f17710a |
184 | |
d05cc330 |
185 | r= fcntl(fd,F_GETFL,0); if (r<0) return errno; |
186 | r |= O_NONBLOCK; |
187 | r= fcntl(fd,F_SETFL,r); if (r<0) return errno; |
188 | return 0; |
189 | } |
190 | |
191 | int adns_init(adns_state *ads_r, adns_initflags flags, FILE *diagfile) { |
6f17710a |
192 | adns_state ads; |
193 | const char *res_options, *adns_res_options; |
194 | struct protoent *proto; |
195 | int r; |
196 | |
197 | ads= malloc(sizeof(*ads)); if (!ads) return errno; |
6f17710a |
198 | ads->iflags= flags; |
d05cc330 |
199 | ads->diagfile= diagfile ? diagfile : stderr; |
200 | LIST_INIT(ads->timew); |
201 | LIST_INIT(ads->childw); |
202 | LIST_INIT(ads->output); |
203 | ads->nextid= 0x311f; |
204 | ads->udpsocket= ads->tcpsocket= -1; |
d05cc330 |
205 | adns__vbuf_init(&ads->tcpsend); |
206 | adns__vbuf_init(&ads->tcprecv); |
207 | ads->nservers= ads->tcpserver= 0; |
208 | ads->tcpstate= server_disconnected; |
209 | timerclear(&ads->tcptimeout); |
6f17710a |
210 | |
211 | res_options= instrum_getenv(ads,"RES_OPTIONS"); |
212 | adns_res_options= instrum_getenv(ads,"ADNS_RES_OPTIONS"); |
213 | ccf_options(ads,"RES_OPTIONS",-1,res_options); |
214 | ccf_options(ads,"ADNS_RES_OPTIONS",-1,adns_res_options); |
215 | |
216 | readconfig(ads,"/etc/resolv.conf"); |
217 | readconfigenv(ads,"RES_CONF"); |
218 | readconfigenv(ads,"ADNS_RES_CONF"); |
219 | |
220 | ccf_options(ads,"RES_OPTIONS",-1,res_options); |
221 | ccf_options(ads,"ADNS_RES_OPTIONS",-1,adns_res_options); |
222 | |
223 | ccf_search(ads,"LOCALDOMAIN",-1,instrum_getenv(ads,"LOCALDOMAIN")); |
224 | ccf_search(ads,"ADNS_LOCALDOMAIN",-1,instrum_getenv(ads,"ADNS_LOCALDOMAIN")); |
225 | |
226 | if (!ads->nservers) { |
227 | struct in_addr ia; |
228 | if (ads->iflags & adns_if_debug) |
229 | fprintf(stderr,"adns: no nameservers, using localhost\n"); |
230 | ia.s_addr= INADDR_LOOPBACK; |
231 | addserver(ads,ia); |
232 | } |
233 | |
234 | proto= getprotobyname("udp"); if (!proto) { r= ENOPROTOOPT; goto x_free; } |
235 | ads->udpsocket= socket(AF_INET,SOCK_DGRAM,proto->p_proto); |
71324651 |
236 | if (ads->udpsocket<0) { r= errno; goto x_free; } |
48cb0b4b |
237 | |
de8b18da |
238 | r= adns__setnonblock(ads,ads->udpsocket); |
239 | if (r) { r= errno; goto x_closeudp; } |
6f17710a |
240 | |
241 | *ads_r= ads; |
242 | return 0; |
243 | |
de8b18da |
244 | x_closeudp: |
245 | close(ads->udpsocket); |
6f17710a |
246 | x_free: |
247 | free(ads); |
248 | return r; |
249 | } |
250 | |
251 | int adns_finish(adns_state ads) { |
de8b18da |
252 | abort(); /* fixme */ |
6f17710a |
253 | } |