Blame extensions/libebt_ip.c

Packit 7b22a4
/* ebt_ip
Packit 7b22a4
 *
Packit 7b22a4
 * Authors:
Packit 7b22a4
 * Bart De Schuymer <bdschuym@pandora.be>
Packit 7b22a4
 *
Packit 7b22a4
 * Changes:
Packit 7b22a4
 *    added ip-sport and ip-dport; parsing of port arguments is
Packit 7b22a4
 *    based on code from iptables-1.2.7a
Packit 7b22a4
 *    Innominate Security Technologies AG <mhopf@innominate.com>
Packit 7b22a4
 *    September, 2002
Packit 7b22a4
 *
Packit 7b22a4
 * Adapted by Arturo Borrero Gonzalez <arturo@debian.org>
Packit 7b22a4
 * to use libxtables for ebtables-compat in 2015.
Packit 7b22a4
 */
Packit 7b22a4
Packit 7b22a4
#include <stdio.h>
Packit 7b22a4
#include <stdlib.h>
Packit 7b22a4
#include <string.h>
Packit 7b22a4
#include <getopt.h>
Packit 7b22a4
#include <netdb.h>
Packit 7b22a4
#include <inttypes.h>
Packit 7b22a4
#include <xtables.h>
Packit 7b22a4
Packit 7b22a4
#include "libxt_icmp.h"
Packit 7b22a4
Packit 7b22a4
#define EBT_IP_SOURCE 0x01
Packit 7b22a4
#define EBT_IP_DEST 0x02
Packit 7b22a4
#define EBT_IP_TOS 0x04
Packit 7b22a4
#define EBT_IP_PROTO 0x08
Packit 7b22a4
#define EBT_IP_SPORT 0x10
Packit 7b22a4
#define EBT_IP_DPORT 0x20
Packit 7b22a4
#define EBT_IP_ICMP 0x40
Packit 7b22a4
#define EBT_IP_IGMP 0x80
Packit 7b22a4
#define EBT_IP_MASK (EBT_IP_SOURCE | EBT_IP_DEST | EBT_IP_TOS | EBT_IP_PROTO |\
Packit 7b22a4
		     EBT_IP_SPORT | EBT_IP_DPORT | EBT_IP_ICMP | EBT_IP_IGMP)
