1 #include <time.h>
2 #include <unistd.h>
3 #include <stdio.h>
4 #include <string.h>
5 #include "firedns.h"
6 
7 #define max(a,b) (a > b ? a : b)
8 
checkjunk(struct in_addr * ip)9 int checkjunk(struct in_addr *ip) {
10 	unsigned char *cip = (unsigned char *)ip;
11 	if (cip[0] == 10)
12 		return 1;
13 	if (cip[0] == 172 && (cip[1] >= 16 && cip[1] <= 31))
14 		return 1;
15 	if (cip[0] == 192 && cip[1] == 168)
16 		return 1;
17 	if (cip[0] == 192 && cip[1] == 0 && cip[2] == 2)
18 		return 1;
19 	if (cip[0] == 198 && (cip[1] == 18 || cip[1] == 19))
20 		return 1;
21 	if (cip[0] == 127)
22 		return 1;
23 	if (cip[0] >= 224 && cip[0] <= 240)
24 		return 1;
25 	if (cip[0] == 0)
26 		return 1;
27 
28 	return 0;
29 }
30 
checkjunk6(struct in6_addr * ip)31 int checkjunk6(struct in6_addr *ip) {
32 	if (memcmp(ip,"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",16) == 0)
33 		return 1;
34 	if (memcmp(ip,"\xfe\x80",2) == 0)
35 		return 1;
36 	/* FIXME: there's gotta be more of these */
37 	return 0;
38 }
39 
40 /* 0 - Everything looks good
41  * 1 - An MX has a non-routable IP
42  * 2 - An MX doesn't exist
43  * 3 - An MX is a CNAME
44  * 4 - An MX is an IP address
45  *
46  * 100 - Invalid syntax
47  * 103 - DNS timeout
48  */
main(int argc,char ** argv)49 int main(int argc, char **argv) {
50 	struct firedns_mxlist *iter, *list;
51 	int ret = 0;
52 	int xml = 0;
53 
54 	if (argc == 3 && argv[1][0] == '-') {
55 		int i = 1;
56 		while (argv[1][i] != '\0') {
57 			switch (argv[1][i]) {
58 				case 'x':
59 					xml = 1;
60 					break;
61 			}
62 			i++;
63 		}
64 		argv[1] = argv[2];
65 		argc--;
66 	}
67 
68 	if (argc != 2) {
69 		fprintf(stderr,"usage: [-x] %s <hostname>\n",argv[0]);
70 		return 100;
71 	}
72 
73 	list = iter = firedns_resolvemxalist(argv[1]);
74 
75 	if (iter == NULL)
76 		return 103;
77 
78 	if (xml)
79 		printf("<?xml version=\"1.0\"?>\n"
80 "<fdnsmxalist time=\"%d\" hostname=\"%s\">\n",(int)time(NULL),argv[1]);
81 
82 	while (iter != NULL) {
83 		if (xml)
84 			printf("	<mx hostname=\"%s\" protocol=\"%s\" priority=\"%d\" port=\"%d\">\n",iter->name,firedns_mx_name[iter->protocol],iter->priority,firedns_mx_port[iter->protocol]);
85 		else
86 			printf("%7s (%05d) %s:%d\n",firedns_mx_name[iter->protocol],iter->priority,iter->name,firedns_mx_port[iter->protocol]);
87 		if (iter->cname != NULL) {
88 			if (xml)
89 				printf("		<error type=\"cname\" cname=\"%s\" />\n",iter->cname);
90 			else
91 				printf("ERROR: %s is a CNAME for %s\n",iter->name,iter->cname);
92 			ret = max(ret,3);
93 		}
94 		if (firedns_aton4(iter->name) != NULL) {
95 			if (xml)
96 				printf("		<error type=\"ip4_mx\" />\n");
97 			else
98 				printf("ERROR: %s is an IPv4 address\n",iter->name);
99 			ret = max(ret,4);
100 			goto wrap;
101 		}
102 		if (firedns_aton6(iter->name) != NULL) {
103 			if (xml)
104 				printf("		<error type=\"ip6_mx\" />\n");
105 			else
106 				printf("ERROR: %s is an IPv6 address\n",iter->name);
107 			ret = max(ret,4);
108 			goto wrap;
109 		}
110 		if (iter->ip4list == NULL && iter->ip6list == NULL) {
111 			if (xml)
112 				printf("		<error type=\"nxdomain\" />\n");
113 			else
114 				printf("ERROR: %s does not exist\n",iter->name);
115 			ret = max(ret,2);
116 		} else {
117 			struct firedns_ip4list *ipiter = iter->ip4list;
118 			struct firedns_ip6list *ip6iter = iter->ip6list;
119 
120 			while (ipiter) {
121 				if (xml)
122 					printf("		<ip version=\"4\">%s",firedns_ntoa4(&ipiter->ip));
123 				else
124 					printf("             %s\n",firedns_ntoa4(&ipiter->ip));
125 				if (checkjunk(&ipiter->ip)) {
126 					if (xml)
127 						printf("\n			<error type=\"private-ip\" />\n		");
128 					else
129 						printf("ERROR: %s has an IP of %s, which is non-routable\n",iter->name,firedns_ntoa4(&ipiter->ip));
130 					ret = max(ret,1);
131 				}
132 				if (xml)
133 					printf("</ip>\n");
134 				ipiter = ipiter->next;
135 			}
136 
137 			while (ip6iter) {
138 				if (xml)
139 					printf("		<ip version=\"6\">%s",firedns_ntoa6(&ip6iter->ip));
140 				else
141 					printf("             %s\n",firedns_ntoa6(&ip6iter->ip));
142 				if (checkjunk6(&ip6iter->ip)) {
143 					if (xml)
144 						printf("\n			<error type=\"private-ip\" />\n		");
145 					else
146 						printf("ERROR: %s has an IP of %s, which is non-routable\n",iter->name,firedns_ntoa6(&ip6iter->ip));
147 					ret = max(ret,1);
148 				}
149 				if (xml)
150 					printf("</ip>\n");
151 				ip6iter = ip6iter->next;
152 			}
153 		}
154 wrap:
155 		if (xml)
156 			printf("	</mx>\n");
157 		iter = iter->next;
158 	}
159 
160 	/* this is more to make sure freeing works than anything else */
161 	firedns_free_mxalist(list);
162 
163 	if (xml)
164 		printf("</fdnsmxalist>\n");
165 
166 	return ret;
167 }
168