queue_msg.c revision 28233246cd8fad47613e7ffd85ea0b1d69c0f8c2
1/*
2 * lib/netfilter/queue_msg.c	Netfilter Queue Messages
3 *
4 *	This library is free software; you can redistribute it and/or
5 *	modify it under the terms of the GNU Lesser General Public
6 *	License as published by the Free Software Foundation version 2.1
7 *	of the License.
8 *
9 * Copyright (c) 2007, 2008 Patrick McHardy <kaber@trash.net>
10 */
11
12/**
13 * @ingroup nfnl
14 * @defgroup queue Queue
15 * @brief
16 * @{
17 */
18
19#include <sys/types.h>
20#include <linux/netfilter/nfnetlink_queue.h>
21
22#include <netlink-local.h>
23#include <netlink/attr.h>
24#include <netlink/netfilter/nfnl.h>
25#include <netlink/netfilter/queue_msg.h>
26
27static struct nl_cache_ops nfnl_queue_msg_ops;
28
29#if __BYTE_ORDER == __BIG_ENDIAN
30static uint64_t ntohll(uint64_t x)
31{
32	return x;
33}
34#elif __BYTE_ORDER == __LITTLE_ENDIAN
35static uint64_t ntohll(uint64_t x)
36{
37	return __bswap_64(x);
38}
39#endif
40
41static struct nla_policy queue_policy[NFQA_MAX+1] = {
42	[NFQA_PACKET_HDR]		= {
43		.minlen	= sizeof(struct nfqnl_msg_packet_hdr),
44	},
45	[NFQA_VERDICT_HDR]		= {
46		.minlen	= sizeof(struct nfqnl_msg_verdict_hdr),
47	},
48	[NFQA_MARK]			= { .type = NLA_U32 },
49	[NFQA_TIMESTAMP]		= {
50		.minlen = sizeof(struct nfqnl_msg_packet_timestamp),
51	},
52	[NFQA_IFINDEX_INDEV]		= { .type = NLA_U32 },
53	[NFQA_IFINDEX_OUTDEV]		= { .type = NLA_U32 },
54	[NFQA_IFINDEX_PHYSINDEV]	= { .type = NLA_U32 },
55	[NFQA_IFINDEX_PHYSOUTDEV]	= { .type = NLA_U32 },
56	[NFQA_HWADDR]			= {
57		.minlen	= sizeof(struct nfqnl_msg_packet_hw),
58	},
59};
60
61int nfnlmsg_queue_msg_parse(struct nlmsghdr *nlh,
62			    struct nfnl_queue_msg **result)
63{
64	struct nfnl_queue_msg *msg;
65	struct nlattr *tb[NFQA_MAX+1];
66	struct nlattr *attr;
67	int err;
68
69	msg = nfnl_queue_msg_alloc();
70	if (!msg)
71		return -NLE_NOMEM;
72
73	msg->ce_msgtype = nlh->nlmsg_type;
74
75	err = nlmsg_parse(nlh, sizeof(struct nfgenmsg), tb, NFQA_MAX,
76			  queue_policy);
77	if (err < 0)
78		goto errout;
79
80	nfnl_queue_msg_set_group(msg, nfnlmsg_res_id(nlh));
81	nfnl_queue_msg_set_family(msg, nfnlmsg_family(nlh));
82
83	attr = tb[NFQA_PACKET_HDR];
84	if (attr) {
85		struct nfqnl_msg_packet_hdr *hdr = nla_data(attr);
86
87		nfnl_queue_msg_set_packetid(msg, ntohl(hdr->packet_id));
88		if (hdr->hw_protocol)
89			nfnl_queue_msg_set_hwproto(msg, hdr->hw_protocol);
90		nfnl_queue_msg_set_hook(msg, hdr->hook);
91	}
92
93	attr = tb[NFQA_MARK];
94	if (attr)
95		nfnl_queue_msg_set_mark(msg, ntohl(nla_get_u32(attr)));
96
97	attr = tb[NFQA_TIMESTAMP];
98	if (attr) {
99		struct nfqnl_msg_packet_timestamp *timestamp = nla_data(attr);
100		struct timeval tv;
101
102		tv.tv_sec = ntohll(timestamp->sec);
103		tv.tv_usec = ntohll(timestamp->usec);
104		nfnl_queue_msg_set_timestamp(msg, &tv);
105	}
106
107	attr = tb[NFQA_IFINDEX_INDEV];
108	if (attr)
109		nfnl_queue_msg_set_indev(msg, ntohl(nla_get_u32(attr)));
110
111	attr = tb[NFQA_IFINDEX_OUTDEV];
112	if (attr)
113		nfnl_queue_msg_set_outdev(msg, ntohl(nla_get_u32(attr)));
114
115	attr = tb[NFQA_IFINDEX_PHYSINDEV];
116	if (attr)
117		nfnl_queue_msg_set_physindev(msg, ntohl(nla_get_u32(attr)));
118
119	attr = tb[NFQA_IFINDEX_PHYSOUTDEV];
120	if (attr)
121		nfnl_queue_msg_set_physoutdev(msg, ntohl(nla_get_u32(attr)));
122
123	attr = tb[NFQA_HWADDR];
124	if (attr) {
125		struct nfqnl_msg_packet_hw *hw = nla_data(attr);
126
127		nfnl_queue_msg_set_hwaddr(msg, hw->hw_addr,
128					  ntohs(hw->hw_addrlen));
129	}
130
131	attr = tb[NFQA_PAYLOAD];
132	if (attr) {
133		err = nfnl_queue_msg_set_payload(msg, nla_data(attr),
134						 nla_len(attr));
135		if (err < 0)
136			goto errout;
137	}
138
139	*result = msg;
140	return 0;
141
142errout:
143	nfnl_queue_msg_put(msg);
144	return err;
145}
146
147static int queue_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
148			    struct nlmsghdr *nlh, struct nl_parser_param *pp)
149{
150	struct nfnl_queue_msg *msg;
151	int err;
152
153	if ((err = nfnlmsg_queue_msg_parse(nlh, &msg)) < 0)
154		goto errout;
155
156	err = pp->pp_cb((struct nl_object *) msg, pp);
157errout:
158	nfnl_queue_msg_put(msg);
159	return err;
160}
161
162/** @} */
163
164struct nl_msg *nfnl_queue_msg_build_verdict(const struct nfnl_queue_msg *msg)
165{
166	struct nl_msg *nlmsg;
167	struct nfqnl_msg_verdict_hdr verdict;
168
169	nlmsg = nfnlmsg_alloc_simple(NFNL_SUBSYS_QUEUE, NFQNL_MSG_VERDICT, 0,
170				     nfnl_queue_msg_get_family(msg),
171				     nfnl_queue_msg_get_group(msg));
172	if (nlmsg == NULL)
173		return NULL;
174
175	verdict.id = htonl(nfnl_queue_msg_get_packetid(msg));
176	verdict.verdict = htonl(nfnl_queue_msg_get_verdict(msg));
177	if (nla_put(nlmsg, NFQA_VERDICT_HDR, sizeof(verdict), &verdict) < 0)
178		goto nla_put_failure;
179
180	if (nfnl_queue_msg_test_mark(msg) &&
181	    nla_put_u32(nlmsg, NFQA_MARK,
182			ntohl(nfnl_queue_msg_get_mark(msg))) < 0)
183		goto nla_put_failure;
184
185	return nlmsg;
186
187nla_put_failure:
188	nlmsg_free(nlmsg);
189	return NULL;
190}
191
192int nfnl_queue_msg_send_verdict(struct nl_sock *nlh,
193				const struct nfnl_queue_msg *msg)
194{
195	struct nl_msg *nlmsg;
196	int err;
197
198	nlmsg = nfnl_queue_msg_build_verdict(msg);
199	if (nlmsg == NULL)
200		return -NLE_NOMEM;
201
202	err = nl_send_auto_complete(nlh, nlmsg);
203	nlmsg_free(nlmsg);
204	if (err < 0)
205		return err;
206	return nl_wait_for_ack(nlh);
207}
208
209#define NFNLMSG_QUEUE_TYPE(type) NFNLMSG_TYPE(NFNL_SUBSYS_QUEUE, (type))
210static struct nl_cache_ops nfnl_queue_msg_ops = {
211	.co_name		= "netfilter/queue_msg",
212	.co_hdrsize		= NFNL_HDRLEN,
213	.co_msgtypes		= {
214		{ NFNLMSG_QUEUE_TYPE(NFQNL_MSG_PACKET), NL_ACT_NEW, "new" },
215		END_OF_MSGTYPES_LIST,
216	},
217	.co_protocol		= NETLINK_NETFILTER,
218	.co_msg_parser		= queue_msg_parser,
219	.co_obj_ops		= &queue_msg_obj_ops,
220};
221
222static void __init nfnl_msg_queue_init(void)
223{
224	nl_cache_mngt_register(&nfnl_queue_msg_ops);
225}
226
227static void __exit nfnl_queue_msg_exit(void)
228{
229	nl_cache_mngt_unregister(&nfnl_queue_msg_ops);
230}
231
232/** @} */
233