• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright(c) 2014-2018 Tim Ruehsen
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20  * DEALINGS IN THE SOFTWARE.
21  *
22  * This file is part of libpsl.
23  *
24  * Using the libpsl functions via command line
25  *
26  * Changelog
27  * 11.04.2014  Tim Ruehsen  created
28  *
29  */
30 
31 #if HAVE_CONFIG_H
32 # include <config.h>
33 #endif
34 
35 #ifdef HAVE_UNISTD_H
36 # include <unistd.h>
37 #endif
38 
39 #include <stdlib.h>
40 #include <string.h>
41 #include <ctype.h>
42 #include <locale.h>
43 
44 #include <libpsl.h>
45 
usage(int err,FILE * f)46 static void usage(int err, FILE* f)
47 {
48 	fprintf(f, "Usage: psl [options] <domains...>\n");
49 	fprintf(f, "\n");
50 	fprintf(f, "Options:\n");
51 	fprintf(f, "  --version                    show library version information\n");
52 	fprintf(f, "  --use-latest-data            use the latest PSL data available [default]\n");
53 	fprintf(f, "  --use-builtin-data           use the builtin PSL data\n");
54 	fprintf(f, "  --no-star-rule               do not apply the prevailing star rule\n");
55 	fprintf(f, "                                 (only applies to --is-public-suffix)\n");
56 	fprintf(f, "  --load-psl-file <filename>   load PSL data from file\n");
57 	fprintf(f, "  --is-public-suffix           check if domains are public suffixes [default]\n");
58 	fprintf(f, "  --is-cookie-domain-acceptable <cookie-domain>\n");
59 	fprintf(f, "                               check if cookie-domain is acceptable for domains\n");
60 	fprintf(f, "  --print-unreg-domain         print the longest public suffix part\n");
61 	fprintf(f, "  --print-reg-domain           print the shortest private suffix part\n");
62 	fprintf(f, "  --print-info                 print info about library builtin data\n");
63 	fprintf(f, "  -b,  --batch                 don't print leading domain\n");
64 	fprintf(f, "\n");
65 
66 	exit(err);
67 }
68 
69 /* RFC 2822-compliant date format */
time2str(time_t t)70 static const char *time2str(time_t t)
71 {
72 	static char buf[64];
73 	struct tm *tp = localtime(&t);
74 
75 	strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S %Z", tp);
76 	return buf;
77 }
78 
main(int argc,const char * const * argv)79 int main(int argc, const char *const *argv)
80 {
81 	int mode = 1, no_star_rule = 0, batch_mode = 0;
82 	const char *const *arg, *psl_file = NULL, *cookie_domain = NULL;
83 	psl_ctx_t *psl = (psl_ctx_t *) psl_latest(NULL);
84 
85 	/* set current locale according to the environment variables */
86 	setlocale(LC_ALL, "");
87 
88 	for (arg = argv + 1; arg < argv + argc; arg++) {
89 		if (**arg == '-') {
90 			if (!strcmp(*arg, "--is-public-suffix"))
91 				mode = 1;
92 			else if (!strcmp(*arg, "--print-unreg-domain"))
93 				mode = 2;
94 			else if (!strcmp(*arg, "--print-reg-domain"))
95 				mode = 3;
96 			else if (!strcmp(*arg, "--print-info"))
97 				mode = 99;
98 			else if (!strcmp(*arg, "--is-cookie-domain-acceptable") && arg < argv + argc - 1) {
99 				mode = 4;
100 				cookie_domain = *(++arg);
101 			}
102 			else if (!strcmp(*arg, "--use-latest-data")) {
103 				psl_free(psl);
104 				if (psl_file) {
105 					fprintf(stderr, "Dropped data from %s\n", psl_file);
106 					psl_file = NULL;
107 				}
108 				if (!(psl = (psl_ctx_t *) psl_latest(NULL)))
109 					printf("No PSL data available\n");
110 			}
111 			else if (!strcmp(*arg, "--use-builtin-data")) {
112 				psl_free(psl);
113 				if (psl_file) {
114 					fprintf(stderr, "Dropped data from %s\n", psl_file);
115 					psl_file = NULL;
116 				}
117 				if (!(psl = (psl_ctx_t *) psl_builtin()))
118 					printf("No builtin PSL data available\n");
119 			}
120 			else if (!strcmp(*arg, "--no-star-rule")) {
121 				no_star_rule = 1;
122 			}
123 			else if (!strcmp(*arg, "--load-psl-file") && arg < argv + argc - 1) {
124 				psl_free(psl);
125 				if (psl_file) {
126 					fprintf(stderr, "Dropped data from %s\n", psl_file);
127 					psl_file = NULL;
128 				}
129 				if (!(psl = psl_load_file(psl_file = *(++arg)))) {
130 					fprintf(stderr, "Failed to load PSL data from %s\n\n", psl_file);
131 					psl_file = NULL;
132 				}
133 			}
134 			else if (!strcmp(*arg, "--batch") || !strcmp(*arg, "-b")) {
135 				batch_mode = 1;
136 			}
137 			else if (!strcmp(*arg, "--help")) {
138 				fprintf(stdout, "`psl' explores the Public Suffix List\n\n");
139 				usage(0, stdout);
140 			}
141 			else if (!strcmp(*arg, "--version")) {
142 				printf("psl %s (0x%06x)\n", PACKAGE_VERSION, psl_check_version_number(0));
143 				printf("libpsl %s\n", psl_get_version());
144 				printf("\n");
145 				printf("Copyright (C) 2014-2018 Tim Ruehsen\n");
146 				printf("License: MIT\n");
147 				exit(0);
148 			}
149 			else if (!strcmp(*arg, "--")) {
150 				arg++;
151 				break;
152 			}
153 			else {
154 				fprintf(stderr, "Unknown option '%s'\n", *arg);
155 				usage(1, stderr);
156 			}
157 		} else
158 			break;
159 	}
160 
161 	if (mode != 99) {
162 		if (mode != 1 && no_star_rule) {
163 			fprintf(stderr, "--no-star-rule only combines with --is-public-suffix\n");
164 			usage(1, stderr);
165 		}
166 		if (!psl) {
167 			fprintf(stderr, "No PSL data available - aborting\n");
168 			exit(2);
169 		}
170 		if (arg >= argv + argc) {
171 			char buf[256], *domain, *lower;
172 			size_t len;
173 			psl_error_t rc;
174 
175 			/* read URLs from STDIN */
176 			while (fgets(buf, sizeof(buf), stdin)) {
177 				for (domain = buf; isspace(*domain); domain++); /* skip leading spaces */
178 				if (*domain == '#' || !*domain) continue; /* skip empty lines and comments */
179 				for (len = strlen(domain); len && isspace(domain[len - 1]); len--); /* skip trailing spaces */
180 				domain[len] = 0;
181 
182 				if ((rc = psl_str_to_utf8lower(domain, NULL, NULL, &lower)) != PSL_SUCCESS) {
183 					fprintf(stderr, "%s: Failed to convert to lowercase UTF-8 (%d)\n", domain, rc);
184 					continue;
185 				}
186 
187 				if (!batch_mode && mode != 4)
188 					printf("%s: ", domain);
189 
190 				if (mode == 1) {
191 					if (no_star_rule)
192 						printf("%d", psl_is_public_suffix2(psl, lower, PSL_TYPE_ANY|PSL_TYPE_NO_STAR_RULE));
193 					else
194 						printf("%d", psl_is_public_suffix(psl, lower));
195 
196 					if (!batch_mode)
197 						printf(" (%s)\n", lower);
198 					else
199 						putchar('\n');
200 				}
201 				else if (mode == 2) {
202 					const char *dom = psl_unregistrable_domain(psl, lower);
203 					printf("%s\n", dom ? dom : "(null)");
204 				}
205 				else if (mode == 3) {
206 					const char *dom = psl_registrable_domain(psl, lower);
207 					printf("%s\n", dom ? dom : "(null)");
208 				}
209 				else if (mode == 4) {
210 					char *cookie_domain_lower;
211 
212 					if ((rc = psl_str_to_utf8lower(domain, NULL, NULL, &cookie_domain_lower)) == PSL_SUCCESS) {
213 						if (!batch_mode)
214 							printf("%s: ", domain);
215 						printf("%d\n", psl_is_cookie_domain_acceptable(psl, lower, cookie_domain));
216 						free(cookie_domain_lower);
217 					} else
218 						fprintf(stderr, "%s: Failed to convert cookie domain '%s' to lowercase UTF-8 (%d)\n", domain, cookie_domain, rc);
219 				}
220 
221 				psl_free_string(lower);
222 			}
223 
224 			psl_free(psl);
225 			exit(0);
226 		}
227 	}
228 
229 	if (mode == 1) {
230 		for (; arg < argv + argc; arg++) {
231 			if (!batch_mode)
232 				printf("%s: ", *arg);
233 			if (no_star_rule)
234 				printf("%d\n", psl_is_public_suffix2(psl, *arg, PSL_TYPE_ANY|PSL_TYPE_NO_STAR_RULE));
235 			else
236 				printf("%d\n", psl_is_public_suffix(psl, *arg));
237 		}
238 	}
239 	else if (mode == 2) {
240 		for (; arg < argv + argc; arg++) {
241 			const char *dom = psl_unregistrable_domain(psl, *arg);
242 			if (!batch_mode)
243 				printf("%s: ", *arg);
244 			printf("%s\n", dom ? dom : "(null)");
245 		}
246 	}
247 	else if (mode == 3) {
248 		for (; arg < argv + argc; arg++) {
249 			const char *dom = psl_registrable_domain(psl, *arg);
250 			if (!batch_mode)
251 				printf("%s: ", *arg);
252 			printf("%s\n", dom ? dom : "(null)");
253 		}
254 	}
255 	else if (mode == 4) {
256 		for (; arg < argv + argc; arg++) {
257 			if (!batch_mode)
258 				printf("%s: ", *arg);
259 			printf("%d\n", psl_is_cookie_domain_acceptable(psl, *arg, cookie_domain));
260 		}
261 	}
262 	else if (mode == 99) {
263 		printf("dist filename: %s\n", psl_dist_filename());
264 
265 		if (psl && psl != psl_builtin()) {
266 			static char not_avail[] = "- information not available -";
267 			int n;
268 
269 			if ((n = psl_suffix_count(psl)) >= 0)
270 				printf("suffixes: %d\n", n);
271 			else
272 				printf("suffixes: %s\n", not_avail);
273 
274 			if ((n = psl_suffix_exception_count(psl)) >= 0)
275 				printf("exceptions: %d\n", n);
276 			else
277 				printf("exceptions: %s\n", not_avail);
278 
279 			if ((n = psl_suffix_wildcard_count(psl)) >= 0)
280 				printf("wildcards: %d\n", n);
281 			else
282 				printf("wildcards: %s\n", not_avail);
283 		}
284 
285 		psl_free(psl);
286 		psl = (psl_ctx_t *) psl_builtin();
287 
288 		if (psl) {
289 			printf("builtin suffixes: %d\n", psl_suffix_count(psl));
290 			printf("builtin exceptions: %d\n", psl_suffix_exception_count(psl));
291 			printf("builtin wildcards: %d\n", psl_suffix_wildcard_count(psl));
292 			printf("builtin filename: %s\n", psl_builtin_filename());
293 			printf("builtin file time: %ld (%s)\n", (long) psl_builtin_file_time(), time2str(psl_builtin_file_time()));
294 			printf("builtin SHA1 file hash: %s\n", psl_builtin_sha1sum());
295 			printf("builtin outdated: %d\n", psl_builtin_outdated());
296 		} else
297 			printf("No builtin PSL data available\n");
298 	}
299 
300 	psl_free(psl);
301 
302 	return 0;
303 }
304