Ejemplo n.º 1
0
/* Generate and set the filter for pcap. That way only the relevant packets will
 * be forwarded to us (in sniff()). Note that generate_pcap_filter() will first
 * generate a subfilter (=substring of the whole filter string) for each door if
 * door->pcap_filter_exp is NULL. This behaviour can be used for doors with one
 * time sequences, where the subfilter has to be generated after each sequence.
 */
void generate_pcap_filter()
{
	PMList *lp;
	opendoor_t *door;
	ip_literal_t *myip;
	char *buffer = NULL;   /* temporary buffer to create the individual filter strings */
	size_t bufsize = 0;    /* size of buffer */
	char port_str[10];     /* used by snprintf to convert unsigned short --> string */
	short head_set = 0;	   /* flag indicating if protocol head is set (i.e. "((tcp dst port") */
	short tcp_present = 0; /* flag indicating if TCP is used */
	short udp_present = 0; /* flag indicating if UDP is used */
	unsigned int i;
	short modified_filters = 0;  /* flag indicating if at least one filter has changed --> recompile the filter */
	struct bpf_program bpf_prog; /* compiled BPF filter program */

	/* generate subfilters for each door having a NULL pcap_filter_exp
	 *
	 * Example filter for one single door:
	 * ((tcp dst port 8000 or 8001 or 8002) and tcp[tcpflags] & tcp-syn != 0) or (udp dst port 4000 or 4001)
	 */
	for(lp = doors; lp; lp = lp->next) {
		door = (opendoor_t*)lp->data;

		if(door->pcap_filter_exp != NULL) {
			continue;
		}

		/* if we get here at least one door had a pcap_filter_exp == NULL */
		modified_filters = 1;

		head_set = 0;
		tcp_present = 0;
		udp_present = 0;

		/* allocate memory for buffer if needed.
		 * The first allocation will be 200 Bytes (should be large enough for common sequences). If there is
		 * not enough space, a call to realloc_strcat() will eventually increase its size. The buffer will be
		 * reused for successive doors */
		if(buffer == NULL) {
			bufsize = 200;
			buffer = (char*)malloc(sizeof(char) * bufsize);
			if(buffer == NULL) {
				perror("malloc");
				cleanup(1);
			}
			buffer[0] = '\0';
		}

		/* accept only incoming packets */
		for(myip = myips; myip != NULL; myip = myip->next) {
			if(!head_set) {
				bufsize = realloc_strcat(&buffer, "((dst host ", bufsize);
				head_set = 1;
			} else {
				bufsize = realloc_strcat(&buffer, " or dst host ", bufsize);
			}
			bufsize = realloc_strcat(&buffer, door->target ? door->target : myip->value, bufsize);
		}

		bufsize = realloc_strcat(&buffer, ") and (", bufsize);
		head_set = 0;

		/* generate filter for all TCP ports (i.e. "((tcp dst port 4000 or 4001 or 4002) and tcp[tcpflags] & tcp-syn != 0)" */
		for(i = 0; i < door->seqcount; i++) {
			if(door->protocol[i] == IPPROTO_TCP) {
				if(!head_set) {		/* first TCP port in the sequence */
					bufsize = realloc_strcat(&buffer, "((tcp dst port ", bufsize);
					head_set = 1;
					tcp_present = 1;
				} else {		/* not the first TCP port in the sequence */
					bufsize = realloc_strcat(&buffer, " or ", bufsize);
				}
				snprintf(port_str, sizeof(port_str), "%hu", door->sequence[i]);		/* unsigned short to string */
				bufsize = realloc_strcat(&buffer, port_str, bufsize);			/* append port number */
			}
		}
		if(tcp_present) {
			bufsize = realloc_strcat(&buffer, ")", bufsize);		/* close parentheses of TCP ports */
		}

		/* append the TCP flag filters */
		if(tcp_present) {
			if(door->flag_fin != DONT_CARE) {
				bufsize = realloc_strcat(&buffer, " and tcp[tcpflags] & tcp-fin ", bufsize);
				if(door->flag_fin == SET) {
					bufsize = realloc_strcat(&buffer, "!= 0", bufsize);
				}
				if(door->flag_fin == NOT_SET) {
					bufsize = realloc_strcat(&buffer, "== 0", bufsize);
				}
			}
			if(door->flag_syn != DONT_CARE) {
				bufsize = realloc_strcat(&buffer, " and tcp[tcpflags] & tcp-syn ", bufsize);
				if(door->flag_syn == SET) {
					bufsize = realloc_strcat(&buffer, "!= 0", bufsize);
				}
				if(door->flag_syn == NOT_SET) {
					bufsize = realloc_strcat(&buffer, "== 0", bufsize);
				}
			}
			if(door->flag_rst != DONT_CARE) {
				bufsize = realloc_strcat(&buffer, " and tcp[tcpflags] & tcp-rst ", bufsize);
				if(door->flag_rst == SET) {
					bufsize = realloc_strcat(&buffer, "!= 0", bufsize);
				}
				if(door->flag_rst == NOT_SET) {
					bufsize = realloc_strcat(&buffer, "== 0", bufsize);
				}
			}
			if(door->flag_psh != DONT_CARE) {
				bufsize = realloc_strcat(&buffer, " and tcp[tcpflags] & tcp-push ", bufsize);
				if(door->flag_psh == SET) {
					bufsize = realloc_strcat(&buffer, "!= 0", bufsize);
				}
				if(door->flag_psh == NOT_SET) {
					bufsize = realloc_strcat(&buffer, "== 0", bufsize);
				}
			}
			if(door->flag_ack != DONT_CARE) {
				bufsize = realloc_strcat(&buffer, " and tcp[tcpflags] & tcp-ack ", bufsize);
				if(door->flag_ack == SET) {
					bufsize = realloc_strcat(&buffer, "!= 0", bufsize);
				}
				if(door->flag_ack == NOT_SET) {
					bufsize = realloc_strcat(&buffer, "== 0", bufsize);
				}
			}
			if(door->flag_urg != DONT_CARE) {
				bufsize = realloc_strcat(&buffer, " and tcp[tcpflags] & tcp-urg ", bufsize);
				if(door->flag_urg == SET) {
					bufsize = realloc_strcat(&buffer, "!= 0", bufsize);
				}
				if(door->flag_urg == NOT_SET) {
					bufsize = realloc_strcat(&buffer, "== 0", bufsize);
				}
			}
			bufsize = realloc_strcat(&buffer, ")", bufsize);		/* close parentheses of flags */
		}

		/* append filter for all UDP ports (i.e. "(udp dst port 6543 or 6544 or 6545)" */
		head_set = 0;
		for(i = 0; i < door->seqcount; i++) {
			if(door->protocol[i] == IPPROTO_UDP) {
				if(!head_set) {		/* first UDP port in the sequence */
					if(tcp_present) {
						bufsize = realloc_strcat(&buffer, " or ", bufsize);
					}
					bufsize = realloc_strcat(&buffer, "(udp dst port ", bufsize);
					head_set = 1;
					udp_present = 1;
				} else {		/* not the first UDP port in the sequence */
					bufsize = realloc_strcat(&buffer, " or ", bufsize);
				}
				snprintf(port_str, sizeof(port_str), "%hu", door->sequence[i]);		/* unsigned short to string */
				bufsize = realloc_strcat(&buffer, port_str, bufsize);			/* append port number */
			}
		}
		if(udp_present) {
			bufsize = realloc_strcat(&buffer, ")", bufsize);		/* close parentheses of UDP ports */
		}

		bufsize = realloc_strcat(&buffer, "))", bufsize);		/* close parantheses around port filters */

		/* test if in any of the precedent calls to realloc_strcat() failed. We can do this safely here because
		 * realloc_strcat() returns 0 on failure and if a buffer size of 0 is passed to it, the function does
		 * nothing but returning 0 again. Because we never read buffer in the above code, it is secure to test
		 * for failure only at this point (it makes the code more readable than checking for failure each time
		 * realloc_strcat() is called). */
		if(bufsize == 0) {
			perror("realloc");
			cleanup(1);
		}

		/* allocate the buffer in door holding the filter string, copy it and prepare buffer for being reused. */
		door->pcap_filter_exp = (char*)malloc(strlen(buffer) + 1);
		if(door->pcap_filter_exp == NULL) {
			perror("malloc");
			cleanup(1);
		}
		strcpy(door->pcap_filter_exp, buffer);
		dprint("Adding pcap expression for door '%s': %s\n", door->name, door->pcap_filter_exp);
		buffer[0] = '\0';	/* "clear" the buffer */
	}


	/* generate the whole pcap filter string if a filter had been modified. Reuse buffer (already "cleared").
	 *
	 * Note that we don't check if a port is included in multiple doors, we simply concatenate the individual door
	 * filters and rely on pcap's optimization capabilities.
	 *
	 * Example filter for two doors with sequences 8000:tcp,4000:udp,8001:tcp,4001:udp,8002:tcp (syn) and
	 * 1234:tcp,4567:tcp,8901:tcp (syn,ack) :
	 * dst host the.hosts.ip.address and (
	 *      ((tcp dst port 8000 or 8001 or 8002) and tcp[tcpflags] & tcp-syn != 0) or (udp dst port 4000 or 4001)
	 *   or ((tcp dst port 1234 or 4567 or 8901) and tcp[tcpflags] & tcp-syn != 0 and tcp[tcpflags] & tcp-ack != 0)
	 * )
	 */
	if(modified_filters) {
		/* iterate over all doors */
		for(lp = doors; lp; lp = lp->next) {
			door = (opendoor_t*)lp->data;
			bufsize = realloc_strcat(&buffer, door->pcap_filter_exp, bufsize);
			if(lp->next != NULL) {
				bufsize = realloc_strcat(&buffer, " or ", bufsize);
			}
		}

		/* test if in any of the precedent calls to realloc_strcat() failed. See above why this is ok to do this only
		 * at this point */
		if(bufsize == 0) {
			perror("realloc");
			cleanup(1);
		}

		if(pcap_compile(cap, &bpf_prog, buffer, 1, 0) < 0) {	/* optimize filter (1), no netmask (0) (we're not interested in broadcasts) */
			pcap_perror(cap, "pcap");
			cleanup(1);
		}
		if(pcap_setfilter(cap, &bpf_prog) < 0) {
			pcap_perror(cap, "pcap");
			cleanup(1);
		}
		pcap_freecode(&bpf_prog);
		free(buffer);
	}
}
Ejemplo n.º 2
0
int
apply_substitution(struct bsdtar *bsdtar, const char *name, char **result,
    int symlink_target, int hardlink_target)
{
	const char *path = name;
	regmatch_t matches[10];
	size_t i, j;
	struct subst_rule *rule;
	struct substitution *subst;
	int c, got_match, print_match;

	*result = NULL;

	if ((subst = bsdtar->substitution) == NULL)
		return 0;

	got_match = 0;
	print_match = 0;

	for (rule = subst->first_rule; rule != NULL; rule = rule->next) {
		if (symlink_target) {
			if (!rule->symlink)
				continue;
		} else if (hardlink_target) {
			if (!rule->hardlink)
				continue;
		} else { /* Regular filename. */
			if (!rule->regular)
				continue;
		}

		if (regexec(&rule->re, name, 10, matches, 0))
			continue;

		got_match = 1;
		print_match |= rule->print;
		realloc_strncat(result, name, matches[0].rm_so);

		for (i = 0, j = 0; rule->result[i] != '\0'; ++i) {
			if (rule->result[i] == '~') {
				realloc_strncat(result, rule->result + j, i - j);
				realloc_strncat(result,
				    name + matches[0].rm_so,
				    matches[0].rm_eo - matches[0].rm_so);
				j = i + 1;
				continue;
			}
			if (rule->result[i] != '\\')
				continue;

			++i;
			c = rule->result[i];
			switch (c) {
			case '~':
			case '\\':
				realloc_strncat(result, rule->result + j, i - j - 1);
				j = i;
				break;
			case '1':
			case '2':
			case '3':
			case '4':
			case '5':
			case '6':
			case '7':
			case '8':
			case '9':
				realloc_strncat(result, rule->result + j, i - j - 1);
				if ((size_t)(c - '0') > (size_t)(rule->re.re_nsub)) {
					free(*result);
					*result = NULL;
					return -1;
				}
				realloc_strncat(result, name + matches[c - '0'].rm_so, matches[c - '0'].rm_eo - matches[c - '0'].rm_so);
				j = i + 1;
				break;
			default:
				/* Just continue; */
				break;
			}

		}

		realloc_strcat(result, rule->result + j);

		name += matches[0].rm_eo;

		if (!rule->global)
			break;
	}

	if (got_match)
		realloc_strcat(result, name);

	if (print_match)
		fprintf(stderr, "%s >> %s\n", path, *result);

	return got_match;
}