Clarification of the procedure for filtering IP option fields

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

I am investigating ip options filtering using the exthdr expression and exploring the code in the kernel and the following is not quite clear to me:  

> On 19 Aug 2019, at 17:58, Pablo Neira Ayuso <pablo@xxxxxxxxxxxxx> wrote:
> 
> * Match on IPv4 options, e.g.
> 
>        add rule x y ip option rr exists drop
> 
>  You can also match on type, ptr, length and addr fields of routing
>  options, e.g.
> 
>        add rule x y ip option rr type 1 drop
> 
>  lsrr, rr, ssrr and ra IPv4 options are supported.

What is meant by type in this example? As you can read in RFC791[1], the Record Route (rr) designation in this example is the type of the ip option. The first octet defines the option type, which is a constant and cannot have any other value. For clarity: 

> IPOPT_LSRR       (3 | IPOPT_CONTROL | IPOPT_COPY)  = type 131
> IPOPT_RR (7 | IPOPT_CONTROL)  = type 7
> IPOPT_SSRR       (9 | IPOPT_CONTROL | IPOPT_COPY)  = type 137
> IPOPT_RA         (20 | IPOPT_CONTROL | IPOPT_COPY)  = type 148


Based on the ipv4_find_option() function I can see that it only returns the value whether the option is present in the IP header or not and if it is present then its offset in the buffer is taken, but how is the addr field checked? For example, I want to filter traffic with LSRR option and certain addresses in the route data of this option, but I don't see in the kernel where it will be checked.

> static int ipv4_find_option(struct net *net, struct sk_buff *skb,
> 			    unsigned int *offset, int target)
> {
> 	unsigned char optbuf[sizeof(struct ip_options) + 40];
> 	struct ip_options *opt = (struct ip_options *)optbuf;
> 	struct iphdr *iph, _iph;
> 	unsigned int start;
> 	bool found = false;
> 	__be32 info;
> 	int optlen;
> 	iph = skb_header_pointer(skb, 0, sizeof(_iph), &_iph);
> 	if (!iph)
> 		return -EBADMSG;
> 	start = sizeof(struct iphdr);
> 	optlen = iph->ihl * 4 - (int)sizeof(struct iphdr);
> 	if (optlen <= 0)
> 		return -ENOENT;
> 	memset(opt, 0, sizeof(struct ip_options));
> 	/* Copy the options since __ip_options_compile() modifies
> 	 * the options.
> 	 */
> 	if (skb_copy_bits(skb, start, opt->__data, optlen))
> 		return -EBADMSG;
> 	opt->optlen = optlen;
> 	if (__ip_options_compile(net, opt, NULL, &info))
> 		return -EBADMSG;
> 	switch (target) {
> 	case IPOPT_SSRR:
> 	case IPOPT_LSRR:
> 		if (!opt->srr)
> 			break;
> 		found = target == IPOPT_SSRR ? opt->is_strictroute :
> 					       !opt->is_strictroute;
> 		if (found)
> 			*offset = opt->srr + start;
> 		break;
> 	case IPOPT_RR:
> 		if (!opt->rr)
> 			break;
> 		*offset = opt->rr + start;
> 		found = true;
> 		break;
> 	case IPOPT_RA:
> 		if (!opt->router_alert)
> 			break;
> 		*offset = opt->router_alert + start;
> 		found = true;
> 		break;
> 	default:
> 		return -EOPNOTSUPP;
> 	}
> 	return found ? target : -ENOENT;
> }

I also don't see a check in the nft_exthdr_ipv4_eval() function.

If you can make this point more transparent with a code example, I would really appreciate it. I need this for further writing my module for nftables.

1. https://www.rfc-editor.org/rfc/rfc791.html

Regards, 
Alexey.




[Index of Archives]     [Linux Netfilter Development]     [Linux Kernel Networking Development]     [Netem]     [Berkeley Packet Filter]     [Linux Kernel Development]     [Advanced Routing & Traffice Control]     [Bugtraq]

  Powered by Linux