diff mbox series

[PATCHv2] netfilter: nfnetlink_log:add support for VLAN information

Message ID 20190820112617.18095-1-michael-dev@fami-braun.de
State Changes Requested
Delegated to: Pablo Neira
Headers show
Series [PATCHv2] netfilter: nfnetlink_log:add support for VLAN information | expand

Commit Message

michael-dev Aug. 20, 2019, 11:26 a.m. UTC
Currently, there is no vlan information (e.g. when used with a vlan aware
bridge) passed to userspache, HWHEADER will contain an 08 00 (ip) suffix
even for tagged ip packets.

Therefore, add an extra netlink attribute that passes the vlan information
to userspace similarly to 15824ab29f for nfqueue.

Signed-off-by: Michael Braun <michael-dev@fami-braun.de>

--
v2: mirror nfqueue behaviour
---
 include/uapi/linux/netfilter/nfnetlink_log.h | 11 ++++++
 net/netfilter/nf_log_common.c                |  2 +
 net/netfilter/nfnetlink_log.c                | 40 ++++++++++++++++++++
 3 files changed, 53 insertions(+)

Comments

Pablo Neira Ayuso Aug. 20, 2019, 11:49 a.m. UTC | #1
On Tue, Aug 20, 2019 at 01:26:17PM +0200, Michael Braun wrote:
[...]
> diff --git a/include/uapi/linux/netfilter/nfnetlink_log.h b/include/uapi/linux/netfilter/nfnetlink_log.h
> index 20983cb195a0..45c8d3b027e0 100644
> --- a/include/uapi/linux/netfilter/nfnetlink_log.h
> +++ b/include/uapi/linux/netfilter/nfnetlink_log.h
> @@ -33,6 +33,15 @@ struct nfulnl_msg_packet_timestamp {
>  	__aligned_be64	usec;
>  };
>  
> +enum nfulnl_vlan_attr {
> +	NFULA_VLAN_UNSPEC,
> +	NFULA_VLAN_PROTO,		/* __be16 skb vlan_proto */
> +	NFULA_VLAN_TCI,			/* __be16 skb htons(vlan_tci) */
> +	__NFULA_VLAN_MAX,
> +};
> +
> +#define NFULA_VLAN_MAX (__NFULA_VLAN_MAX + 1)
> +
>  enum nfulnl_attr_type {
>  	NFULA_UNSPEC,
>  	NFULA_PACKET_HDR,
> @@ -54,6 +63,8 @@ enum nfulnl_attr_type {
>  	NFULA_HWLEN,			/* hardware header length */
>  	NFULA_CT,                       /* nf_conntrack_netlink.h */
>  	NFULA_CT_INFO,                  /* enum ip_conntrack_info */
> +	NFULA_VLAN,			/* nested attribute: packet vlan info */
> +	NFULA_L2HDR,			/* full L2 header */
>  
>  	__NFULA_MAX
>  };
> diff --git a/net/netfilter/nf_log_common.c b/net/netfilter/nf_log_common.c
> index ae5628ddbe6d..c127bcc119d8 100644
> --- a/net/netfilter/nf_log_common.c
> +++ b/net/netfilter/nf_log_common.c
> @@ -167,6 +167,8 @@ nf_log_dump_packet_common(struct nf_log_buf *m, u_int8_t pf,
>  	physoutdev = nf_bridge_get_physoutdev(skb);
>  	if (physoutdev && out != physoutdev)
>  		nf_log_buf_add(m, "PHYSOUT=%s ", physoutdev->name);
> +	if (skb_vlan_tag_present(skb))
> +		nf_log_buf_add(m, "VLAN=%d ", skb_vlan_tag_get_id(skb));
>  #endif
>  }
>  EXPORT_SYMBOL_GPL(nf_log_dump_packet_common);
> diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
> index 6dee4f9a944c..dd5b63205d31 100644
> --- a/net/netfilter/nfnetlink_log.c
> +++ b/net/netfilter/nfnetlink_log.c
> @@ -385,6 +385,40 @@ nfulnl_timer(struct timer_list *t)
>  	instance_put(inst);
>  }
>  
> +#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)

