0001
0002
0003
0004
0005
0006
0007 #include <linux/module.h>
0008 #include <linux/static_key.h>
0009 #include <linux/hash.h>
0010 #include <linux/siphash.h>
0011 #include <linux/if_vlan.h>
0012 #include <linux/init.h>
0013 #include <linux/skbuff.h>
0014 #include <linux/netlink.h>
0015 #include <linux/netfilter.h>
0016 #include <linux/netfilter/nfnetlink.h>
0017 #include <linux/netfilter/nf_tables.h>
0018 #include <net/netfilter/nf_tables_core.h>
0019 #include <net/netfilter/nf_tables.h>
0020
0021 #define NFT_TRACETYPE_LL_HSIZE 20
0022 #define NFT_TRACETYPE_NETWORK_HSIZE 40
0023 #define NFT_TRACETYPE_TRANSPORT_HSIZE 20
0024
0025 DEFINE_STATIC_KEY_FALSE(nft_trace_enabled);
0026 EXPORT_SYMBOL_GPL(nft_trace_enabled);
0027
0028 static int trace_fill_header(struct sk_buff *nlskb, u16 type,
0029 const struct sk_buff *skb,
0030 int off, unsigned int len)
0031 {
0032 struct nlattr *nla;
0033
0034 if (len == 0)
0035 return 0;
0036
0037 nla = nla_reserve(nlskb, type, len);
0038 if (!nla || skb_copy_bits(skb, off, nla_data(nla), len))
0039 return -1;
0040
0041 return 0;
0042 }
0043
0044 static int nf_trace_fill_ll_header(struct sk_buff *nlskb,
0045 const struct sk_buff *skb)
0046 {
0047 struct vlan_ethhdr veth;
0048 int off;
0049
0050 BUILD_BUG_ON(sizeof(veth) > NFT_TRACETYPE_LL_HSIZE);
0051
0052 off = skb_mac_header(skb) - skb->data;
0053 if (off != -ETH_HLEN)
0054 return -1;
0055
0056 if (skb_copy_bits(skb, off, &veth, ETH_HLEN))
0057 return -1;
0058
0059 veth.h_vlan_proto = skb->vlan_proto;
0060 veth.h_vlan_TCI = htons(skb_vlan_tag_get(skb));
0061 veth.h_vlan_encapsulated_proto = skb->protocol;
0062
0063 return nla_put(nlskb, NFTA_TRACE_LL_HEADER, sizeof(veth), &veth);
0064 }
0065
0066 static int nf_trace_fill_dev_info(struct sk_buff *nlskb,
0067 const struct net_device *indev,
0068 const struct net_device *outdev)
0069 {
0070 if (indev) {
0071 if (nla_put_be32(nlskb, NFTA_TRACE_IIF,
0072 htonl(indev->ifindex)))
0073 return -1;
0074
0075 if (nla_put_be16(nlskb, NFTA_TRACE_IIFTYPE,
0076 htons(indev->type)))
0077 return -1;
0078 }
0079
0080 if (outdev) {
0081 if (nla_put_be32(nlskb, NFTA_TRACE_OIF,
0082 htonl(outdev->ifindex)))
0083 return -1;
0084
0085 if (nla_put_be16(nlskb, NFTA_TRACE_OIFTYPE,
0086 htons(outdev->type)))
0087 return -1;
0088 }
0089
0090 return 0;
0091 }
0092
0093 static int nf_trace_fill_pkt_info(struct sk_buff *nlskb,
0094 const struct nft_pktinfo *pkt)
0095 {
0096 const struct sk_buff *skb = pkt->skb;
0097 int off = skb_network_offset(skb);
0098 unsigned int len, nh_end;
0099
0100 nh_end = pkt->flags & NFT_PKTINFO_L4PROTO ? nft_thoff(pkt) : skb->len;
0101 len = min_t(unsigned int, nh_end - skb_network_offset(skb),
0102 NFT_TRACETYPE_NETWORK_HSIZE);
0103 if (trace_fill_header(nlskb, NFTA_TRACE_NETWORK_HEADER, skb, off, len))
0104 return -1;
0105
0106 if (pkt->flags & NFT_PKTINFO_L4PROTO) {
0107 len = min_t(unsigned int, skb->len - nft_thoff(pkt),
0108 NFT_TRACETYPE_TRANSPORT_HSIZE);
0109 if (trace_fill_header(nlskb, NFTA_TRACE_TRANSPORT_HEADER, skb,
0110 nft_thoff(pkt), len))
0111 return -1;
0112 }
0113
0114 if (!skb_mac_header_was_set(skb))
0115 return 0;
0116
0117 if (skb_vlan_tag_get(skb))
0118 return nf_trace_fill_ll_header(nlskb, skb);
0119
0120 off = skb_mac_header(skb) - skb->data;
0121 len = min_t(unsigned int, -off, NFT_TRACETYPE_LL_HSIZE);
0122 return trace_fill_header(nlskb, NFTA_TRACE_LL_HEADER,
0123 skb, off, len);
0124 }
0125
0126 static int nf_trace_fill_rule_info(struct sk_buff *nlskb,
0127 const struct nft_traceinfo *info)
0128 {
0129 if (!info->rule || info->rule->is_last)
0130 return 0;
0131
0132
0133
0134
0135
0136
0137 if (info->type == NFT_TRACETYPE_RETURN &&
0138 info->verdict->code == NFT_CONTINUE)
0139 return 0;
0140
0141 return nla_put_be64(nlskb, NFTA_TRACE_RULE_HANDLE,
0142 cpu_to_be64(info->rule->handle),
0143 NFTA_TRACE_PAD);
0144 }
0145
0146 static bool nft_trace_have_verdict_chain(struct nft_traceinfo *info)
0147 {
0148 switch (info->type) {
0149 case NFT_TRACETYPE_RETURN:
0150 case NFT_TRACETYPE_RULE:
0151 break;
0152 default:
0153 return false;
0154 }
0155
0156 switch (info->verdict->code) {
0157 case NFT_JUMP:
0158 case NFT_GOTO:
0159 break;
0160 default:
0161 return false;
0162 }
0163
0164 return true;
0165 }
0166
0167 void nft_trace_notify(struct nft_traceinfo *info)
0168 {
0169 const struct nft_pktinfo *pkt = info->pkt;
0170 struct nlmsghdr *nlh;
0171 struct sk_buff *skb;
0172 unsigned int size;
0173 u32 mark = 0;
0174 u16 event;
0175
0176 if (!nfnetlink_has_listeners(nft_net(pkt), NFNLGRP_NFTRACE))
0177 return;
0178
0179 size = nlmsg_total_size(sizeof(struct nfgenmsg)) +
0180 nla_total_size(strlen(info->chain->table->name)) +
0181 nla_total_size(strlen(info->chain->name)) +
0182 nla_total_size_64bit(sizeof(__be64)) +
0183 nla_total_size(sizeof(__be32)) +
0184 nla_total_size(0) +
0185 nla_total_size(sizeof(u32)) +
0186 nla_total_size(sizeof(u32)) +
0187 nla_total_size(NFT_TRACETYPE_LL_HSIZE) +
0188 nla_total_size(NFT_TRACETYPE_NETWORK_HSIZE) +
0189 nla_total_size(NFT_TRACETYPE_TRANSPORT_HSIZE) +
0190 nla_total_size(sizeof(u32)) +
0191 nla_total_size(sizeof(__be16)) +
0192 nla_total_size(sizeof(u32)) +
0193 nla_total_size(sizeof(__be16)) +
0194 nla_total_size(sizeof(u32)) +
0195 nla_total_size(sizeof(u32)) +
0196 nla_total_size(sizeof(u32));
0197
0198 if (nft_trace_have_verdict_chain(info))
0199 size += nla_total_size(strlen(info->verdict->chain->name));
0200
0201 skb = nlmsg_new(size, GFP_ATOMIC);
0202 if (!skb)
0203 return;
0204
0205 event = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, NFT_MSG_TRACE);
0206 nlh = nfnl_msg_put(skb, 0, 0, event, 0, info->basechain->type->family,
0207 NFNETLINK_V0, 0);
0208 if (!nlh)
0209 goto nla_put_failure;
0210
0211 if (nla_put_be32(skb, NFTA_TRACE_NFPROTO, htonl(nft_pf(pkt))))
0212 goto nla_put_failure;
0213
0214 if (nla_put_be32(skb, NFTA_TRACE_TYPE, htonl(info->type)))
0215 goto nla_put_failure;
0216
0217 if (nla_put_u32(skb, NFTA_TRACE_ID, info->skbid))
0218 goto nla_put_failure;
0219
0220 if (nla_put_string(skb, NFTA_TRACE_CHAIN, info->chain->name))
0221 goto nla_put_failure;
0222
0223 if (nla_put_string(skb, NFTA_TRACE_TABLE, info->chain->table->name))
0224 goto nla_put_failure;
0225
0226 if (nf_trace_fill_rule_info(skb, info))
0227 goto nla_put_failure;
0228
0229 switch (info->type) {
0230 case NFT_TRACETYPE_UNSPEC:
0231 case __NFT_TRACETYPE_MAX:
0232 break;
0233 case NFT_TRACETYPE_RETURN:
0234 case NFT_TRACETYPE_RULE:
0235 if (nft_verdict_dump(skb, NFTA_TRACE_VERDICT, info->verdict))
0236 goto nla_put_failure;
0237
0238
0239 if (info->verdict->code == NF_STOLEN)
0240 info->packet_dumped = true;
0241 else
0242 mark = pkt->skb->mark;
0243
0244 break;
0245 case NFT_TRACETYPE_POLICY:
0246 mark = pkt->skb->mark;
0247
0248 if (nla_put_be32(skb, NFTA_TRACE_POLICY,
0249 htonl(info->basechain->policy)))
0250 goto nla_put_failure;
0251 break;
0252 }
0253
0254 if (mark && nla_put_be32(skb, NFTA_TRACE_MARK, htonl(mark)))
0255 goto nla_put_failure;
0256
0257 if (!info->packet_dumped) {
0258 if (nf_trace_fill_dev_info(skb, nft_in(pkt), nft_out(pkt)))
0259 goto nla_put_failure;
0260
0261 if (nf_trace_fill_pkt_info(skb, pkt))
0262 goto nla_put_failure;
0263 info->packet_dumped = true;
0264 }
0265
0266 nlmsg_end(skb, nlh);
0267 nfnetlink_send(skb, nft_net(pkt), 0, NFNLGRP_NFTRACE, 0, GFP_ATOMIC);
0268 return;
0269
0270 nla_put_failure:
0271 WARN_ON_ONCE(1);
0272 kfree_skb(skb);
0273 }
0274
0275 void nft_trace_init(struct nft_traceinfo *info, const struct nft_pktinfo *pkt,
0276 const struct nft_verdict *verdict,
0277 const struct nft_chain *chain)
0278 {
0279 static siphash_key_t trace_key __read_mostly;
0280 struct sk_buff *skb = pkt->skb;
0281
0282 info->basechain = nft_base_chain(chain);
0283 info->trace = true;
0284 info->nf_trace = pkt->skb->nf_trace;
0285 info->packet_dumped = false;
0286 info->pkt = pkt;
0287 info->verdict = verdict;
0288
0289 net_get_random_once(&trace_key, sizeof(trace_key));
0290
0291 info->skbid = (u32)siphash_3u32(hash32_ptr(skb),
0292 skb_get_hash(skb),
0293 skb->skb_iif,
0294 &trace_key);
0295 }