1 /*
2  * Blacklist 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 #include "blacklist.h"
10 
11 #include <errno.h>
12 #include <stdio.h>
13 #include <assert.h>
14 #include <stdint.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <sys/socket.h>
18 #include <netinet/in.h>
19 #include <arpa/inet.h>
20 #include <netdb.h>
21 
22 #include "constraint.h"
23 #include "logger.h"
24 #include "xalloc.h"
25 
26 #define ADDR_DISALLOWED 0
27 #define ADDR_ALLOWED 1
28 
29 typedef struct bl_linked_list {
30         bl_cidr_node_t *first;
31         bl_cidr_node_t *last;
32         uint32_t len;
33 } bl_ll_t;
34 
35 static constraint_t *constraint = NULL;
36 
37 // keep track of the prefixes we've tried to BL/WL
38 // for logging purposes
39 static bl_ll_t *blacklisted_cidrs = NULL;
40 static bl_ll_t *whitelisted_cidrs = NULL;
41 
bl_ll_add(bl_ll_t * l,struct in_addr addr,uint16_t p)42 void bl_ll_add(bl_ll_t *l, struct in_addr addr, uint16_t p)
43 {
44 	assert(l);
45         bl_cidr_node_t *new = xmalloc(sizeof(bl_cidr_node_t));
46         new->next = NULL;
47         new->ip_address = addr.s_addr;
48     	new->prefix_len = p;
49         if (!l->first) {
50                 l->first = new;
51         } else {
52                 l->last->next = new;
53         }
54         l->last = new;
55         l->len++;
56 }
57 
get_blacklisted_cidrs(void)58 bl_cidr_node_t *get_blacklisted_cidrs(void)
59 {
60 	return blacklisted_cidrs->first;
61 }
62 
get_whitelisted_cidrs(void)63 bl_cidr_node_t *get_whitelisted_cidrs(void)
64 {
65 	return whitelisted_cidrs->first;
66 }
67 
68 
blacklist_lookup_index(uint64_t index)69 uint32_t blacklist_lookup_index(uint64_t index) {
70 	return ntohl(constraint_lookup_index(constraint, index, ADDR_ALLOWED));
71 }
72 
73 // check whether a single IP address is allowed to be scanned.
74 //		1 => is allowed
75 //		0 => is not allowed
blacklist_is_allowed(uint32_t s_addr)76 int blacklist_is_allowed(uint32_t s_addr) {
77 	return constraint_lookup_ip(constraint, ntohl(s_addr)) == ADDR_ALLOWED;
78 }
79 
_add_constraint(struct in_addr addr,int prefix_len,int value)80 static void _add_constraint(struct in_addr addr, int prefix_len, int value)
81 {
82 	constraint_set(constraint, ntohl(addr.s_addr), prefix_len, value);
83 	if (value == ADDR_ALLOWED) {
84 		bl_ll_add(whitelisted_cidrs, addr, prefix_len);
85 	} else if (value == ADDR_DISALLOWED) {
86 		bl_ll_add(blacklisted_cidrs, addr, prefix_len);
87 	} else {
88 		log_fatal("blacklist", "unknown type of blacklist operation specified");
89 	}
90 }
91 
92 // blacklist a CIDR network allocation
93 // e.g. blacklist_add("128.255.134.0", 24)
blacklist_prefix(char * ip,int prefix_len)94 void blacklist_prefix(char *ip, int prefix_len)
95 {
96 	struct in_addr addr;
97 	addr.s_addr = inet_addr(ip);
98 	_add_constraint(addr, prefix_len, ADDR_DISALLOWED);
99 }
100 
101 // whitelist a CIDR network allocation
whitelist_prefix(char * ip,int prefix_len)102 void whitelist_prefix(char *ip, int prefix_len)
103 {
104 	struct in_addr addr;
105 	addr.s_addr = inet_addr(ip);
106 	_add_constraint(addr, prefix_len, ADDR_ALLOWED);
107 }
108 
init_from_string(char * ip,int value)109 static int init_from_string(char *ip, int value)
110 {
111 	int prefix_len = 32;
112 	char *slash = strchr(ip, '/');
113 	if (slash) {  // split apart network and prefix length
114 		*slash = '\0';
115 		char *end;
116 		char *len = slash+1;
117 		errno = 0;
118 		prefix_len = strtol(len, &end, 10);
119 		if (end == len || errno != 0 || prefix_len < 0 || prefix_len > 32) {
120 			log_fatal("constraint", "'%s' is not a valid prefix length", len);
121 			return -1;
122 		}
123 	}
124 	struct in_addr addr;
125 	int ret = -1;
126 	if (inet_aton(ip, &addr) == 0) {
127 		// Not an IP and not a CIDR block, try dns resolution
128 		struct addrinfo hint, *res;
129 		memset(&hint, 0, sizeof(hint));
130 		hint.ai_family = PF_INET;
131 		int r = getaddrinfo(ip, NULL, &hint, &res);
132 		if (r) {
133 			log_error("constraint", "'%s' is not a valid IP "
134 				  "address or hostname", ip);
135 			return -1;
136 		}
137 		// Got some addrinfo, let's see what happens
138 		for (struct addrinfo *aip = res; aip; aip = aip->ai_next) {
139 			if (aip->ai_family != AF_INET) {
140 				continue;
141 			}
142 			struct sockaddr_in *sa = (struct sockaddr_in *) aip->ai_addr;
143 			memcpy(&addr, &sa->sin_addr, sizeof(addr));
144 			log_debug("constraint", "%s retrieved by hostname",
145 				  inet_ntoa(addr));
146 			ret = 0;
147 			_add_constraint(addr, prefix_len, value);
148 		}
149 	} else {
150 		_add_constraint(addr, prefix_len, value);
151 		return 0;
152 	}
153 	return ret;
154 }
155 
init_from_file(char * file,const char * name,int value,int ignore_invalid_hosts)156 static int init_from_file(char *file, const char *name, int value, int ignore_invalid_hosts)
157 {
158 	FILE *fp;
159 	char line[1000];
160 
161 	fp = fopen(file, "r");
162 	if (fp == NULL) {
163 		log_fatal(name, "unable to open %s file: %s: %s",
164 				name, file, strerror(errno));
165 	}
166 
167 	while (fgets(line, sizeof(line), fp) != NULL) {
168 		char *comment = strchr(line, '#');
169 		if (comment) {
170 			*comment = '\0';
171 		}
172 		char ip[33];
173 		if ((sscanf(line, "%32s", ip)) == EOF) {
174 			continue;
175 		}
176 		if (init_from_string(ip, value)) {
177 			if (!ignore_invalid_hosts) {
178 				log_fatal(name, "unable to parse %s file: %s",
179 						name, file);
180 			}
181 		}
182 	}
183 	fclose(fp);
184 
185 	return 0;
186 }
187 
init_from_array(char ** cidrs,size_t len,int value,int ignore_invalid_hosts)188 static void init_from_array(char **cidrs, size_t len, int value, int ignore_invalid_hosts)
189 {
190 	for (int i=0; i < (int) len; i++) {
191 		int ret = init_from_string(cidrs[i], value);
192                 if (ret && !ignore_invalid_hosts) {
193         			log_fatal("constraint",
194 		        			"Unable to init from CIDR list");
195                 }
196 	}
197 }
198 
blacklist_count_allowed()199 uint64_t blacklist_count_allowed()
200 {
201 	assert(constraint);
202 	return constraint_count_ips(constraint, ADDR_ALLOWED);
203 }
204 
blacklist_count_not_allowed()205 uint64_t blacklist_count_not_allowed()
206 {
207 	assert(constraint);
208 	return constraint_count_ips(constraint, ADDR_DISALLOWED);
209 }
210 
211 // Initialize address constraints from whitelist and blacklist files.
212 // Either can be set to NULL to omit.
blacklist_init(char * whitelist_filename,char * blacklist_filename,char ** whitelist_entries,size_t whitelist_entries_len,char ** blacklist_entries,size_t blacklist_entries_len,int ignore_invalid_hosts)213 int blacklist_init(char *whitelist_filename, char *blacklist_filename,
214 		char **whitelist_entries, size_t whitelist_entries_len,
215 		char **blacklist_entries, size_t blacklist_entries_len,
216         int ignore_invalid_hosts)
217 {
218 	assert(!constraint);
219 
220 	blacklisted_cidrs = xcalloc(1, sizeof(bl_ll_t));
221 
222 	whitelisted_cidrs = xcalloc(1, sizeof(bl_ll_t));
223 
224 	if (whitelist_filename && whitelist_entries) {
225 		log_warn("whitelist", "both a whitelist file and destination addresses "
226 					"were specified. The union of these two sources "
227 					"will be utilized.");
228 	}
229 	if (whitelist_filename || whitelist_entries) {
230 		// using a whitelist, so default to allowing nothing
231 		constraint = constraint_init(ADDR_DISALLOWED);
232 		log_debug("constraint", "blacklisting 0.0.0.0/0");
233 		if (whitelist_filename) {
234 			init_from_file(whitelist_filename, "whitelist", ADDR_ALLOWED,
235                     ignore_invalid_hosts);
236 		}
237 		if (whitelist_entries) {
238 			init_from_array(whitelist_entries,
239 					whitelist_entries_len, ADDR_ALLOWED,
240                     ignore_invalid_hosts);
241 		}
242 	} else {
243 		// no whitelist, so default to allowing everything
244 		constraint = constraint_init(ADDR_ALLOWED);
245 	}
246 	if (blacklist_filename) {
247 		init_from_file(blacklist_filename, "blacklist",
248                 ADDR_DISALLOWED, ignore_invalid_hosts);
249 	}
250 	if (blacklist_entries) {
251 		init_from_array(blacklist_entries,
252 				blacklist_entries_len, ADDR_DISALLOWED,
253                 ignore_invalid_hosts);
254 	}
255 	init_from_string(strdup("0.0.0.0"), ADDR_DISALLOWED);
256 	constraint_paint_value(constraint, ADDR_ALLOWED);
257 	uint64_t allowed = blacklist_count_allowed();
258 	log_debug("constraint", "%lu addresses (%0.0f%% of address "
259 			"space) can be scanned",
260 			allowed, allowed*100./((long long int)1 << 32));
261 	if (!allowed) {
262 		log_error("blacklist", "no addresses are eligible to be scanned in the "
263 			  "current configuration. This may be because the "
264 			  "blacklist being used by ZMap (%s) prevents "
265 			  "any addresses from receiving probe packets.",
266 			  blacklist_filename
267 			);
268 		return EXIT_FAILURE;
269 	}
270 	return EXIT_SUCCESS;
271 }
272