This could be used from nftables netdev family (ingress type chains),
I think you can remove this #if.

Unlike nfqueue, there's support for nfnetlink_log from nftables netdev
family. You can test it with this:

table netdev x {
        chain y {
                type filter hook ingress device "eth0" priority filter; policy accept;
                log prefix "test: " group 10
        }
}

I think you can safely remove this #if.

> +static int nfulnl_put_bridge(struct nfulnl_instance *inst, struct sk_buff *skb)
> +{
> +	if (!skb_mac_header_was_set(skb))
> +		return 0;
> +
> +	if (skb_vlan_tag_present(skb)) {
> +		struct nlattr *nest;
> +
> +		nest = nla_nest_start(inst->skb, NFULA_VLAN);
> +		if (!nest)
> +			goto nla_put_failure;
> +
> +		if (nla_put_be16(inst->skb, NFULA_VLAN_TCI, htons(skb->vlan_tci)) ||
> +		    nla_put_be16(inst->skb, NFULA_VLAN_PROTO, skb->vlan_proto))
> +			goto nla_put_failure;
> +
> +		nla_nest_end(inst->skb, nest);
> +	}
> +
> +	if (skb->mac_header < skb->network_header) {
> +		int len = (int)(skb->network_header - skb->mac_header);
> +
> +		if (nla_put(inst->skb, NFULA_L2HDR, len, skb_mac_header(skb)))
> +			goto nla_put_failure;
> +	}
> +
> +	return 0;
> +
> +nla_put_failure:
> +	return -1;
> +}
> +#endif /* IS_ENABLED(CONFIG_BRIDGE_NETFILTER) */
> +
>  /* This is an inline function, we don't really care about a long
>   * list of arguments */
>  static inline int
> @@ -580,6 +614,12 @@ __build_packet_message(struct nfnl_log_net *log,
>  				 NFULA_CT, NFULA_CT_INFO) < 0)
>  		goto nla_put_failure;
>  
> +#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
> +	if (pf == PF_BRIDGE &&

Allow for NFPROTO_NETDEV where too, please.

Thanks.
Florian Westphal Aug. 20, 2019, 11:50 a.m. UTC | #2
Michael Braun <michael-dev@fami-braun.de> wrote:
> Currently, there is no vlan information (e.g. when used with a vlan aware
> bridge) passed to userspache, HWHEADER will contain an 08 00 (ip) suffix
> even for tagged ip packets.
> 
> Therefore, add an extra netlink attribute that passes the vlan information
> to userspace similarly to 15824ab29f for nfqueue.
> 
> Signed-off-by: Michael Braun <michael-dev@fami-braun.de>
> 
> --
> v2: mirror nfqueue behaviour

Thanks, looks good with one minor detail, see below.

>  /* This is an inline function, we don't really care about a long
>   * list of arguments */
>  static inline int
> @@ -580,6 +614,12 @@ __build_packet_message(struct nfnl_log_net *log,
>  				 NFULA_CT, NFULA_CT_INFO) < 0)
>  		goto nla_put_failure;

In nfulnl_log_packet(), you will need to add to "size" calculation, i.e.

+= nla_total_size(0)  /* nested */
+= nla_total_size(sizef(u16)) /* id */
+= nla_total_size(sizef(u16)) /* tag */

Furthermore (Unrelated to your patch), I think that the end of
__build_packet_message() (error handling) lacks a call to
nlmsg_cancel().

The printk could be removed and replaced by a WARN_ON_ONCE, it should
never be hit.
diff mbox series

Patch

diff --git a/include/uapi/linux/netfilter/nfnetlink_log.h b/include/uapi/linux/netfilter/nfnetlink_log.h
index 20983cb195a0..45c8d3b027e0 100644
--- a/include/uapi/linux/netfilter/nfnetlink_log.h
+++ b/include/uapi/linux/netfilter/nfnetlink_log.h
@@ -33,6 +33,15 @@  struct nfulnl_msg_packet_timestamp {
 	__aligned_be64	usec;
 };
 