Packit 7b22a4
Packit 7b22a4
struct ebt_ip_info {
Packit 7b22a4
	__be32 saddr;
Packit 7b22a4
	__be32 daddr;
Packit 7b22a4
	__be32 smsk;
Packit 7b22a4
	__be32 dmsk;
Packit 7b22a4
	__u8  tos;
Packit 7b22a4
	__u8  protocol;
Packit 7b22a4
	__u8  bitmask;
Packit 7b22a4
	__u8  invflags;
Packit 7b22a4
	union {
Packit 7b22a4
		__u16 sport[2];
Packit 7b22a4
		__u8 icmp_type[2];
Packit 7b22a4
		__u8 igmp_type[2];
Packit 7b22a4
	};
Packit 7b22a4
	union {
Packit 7b22a4
		__u16 dport[2];
Packit 7b22a4
		__u8 icmp_code[2];
Packit 7b22a4
	};
Packit 7b22a4
};
Packit 7b22a4
Packit 7b22a4
#define IP_SOURCE	'1'
Packit 7b22a4
#define IP_DEST		'2'
Packit 7b22a4
#define IP_EBT_TOS	'3' /* include/bits/in.h seems to already define IP_TOS */
Packit 7b22a4
#define IP_PROTO	'4'
Packit 7b22a4
#define IP_SPORT	'5'
Packit 7b22a4
#define IP_DPORT	'6'
Packit 7b22a4
#define IP_EBT_ICMP	'7'
Packit 7b22a4
#define IP_EBT_IGMP	'8'
Packit 7b22a4
Packit 7b22a4
static const struct option brip_opts[] = {
Packit 7b22a4
	{ .name = "ip-source",		.has_arg = true, .val = IP_SOURCE },
Packit 7b22a4
	{ .name = "ip-src",		.has_arg = true, .val = IP_SOURCE },
Packit 7b22a4
	{ .name = "ip-destination",	.has_arg = true, .val = IP_DEST },
Packit 7b22a4
	{ .name = "ip-dst",		.has_arg = true, .val = IP_DEST },
Packit 7b22a4
	{ .name = "ip-tos",		.has_arg = true, .val = IP_EBT_TOS },
Packit 7b22a4
	{ .name = "ip-protocol",	.has_arg = true, .val = IP_PROTO },
Packit 7b22a4
	{ .name = "ip-proto",		.has_arg = true, .val = IP_PROTO },
Packit 7b22a4
	{ .name = "ip-source-port",	.has_arg = true, .val = IP_SPORT },
Packit 7b22a4
	{ .name = "ip-sport",		.has_arg = true, .val = IP_SPORT },
Packit 7b22a4
	{ .name = "ip-destination-port",.has_arg = true, .val = IP_DPORT },
Packit 7b22a4
	{ .name = "ip-dport",		.has_arg = true, .val = IP_DPORT },
Packit 7b22a4
	{ .name = "ip-icmp-type",       .has_arg = true, .val = IP_EBT_ICMP },
Packit 7b22a4
	{ .name = "ip-igmp-type",       .has_arg = true, .val = IP_EBT_IGMP },
Packit 7b22a4
	XT_GETOPT_TABLEEND,
Packit 7b22a4
};
Packit 7b22a4
Packit 7b22a4
static const struct xt_icmp_names icmp_codes[] = {
Packit 7b22a4
	{ "echo-reply", 0, 0, 0xFF },
Packit 7b22a4
	/* Alias */ { "pong", 0, 0, 0xFF },
Packit 7b22a4
Packit 7b22a4
	{ "destination-unreachable", 3, 0, 0xFF },
Packit 7b22a4
	{   "network-unreachable", 3, 0, 0 },
Packit 7b22a4
	{   "host-unreachable", 3, 1, 1 },
Packit 7b22a4
	{   "protocol-unreachable", 3, 2, 2 },
Packit 7b22a4
	{   "port-unreachable", 3, 3, 3 },
Packit 7b22a4
	{   "fragmentation-needed", 3, 4, 4 },
Packit 7b22a4
	{   "source-route-failed", 3, 5, 5 },
Packit 7b22a4
	{   "network-unknown", 3, 6, 6 },
Packit 7b22a4
	{   "host-unknown", 3, 7, 7 },
Packit 7b22a4
	{   "network-prohibited", 3, 9, 9 },
Packit 7b22a4
	{   "host-prohibited", 3, 10, 10 },
Packit 7b22a4
	{   "TOS-network-unreachable", 3, 11, 11 },
Packit 7b22a4
	{   "TOS-host-unreachable", 3, 12, 12 },
Packit 7b22a4
	{   "communication-prohibited", 3, 13, 13 },
Packit 7b22a4
	{   "host-precedence-violation", 3, 14, 14 },
Packit 7b22a4
	{   "precedence-cutoff", 3, 15, 15 },
Packit 7b22a4
Packit 7b22a4
	{ "source-quench", 4, 0, 0xFF },
Packit 7b22a4
Packit 7b22a4
	{ "redirect", 5, 0, 0xFF },
Packit 7b22a4
	{   "network-redirect", 5, 0, 0 },
Packit 7b22a4
	{   "host-redirect", 5, 1, 1 },
Packit 7b22a4
	{   "TOS-network-redirect", 5, 2, 2 },
Packit 7b22a4
	{   "TOS-host-redirect", 5, 3, 3 },
Packit 7b22a4
Packit 7b22a4
	{ "echo-request", 8, 0, 0xFF },
Packit 7b22a4
	/* Alias */ { "ping", 8, 0, 0xFF },
Packit 7b22a4
Packit 7b22a4
	{ "router-advertisement", 9, 0, 0xFF },
Packit 7b22a4
Packit 7b22a4
	{ "router-solicitation", 10, 0, 0xFF },
Packit 7b22a4
Packit 7b22a4
	{ "time-exceeded", 11, 0, 0xFF },
Packit 7b22a4
	/* Alias */ { "ttl-exceeded", 11, 0, 0xFF },
Packit 7b22a4
	{   "ttl-zero-during-transit", 11, 0, 0 },
Packit 7b22a4
	{   "ttl-zero-during-reassembly", 11, 1, 1 },
Packit 7b22a4
Packit 7b22a4
	{ "parameter-problem", 12, 0, 0xFF },
Packit 7b22a4
	{   "ip-header-bad", 12, 0, 0 },
Packit 7b22a4
	{   "required-option-missing", 12, 1, 1 },
Packit 7b22a4
Packit 7b22a4
	{ "timestamp-request", 13, 0, 0xFF },
Packit 7b22a4
Packit 7b22a4
	{ "timestamp-reply", 14, 0, 0xFF },
Packit 7b22a4
Packit 7b22a4
	{ "address-mask-request", 17, 0, 0xFF },
Packit 7b22a4
Packit 7b22a4
	{ "address-mask-reply", 18, 0, 0xFF }
Packit 7b22a4
};
Packit 7b22a4
Packit 7b22a4
static const struct xt_icmp_names igmp_types[] = {
Packit 7b22a4
	{ "membership-query", 0x11 },
Packit 7b22a4
	{ "membership-report-v1", 0x12 },
Packit 7b22a4
	{ "membership-report-v2", 0x16 },
Packit 7b22a4
	{ "leave-group", 0x17 },
Packit 7b22a4
	{ "membership-report-v3", 0x22 },
Packit 7b22a4
};
Packit 7b22a4
Packit 7b22a4
static void brip_print_help(void)
Packit 7b22a4
{
Packit 7b22a4
	printf(
Packit 7b22a4
"ip options:\n"
Packit 7b22a4
"--ip-src    [!] address[/mask]: ip source specification\n"
Packit 7b22a4
"--ip-dst    [!] address[/mask]: ip destination specification\n"
Packit 7b22a4
"--ip-tos    [!] tos           : ip tos specification\n"
Packit 7b22a4
"--ip-proto  [!] protocol      : ip protocol specification\n"
Packit 7b22a4
"--ip-sport  [!] port[:port]   : tcp/udp source port or port range\n"
Packit 7b22a4
"--ip-dport  [!] port[:port]   : tcp/udp destination port or port range\n"
Packit 7b22a4
"--ip-icmp-type [!] type[[:type]/code[:code]] : icmp type/code or type/code range\n"
Packit 7b22a4
"--ip-igmp-type [!] type[:type]               : igmp type or type range\n");
Packit 7b22a4
Packit 7b22a4
	printf("\nValid ICMP Types:\n");
Packit 7b22a4
	xt_print_icmp_types(icmp_codes, ARRAY_SIZE(icmp_codes));
Packit 7b22a4
	printf("\nValid IGMP Types:\n");
Packit 7b22a4
	xt_print_icmp_types(igmp_types, ARRAY_SIZE(igmp_types));
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void brip_init(struct xt_entry_match *match)
Packit 7b22a4
{
Packit 7b22a4
	struct ebt_ip_info *info = (struct ebt_ip_info *)match->data;
Packit 7b22a4
Packit 7b22a4
	info->invflags = 0;
Packit 7b22a4
	info->bitmask = 0;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void
Packit 7b22a4
parse_port_range(const char *protocol, const char *portstring, uint16_t *ports)
Packit 7b22a4
{
Packit 7b22a4
	char *buffer;
Packit 7b22a4
	char *cp;
Packit 7b22a4
Packit 7b22a4
	buffer = strdup(portstring);
Packit 7b22a4
	if ((cp = strchr(buffer, ':')) == NULL)
Packit 7b22a4
		ports[0] = ports[1] = xtables_parse_port(buffer, NULL);
Packit 7b22a4
	else {
Packit 7b22a4
		*cp = '\0';
Packit 7b22a4
		cp++;
Packit 7b22a4
Packit 7b22a4
		ports[0] = buffer[0] ? xtables_parse_port(buffer, NULL) : 0;
Packit 7b22a4
		ports[1] = cp[0] ? xtables_parse_port(cp, NULL) : 0xFFFF;
Packit 7b22a4
Packit 7b22a4
		if (ports[0] > ports[1])
Packit 7b22a4
			xtables_error(PARAMETER_PROBLEM,
Packit 7b22a4
				      "invalid portrange (min > max)");
Packit 7b22a4
	}
Packit 7b22a4
	free(buffer);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
/* original code from ebtables: useful_functions.c */
Packit 7b22a4
static int undot_ip(char *ip, unsigned char *ip2)
Packit 7b22a4
{
Packit 7b22a4
	char *p, *q, *end;
Packit 7b22a4
	long int onebyte;
Packit 7b22a4
	int i;
Packit 7b22a4
	char buf[20];
Packit 7b22a4
Packit 7b22a4
	strncpy(buf, ip, sizeof(buf) - 1);
Packit 7b22a4
Packit 7b22a4
	p = buf;
Packit 7b22a4
	for (i = 0; i < 3; i++) {
Packit 7b22a4
		if ((q = strchr(p, '.')) == NULL)
Packit 7b22a4
			return -1;
Packit 7b22a4
		*q = '\0';
Packit 7b22a4
		onebyte = strtol(p, &end, 10);
Packit 7b22a4
		if (*end != '\0' || onebyte > 255 || onebyte < 0)
Packit 7b22a4
			return -1;
Packit 7b22a4
		ip2[i] = (unsigned char)onebyte;
Packit 7b22a4
		p = q + 1;
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	onebyte = strtol(p, &end, 10);
Packit 7b22a4
	if (*end != '\0' || onebyte > 255 || onebyte < 0)
Packit 7b22a4
		return -1;
Packit 7b22a4
	ip2[3] = (unsigned char)onebyte;
Packit 7b22a4
Packit 7b22a4
	return 0;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static int ip_mask(char *mask, unsigned char *mask2)
Packit 7b22a4
{
Packit 7b22a4
	char *end;
Packit 7b22a4
	long int bits;
Packit 7b22a4
	uint32_t mask22;
Packit 7b22a4
Packit 7b22a4
	if (undot_ip(mask, mask2)) {
Packit 7b22a4
		/* not the /a.b.c.e format, maybe the /x format */
Packit 7b22a4
		bits = strtol(mask, &end, 10);
Packit 7b22a4
		if (*end != '\0' || bits > 32 || bits < 0)
Packit 7b22a4
			return -1;
Packit 7b22a4
		if (bits != 0) {
Packit 7b22a4
			mask22 = htonl(0xFFFFFFFF << (32 - bits));
Packit 7b22a4
			memcpy(mask2, &mask22, 4);
Packit 7b22a4
		} else {
Packit 7b22a4
			mask22 = 0xFFFFFFFF;
Packit 7b22a4
			memcpy(mask2, &mask22, 4);
Packit 7b22a4
		}
Packit 7b22a4
	}
Packit 7b22a4
	return 0;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void ebt_parse_ip_address(char *address, uint32_t *addr, uint32_t *msk)
Packit 7b22a4
{
Packit 7b22a4
	char *p;
Packit 7b22a4
Packit 7b22a4
	/* first the mask */
Packit 7b22a4
	if ((p = strrchr(address, '/')) != NULL) {
Packit 7b22a4
		*p = '\0';
Packit 7b22a4
		if (ip_mask(p + 1, (unsigned char *)msk)) {
Packit 7b22a4
			xtables_error(PARAMETER_PROBLEM,
Packit 7b22a4
				      "Problem with the IP mask '%s'", p + 1);
Packit 7b22a4
			return;
Packit 7b22a4
		}
Packit 7b22a4
	} else
Packit 7b22a4
		*msk = 0xFFFFFFFF;
Packit 7b22a4
Packit 7b22a4
	if (undot_ip(address, (unsigned char *)addr)) {
Packit 7b22a4
		xtables_error(PARAMETER_PROBLEM,
Packit 7b22a4
			      "Problem with the IP address '%s'", address);
Packit 7b22a4
		return;
Packit 7b22a4
	}
Packit 7b22a4
	*addr = *addr & *msk;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static char *parse_range(const char *str, unsigned int res[])
Packit 7b22a4
{
Packit 7b22a4
	char *next;
Packit 7b22a4
Packit 7b22a4
	if (!xtables_strtoui(str, &next, &res[0], 0, 255))
Packit 7b22a4
		return NULL;
Packit 7b22a4
Packit 7b22a4
	res[1] = res[0];
Packit 7b22a4
	if (*next == ':') {
Packit 7b22a4
		str = next + 1;
Packit 7b22a4
		if (!xtables_strtoui(str, &next, &res[1], 0, 255))
Packit 7b22a4
			return NULL;
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	return next;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static int ebt_parse_icmp(const struct xt_icmp_names *codes, size_t n_codes,
Packit 7b22a4
			  const char *icmptype, uint8_t type[], uint8_t code[])
Packit 7b22a4
{
Packit 7b22a4
	unsigned int match = n_codes;
Packit 7b22a4
	unsigned int i, number[2];
Packit 7b22a4
Packit 7b22a4
	for (i = 0; i < n_codes; i++) {
Packit 7b22a4
		if (strncasecmp(codes[i].name, icmptype, strlen(icmptype)))
Packit 7b22a4
			continue;
Packit 7b22a4
		if (match != n_codes)
Packit 7b22a4
			xtables_error(PARAMETER_PROBLEM, "Ambiguous ICMP type `%s':"
Packit 7b22a4
					" `%s' or `%s'?",
Packit 7b22a4
					icmptype, codes[match].name,
Packit 7b22a4
					codes[i].name);
Packit 7b22a4
		match = i;
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	if (match < n_codes) {
Packit 7b22a4
		type[0] = type[1] = codes[match].type;
Packit 7b22a4
		if (code) {
Packit 7b22a4
			code[0] = codes[match].code_min;
Packit 7b22a4
			code[1] = codes[match].code_max;
Packit 7b22a4
		}
Packit 7b22a4
	} else {
Packit 7b22a4
		char *next = parse_range(icmptype, number);
Packit 7b22a4
		if (!next) {
Packit 7b22a4
			xtables_error(PARAMETER_PROBLEM, "Unknown ICMP type `%s'",
Packit 7b22a4
							icmptype);
Packit 7b22a4
			return -1;
Packit 7b22a4
		}
Packit 7b22a4
Packit 7b22a4
		type[0] = (uint8_t) number[0];
Packit 7b22a4
		type[1] = (uint8_t) number[1];
Packit 7b22a4
		switch (*next) {
Packit 7b22a4
		case 0:
Packit 7b22a4
			if (code) {
Packit 7b22a4
				code[0] = 0;
Packit 7b22a4
				code[1] = 255;
Packit 7b22a4
			}
Packit 7b22a4
			return 0;
Packit 7b22a4
		case '/':
Packit 7b22a4
			if (code) {
Packit 7b22a4
				next = parse_range(next+1, number);
Packit 7b22a4
				code[0] = (uint8_t) number[0];
Packit 7b22a4
				code[1] = (uint8_t) number[1];
Packit 7b22a4
				if (next == NULL)
Packit 7b22a4
					return -1;
Packit 7b22a4
				if (next && *next == 0)
Packit 7b22a4
					return 0;
Packit 7b22a4
			}
Packit 7b22a4
		/* fallthrough */
Packit 7b22a4
		default:
Packit 7b22a4
			xtables_error(PARAMETER_PROBLEM, "unknown character %c", *next);
Packit 7b22a4
			return -1;
Packit 7b22a4
		}
Packit 7b22a4
	}
Packit 7b22a4
	return 0;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void print_icmp_code(uint8_t *code)
Packit 7b22a4
{
Packit 7b22a4
	if (!code)
Packit 7b22a4
		return;
Packit 7b22a4
Packit 7b22a4
	if (code[0] == code[1])
Packit 7b22a4
		printf("/%"PRIu8 " ", code[0]);
Packit 7b22a4
	else
Packit 7b22a4
		printf("/%"PRIu8":%"PRIu8 " ", code[0], code[1]);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void ebt_print_icmp_type(const struct xt_icmp_names *codes,
Packit 7b22a4
				size_t n_codes, uint8_t *type, uint8_t *code)
Packit 7b22a4
{
Packit 7b22a4
	unsigned int i;
Packit 7b22a4
Packit 7b22a4
	if (type[0] != type[1]) {
Packit 7b22a4
		printf("%"PRIu8 ":%" PRIu8, type[0], type[1]);
Packit 7b22a4
		print_icmp_code(code);
Packit 7b22a4
		return;
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	for (i = 0; i < n_codes; i++) {
Packit 7b22a4
		if (codes[i].type != type[0])
Packit 7b22a4
			continue;
Packit 7b22a4
Packit 7b22a4
		if (!code || (codes[i].code_min == code[0] &&
Packit 7b22a4
			      codes[i].code_max == code[1])) {
Packit 7b22a4
			printf("%s ", codes[i].name);
Packit 7b22a4
			return;
Packit 7b22a4
		}
Packit 7b22a4
	}
Packit 7b22a4
	printf("%"PRIu8, type[0]);
Packit 7b22a4
	print_icmp_code(code);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static int
Packit 7b22a4
brip_parse(int c, char **argv, int invert, unsigned int *flags,
Packit 7b22a4
	   const void *entry, struct xt_entry_match **match)
Packit 7b22a4
{
Packit 7b22a4
	struct ebt_ip_info *info = (struct ebt_ip_info *)(*match)->data;
Packit 7b22a4
Packit 7b22a4
	switch (c) {
Packit 7b22a4
	case IP_SOURCE:
Packit 7b22a4
		if (invert)
Packit 7b22a4
			info->invflags |= EBT_IP_SOURCE;
Packit 7b22a4
		ebt_parse_ip_address(optarg, &info->saddr, &info->smsk);
Packit 7b22a4
		info->bitmask |= EBT_IP_SOURCE;
Packit 7b22a4
		break;
Packit 7b22a4
	case IP_DEST:
Packit 7b22a4
		if (invert)
Packit 7b22a4
			info->invflags |= EBT_IP_DEST;
Packit 7b22a4
		ebt_parse_ip_address(optarg, &info->daddr, &info->dmsk);
Packit 7b22a4
		info->bitmask |= EBT_IP_DEST;
Packit 7b22a4
		break;
Packit 7b22a4
	case IP_SPORT:
Packit 7b22a4
		if (invert)
Packit 7b22a4
			info->invflags |= EBT_IP_SPORT;
Packit 7b22a4
		parse_port_range(NULL, optarg, info->sport);
Packit 7b22a4
		info->bitmask |= EBT_IP_SPORT;
Packit 7b22a4
		break;
Packit 7b22a4
	case IP_DPORT:
Packit 7b22a4
		if (invert)
Packit 7b22a4
			info->invflags |= EBT_IP_DPORT;
Packit 7b22a4
		parse_port_range(NULL, optarg, info->dport);
Packit 7b22a4
		info->bitmask |= EBT_IP_DPORT;
Packit 7b22a4
		break;
Packit 7b22a4
	case IP_EBT_ICMP:
Packit 7b22a4
		if (invert)
Packit 7b22a4
			info->invflags |= EBT_IP_ICMP;
Packit 7b22a4
		ebt_parse_icmp(icmp_codes, ARRAY_SIZE(icmp_codes), optarg,
Packit 7b22a4
			      info->icmp_type, info->icmp_code);
Packit 7b22a4
		info->bitmask |= EBT_IP_ICMP;
Packit 7b22a4
		break;
Packit 7b22a4
	case IP_EBT_IGMP:
Packit 7b22a4
		if (invert)
Packit 7b22a4
			info->invflags |= EBT_IP_IGMP;
Packit 7b22a4
		ebt_parse_icmp(igmp_types, ARRAY_SIZE(igmp_types), optarg,
Packit 7b22a4
			       info->igmp_type, NULL);
Packit 7b22a4
		info->bitmask |= EBT_IP_IGMP;
Packit 7b22a4
		break;
Packit 7b22a4
	case IP_EBT_TOS: {
Packit 7b22a4
		uintmax_t tosvalue;
Packit 7b22a4
Packit 7b22a4
		if (invert)
Packit 7b22a4
			info->invflags |= EBT_IP_TOS;
Packit 7b22a4
		if (!xtables_strtoul(optarg, NULL, &tosvalue, 0, 255))
Packit 7b22a4
			xtables_error(PARAMETER_PROBLEM,
Packit 7b22a4
				      "Problem with specified IP tos");
Packit 7b22a4
		info->tos = tosvalue;
Packit 7b22a4
		info->bitmask |= EBT_IP_TOS;
Packit 7b22a4
	}
Packit 7b22a4
		break;
Packit 7b22a4
	case IP_PROTO:
Packit 7b22a4
		if (invert)
Packit 7b22a4
			info->invflags |= EBT_IP_PROTO;
Packit 7b22a4
		info->protocol = xtables_parse_protocol(optarg);
Packit 7b22a4
		info->bitmask |= EBT_IP_PROTO;
Packit 7b22a4
		break;
Packit 7b22a4
	default:
Packit 7b22a4
		return 0;
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	*flags |= info->bitmask;
Packit 7b22a4
	return 1;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void brip_final_check(unsigned int flags)
Packit 7b22a4
{
Packit 7b22a4
	if (!flags)
Packit 7b22a4
		xtables_error(PARAMETER_PROBLEM,
Packit 7b22a4
			      "You must specify proper arguments");
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void print_port_range(uint16_t *ports)
Packit 7b22a4
{
Packit 7b22a4
	if (ports[0] == ports[1])
Packit 7b22a4
		printf("%d ", ports[0]);
Packit 7b22a4
	else
Packit 7b22a4
		printf("%d:%d ", ports[0], ports[1]);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void brip_print(const void *ip, const struct xt_entry_match *match,
Packit 7b22a4
		       int numeric)
Packit 7b22a4
{
Packit 7b22a4
	struct ebt_ip_info *info = (struct ebt_ip_info *)match->data;
Packit 7b22a4
	struct in_addr *addrp, *maskp;
Packit 7b22a4
Packit 7b22a4
	if (info->bitmask & EBT_IP_SOURCE) {
Packit 7b22a4
		printf("--ip-src ");
Packit 7b22a4
		if (info->invflags & EBT_IP_SOURCE)
Packit 7b22a4
			printf("! ");
Packit 7b22a4
		addrp = (struct in_addr *)&info->saddr;
Packit 7b22a4
		maskp = (struct in_addr *)&info->smsk;
Packit 7b22a4
		printf("%s%s ", xtables_ipaddr_to_numeric(addrp),
Packit 7b22a4
		       xtables_ipmask_to_numeric(maskp));
Packit 7b22a4
	}
Packit 7b22a4
	if (info->bitmask & EBT_IP_DEST) {
Packit 7b22a4
		printf("--ip-dst ");
Packit 7b22a4
		if (info->invflags & EBT_IP_DEST)
Packit 7b22a4
			printf("! ");
Packit 7b22a4
		addrp = (struct in_addr *)&info->daddr;
Packit 7b22a4
		maskp = (struct in_addr *)&info->dmsk;
Packit 7b22a4
		printf("%s%s ", xtables_ipaddr_to_numeric(addrp),
Packit 7b22a4
		       xtables_ipmask_to_numeric(maskp));
Packit 7b22a4
	}
Packit 7b22a4
	if (info->bitmask & EBT_IP_TOS) {
Packit 7b22a4
		printf("--ip-tos ");
Packit 7b22a4
		if (info->invflags & EBT_IP_TOS)
Packit 7b22a4
			printf("! ");
Packit 7b22a4
		printf("0x%02X ", info->tos);
Packit 7b22a4
	}
Packit 7b22a4
	if (info->bitmask & EBT_IP_PROTO) {
Packit 7b22a4
		struct protoent *pe;
Packit 7b22a4
Packit 7b22a4
		printf("--ip-proto ");
Packit 7b22a4
		if (info->invflags & EBT_IP_PROTO)
Packit 7b22a4
			printf("! ");
Packit 7b22a4
		pe = getprotobynumber(info->protocol);
Packit 7b22a4
		if (pe == NULL) {
Packit 7b22a4
			printf("%d ", info->protocol);
Packit 7b22a4
		} else {
Packit 7b22a4
			printf("%s ", pe->p_name);
Packit 7b22a4
		}
Packit 7b22a4
	}
Packit 7b22a4
	if (info->bitmask & EBT_IP_SPORT) {
Packit 7b22a4
		printf("--ip-sport ");
Packit 7b22a4
		if (info->invflags & EBT_IP_SPORT)
Packit 7b22a4
			printf("! ");
Packit 7b22a4
		print_port_range(info->sport);
Packit 7b22a4
	}
Packit 7b22a4
	if (info->bitmask & EBT_IP_DPORT) {
Packit 7b22a4
		printf("--ip-dport ");
Packit 7b22a4
		if (info->invflags & EBT_IP_DPORT)
Packit 7b22a4
			printf("! ");
Packit 7b22a4
		print_port_range(info->dport);
Packit 7b22a4
	}
Packit 7b22a4
	if (info->bitmask & EBT_IP_ICMP) {
Packit 7b22a4
		printf("--ip-icmp-type ");
Packit 7b22a4
		if (info->invflags & EBT_IP_ICMP)
Packit 7b22a4
			printf("! ");
Packit 7b22a4
		ebt_print_icmp_type(icmp_codes, ARRAY_SIZE(icmp_codes),
Packit 7b22a4
				    info->icmp_type, info->icmp_code);
Packit 7b22a4
	}
Packit 7b22a4
	if (info->bitmask & EBT_IP_IGMP) {
Packit 7b22a4
		printf("--ip-igmp-type ");
Packit 7b22a4
		if (info->invflags & EBT_IP_IGMP)
Packit 7b22a4
			printf("! ");
Packit 7b22a4
		ebt_print_icmp_type(igmp_types, ARRAY_SIZE(igmp_types),
Packit 7b22a4
				    info->igmp_type, NULL);
Packit 7b22a4
	}
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static const char *brip_xlate_proto_to_name(uint8_t proto)
Packit 7b22a4
{
Packit 7b22a4
	switch (proto) {
Packit 7b22a4
	case IPPROTO_TCP:
Packit 7b22a4
		return "tcp";
Packit 7b22a4
	case IPPROTO_UDP:
Packit 7b22a4
		return "udp";
Packit 7b22a4
	case IPPROTO_UDPLITE:
Packit 7b22a4
		return "udplite";
Packit 7b22a4
	case IPPROTO_SCTP:
Packit 7b22a4
		return "sctp";
Packit 7b22a4
	case IPPROTO_DCCP:
Packit 7b22a4
		return "dccp";
Packit 7b22a4
	default:
Packit 7b22a4
		return NULL;
Packit 7b22a4
	}
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void brip_xlate_icmp(struct xt_xlate *xl,
Packit 7b22a4
			    const struct ebt_ip_info *info, int bit)
Packit 7b22a4
{
Packit 7b22a4
	if ((info->bitmask & bit) == 0)
Packit 7b22a4
		return;
Packit 7b22a4
Packit 7b22a4
	xt_xlate_add(xl, "icmp type ");
Packit 7b22a4
	if (info->invflags & bit)
Packit 7b22a4
		xt_xlate_add(xl, "!= ");
Packit 7b22a4
	if (info->icmp_type[0] == info->icmp_type[1])
Packit 7b22a4
		xt_xlate_add(xl, "%d ", info->icmp_type[0]);
Packit 7b22a4
	else
Packit 7b22a4
		xt_xlate_add(xl, "%d-%d ", info->icmp_type[0],
Packit 7b22a4
					   info->icmp_type[1]);
Packit 7b22a4
	if (info->icmp_code[0] == 0 &&
Packit 7b22a4
	    info->icmp_code[1] == 0xff)
Packit 7b22a4
		return;
Packit 7b22a4
Packit 7b22a4
	xt_xlate_add(xl, "icmp code ");
Packit 7b22a4
	if (info->invflags & bit)
Packit 7b22a4
		xt_xlate_add(xl, "!= ");
Packit 7b22a4
	if (info->icmp_code[0] == info->icmp_code[1])
Packit 7b22a4
		xt_xlate_add(xl, "%d ", info->icmp_code[0]);
Packit 7b22a4
	else
Packit 7b22a4
		xt_xlate_add(xl, "%d-%d ", info->icmp_code[0],
Packit 7b22a4
					   info->icmp_code[1]);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void brip_xlate_igmp(struct xt_xlate *xl,
Packit 7b22a4
			    const struct ebt_ip_info *info, int bit)
Packit 7b22a4
{
Packit 7b22a4
	if ((info->bitmask & bit) == 0)
Packit 7b22a4
		return;
Packit 7b22a4
Packit 7b22a4
	xt_xlate_add(xl, "@th,0,8 ");
Packit 7b22a4
	if (info->invflags & bit)
Packit 7b22a4
		xt_xlate_add(xl, "!= ");
Packit 7b22a4
	if (info->icmp_type[0] == info->icmp_type[1])
Packit 7b22a4
		xt_xlate_add(xl, "%d ", info->icmp_type[0]);
Packit 7b22a4
	else
Packit 7b22a4
		xt_xlate_add(xl, "%d-%d ", info->icmp_type[0],
Packit 7b22a4
					   info->icmp_type[1]);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void brip_xlate_th(struct xt_xlate *xl,
Packit 7b22a4
			  const struct ebt_ip_info *info, int bit,
Packit 7b22a4
			  const char *pname)
Packit 7b22a4
{
Packit 7b22a4
	const uint16_t *ports;
Packit 7b22a4
Packit 7b22a4
	if ((info->bitmask & bit) == 0)
Packit 7b22a4
		return;
Packit 7b22a4
Packit 7b22a4
	switch (bit) {
Packit 7b22a4
	case EBT_IP_SPORT:
Packit 7b22a4
		if (pname)
Packit 7b22a4
			xt_xlate_add(xl, "%s sport ", pname);
Packit 7b22a4
		else
Packit 7b22a4
			xt_xlate_add(xl, "@th,0,16 ");
Packit 7b22a4
Packit 7b22a4
		ports = info->sport;
Packit 7b22a4
		break;
Packit 7b22a4
	case EBT_IP_DPORT:
Packit 7b22a4
		if (pname)
Packit 7b22a4
			xt_xlate_add(xl, "%s dport ", pname);
Packit 7b22a4
		else
Packit 7b22a4
			xt_xlate_add(xl, "@th,16,16 ");
Packit 7b22a4
Packit 7b22a4
		ports = info->dport;
Packit 7b22a4
		break;
Packit 7b22a4
	default:
Packit 7b22a4
		return;
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	if (info->invflags & bit)
Packit 7b22a4
		xt_xlate_add(xl, "!= ");
Packit 7b22a4
Packit 7b22a4
	if (ports[0] == ports[1])
Packit 7b22a4
		xt_xlate_add(xl, "%d ", ports[0]);
Packit 7b22a4
	else
Packit 7b22a4
		xt_xlate_add(xl, "%d-%d ", ports[0], ports[1]);
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static void brip_xlate_nh(struct xt_xlate *xl,
Packit 7b22a4
			  const struct ebt_ip_info *info, int bit)
Packit 7b22a4
{
Packit 7b22a4
	struct in_addr *addrp, *maskp;
Packit 7b22a4
Packit 7b22a4
	if ((info->bitmask & bit) == 0)
Packit 7b22a4
		return;
Packit 7b22a4
Packit 7b22a4
	switch (bit) {
Packit 7b22a4
	case EBT_IP_SOURCE:
Packit 7b22a4
		xt_xlate_add(xl, "ip saddr ");
Packit 7b22a4
		addrp = (struct in_addr *)&info->saddr;
Packit 7b22a4
		maskp = (struct in_addr *)&info->smsk;
Packit 7b22a4
		break;
Packit 7b22a4
	case EBT_IP_DEST:
Packit 7b22a4
		xt_xlate_add(xl, "ip daddr ");
Packit 7b22a4
		addrp = (struct in_addr *)&info->daddr;
Packit 7b22a4
		maskp = (struct in_addr *)&info->dmsk;
Packit 7b22a4
		break;
Packit 7b22a4
	default:
Packit 7b22a4
		return;
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	if (info->invflags & bit)
Packit 7b22a4
		xt_xlate_add(xl, "!= ");
Packit 7b22a4
Packit 7b22a4
	xt_xlate_add(xl, "%s%s ", xtables_ipaddr_to_numeric(addrp),
Packit 7b22a4
				  xtables_ipmask_to_numeric(maskp));
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static int brip_xlate(struct xt_xlate *xl,
Packit 7b22a4
		      const struct xt_xlate_mt_params *params)
Packit 7b22a4
{
Packit 7b22a4
	const struct ebt_ip_info *info = (const void *)params->match->data;
Packit 7b22a4
	const char *pname = NULL;
Packit 7b22a4
Packit 7b22a4
	brip_xlate_nh(xl, info, EBT_IP_SOURCE);
Packit 7b22a4
	brip_xlate_nh(xl, info, EBT_IP_DEST);
Packit 7b22a4
Packit 7b22a4
	if (info->bitmask & EBT_IP_TOS) {
Packit 7b22a4
		xt_xlate_add(xl, "ip dscp ");
Packit 7b22a4
		if (info->invflags & EBT_IP_TOS)
Packit 7b22a4
			xt_xlate_add(xl, "!= ");
Packit 7b22a4
		xt_xlate_add(xl, "0x%02x ", info->tos & 0x3f); /* remove ECN bits */
Packit 7b22a4
	}
Packit 7b22a4
	if (info->bitmask & EBT_IP_PROTO) {
Packit 7b22a4
		struct protoent *pe;
Packit 7b22a4
Packit 7b22a4
		if (info->bitmask & (EBT_IP_SPORT|EBT_IP_DPORT|EBT_IP_ICMP) &&
Packit 7b22a4
		    (info->invflags & EBT_IP_PROTO) == 0) {
Packit 7b22a4
			/* port number or icmp given and not inverted, no need to print this */
Packit 7b22a4
			pname = brip_xlate_proto_to_name(info->protocol);
Packit 7b22a4
		} else {
Packit 7b22a4
			xt_xlate_add(xl, "ip protocol ");
Packit 7b22a4
			if (info->invflags & EBT_IP_PROTO)
Packit 7b22a4
				xt_xlate_add(xl, "!= ");
Packit 7b22a4
			pe = getprotobynumber(info->protocol);
Packit 7b22a4
			if (pe == NULL)
Packit 7b22a4
				xt_xlate_add(xl, "%d ", info->protocol);
Packit 7b22a4
			else
Packit 7b22a4
				xt_xlate_add(xl, "%s ", pe->p_name);
Packit 7b22a4
		}
Packit 7b22a4
	}
Packit 7b22a4
Packit 7b22a4
	brip_xlate_th(xl, info, EBT_IP_SPORT, pname);
Packit 7b22a4
	brip_xlate_th(xl, info, EBT_IP_DPORT, pname);
Packit 7b22a4
Packit 7b22a4
	brip_xlate_icmp(xl, info, EBT_IP_ICMP);
Packit 7b22a4
	brip_xlate_igmp(xl, info, EBT_IP_IGMP);
Packit 7b22a4
Packit 7b22a4
	return 1;
Packit 7b22a4
}
Packit 7b22a4
Packit 7b22a4
static struct xtables_match brip_match = {
Packit 7b22a4
	.name		= "ip",
Packit 7b22a4
	.revision	= 0,
Packit 7b22a4
	.version	= XTABLES_VERSION,
Packit 7b22a4
	.family		= NFPROTO_BRIDGE,
Packit 7b22a4
	.size		= XT_ALIGN(sizeof(struct ebt_ip_info)),
Packit 7b22a4
	.userspacesize	= XT_ALIGN(sizeof(struct ebt_ip_info)),
Packit 7b22a4
	.init		= brip_init,
Packit 7b22a4
	.help		= brip_print_help,
Packit 7b22a4
	.parse		= brip_parse,
Packit 7b22a4
	.final_check	= brip_final_check,
Packit 7b22a4
	.print		= brip_print,
Packit 7b22a4
	.xlate		= brip_xlate,
Packit 7b22a4
	.extra_opts	= brip_opts,
Packit 7b22a4
};
Packit 7b22a4
Packit 7b22a4
void _init(void)
Packit 7b22a4
{
Packit 7b22a4
	xtables_register_match(&brip_match);
Packit 7b22a4
}