[NETFILTER]: nfnetlink_log: fix sending of multipart messages

The following patch fixes the handling of netlink packets containing
multiple messages.

As exposed during netfilter workshop, nfnetlink_log was overwritten the
message type of the last message (setting it to MSG_DONE) in a multipart
packet. The consequence was libnfnetlink to ignore the last message in the
packet.

The following patch adds a supplementary message (with type MSG_DONE) af
the end of the netlink skb.

Signed-off-by: Eric Leblond <eric@inl.fr>
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Eric Leblond 2007-09-18 13:07:15 -07:00 committed by David S. Miller
parent 6d0b842d3b
commit 29c5d4afba

View File

@ -58,7 +58,6 @@ struct nfulnl_instance {
unsigned int qlen; /* number of nlmsgs in skb */ unsigned int qlen; /* number of nlmsgs in skb */
struct sk_buff *skb; /* pre-allocatd skb */ struct sk_buff *skb; /* pre-allocatd skb */
struct nlmsghdr *lastnlh; /* netlink header of last msg in skb */
struct timer_list timer; struct timer_list timer;
int peer_pid; /* PID of the peer process */ int peer_pid; /* PID of the peer process */
@ -345,10 +344,12 @@ static struct sk_buff *nfulnl_alloc_skb(unsigned int inst_size,
static int static int
__nfulnl_send(struct nfulnl_instance *inst) __nfulnl_send(struct nfulnl_instance *inst)
{ {
int status; int status = -1;
if (inst->qlen > 1) if (inst->qlen > 1)
inst->lastnlh->nlmsg_type = NLMSG_DONE; NLMSG_PUT(inst->skb, 0, 0,
NLMSG_DONE,
sizeof(struct nfgenmsg));
status = nfnetlink_unicast(inst->skb, inst->peer_pid, MSG_DONTWAIT); status = nfnetlink_unicast(inst->skb, inst->peer_pid, MSG_DONTWAIT);
if (status < 0) { if (status < 0) {
@ -358,8 +359,8 @@ __nfulnl_send(struct nfulnl_instance *inst)
inst->qlen = 0; inst->qlen = 0;
inst->skb = NULL; inst->skb = NULL;
inst->lastnlh = NULL;
nlmsg_failure:
return status; return status;
} }
@ -538,7 +539,6 @@ __build_packet_message(struct nfulnl_instance *inst,
} }
nlh->nlmsg_len = inst->skb->tail - old_tail; nlh->nlmsg_len = inst->skb->tail - old_tail;
inst->lastnlh = nlh;
return 0; return 0;
nlmsg_failure: nlmsg_failure:
@ -644,7 +644,8 @@ nfulnl_log_packet(unsigned int pf,
} }
if (inst->qlen >= qthreshold || if (inst->qlen >= qthreshold ||
(inst->skb && size > skb_tailroom(inst->skb))) { (inst->skb && size >
skb_tailroom(inst->skb) - sizeof(struct nfgenmsg))) {
/* either the queue len is too high or we don't have /* either the queue len is too high or we don't have
* enough room in the skb left. flush to userspace. */ * enough room in the skb left. flush to userspace. */
UDEBUG("flushing old skb\n"); UDEBUG("flushing old skb\n");