1 /*
2  * ZMap Copyright 2013 Regents of the University of Michigan
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy
6  * of the License at http://www.apache.org/licenses/LICENSE-2.0
7  */
8 
9 /*
10  * ZBlacklist is a simple utility that (1) excludes IP addresses on a specified
11  * blacklist from being scanned, and (2) ensures the uniqueness of output
12  * addresses such that no host is scanned twice. ZBlacklist takes in a list
13  * of addresses on stdin and outputs addresses that are acceptable to scan
14  * on stdout. The utility uses the blacklist data structures from ZMap for
15  * checking scan eligibility and a paged bitmap for duplicate prevention.
16  */
17 
18 #define _GNU_SOURCE
19 
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <getopt.h>
25 #include <assert.h>
26 #include <sched.h>
27 #include <errno.h>
28 #include <pwd.h>
29 #include <time.h>
30 
31 #include "../lib/includes.h"
32 #include "../lib/blacklist.h"
33 #include "../lib/logger.h"
34 #include "../lib/pbm.h"
35 
36 #include "zbopt.h"
37 
38 
39 //struct zbl_stats {
40 //	uint32_t cidr_entries;
41 //	uint32_t allowed_addrs;
42 //	uint32_t input_addrs;
43 //	uint32_t uniq_input_addrs;
44 //	uint32_t blocked_addrs;
45 //	uint32_t output_addrs;
46 //	uint32_t duplicates;
47 //};
48 
49 #undef  MIN
50 #define MIN(X,Y) ((X) < (Y) ? (X) : (Y))
51 
zmin(char * a,char * b)52 static inline char* zmin(char *a, char *b) {
53     if (a && !b)
54         return a;
55     else if (b && !a)
56         return b;
57     else
58         return MIN(a,b);
59 }
60 
61 struct zbl_conf {
62 	char *blacklist_filename;
63 	char *whitelist_filename;
64 	char *log_filename;
65 	int check_duplicates;
66 	int ignore_errors;
67 	int verbosity;
68 	//struct zbl_stats stats;
69 };
70 
71 #define SET_IF_GIVEN(DST,ARG) \
72 	{ if (args.ARG##_given) { (DST) = args.ARG##_arg; }; }
73 #define SET_BOOL(DST,ARG) \
74 	{ if (args.ARG##_given) { (DST) = 1; }; }
75 
main(int argc,char ** argv)76 int main(int argc, char **argv)
77 {
78 	struct zbl_conf conf;
79 	conf.verbosity = 3;
80 	memset(&conf, 0, sizeof(struct zbl_conf));
81 	int no_dupchk_pres = 0;
82   conf.ignore_errors = 0;
83 
84   struct gengetopt_args_info args;
85   struct cmdline_parser_params *params;
86   params = cmdline_parser_params_create();
87   assert(params);
88   params->initialize = 1;
89   params->override = 0;
90   params->check_required = 0;
91 
92   if (cmdline_parser_ext(argc, argv, &args, params) != 0) {
93     exit(EXIT_SUCCESS);
94   }
95 
96   // Handle help text and version
97   if (args.help_given) {
98     cmdline_parser_print_help();
99     exit(EXIT_SUCCESS);
100   }
101   if (args.version_given) {
102     cmdline_parser_print_version();
103     exit(EXIT_SUCCESS);
104   }
105 
106   // Set the log file and metadata file
107   if (args.log_file_given) {
108     conf.log_filename = strdup(args.log_file_arg);
109   }
110   if (args.verbosity_given) {
111     conf.verbosity = args.verbosity_arg;
112   }
113 
114   // Blacklist and whitelist
115   if (args.blacklist_file_given) {
116     conf.blacklist_filename = strdup(args.blacklist_file_arg);
117   }
118   if (args.whitelist_file_given) {
119     conf.whitelist_filename = strdup(args.whitelist_file_arg);
120   }
121 
122   // Read the boolean flags
123   SET_BOOL(no_dupchk_pres, no_duplicate_checking);
124   conf.check_duplicates = !no_dupchk_pres;
125   SET_BOOL(conf.ignore_errors, ignore_blacklist_errors);
126 
127 	// initialize logging
128 	FILE *logfile = stderr;
129 	if (conf.log_filename) {
130 		logfile = fopen(conf.log_filename, "w");
131 		if (!logfile) {
132 			fprintf(stderr, "FATAL: unable to open specified logfile (%s)\n",
133 					conf.log_filename);
134 			exit(1);
135 		}
136 	}
137 	if (log_init(logfile, conf.verbosity, 1, "zblacklist")) {
138 		fprintf(stderr, "FATAL: unable able to initialize logging\n");
139 		exit(1);
140 	}
141 
142 	if (!conf.blacklist_filename && !conf.whitelist_filename) {
143 		log_fatal("zblacklist", "must specify either a whitelist or blacklist file");
144 	}
145 
146 	// parse blacklist
147 	if (conf.blacklist_filename) {
148 		log_debug("zblacklist", "blacklist file at %s to be used", conf.blacklist_filename);
149 	} else {
150 		log_debug("zblacklist", "no blacklist file specified");
151 	}
152 	if (conf.blacklist_filename && access(conf.blacklist_filename, R_OK) == -1) {
153 		log_fatal("zblacklist", "unable to read specified blacklist file (%s)",
154 				conf.blacklist_filename);
155 	}
156 	if (conf.whitelist_filename) {
157 		log_debug("zblacklist", "whitelist file at %s to be used", conf.whitelist_filename);
158 	} else {
159 		log_debug("zblacklist", "no whitelist file specified");
160 	}
161 	if (conf.whitelist_filename && access(conf.whitelist_filename, R_OK) == -1) {
162 		log_fatal("zblacklist", "unable to read specified whitelist file (%s)",
163 				conf.whitelist_filename);
164 	}
165 
166 	if (blacklist_init(conf.whitelist_filename, conf.blacklist_filename,
167 			NULL, 0, NULL, 0, conf.ignore_errors)) {
168 		log_fatal("zmap", "unable to initialize blacklist / whitelist");
169 	}
170 	// initialize paged bitmap
171 	uint8_t **seen = NULL;
172 	if (conf.check_duplicates) {
173 		seen = pbm_init();
174 		if (!seen) {
175 			log_fatal("zblacklist", "unable to initialize paged bitmap");
176 		}
177 	}
178 	// process addresses
179 	char line[1000];
180 	char original[1000];
181 	while (fgets(line, 1000, stdin) != NULL) {
182 		// remove new line
183 		memcpy(original, line, strlen(line) + 1);
184 		char *n = zmin(zmin(zmin(zmin(strchr(line, '\n'),
185                         strchr(line, ',')),
186                         strchr(line, '\t')),
187                         strchr(line, ' ')),
188                         strchr(line, '#'));
189 		assert(n);
190 		n[0] = 0;
191 		log_trace("zblacklist", "input value %s", line);
192 		// parse into int
193 		struct in_addr addr;
194 		if (!inet_aton(line, &addr)) {
195 			log_warn("zblacklist", "invalid input address: %s", line);
196 		}
197 		if (conf.check_duplicates) {
198 			if (pbm_check(seen, ntohl(addr.s_addr))) {
199 				log_trace("zblacklist", "%s is a duplicate: skipped", line);
200 				continue;
201 			} else {
202 				log_trace("zblacklist", "%s not a duplicate: skipped", line);
203 			}
204 		} else {
205 				log_trace("zblacklist", "no duplicate checking for %s", line);
206 		}
207 		// check if in blacklist
208 		if (blacklist_is_allowed(addr.s_addr)) {
209 			if (conf.check_duplicates) {
210 				if (!pbm_check(seen, ntohl(addr.s_addr))) {
211 					pbm_set(seen, ntohl(addr.s_addr));
212 					printf("%s", original);
213 				}
214 			} else {
215 				printf("%s", original);
216 			}
217 		}
218 	}
219 	return EXIT_SUCCESS;
220 }
221