* Clarification of the procedure for filtering IP option fields @ 2024-12-31 10:54 Alexey Kashavkin 2025-01-30 13:52 ` Alexey Kashavkin 0 siblings, 1 reply; 6+ messages in thread From: Alexey Kashavkin @ 2024-12-31 10:54 UTC (permalink / raw) To: netfilter; +Cc: pablo, ssuryaextr 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@netfilter.org> 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. ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Clarification of the procedure for filtering IP option fields 2024-12-31 10:54 Clarification of the procedure for filtering IP option fields Alexey Kashavkin @ 2025-01-30 13:52 ` Alexey Kashavkin 2025-01-30 17:49 ` Pablo Neira Ayuso 0 siblings, 1 reply; 6+ messages in thread From: Alexey Kashavkin @ 2025-01-30 13:52 UTC (permalink / raw) To: netfilter; +Cc: pablo, ssuryaextr Hello, I am still figuring out the syntax for adding rules to filter IP options. Please, if anyone has an understanding of how this works give at least a short reply. I understand how the exthdr expression works in the kernel code. But so far there is still a question about specifying the type field, what is the purpose of this field here? There is also a question about other fields, let's take for example the IP option LSRR, it has an addr field. I assume, knowing this option from RFC791 it specifies IP addresses, but in the case of nft it is not so, this field has datatype intereger. With length and ptr fields it is clear, but with addr it is not. Please write how it works, what value is substituted in the addr field. Thanks in advance. > On 31 Dec 2024, at 13:54, Alexey Kashavkin <akashavkin@gmail.com> wrote: > > 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@netfilter.org> 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. ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Clarification of the procedure for filtering IP option fields 2025-01-30 13:52 ` Alexey Kashavkin @ 2025-01-30 17:49 ` Pablo Neira Ayuso 2025-01-30 17:52 ` Pablo Neira Ayuso 0 siblings, 1 reply; 6+ messages in thread From: Pablo Neira Ayuso @ 2025-01-30 17:49 UTC (permalink / raw) To: Alexey Kashavkin; +Cc: netfilter, ssuryaextr Hi, On Thu, Jan 30, 2025 at 04:52:29PM +0300, Alexey Kashavkin wrote: > Hello, > > I am still figuring out the syntax for adding rules to filter IP > options. Please, if anyone has an understanding of how this works > give at least a short reply. This 'type' field is redundant. > I understand how the exthdr expression works in the kernel code. But > so far there is still a question about specifying the type field, > what is the purpose of this field here? There is also a question > about other fields, let's take for example the IP option LSRR, it > has an addr field. I assume, knowing this option from RFC791 it > specifies IP addresses, but in the case of nft it is not so, this > field has datatype intereger. Yes, this should be at least 32-bits. > With length and ptr fields it is clear, but with addr it is not. > Please write how it works, what value is substituted in the addr > field. I remember to have mentioned the limitations of this with Stephen (only a few ip options can be matched), Stephen told me this was good enough for his use case at the time. I regret I did not push back harder on this. This extension really needs more work. ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Clarification of the procedure for filtering IP option fields 2025-01-30 17:49 ` Pablo Neira Ayuso @ 2025-01-30 17:52 ` Pablo Neira Ayuso 2025-01-30 18:06 ` Pablo Neira Ayuso 0 siblings, 1 reply; 6+ messages in thread From: Pablo Neira Ayuso @ 2025-01-30 17:52 UTC (permalink / raw) To: Alexey Kashavkin; +Cc: netfilter, ssuryaextr On Thu, Jan 30, 2025 at 06:49:41PM +0100, Pablo Neira Ayuso wrote: > Hi, > > On Thu, Jan 30, 2025 at 04:52:29PM +0300, Alexey Kashavkin wrote: > > Hello, > > > > I am still figuring out the syntax for adding rules to filter IP > > options. Please, if anyone has an understanding of how this works > > give at least a short reply. > > This 'type' field is redundant. > > > I understand how the exthdr expression works in the kernel code. But > > so far there is still a question about specifying the type field, > > what is the purpose of this field here? There is also a question > > about other fields, let's take for example the IP option LSRR, it > > has an addr field. I assume, knowing this option from RFC791 it > > specifies IP addresses, but in the case of nft it is not so, this > > field has datatype intereger. > > Yes, this should be at least 32-bits. Actually, this is 32-bits already: # nft describe ip option lsrr addr exthdr expression, datatype integer (integer), 32 bits ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Clarification of the procedure for filtering IP option fields 2025-01-30 17:52 ` Pablo Neira Ayuso @ 2025-01-30 18:06 ` Pablo Neira Ayuso 2025-01-30 23:23 ` Alexey Kashavkin 0 siblings, 1 reply; 6+ messages in thread From: Pablo Neira Ayuso @ 2025-01-30 18:06 UTC (permalink / raw) To: Alexey Kashavkin; +Cc: netfilter, ssuryaextr [-- Attachment #1: Type: text/plain, Size: 1257 bytes --] On Thu, Jan 30, 2025 at 06:52:52PM +0100, Pablo Neira Ayuso wrote: > On Thu, Jan 30, 2025 at 06:49:41PM +0100, Pablo Neira Ayuso wrote: > > Hi, > > > > On Thu, Jan 30, 2025 at 04:52:29PM +0300, Alexey Kashavkin wrote: > > > Hello, > > > > > > I am still figuring out the syntax for adding rules to filter IP > > > options. Please, if anyone has an understanding of how this works > > > give at least a short reply. > > > > This 'type' field is redundant. > > > > > I understand how the exthdr expression works in the kernel code. But > > > so far there is still a question about specifying the type field, > > > what is the purpose of this field here? There is also a question > > > about other fields, let's take for example the IP option LSRR, it > > > has an addr field. I assume, knowing this option from RFC791 it > > > specifies IP addresses, but in the case of nft it is not so, this > > > field has datatype intereger. > > > > Yes, this should be at least 32-bits. > > Actually, this is 32-bits already: > > # nft describe ip option lsrr addr > exthdr expression, datatype integer (integer), 32 bits This is what you mean: # nft describe ip option lsrr addr exthdr expression, datatype ipv4_addr (IPv4 address) (basetype integer), 32 bits [-- Attachment #2: ip-option-use-ipv4-type.patch --] [-- Type: text/x-diff, Size: 1560 bytes --] diff --git a/src/ipopt.c b/src/ipopt.c index 37f779d468ab..ddb42f5712d4 100644 --- a/src/ipopt.c +++ b/src/ipopt.c @@ -24,7 +24,7 @@ static const struct exthdr_desc ipopt_lsrr = { [IPOPT_FIELD_TYPE] = PHT("type", 0, 8), [IPOPT_FIELD_LENGTH] = PHT("length", 8, 8), [IPOPT_FIELD_PTR] = PHT("ptr", 16, 8), - [IPOPT_FIELD_ADDR_0] = PHT("addr", 24, 32), + [IPOPT_FIELD_ADDR_0] = PROTO_HDR_TEMPLATE("addr", &ipaddr_type, BYTEORDER_BIG_ENDIAN, 24, 32), }, }; @@ -35,7 +35,7 @@ static const struct exthdr_desc ipopt_rr = { [IPOPT_FIELD_TYPE] = PHT("type", 0, 8), [IPOPT_FIELD_LENGTH] = PHT("length", 8, 8), [IPOPT_FIELD_PTR] = PHT("ptr", 16, 8), - [IPOPT_FIELD_ADDR_0] = PHT("addr", 24, 32), + [IPOPT_FIELD_ADDR_0] = PROTO_HDR_TEMPLATE("addr", &ipaddr_type, BYTEORDER_BIG_ENDIAN, 24, 32), }, }; @@ -46,7 +46,7 @@ static const struct exthdr_desc ipopt_ssrr = { [IPOPT_FIELD_TYPE] = PHT("type", 0, 8), [IPOPT_FIELD_LENGTH] = PHT("length", 8, 8), [IPOPT_FIELD_PTR] = PHT("ptr", 16, 8), - [IPOPT_FIELD_ADDR_0] = PHT("addr", 24, 32), + [IPOPT_FIELD_ADDR_0] = PROTO_HDR_TEMPLATE("addr", &ipaddr_type, BYTEORDER_BIG_ENDIAN, 24, 32), }, }; @@ -56,7 +56,7 @@ static const struct exthdr_desc ipopt_ra = { .templates = { [IPOPT_FIELD_TYPE] = PHT("type", 0, 8), [IPOPT_FIELD_LENGTH] = PHT("length", 8, 8), - [IPOPT_FIELD_VALUE] = PHT("value", 16, 16), + [IPOPT_FIELD_ADDR_0] = PROTO_HDR_TEMPLATE("addr", &ipaddr_type, BYTEORDER_BIG_ENDIAN, 24, 32), }, }; ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: Clarification of the procedure for filtering IP option fields 2025-01-30 18:06 ` Pablo Neira Ayuso @ 2025-01-30 23:23 ` Alexey Kashavkin 0 siblings, 0 replies; 6+ messages in thread From: Alexey Kashavkin @ 2025-01-30 23:23 UTC (permalink / raw) To: Pablo Neira Ayuso; +Cc: netfilter, ssuryaextr > On 30 Jan 2025, at 21:06, Pablo Neira Ayuso <pablo@netfilter.org> wrote: > This is what you mean: > > # nft describe ip option lsrr addr > exthdr expression, datatype ipv4_addr (IPv4 address) (basetype integer), 32 bits > <ip-option-use-ipv4-type.patch> Yes, changing the data type for the addr field in the templates with this macro makes it more user friendly and allows the user to specify the first IP address in the IP option in the network packet as the value of the addr field. # nft list table ip ipopt table ip ipopt { chain ipopt { ip option lsrr addr 192.168.0.11 drop ip option lsrr addr 10.0.0.1 drop ip option lsrr length 11 counter packets 0 bytes 0 drop } } I assume that Stefan converted the IP to a decimal number and then already specified the resulting value in the addr field. For example like this: # echo '192*2^24 + 168*2^16 + 0 + 11' | bc 3232235531 # echo '10*2^24 + 0 + 0 + 1' | bc 167772161 # nft add rule ip ipopt_t test_ipopt_c ip option lsrr addr 3232235531 drop # nft add rule ip ipopt_t test_ipopt_c ip option lsrr addr 167772161 drop table ip ipopt_t { chain ipopt_c { ip option lsrr addr 3232235531 drop ip option lsrr addr 167772161 drop ip option lsrr length 11 counter packets 0 bytes 0 drop } } Without the type field in the templates as a token for bison and ipaddr_type as the data type, this functionality in nft becomes more correct according to RFC791. Thank you for the clarification. ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2025-01-30 23:23 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2024-12-31 10:54 Clarification of the procedure for filtering IP option fields Alexey Kashavkin 2025-01-30 13:52 ` Alexey Kashavkin 2025-01-30 17:49 ` Pablo Neira Ayuso 2025-01-30 17:52 ` Pablo Neira Ayuso 2025-01-30 18:06 ` Pablo Neira Ayuso 2025-01-30 23:23 ` Alexey Kashavkin
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).