Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5adc1668 authored by Matthias Schiffer's avatar Matthias Schiffer Committed by Pablo Neira Ayuso
Browse files

netfilter: ebtables: add support for matching ICMP type and code



We already have ICMPv6 type/code matches. This adds support for IPv4 ICMP
matches in the same way.

Signed-off-by: default avatarMatthias Schiffer <mschiffer@universe-factory.net>
Acked-by: default avatarFlorian Westphal <fw@strlen.de>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent 20710b3b
Loading
Loading
Loading
Loading
+10 −3
Original line number Diff line number Diff line
@@ -24,8 +24,9 @@
#define EBT_IP_PROTO 0x08
#define EBT_IP_SPORT 0x10
#define EBT_IP_DPORT 0x20
#define EBT_IP_ICMP 0x40
#define EBT_IP_MASK (EBT_IP_SOURCE | EBT_IP_DEST | EBT_IP_TOS | EBT_IP_PROTO |\
 EBT_IP_SPORT | EBT_IP_DPORT )
		     EBT_IP_SPORT | EBT_IP_DPORT | EBT_IP_ICMP)
#define EBT_IP_MATCH "ip"

/* the same values are used for the invflags */
@@ -38,8 +39,14 @@ struct ebt_ip_info {
	__u8  protocol;
	__u8  bitmask;
	__u8  invflags;
	union {
		__u16 sport[2];
		__u8 icmp_type[2];
	};
	union {
		__u16 dport[2];
		__u8 icmp_code[2];
	};
};

#endif
+33 −10
Original line number Diff line number Diff line
@@ -19,9 +19,15 @@
#include <linux/netfilter_bridge/ebtables.h>
#include <linux/netfilter_bridge/ebt_ip.h>

struct tcpudphdr {
union pkthdr {
	struct {
		__be16 src;
		__be16 dst;
	} tcpudphdr;
	struct {
		u8 type;
		u8 code;
	} icmphdr;
};

static bool
@@ -30,8 +36,8 @@ ebt_ip_mt(const struct sk_buff *skb, struct xt_action_param *par)
	const struct ebt_ip_info *info = par->matchinfo;
	const struct iphdr *ih;
	struct iphdr _iph;
	const struct tcpudphdr *pptr;
	struct tcpudphdr _ports;
	const union pkthdr *pptr;
	union pkthdr _pkthdr;

	ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph);
	if (ih == NULL)
@@ -50,29 +56,38 @@ ebt_ip_mt(const struct sk_buff *skb, struct xt_action_param *par)
	if (info->bitmask & EBT_IP_PROTO) {
		if (NF_INVF(info, EBT_IP_PROTO, info->protocol != ih->protocol))
			return false;
		if (!(info->bitmask & EBT_IP_DPORT) &&
		    !(info->bitmask & EBT_IP_SPORT))
		if (!(info->bitmask & (EBT_IP_DPORT | EBT_IP_SPORT |
				       EBT_IP_ICMP)))
			return true;
		if (ntohs(ih->frag_off) & IP_OFFSET)
			return false;

		/* min icmp headersize is 4, so sizeof(_pkthdr) is ok. */
		pptr = skb_header_pointer(skb, ih->ihl*4,
					  sizeof(_ports), &_ports);
					  sizeof(_pkthdr), &_pkthdr);
		if (pptr == NULL)
			return false;
		if (info->bitmask & EBT_IP_DPORT) {
			u32 dst = ntohs(pptr->dst);
			u32 dst = ntohs(pptr->tcpudphdr.dst);
			if (NF_INVF(info, EBT_IP_DPORT,
				    dst < info->dport[0] ||
				    dst > info->dport[1]))
				return false;
		}
		if (info->bitmask & EBT_IP_SPORT) {
			u32 src = ntohs(pptr->src);
			u32 src = ntohs(pptr->tcpudphdr.src);
			if (NF_INVF(info, EBT_IP_SPORT,
				    src < info->sport[0] ||
				    src > info->sport[1]))
				return false;
		}
		if ((info->bitmask & EBT_IP_ICMP) &&
		    NF_INVF(info, EBT_IP_ICMP,
			    pptr->icmphdr.type < info->icmp_type[0] ||
			    pptr->icmphdr.type > info->icmp_type[1] ||
			    pptr->icmphdr.code < info->icmp_code[0] ||
			    pptr->icmphdr.code > info->icmp_code[1]))
			return false;
	}
	return true;
}
@@ -101,6 +116,14 @@ static int ebt_ip_mt_check(const struct xt_mtchk_param *par)
		return -EINVAL;
	if (info->bitmask & EBT_IP_SPORT && info->sport[0] > info->sport[1])
		return -EINVAL;
	if (info->bitmask & EBT_IP_ICMP) {
		if ((info->invflags & EBT_IP_PROTO) ||
		    info->protocol != IPPROTO_ICMP)
			return -EINVAL;
		if (info->icmp_type[0] > info->icmp_type[1] ||
		    info->icmp_code[0] > info->icmp_code[1])
			return -EINVAL;
	}
	return 0;
}