1 /*
2 ** Copyright 1998 - 2011 Double Precision, Inc.
3 ** See COPYING for distribution information.
4 */
5 
6 #include	"config.h"
7 #include	"rfc1035.h"
8 #include	"spf.h"
9 #include	<sys/types.h>
10 #include	<stdio.h>
11 #include	<stdlib.h>
12 #include	<string.h>
13 #include	<errno.h>
14 #include	<arpa/inet.h>
15 
16 #include	"soxwrap/soxwrap.h"
17 
18 
setns(const char * p,struct rfc1035_res * res)19 static void setns(const char *p, struct rfc1035_res *res)
20 {
21 RFC1035_ADDR ia[4];
22 int	i=0;
23 char	*q=malloc(strlen(p)+1), *r;
24 
25 	strcpy(q, p);
26 	for (r=q; (r=strtok(r, ", ")) != 0; r=0)
27 		if (i < 4)
28 		{
29 			if (rfc1035_aton(r, &ia[i]) == 0)
30 			{
31 				++i;
32 			}
33 			else
34 			{
35 				fprintf(stderr, "%s: invalid IP address\n",
36 					r);
37 			}
38 		}
39 	free(q);
40 	rfc1035_init_ns(res, ia, i);
41 }
42 
43 extern char rfc1035_spf_gettxt(const char *current_domain,
44 			       char *buf);
45 extern char rfc1035_spf_gettxt_n(const char *current_domain,
46 			  char **buf);
47 
48 
spflookup(const char * current_domain)49 static void spflookup(const char *current_domain)
50 {
51 	char *buf;
52 
53 	switch (rfc1035_spf_gettxt_n(current_domain, &buf)) {
54 	case SPF_NONE:
55 		printf("none\n");
56 		return;
57 	case SPF_NEUTRAL:
58 		printf("neutral\n");
59 		return;
60 	case SPF_PASS:
61 		printf("pass: %s\n", buf);
62 		return;
63 	case SPF_FAIL:
64 		printf("fail\n");
65 		return;
66 	case SPF_SOFTFAIL:
67 		printf("softfail\n");
68 		return;
69 	case SPF_ERROR:
70 		printf("error\n");
71 		return;
72 	default:
73 		printf("unknown\n");
74 	}
75 }
76 
get_q_type_pass(const char * p,void (* cb)(unsigned char,void *),void * ptr)77 static int get_q_type_pass(const char *p,
78 			    void (*cb)(unsigned char, void *),
79 			    void *ptr)
80 {
81 	char qbuf[strlen(p)+1];
82 	char *q;
83 
84 	strcpy(qbuf, p);
85 
86 	for (q=qbuf; (q=strtok(q, ", \t\r\n")); q=0)
87 	{
88 		int n=rfc1035_type_strtoi(q);
89 
90 		if (n < 0)
91 			return -1;
92 
93 		(*cb)(n, ptr);
94 	}
95 
96 	return 0;
97 }
98 
get_q_type_count(unsigned char c,void * ptr)99 static void get_q_type_count(unsigned char c, void *ptr)
100 {
101 	++*(size_t *)ptr;
102 }
103 
get_q_type_save(unsigned char c,void * ptr)104 static void get_q_type_save(unsigned char c, void *ptr)
105 {
106 	*(*(unsigned char **)ptr)++=c;
107 }
108 
get_q_type(const char * p)109 static unsigned char *get_q_type(const char *p)
110 {
111 	size_t n=0;
112 	unsigned char *buf, *q;
113 
114 	errno=EINVAL;
115 	if (get_q_type_pass(p, &get_q_type_count, &n) < 0)
116 		return 0;
117 
118 	if ((buf=(unsigned char *)malloc(n+1)) == 0)
119 		return 0;
120 
121 	q=buf;
122 	get_q_type_pass(p, &get_q_type_save, &q);
123 
124 	*q=0;
125 
126 	return buf;
127 }
128 
main(int argc,char ** argv)129 int main(int argc, char **argv)
130 {
131 struct  rfc1035_res res;
132 struct	rfc1035_reply *replyp;
133 int	argn;
134 const char *q_name;
135 unsigned char *q_type;
136 int	q_class;
137 int	q_xflag=0;
138 int	q_rflag=0;
139 char	ptrbuf[RFC1035_MAXNAMESIZE+1];
140 
141 	rfc1035_init_resolv(&res);
142 
143 	argn=1;
144 	while (argn < argc)
145 	{
146 		if (argv[argn][0] == '@')
147 		{
148 			setns(argv[argn]+1, &res);
149 			++argn;
150 			continue;
151 		}
152 
153 		if (strcmp(argv[argn], "-x") == 0)
154 		{
155 			q_xflag=1;
156 			++argn;
157 			continue;
158 		}
159 		if (strcmp(argv[argn], "-r") == 0)
160 		{
161 			q_rflag=1;
162 			++argn;
163 			continue;
164 		}
165 
166 		if (strcmp(argv[argn], "-dnssec") == 0)
167 		{
168 			rfc1035_init_dnssec_enable(&res, 1);
169 			++argn;
170 			continue;
171 		}
172 
173 		if (strcmp(argv[argn], "-udpsize") == 0)
174 		{
175 			++argn;
176 
177 			if (argn < argc)
178 			{
179 				rfc1035_init_edns_payload(&res,
180 							  atoi(argv[argn]));
181 				++argn;
182 			}
183 			continue;
184 		}
185 
186 		break;
187 	}
188 
189 	if (argn >= argc)	exit(0);
190 
191 	q_name=argv[argn++];
192 
193 	if (q_xflag)
194 	{
195 	struct in_addr ia;
196 #if	RFC1035_IPV6
197 	struct in6_addr ia6;
198 
199 		if (inet_pton(AF_INET6, q_name, &ia6) > 0)
200 		{
201 		const char *sin6=(const char *)&ia6;
202 		unsigned i;
203 
204 			ptrbuf[0]=0;
205 
206 			for (i=sizeof(struct in6_addr); i; )
207 			{
208 			char    buf[10];
209 
210 				--i;
211 				sprintf(buf, "%x.%x.",
212 					(int)(unsigned char)(sin6[i] & 0x0F),
213 					(int)(unsigned char)((sin6[i] >> 4)
214 							& 0x0F));
215 				strcat(ptrbuf, buf);
216 			}
217 			strcat(ptrbuf, "ip6.arpa");
218 			q_name=ptrbuf;
219 		}
220 		else
221 #endif
222 		if ( rfc1035_aton_ipv4(q_name, &ia) == 0)
223 		{
224 		char buf[RFC1035_MAXNAMESIZE];
225 		unsigned char a=0,b=0,c=0,d=0;
226 		const char *p=buf;
227 
228 			rfc1035_ntoa_ipv4(&ia, buf);
229 
230 			while (*p >= '0' && *p <= '9')
231 				a= (int)a * 10 + (*p++ - '0');
232 			if (*p)	p++;
233 			while (*p >= '0' && *p <= '9')
234 				b= (int)b * 10 + (*p++ - '0');
235 			if (*p)	p++;
236 			while (*p >= '0' && *p <= '9')
237 				c= (int)c * 10 + (*p++ - '0');
238 			if (*p)	p++;
239 			while (*p >= '0' && *p <= '9')
240 				d= (int)d * 10 + (*p++ - '0');
241 
242 			sprintf(ptrbuf, "%d.%d.%d.%d.in-addr.arpa",
243 				(int)d, (int)c, (int)b, (int)a);
244 			q_name=ptrbuf;
245 		}
246 	}
247 
248 	if (q_rflag)
249 	{
250 	RFC1035_ADDR a;
251 	int	rc;
252 
253 		if (rfc1035_aton(q_name, &a) == 0)
254 		{
255 			rc=rfc1035_ptr(&res, &a,ptrbuf);
256 			if (rc == 0)
257 			{
258 				printf("%s\n", ptrbuf);
259 				exit(0);
260 			}
261 		}
262 		else
263 		{
264 		RFC1035_ADDR	*aptr;
265 		unsigned alen;
266 
267 			rc=rfc1035_a(&res, q_name, &aptr, &alen);
268 			if (rc == 0)
269 			{
270 			unsigned i;
271 
272 				for (i=0; i<alen; i++)
273 				{
274 					rfc1035_ntoa(&aptr[i], ptrbuf);
275 					printf("%s\n", ptrbuf);
276 				}
277 				exit(0);
278 			}
279 		}
280 		fprintf(stderr, "%s error.\n", errno == ENOENT ? "Hard":"Soft");
281 		exit(1);
282 	}
283 
284 	q_type=0;
285 
286 	if (argn < argc)
287 	{
288 		if (strcmp(argv[argn], "spf") == 0)
289 		{
290 			spflookup(q_name);
291 			exit(0);
292 		}
293 		q_type=get_q_type(argv[argn]);
294 		if (!q_type)
295 		{
296 			perror(argv[argn]);
297 			exit(1);
298 		}
299 		argn++;
300 	}
301 
302 	if (q_type == 0)
303 		q_type=get_q_type(q_xflag ? "PTR":"ANY");
304 
305 	q_class= -1;
306 	if (argn < argc)
307 		q_class=rfc1035_class_strtoi(argv[argn]);
308 	if (q_class < 0)
309 		q_class=RFC1035_CLASS_IN;
310 
311 	if (q_type[0] && q_type[1])
312 	{
313 		char namebuf[RFC1035_MAXNAMESIZE+1];
314 
315 		namebuf[0]=0;
316 		strncat(namebuf, q_name, RFC1035_MAXNAMESIZE);
317 
318 		if (rfc1035_resolve_cname_multiple(&res, namebuf,
319 						   q_type, q_class,
320 						   &replyp,
321 						   RFC1035_X_RANDOMIZE)
322 		    < 0)
323 			replyp=0;
324 	}
325 	else
326 	{
327 		replyp=rfc1035_resolve(&res, RFC1035_OPCODE_QUERY,
328 				       q_name, q_type[0], q_class);
329 	}
330 	free(q_type);
331 	if (!replyp)
332 	{
333 		perror(argv[0]);
334 		exit(1);
335 	}
336 
337 	if (q_type[0] && q_type[1])
338 	{
339 		struct rfc1035_reply *q;
340 
341 		for (q=replyp; q; q=q->next)
342 		{
343 			struct rfc1035_reply *s=q->next;
344 
345 			q->next=0;
346 			rfc1035_dump(q, stdout);
347 			q->next=s;
348 		}
349 	}
350 	else
351 	{
352 		rfc1035_dump(replyp, stdout);
353 	}
354 	rfc1035_replyfree(replyp);
355 	rfc1035_destroy_resolv(&res);
356 	return (0);
357 }
358