+enum nfulnl_vlan_attr {
+	NFULA_VLAN_UNSPEC,
+	NFULA_VLAN_PROTO,		/* __be16 skb vlan_proto */
+	NFULA_VLAN_TCI,			/* __be16 skb htons(vlan_tci) */
+	__NFULA_VLAN_MAX,
+};
+
+#define NFULA_VLAN_MAX (__NFULA_VLAN_MAX + 1)
+
 enum nfulnl_attr_type {
 	NFULA_UNSPEC,
 	NFULA_PACKET_HDR,
@@ -54,6 +63,8 @@  enum nfulnl_attr_type {
 	NFULA_HWLEN,			/* hardware header length */
 	NFULA_CT,                       /* nf_conntrack_netlink.h */
 	NFULA_CT_INFO,                  /* enum ip_conntrack_info */
+	NFULA_VLAN,			/* nested attribute: packet vlan info */
+	NFULA_L2HDR,			/* full L2 header */
 
 	__NFULA_MAX
 };
diff --git a/net/netfilter/nf_log_common.c b/net/netfilter/nf_log_common.c
index ae5628ddbe6d..c127bcc119d8 100644
--- a/net/netfilter/nf_log_common.c
+++ b/net/netfilter/nf_log_common.c
@@ -167,6 +167,8 @@  nf_log_dump_packet_common(struct nf_log_buf *m, u_int8_t pf,
 	physoutdev = nf_bridge_get_physoutdev(skb);
 	if (physoutdev && out != physoutdev)
 		nf_log_buf_add(m, "PHYSOUT=%s ", physoutdev->name);
+	if (skb_vlan_tag_present(skb))
+		nf_log_buf_add(m, "VLAN=%d ", skb_vlan_tag_get_id(skb));
 #endif
 }
 EXPORT_SYMBOL_GPL(nf_log_dump_packet_common);
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
index 6dee4f9a944c..dd5b63205d31 100644
--- a/net/netfilter/nfnetlink_log.c
+++ b/net/netfilter/nfnetlink_log.c
@@ -385,6 +385,40 @@  nfulnl_timer(struct timer_list *t)
 	instance_put(inst);
 }
 
+#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
+static int nfulnl_put_bridge(struct nfulnl_instance *inst, struct sk_buff *skb)
+{
+	if (!skb_mac_header_was_set(skb))
+		return 0;
+
+	if (skb_vlan_tag_present(skb)) {
+		struct nlattr *nest;
+
+		nest = nla_nest_start(inst->skb, NFULA_VLAN);
+		if (!nest)
+			goto nla_put_failure;
+
+		if (nla_put_be16(inst->skb, NFULA_VLAN_TCI, htons(skb->vlan_tci)) ||
+		    nla_put_be16(inst->skb, NFULA_VLAN_PROTO, skb->vlan_proto))
+			goto nla_put_failure;
+
+		nla_nest_end(inst->skb, nest);
+	}
+
+	if (skb->mac_header < skb->network_header) {
+		int len = (int)(skb->network_header - skb->mac_header);
+
+		if (nla_put(inst->skb, NFULA_L2HDR, len, skb_mac_header(skb)))
+			goto nla_put_failure;
+	}
+
+	return 0;
+
+nla_put_failure:
+	return -1;
+}
+#endif /* IS_ENABLED(CONFIG_BRIDGE_NETFILTER) */
+
 /* This is an inline function, we don't really care about a long
  * list of arguments */
 static inline int
@@ -580,6 +614,12 @@  __build_packet_message(struct nfnl_log_net *log,
 				 NFULA_CT, NFULA_CT_INFO) < 0)
 		goto nla_put_failure;
 
+#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
+	if (pf == PF_BRIDGE &&
+	    nfulnl_put_bridge(inst, skb) < 0)
+		goto nla_put_failure;
+#endif
+
 	if (data_len) {
 		struct nlattr *nla;
 		int size = nla_attr_size(data_len);