Skip to content

Commit 4738c1d

Browse files
kaberdavem330
authored andcommitted
[SKFILTER]: Add SKF_ADF_NLATTR instruction
SKF_ADF_NLATTR searches for a netlink attribute, which avoids manually parsing and walking attributes. It takes the offset at which to start searching in the 'A' register and the attribute type in the 'X' register and returns the offset in the 'A' register. When the attribute is not found it returns zero. A top-level attribute can be located using a filter like this (example for nfnetlink, using struct nfgenmsg): ... { /* A = offset of first attribute */ .code = BPF_LD | BPF_IMM, .k = sizeof(struct nlmsghdr) + sizeof(struct nfgenmsg) }, { /* X = CTA_PROTOINFO */ .code = BPF_LDX | BPF_IMM, .k = CTA_PROTOINFO, }, { /* A = netlink attribute offset */ .code = BPF_LD | BPF_B | BPF_ABS, .k = SKF_AD_OFF + SKF_AD_NLATTR }, { /* Exit if not found */ .code = BPF_JMP | BPF_JEQ | BPF_K, .k = 0, .jt = <error> }, ... A nested attribute below the CTA_PROTOINFO attribute would then be parsed like this: ... { /* A += sizeof(struct nlattr) */ .code = BPF_ALU | BPF_ADD | BPF_K, .k = sizeof(struct nlattr), }, { /* X = CTA_PROTOINFO_TCP */ .code = BPF_LDX | BPF_IMM, .k = CTA_PROTOINFO_TCP, }, { /* A = netlink attribute offset */ .code = BPF_LD | BPF_B | BPF_ABS, .k = SKF_AD_OFF + SKF_AD_NLATTR }, ... The data of an attribute can be loaded into 'A' like this: ... { /* X = A (attribute offset) */ .code = BPF_MISC | BPF_TAX, }, { /* A = skb->data[X + k] */ .code = BPF_LD | BPF_B | BPF_IND, .k = sizeof(struct nlattr), }, ... Signed-off-by: Patrick McHardy <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 3cccd60 commit 4738c1d

File tree

2 files changed

+19
-1
lines changed

2 files changed

+19
-1
lines changed

include/linux/filter.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,8 @@ struct sock_fprog /* Required for SO_ATTACH_FILTER. */
121121
#define SKF_AD_PROTOCOL 0
122122
#define SKF_AD_PKTTYPE 4
123123
#define SKF_AD_IFINDEX 8
124-
#define SKF_AD_MAX 12
124+
#define SKF_AD_NLATTR 12
125+
#define SKF_AD_MAX 16
125126
#define SKF_NET_OFF (-0x100000)
126127
#define SKF_LL_OFF (-0x200000)
127128

net/core/filter.c

+17
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <linux/if_packet.h>
2828
#include <net/ip.h>
2929
#include <net/protocol.h>
30+
#include <net/netlink.h>
3031
#include <linux/skbuff.h>
3132
#include <net/sock.h>
3233
#include <linux/errno.h>
@@ -303,6 +304,22 @@ unsigned int sk_run_filter(struct sk_buff *skb, struct sock_filter *filter, int
303304
case SKF_AD_IFINDEX:
304305
A = skb->dev->ifindex;
305306
continue;
307+
case SKF_AD_NLATTR: {
308+
struct nlattr *nla;
309+
310+
if (skb_is_nonlinear(skb))
311+
return 0;
312+
if (A > skb->len - sizeof(struct nlattr))
313+
return 0;
314+
315+
nla = nla_find((struct nlattr *)&skb->data[A],
316+
skb->len - A, X);
317+
if (nla)
318+
A = (void *)nla - (void *)skb->data;
319+
else
320+
A = 0;
321+
continue;
322+
}
306323
default:
307324
return 0;
308325
}

0 commit comments

Comments
 (0)