History

netfilter: ctnetlink: dump entries from the dying and unconfirmed lists

This patch adds a new operation to dump the content of the dying and unconfirmed lists. Under some situations, the global conntrack counter can be inconsistent with the number of entries that we can dump from the conntrack table. The way to resolve this is to allow dumping the content of the unconfirmed and dying lists, so far it was not possible to look at its content. This provides some extra instrumentation to resolve problematic situations in which anyone suspects memory leaks.

Pablo Neira Ayuso committed 13 years ago

Commit d871bef1 parent 04dac012 files · +110 −0Browse files

Unified · Split

2 files
  1. include/uapi/linux/netfilter/nfnetlink_conntrack.h +2 −0
  2. net/netfilter/nf_conntrack_netlink.c +108 −0
include/uapi/linux/netfilter/nfnetlink_conntrack.h+2−0
@@ -9,6 +9,8 @@ enum cntl_msg_types { · 8 unmodified lines
99 IPCTNL_MSG_CT_GET_CTRZERO,
1010 IPCTNL_MSG_CT_GET_STATS_CPU,
1111 IPCTNL_MSG_CT_GET_STATS,
12+ IPCTNL_MSG_CT_GET_DYING,
13+ IPCTNL_MSG_CT_GET_UNCONFIRMED,
1214
1315 IPCTNL_MSG_MAX
1416 };
net/netfilter/nf_conntrack_netlink.c+108−0
@@ -1089,6 +1089,112 @@ out: · 1088 unmodified lines
10891089 return err == -EAGAIN ? -ENOBUFS : err;
10901090 }
10911091
1092+static int ctnetlink_done_list(struct netlink_callback *cb)
1093+{
1094+ if (cb->args[1])
1095+ nf_ct_put((struct nf_conn *)cb->args[1]);
1096+ return 0;
1097+}
1098+
1099+static int
1100+ctnetlink_dump_list(struct sk_buff *skb, struct netlink_callback *cb,
1101+ struct hlist_nulls_head *list)
1102+{
1103+ struct nf_conn *ct, *last;
1104+ struct nf_conntrack_tuple_hash *h;
1105+ struct hlist_nulls_node *n;
1106+ struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
1107+ u_int8_t l3proto = nfmsg->nfgen_family;
1108+ int res;
1109+
1110+ if (cb->args[2])
1111+ return 0;
1112+
1113+ spin_lock_bh(&nf_conntrack_lock);
1114+ last = (struct nf_conn *)cb->args[1];
1115+restart:
1116+ hlist_nulls_for_each_entry(h, n, list, hnnode) {
1117+ ct = nf_ct_tuplehash_to_ctrack(h);
1118+ if (l3proto && nf_ct_l3num(ct) != l3proto)
1119+ continue;
1120+ if (cb->args[1]) {
1121+ if (ct != last)
1122+ continue;
1123+ cb->args[1] = 0;
1124+ }
1125+ rcu_read_lock();
1126+ res = ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).portid,
1127+ cb->nlh->nlmsg_seq,
1128+ NFNL_MSG_TYPE(cb->nlh->nlmsg_type),
1129+ ct);
1130+ rcu_read_unlock();
1131+ if (res < 0) {
1132+ nf_conntrack_get(&ct->ct_general);
1133+ cb->args[1] = (unsigned long)ct;
1134+ goto out;
1135+ }
1136+ }
1137+ if (cb->args[1]) {
1138+ cb->args[1] = 0;
1139+ goto restart;
1140+ } else
1141+ cb->args[2] = 1;
1142+out:
1143+ spin_unlock_bh(&nf_conntrack_lock);
1144+ if (last)
1145+ nf_ct_put(last);
1146+
1147+ return skb->len;
1148+}
1149+
1150+static int
1151+ctnetlink_dump_dying(struct sk_buff *skb, struct netlink_callback *cb)
1152+{
1153+ struct net *net = sock_net(skb->sk);
1154+
1155+ return ctnetlink_dump_list(skb, cb, &net->ct.dying);
1156+}
1157+
1158+static int
1159+ctnetlink_get_ct_dying(struct sock *ctnl, struct sk_buff *skb,
1160+ const struct nlmsghdr *nlh,
1161+ const struct nlattr * const cda[])
1162+{
1163+ if (nlh->nlmsg_flags & NLM_F_DUMP) {
1164+ struct netlink_dump_control c = {
1165+ .dump = ctnetlink_dump_dying,
1166+ .done = ctnetlink_done_list,
1167+ };
1168+ return netlink_dump_start(ctnl, skb, nlh, &c);
1169+ }
1170+
1171+ return -EOPNOTSUPP;
1172+}
1173+
1174+static int
1175+ctnetlink_dump_unconfirmed(struct sk_buff *skb, struct netlink_callback *cb)
1176+{
1177+ struct net *net = sock_net(skb->sk);
1178+
1179+ return ctnetlink_dump_list(skb, cb, &net->ct.unconfirmed);
1180+}
1181+
1182+static int
1183+ctnetlink_get_ct_unconfirmed(struct sock *ctnl, struct sk_buff *skb,
1184+ const struct nlmsghdr *nlh,
1185+ const struct nlattr * const cda[])
1186+{
1187+ if (nlh->nlmsg_flags & NLM_F_DUMP) {
1188+ struct netlink_dump_control c = {
1189+ .dump = ctnetlink_dump_unconfirmed,
1190+ .done = ctnetlink_done_list,
1191+ };
1192+ return netlink_dump_start(ctnl, skb, nlh, &c);
1193+ }
1194+
1195+ return -EOPNOTSUPP;
1196+}
1197+
10921198 #ifdef CONFIG_NF_NAT_NEEDED
10931199 static int
10941200 ctnetlink_parse_nat_setup(struct nf_conn *ct,
@@ -2712,6 +2818,8 @@ static const struct nfnl_callback ctnl_cb[IPCTNL_MSG_MAX] = { · 1617 unmodified lines
27122818 .policy = ct_nla_policy },
27132819 [IPCTNL_MSG_CT_GET_STATS_CPU] = { .call = ctnetlink_stat_ct_cpu },
27142820 [IPCTNL_MSG_CT_GET_STATS] = { .call = ctnetlink_stat_ct },
2821+ [IPCTNL_MSG_CT_GET_DYING] = { .call = ctnetlink_get_ct_dying },
2822+ [IPCTNL_MSG_CT_GET_UNCONFIRMED] = { .call = ctnetlink_get_ct_unconfirmed },
27152823 };
27162824
27172825 static const struct nfnl_callback ctnl_exp_cb[IPCTNL_MSG_EXP_MAX] = {