struct nfnl_callback
{
- kernel_cap_t cap_required; /* capabilities required for this msg */
int (*call)(struct sock *nl, struct sk_buff *skb,
struct nlmsghdr *nlh, struct nfattr *cda[], int *errp);
+ kernel_cap_t cap_required; /* capabilities required for this msg */
+ u_int16_t attr_count; /* number of nfattr's */
};
struct nfnetlink_subsystem
const char *name;
__u8 subsys_id; /* nfnetlink subsystem ID */
__u8 cb_count; /* number of callbacks */
- u_int32_t attr_count; /* number of nfattr's */
struct nfnl_callback *cb; /* callback for individual types */
};
static struct nfnl_callback ctnl_cb[IPCTNL_MSG_MAX] = {
[IPCTNL_MSG_CT_NEW] = { .call = ctnetlink_new_conntrack,
+ .attr_count = CTA_MAX,
.cap_required = CAP_NET_ADMIN },
[IPCTNL_MSG_CT_GET] = { .call = ctnetlink_get_conntrack,
+ .attr_count = CTA_MAX,
.cap_required = CAP_NET_ADMIN },
[IPCTNL_MSG_CT_DELETE] = { .call = ctnetlink_del_conntrack,
+ .attr_count = CTA_MAX,
.cap_required = CAP_NET_ADMIN },
[IPCTNL_MSG_CT_GET_CTRZERO] = { .call = ctnetlink_get_conntrack,
+ .attr_count = CTA_MAX,
.cap_required = CAP_NET_ADMIN },
};
static struct nfnl_callback ctnl_exp_cb[IPCTNL_MSG_MAX] = {
[IPCTNL_MSG_EXP_GET] = { .call = ctnetlink_get_expect,
+ .attr_count = CTA_EXPECT_MAX,
.cap_required = CAP_NET_ADMIN },
[IPCTNL_MSG_EXP_NEW] = { .call = ctnetlink_new_expect,
+ .attr_count = CTA_EXPECT_MAX,
.cap_required = CAP_NET_ADMIN },
[IPCTNL_MSG_EXP_DELETE] = { .call = ctnetlink_del_expect,
+ .attr_count = CTA_EXPECT_MAX,
.cap_required = CAP_NET_ADMIN },
};
.name = "conntrack",
.subsys_id = NFNL_SUBSYS_CTNETLINK,
.cb_count = IPCTNL_MSG_MAX,
- .attr_count = CTA_MAX,
.cb = ctnl_cb,
};
.name = "conntrack_expect",
.subsys_id = NFNL_SUBSYS_CTNETLINK_EXP,
.cb_count = IPCTNL_MSG_EXP_MAX,
- .attr_count = CTA_MAX,
.cb = ctnl_exp_cb,
};
struct nlmsghdr *nlh, struct nfattr *cda[])
{
int min_len;
+ u_int16_t attr_count;
+ u_int8_t cb_id = NFNL_MSG_TYPE(nlh->nlmsg_type);
- memset(cda, 0, sizeof(struct nfattr *) * subsys->attr_count);
+ if (unlikely(cb_id >= subsys->cb_count)) {
+ DEBUGP("msgtype %u >= %u, returning\n",
+ cb_id, subsys->cb_count);
+ return -EINVAL;
+ }
+
+ attr_count = subsys->cb[cb_id].attr_count;
+
+ memset(cda, 0, sizeof(struct nfattr *) * attr_count);
/* check attribute lengths. */
min_len = NLMSG_ALIGN(sizeof(struct nfgenmsg));
while (NFA_OK(attr, attrlen)) {
unsigned flavor = attr->nfa_type;
if (flavor) {
- if (flavor > subsys->attr_count)
+ if (flavor > attr_count)
return -EINVAL;
cda[flavor - 1] = attr;
}
}
{
- struct nfattr *cda[ss->attr_count];
+ u_int16_t attr_count =
+ ss->cb[NFNL_MSG_TYPE(nlh->nlmsg_type)].attr_count;
+ struct nfattr *cda[attr_count];
- memset(cda, 0, ss->attr_count*sizeof(struct nfattr *));
+ memset(cda, 0, sizeof(struct nfattr *) * attr_count);
err = nfnetlink_check_attributes(ss, nlh, cda);
if (err < 0)
static struct nfnl_callback nfulnl_cb[NFULNL_MSG_MAX] = {
[NFULNL_MSG_PACKET] = { .call = nfulnl_recv_unsupp,
- .cap_required = CAP_NET_ADMIN },
+ .attr_count = NFULA_MAX,
+ .cap_required = CAP_NET_ADMIN, },
[NFULNL_MSG_CONFIG] = { .call = nfulnl_recv_config,
+ .attr_count = NFULA_CFG_MAX,
.cap_required = CAP_NET_ADMIN },
};
.name = "log",
.subsys_id = NFNL_SUBSYS_ULOG,
.cb_count = NFULNL_MSG_MAX,
- .attr_count = NFULA_MAX,
.cb = nfulnl_cb,
};
static struct nfnl_callback nfqnl_cb[NFQNL_MSG_MAX] = {
[NFQNL_MSG_PACKET] = { .call = nfqnl_recv_unsupp,
+ .attr_count = NFQA_MAX,
.cap_required = CAP_NET_ADMIN },
[NFQNL_MSG_VERDICT] = { .call = nfqnl_recv_verdict,
+ .attr_count = NFQA_MAX,
.cap_required = CAP_NET_ADMIN },
[NFQNL_MSG_CONFIG] = { .call = nfqnl_recv_config,
+ .attr_count = NFQA_CFG_MAX,
.cap_required = CAP_NET_ADMIN },
};
.name = "nf_queue",
.subsys_id = NFNL_SUBSYS_QUEUE,
.cb_count = NFQNL_MSG_MAX,
- .attr_count = NFQA_MAX,
.cb = nfqnl_cb,
};