xref: /plan9/sys/src/cmd/ip/httpd/classify.c (revision 7dd7cddf99dd7472612f1413b4da293630e6b1bc)
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <ndb.h>
5 #include "whois.h"
6 
7 typedef struct Country Country;
8 
9 struct Country
10 {
11 	char *code;
12 	char *name;
13 };
14 
15 Country badc[] =
16 {
17 	{"af", "afghanistan"},
18 	{"cu", "cuba"},
19 	{"ir", "iran"},
20 	{"iq", "iraq"},
21 	{"ly", "libya"},
22 	{"kp", "north korea"},
23 	{"sd", "sudan"},
24 	{"sy", "syria"},
25 	{ 0, 0 }
26 };
27 
28 Country goodc[] =
29 {
30 	{"us", "united states of america"},
31 	{"ca", "canada"},
32 	{"gov", "gov"},
33 	{"mil", "mil"},
34 	{ 0, 0 }
35 };
36 
37 char *gov[] =
38 {
39 	"gov",
40 	"gouv",
41 	"mil",
42 	"government",
43 	0,
44 };
45 
46 Country allc[] =
47 {
48 	{ "ad",	"andorra" },
49 	{ "ae",	"united arab emirates" },
50 	{ "af",	"afghanistan" },
51 	{ "ag",	"antigua and barbuda" },
52 	{ "ai",	"anguilla" },
53 	{ "al",	"albania" },
54 	{ "am",	"armenia" },
55 	{ "an",	"netherlands antilles" },
56 	{ "ao",	"angola" },
57 	{ "aq",	"antarctica" },
58 	{ "ar",	"argentina" },
59 	{ "as",	"american samoa" },
60 	{ "at",	"austria" },
61 	{ "au",	"australia" },
62 	{ "aw",	"aruba" },
63 	{ "az",	"azerbaijan" },
64 	{ "ba",	"bosnia and herzegovina" },
65 	{ "bb",	"barbados" },
66 	{ "bd",	"bangladesh" },
67 	{ "be",	"belgium" },
68 	{ "bf",	"burkina faso" },
69 	{ "bg",	"bulgaria" },
70 	{ "bh",	"bahrain" },
71 	{ "bi",	"burundi" },
72 	{ "bj",	"benin" },
73 	{ "bm",	"bermuda" },
74 	{ "bn",	"brunei darussalam" },
75 	{ "bo",	"bolivia" },
76 	{ "br",	"brazil" },
77 	{ "bs",	"bahamas" },
78 	{ "bt",	"bhutan" },
79 	{ "bu",	"burma" },
80 	{ "bv",	"bouvet island" },
81 	{ "bw",	"botswana" },
82 	{ "by",	"belarus" },
83 	{ "bz",	"belize" },
84 	{ "ca",	"canada" },
85 	{ "cc",	"cocos (keeling) islands" },
86 	{ "cf",	"central african republic" },
87 	{ "cg",	"congo" },
88 	{ "ch",	"switzerland" },
89 	{ "ci",	"cote d'ivoire (ivory coast)" },
90 	{ "ck",	"cook islands" },
91 	{ "cl",	"chile" },
92 	{ "cm",	"cameroon" },
93 	{ "cn",	"china" },
94 	{ "co",	"colombia" },
95 	{ "cr",	"costa rica" },
96 	{ "cs",	"czechoslovakia (former)" },
97 	{ "ct",	"canton and enderbury island" },
98 	{ "cu",	"cuba" },
99 	{ "cv",	"cape verde" },
100 	{ "cx",	"christmas island" },
101 	{ "cy",	"cyprus" },
102 	{ "cz",	"czech republic" },
103 	{ "dd",	"german democratic republic" },
104 	{ "de",	"germany" },
105 	{ "dj",	"djibouti" },
106 	{ "dk",	"denmark" },
107 	{ "dm",	"dominica" },
108 	{ "do",	"dominican republic" },
109 	{ "dz",	"algeria" },
110 	{ "ec",	"ecuador" },
111 	{ "ee",	"estonia" },
112 	{ "eg",	"egypt" },
113 	{ "eh",	"western sahara" },
114 	{ "er",	"eritrea" },
115 	{ "es",	"spain" },
116 	{ "et",	"ethiopia" },
117 	{ "eu",	"european union" },
118 	{ "fi",	"finland" },
119 	{ "fj",	"fiji" },
120 	{ "fk",	"falkland islands (malvinas)" },
121 	{ "fm",	"micronesia" },
122 	{ "fo",	"faroe islands" },
123 	{ "fr",	"france" },
124 	{ "fx",	"france, metropolitan" },
125 	{ "ga",	"gabon" },
126 	{ "gb",	"great britain (uk)" },
127 	{ "gd",	"grenada" },
128 	{ "ge",	"georgia" },
129 	{ "gf",	"french guiana" },
130 	{ "gh",	"ghana" },
131 	{ "gi",	"gibraltar" },
132 	{ "gl",	"greenland" },
133 	{ "gm",	"gambia" },
134 	{ "gn",	"guinea" },
135 	{ "gp",	"guadeloupe" },
136 	{ "gq",	"equatorial guinea" },
137 	{ "gr",	"greece" },
138 	{ "gs",	"s. georgia and s. sandwich isls." },
139 	{ "gt",	"guatemala" },
140 	{ "gu",	"guam" },
141 	{ "gw",	"guinea-bissau" },
142 	{ "gy",	"guyana" },
143 	{ "hk",	"hong kong" },
144 	{ "hm",	"heard and mcdonald islands" },
145 	{ "hn",	"honduras" },
146 	{ "hr",	"croatia (hrvatska)" },
147 	{ "ht",	"haiti" },
148 	{ "hu",	"hungary" },
149 	{ "id",	"indonesia" },
150 	{ "ie",	"ireland" },
151 	{ "il",	"israel" },
152 	{ "in",	"india" },
153 	{ "io",	"british indian ocean territory" },
154 	{ "iq",	"iraq" },
155 	{ "ir",	"iran" },
156 	{ "is",	"iceland" },
157 	{ "it",	"italy" },
158 	{ "jm",	"jamaica" },
159 	{ "jo",	"jordan" },
160 	{ "jp",	"japan" },
161 	{ "jt",	"johnston island" },
162 	{ "ke",	"kenya" },
163 	{ "kg",	"kyrgyzstan" },
164 	{ "kh",	"cambodia (democratic kampuchea)" },
165 	{ "ki",	"kiribati" },
166 	{ "km",	"comoros" },
167 	{ "kn",	"saint kitts and nevis" },
168 	{ "kp",	"korea (north)" },
169 	{ "kr",	"korea (south)" },
170 	{ "kw",	"kuwait" },
171 	{ "ky",	"cayman islands" },
172 	{ "kz",	"kazakhstan" },
173 	{ "la",	"laos" },
174 	{ "lb",	"lebanon" },
175 	{ "lc",	"saint lucia" },
176 	{ "li",	"liechtenstein" },
177 	{ "lk",	"sri lanka" },
178 	{ "lr",	"liberia" },
179 	{ "ls",	"lesotho" },
180 	{ "lt",	"lithuania" },
181 	{ "lu",	"luxembourg" },
182 	{ "lv",	"latvia" },
183 	{ "ly",	"libya" },
184 	{ "ma",	"morocco" },
185 	{ "mc",	"monaco" },
186 	{ "md",	"moldova" },
187 	{ "mg",	"madagascar" },
188 	{ "mh",	"marshall islands" },
189 	{ "mi",	"midway islands" },
190 	{ "mk",	"macedonia" },
191 	{ "ml",	"mali" },
192 	{ "mm",	"myanmar" },
193 	{ "mn",	"mongolia" },
194 	{ "mo",	"macau" },
195 	{ "mp",	"northern mariana islands" },
196 	{ "mq",	"martinique" },
197 	{ "mr",	"mauritania" },
198 	{ "ms",	"montserrat" },
199 	{ "mt",	"malta" },
200 	{ "mu",	"mauritius" },
201 	{ "mv",	"maldives" },
202 	{ "mw",	"malawi" },
203 	{ "mx",	"mexico" },
204 	{ "my",	"malaysia" },
205 	{ "mz",	"mozambique" },
206 	{ "na",	"namibia" },
207 	{ "nc",	"new caledonia" },
208 	{ "ne",	"niger" },
209 	{ "nf",	"norfolk island" },
210 	{ "ng",	"nigeria" },
211 	{ "ni",	"nicaragua" },
212 	{ "nl",	"netherlands" },
213 	{ "no",	"norway" },
214 	{ "np",	"nepal" },
215 	{ "nq",	"dronning maud land" },
216 	{ "nr",	"nauru" },
217 	{ "nt",	"neutral zone" },
218 	{ "nu",	"niue" },
219 	{ "nz",	"new zealand (aotearoa)" },
220 	{ "om",	"oman" },
221 	{ "pa",	"panama" },
222 	{ "pc",	"pacific islands" },
223 	{ "pe",	"peru" },
224 	{ "pf",	"french polynesia" },
225 	{ "pg",	"papua new guinea" },
226 	{ "ph",	"philippines" },
227 	{ "pk",	"pakistan" },
228 	{ "pl",	"poland" },
229 	{ "pm",	"st. pierre and miquelon" },
230 	{ "pn",	"pitcairn" },
231 	{ "pr",	"puerto rico" },
232 	{ "pu",	"united states misc. pacific islands" },
233 	{ "pt",	"portugal" },
234 	{ "pw",	"palau" },
235 	{ "py",	"paraguay" },
236 	{ "qa",	"qatar" },
237 	{ "re",	"reunion" },
238 	{ "ro",	"romania" },
239 	{ "ru",	"russian federation" },
240 	{ "rw",	"rwanda" },
241 	{ "sa",	"saudi arabia" },
242 	{ "sb",	"solomon islands" },
243 	{ "sc",	"seychelles" },
244 	{ "sd",	"sudan" },
245 	{ "se",	"sweden" },
246 	{ "sg",	"singapore" },
247 	{ "sh",	"st. helena" },
248 	{ "si",	"slovenia" },
249 	{ "sj",	"svalbard and jan mayen islands" },
250 	{ "sk",	"slovak republic" },
251 	{ "sl",	"sierra leone" },
252 	{ "sm",	"san marino" },
253 	{ "sn",	"senegal" },
254 	{ "so",	"somalia" },
255 	{ "sr",	"suriname" },
256 	{ "st",	"sao tome and principe" },
257 	{ "su",	"ussr (former)" },
258 	{ "sv",	"el salvador" },
259 	{ "sy",	"syria" },
260 	{ "sz",	"swaziland" },
261 	{ "tc",	"turks and caicos islands" },
262 	{ "td",	"chad" },
263 	{ "tf",	"french southern territories" },
264 	{ "tg",	"togo" },
265 	{ "th",	"thailand" },
266 	{ "tj",	"tajikistan" },
267 	{ "tk",	"tokelau" },
268 	{ "tm",	"turkmenistan" },
269 	{ "tn",	"tunisia" },
270 	{ "to",	"tonga" },
271 	{ "tp",	"east timor" },
272 	{ "tr",	"turkey" },
273 	{ "tt",	"trinidad and tobago" },
274 	{ "tv",	"tuvalu" },
275 	{ "tw",	"taiwan" },
276 	{ "tz",	"tanzania" },
277 	{ "ua",	"ukraine" },
278 	{ "ug",	"uganda" },
279 	{ "uk",	"united kingdom" },
280 	{ "um",	"us minor outlying islands" },
281 	{ "us",	"united states" },
282 	{ "uy",	"uruguay" },
283 	{ "uz",	"uzbekistan" },
284 	{ "va",	"vatican city state (holy see)" },
285 	{ "vc",	"saint vincent and the grenadines" },
286 	{ "ve",	"venezuela" },
287 	{ "vg",	"virgin islands (british)" },
288 	{ "vi",	"virgin islands (u.s.)" },
289 	{ "vn",	"viet nam" },
290 	{ "vu",	"vanuatu" },
291 	{ "wf",	"wallis and futuna islands" },
292 	{ "wk",	"wake island" },
293 	{ "ws",	"samoa" },
294 	{ "yd",	"democratic yemen" },
295 	{ "ye",	"yemen" },
296 	{ "yt",	"mayotte" },
297 	{ "yu",	"yugoslavia" },
298 	{ "za",	"south africa" },
299 	{ "zm",	"zambia" },
300 	{ "zr",	"zaire" },
301 	{ "zw",	"zimbabwe" },
302 
303 	{"gov", "gov"},
304 	{"mil", "mil"},
305 
306 	{ 0, 0 }
307 };
308 
309 static int
310 incountries(char *s, Country *cp)
311 {
312 	for(; cp->code != 0; cp++)
313 		if(cistrcmp(s, cp->code) == 0
314 		|| cistrcmp(s, cp->name) == 0)
315 			return 1;
316 	return 0;
317 }
318 
319 static int
320 indomains(char *s, char **dp)
321 {
322 	for(; *dp != nil; dp++)
323 		if(cistrcmp(s, *dp) == 0)
324 			return 1;
325 
326 	return 0;
327 }
328 
329 int
330 classify(char *ip, Ndbtuple *t)
331 {
332 	int isgov, iscountry, isbadc, isgoodc;
333 	char dom[Ndbvlen];
334 	char *df[128];
335 	Ndbtuple *nt;
336 	int n;
337 
338 	isgov = iscountry = isbadc = 0;
339 	isgoodc = 1;
340 
341 	for(nt = t; nt != nil; nt = nt->entry){
342 		if(strcmp(nt->attr, "country") == 0){
343 			iscountry = 1;
344 			if(incountries(nt->val, badc)){
345 				isbadc = 1;
346 				isgoodc = 0;
347 			} else if(!incountries(nt->val, goodc))
348 				isgoodc = 0;
349 		}
350 
351 		/* domain names can always hurt, even without forward verification */
352 		if(strcmp(nt->attr, "dom") == 0){
353 			strcpy(dom, nt->val);
354 			n = getfields(dom, df, nelem(df), 0, ".");
355 
356 			/* a bad country in a domain name is always believed */
357 			if(incountries(df[n-1], badc) || (n > 1 && incountries(df[n-2], badc))){
358 				isbadc = 1;
359 				isgoodc = 0;
360 			}
361 
362 			/* a goverment in a domain name is always believed */
363 			if(n > 1 && indomains(df[n-2], gov))
364 				isgov = 1;
365 		}
366 	}
367 	if(iscountry == 0){
368 		/* did the forward lookup work? */
369 		for(nt = t; nt != nil; nt = nt->entry){
370 			if(strcmp(nt->attr, "ip") == 0 && strcmp(nt->val, ip) == 0)
371 				break;
372 		}
373 
374 		/* see if the domain name ends in a country code */
375 		if(nt != nil && ndblookval(t, nt, "dom", dom) != nil){
376 			n = getfields(dom, df, nelem(df), 0, ".");
377 			if(incountries(df[n-1], allc))
378 				iscountry = 1;
379 		}
380 	}
381 	if(iscountry == 0)
382 		return Cunknown;
383 	if(isbadc)
384 		return Cbadc;
385 	if(!isgoodc && isgov)
386 		return Cbadgov;
387 	return Cok;
388 }
389