aboutsummaryrefslogtreecommitdiffstats
path: root/net/netfilter
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2012-11-27 08:49:42 -0500
committerPablo Neira Ayuso <pablo@netfilter.org>2012-12-03 09:06:52 -0500
commitd871befe357ccc262edbb0a4f9aeea650012edf5 (patch)
treea3fd15012d471a83c58b7d1bb76a0839c6869296 /net/netfilter
parent04dac0111da7e1d284952cd415162451ffaa094d (diff)
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. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net/netfilter')
-rw-r--r--net/netfilter/nf_conntrack_netlink.c108
1 files changed, 108 insertions, 0 deletions
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 34370a928360..c24a00a73c7b 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -1089,6 +1089,112 @@ out:
1089 return err == -EAGAIN ? -ENOBUFS : err; 1089 return err == -EAGAIN ? -ENOBUFS : err;
1090} 1090}
1091 1091
1092static 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
1099static int
1100ctnetlink_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];
1115restart:
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;
1142out:
1143 spin_unlock_bh(&nf_conntrack_lock);
1144 if (last)
1145 nf_ct_put(last);
1146
1147 return skb->len;
1148}
1149
1150static int
1151ctnetlink_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
1158static int
1159ctnetlink_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
1174static int
1175ctnetlink_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
1182static int
1183ctnetlink_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
1092#ifdef CONFIG_NF_NAT_NEEDED 1198#ifdef CONFIG_NF_NAT_NEEDED
1093static int 1199static int
1094ctnetlink_parse_nat_setup(struct nf_conn *ct, 1200ctnetlink_parse_nat_setup(struct nf_conn *ct,
@@ -2712,6 +2818,8 @@ static const struct nfnl_callback ctnl_cb[IPCTNL_MSG_MAX] = {
2712 .policy = ct_nla_policy }, 2818 .policy = ct_nla_policy },
2713 [IPCTNL_MSG_CT_GET_STATS_CPU] = { .call = ctnetlink_stat_ct_cpu }, 2819 [IPCTNL_MSG_CT_GET_STATS_CPU] = { .call = ctnetlink_stat_ct_cpu },
2714 [IPCTNL_MSG_CT_GET_STATS] = { .call = ctnetlink_stat_ct }, 2820 [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 },
2715}; 2823};
2716 2824
2717static const struct nfnl_callback ctnl_exp_cb[IPCTNL_MSG_EXP_MAX] = { 2825static const struct nfnl_callback ctnl_exp_cb[IPCTNL_MSG_EXP_MAX] = {