99 * Development of this code funded by Astaro AG (http://www.astaro.com/)
1010 */
1111
12+ #include <linux/audit.h>
1213#include <linux/kernel.h>
1314#include <linux/init.h>
1415#include <linux/module.h>
1516#include <linux/netlink.h>
1617#include <linux/netfilter.h>
1718#include <linux/netfilter/nf_tables.h>
19+ #include <net/ipv6.h>
20+ #include <net/ip.h>
1821#include <net/netfilter/nf_tables.h>
1922#include <net/netfilter/nf_log.h>
2023#include <linux/netdevice.h>
@@ -26,12 +29,93 @@ struct nft_log {
2629 char * prefix ;
2730};
2831
32+ static bool audit_ip4 (struct audit_buffer * ab , struct sk_buff * skb )
33+ {
34+ struct iphdr _iph ;
35+ const struct iphdr * ih ;
36+
37+ ih = skb_header_pointer (skb , skb_network_offset (skb ), sizeof (_iph ), & _iph );
38+ if (!ih )
39+ return false;
40+
41+ audit_log_format (ab , " saddr=%pI4 daddr=%pI4 proto=%hhu" ,
42+ & ih -> saddr , & ih -> daddr , ih -> protocol );
43+
44+ return true;
45+ }
46+
47+ static bool audit_ip6 (struct audit_buffer * ab , struct sk_buff * skb )
48+ {
49+ struct ipv6hdr _ip6h ;
50+ const struct ipv6hdr * ih ;
51+ u8 nexthdr ;
52+ __be16 frag_off ;
53+
54+ ih = skb_header_pointer (skb , skb_network_offset (skb ), sizeof (_ip6h ), & _ip6h );
55+ if (!ih )
56+ return false;
57+
58+ nexthdr = ih -> nexthdr ;
59+ ipv6_skip_exthdr (skb , skb_network_offset (skb ) + sizeof (_ip6h ), & nexthdr , & frag_off );
60+
61+ audit_log_format (ab , " saddr=%pI6c daddr=%pI6c proto=%hhu" ,
62+ & ih -> saddr , & ih -> daddr , nexthdr );
63+
64+ return true;
65+ }
66+
67+ static void nft_log_eval_audit (const struct nft_pktinfo * pkt )
68+ {
69+ struct sk_buff * skb = pkt -> skb ;
70+ struct audit_buffer * ab ;
71+ int fam = -1 ;
72+
73+ if (!audit_enabled )
74+ return ;
75+
76+ ab = audit_log_start (NULL , GFP_ATOMIC , AUDIT_NETFILTER_PKT );
77+ if (!ab )
78+ return ;
79+
80+ audit_log_format (ab , "mark=%#x" , skb -> mark );
81+
82+ switch (nft_pf (pkt )) {
83+ case NFPROTO_BRIDGE :
84+ switch (eth_hdr (skb )-> h_proto ) {
85+ case htons (ETH_P_IP ):
86+ fam = audit_ip4 (ab , skb ) ? NFPROTO_IPV4 : -1 ;
87+ break ;
88+ case htons (ETH_P_IPV6 ):
89+ fam = audit_ip6 (ab , skb ) ? NFPROTO_IPV6 : -1 ;
90+ break ;
91+ }
92+ break ;
93+ case NFPROTO_IPV4 :
94+ fam = audit_ip4 (ab , skb ) ? NFPROTO_IPV4 : -1 ;
95+ break ;
96+ case NFPROTO_IPV6 :
97+ fam = audit_ip6 (ab , skb ) ? NFPROTO_IPV6 : -1 ;
98+ break ;
99+ }
100+
101+ if (fam == -1 )
102+ audit_log_format (ab , " saddr=? daddr=? proto=-1" );
103+
104+ audit_log_end (ab );
105+ }
106+
29107static void nft_log_eval (const struct nft_expr * expr ,
30108 struct nft_regs * regs ,
31109 const struct nft_pktinfo * pkt )
32110{
33111 const struct nft_log * priv = nft_expr_priv (expr );
34112
113+ if (priv -> loginfo .type == NF_LOG_TYPE_LOG &&
114+ priv -> loginfo .u .log .level == LOGLEVEL_AUDIT ) {
115+ nft_log_eval_audit (pkt );
116+ return ;
117+ }
118+
35119 nf_log_packet (nft_net (pkt ), nft_pf (pkt ), nft_hook (pkt ), pkt -> skb ,
36120 nft_in (pkt ), nft_out (pkt ), & priv -> loginfo , "%s" ,
37121 priv -> prefix );
@@ -84,7 +168,7 @@ static int nft_log_init(const struct nft_ctx *ctx,
84168 } else {
85169 li -> u .log .level = LOGLEVEL_WARNING ;
86170 }
87- if (li -> u .log .level > LOGLEVEL_DEBUG ) {
171+ if (li -> u .log .level > LOGLEVEL_AUDIT ) {
88172 err = - EINVAL ;
89173 goto err1 ;
90174 }
@@ -112,6 +196,9 @@ static int nft_log_init(const struct nft_ctx *ctx,
112196 break ;
113197 }
114198
199+ if (li -> u .log .level == LOGLEVEL_AUDIT )
200+ return 0 ;
201+
115202 err = nf_logger_find_get (ctx -> family , li -> type );
116203 if (err < 0 )
117204 goto err1 ;
@@ -133,6 +220,9 @@ static void nft_log_destroy(const struct nft_ctx *ctx,
133220 if (priv -> prefix != nft_log_null_prefix )
134221 kfree (priv -> prefix );
135222
223+ if (li -> u .log .level == LOGLEVEL_AUDIT )
224+ return ;
225+
136226 nf_logger_put (ctx -> family , li -> type );
137227}
138228
0 commit comments