• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3  * Copyright (c) 2007, 2008 Patrick McHardy <kaber@trash.net>
4  * Copyright (c) 2010       Karl Hiramoto <karl@hiramoto.org>
5  */
6 
7 /**
8  * @ingroup nfnl
9  * @defgroup queue Queue
10  * @brief
11  * @{
12  */
13 
14 #include "nl-default.h"
15 
16 #include <sys/types.h>
17 
18 #include <linux/netfilter/nfnetlink_queue.h>
19 
20 #include <netlink/attr.h>
21 #include <netlink/netfilter/nfnl.h>
22 #include <netlink/netfilter/queue_msg.h>
23 
24 #include "nl-netfilter.h"
25 #include "nl-priv-dynamic-core/nl-core.h"
26 #include "nl-priv-dynamic-core/cache-api.h"
27 
28 static struct nl_cache_ops nfnl_queue_msg_ops;
29 
30 static struct nla_policy queue_policy[NFQA_MAX+1] = {
31 	[NFQA_PACKET_HDR]		= {
32 		.minlen	= sizeof(struct nfqnl_msg_packet_hdr),
33 	},
34 	[NFQA_VERDICT_HDR]		= {
35 		.minlen	= sizeof(struct nfqnl_msg_verdict_hdr),
36 	},
37 	[NFQA_MARK]			= { .type = NLA_U32 },
38 	[NFQA_TIMESTAMP]		= {
39 		.minlen = sizeof(struct nfqnl_msg_packet_timestamp),
40 	},
41 	[NFQA_IFINDEX_INDEV]		= { .type = NLA_U32 },
42 	[NFQA_IFINDEX_OUTDEV]		= { .type = NLA_U32 },
43 	[NFQA_IFINDEX_PHYSINDEV]	= { .type = NLA_U32 },
44 	[NFQA_IFINDEX_PHYSOUTDEV]	= { .type = NLA_U32 },
45 	[NFQA_HWADDR]			= {
46 		.minlen	= sizeof(struct nfqnl_msg_packet_hw),
47 	},
48 };
49 
nfnlmsg_queue_msg_parse(struct nlmsghdr * nlh,struct nfnl_queue_msg ** result)50 int nfnlmsg_queue_msg_parse(struct nlmsghdr *nlh,
51 			    struct nfnl_queue_msg **result)
52 {
53 	struct nfnl_queue_msg *msg;
54 	struct nlattr *tb[NFQA_MAX+1];
55 	struct nlattr *attr;
56 	int err;
57 
58 	msg = nfnl_queue_msg_alloc();
59 	if (!msg)
60 		return -NLE_NOMEM;
61 
62 	msg->ce_msgtype = nlh->nlmsg_type;
63 
64 	err = nlmsg_parse(nlh, sizeof(struct nfgenmsg), tb, NFQA_MAX,
65 			  queue_policy);
66 	if (err < 0)
67 		goto errout;
68 
69 	nfnl_queue_msg_set_group(msg, nfnlmsg_res_id(nlh));
70 	nfnl_queue_msg_set_family(msg, nfnlmsg_family(nlh));
71 
72 	attr = tb[NFQA_PACKET_HDR];
73 	if (attr) {
74 		struct nfqnl_msg_packet_hdr *hdr = nla_data(attr);
75 
76 		nfnl_queue_msg_set_packetid(msg, ntohl(hdr->packet_id));
77 		if (hdr->hw_protocol)
78 			nfnl_queue_msg_set_hwproto(msg, hdr->hw_protocol);
79 		nfnl_queue_msg_set_hook(msg, hdr->hook);
80 	}
81 
82 	attr = tb[NFQA_MARK];
83 	if (attr)
84 		nfnl_queue_msg_set_mark(msg, ntohl(nla_get_u32(attr)));
85 
86 	attr = tb[NFQA_TIMESTAMP];
87 	if (attr) {
88 		struct nfqnl_msg_packet_timestamp *timestamp = nla_data(attr);
89 		struct timeval tv;
90 
91 		tv.tv_sec = ntohll(timestamp->sec);
92 		tv.tv_usec = ntohll(timestamp->usec);
93 		nfnl_queue_msg_set_timestamp(msg, &tv);
94 	}
95 
96 	attr = tb[NFQA_IFINDEX_INDEV];
97 	if (attr)
98 		nfnl_queue_msg_set_indev(msg, ntohl(nla_get_u32(attr)));
99 
100 	attr = tb[NFQA_IFINDEX_OUTDEV];
101 	if (attr)
102 		nfnl_queue_msg_set_outdev(msg, ntohl(nla_get_u32(attr)));
103 
104 	attr = tb[NFQA_IFINDEX_PHYSINDEV];
105 	if (attr)
106 		nfnl_queue_msg_set_physindev(msg, ntohl(nla_get_u32(attr)));
107 
108 	attr = tb[NFQA_IFINDEX_PHYSOUTDEV];
109 	if (attr)
110 		nfnl_queue_msg_set_physoutdev(msg, ntohl(nla_get_u32(attr)));
111 
112 	attr = tb[NFQA_HWADDR];
113 	if (attr) {
114 		struct nfqnl_msg_packet_hw *hw = nla_data(attr);
115 
116 		nfnl_queue_msg_set_hwaddr(msg, hw->hw_addr,
117 					  ntohs(hw->hw_addrlen));
118 	}
119 
120 	attr = tb[NFQA_PAYLOAD];
121 	if (attr) {
122 		err = nfnl_queue_msg_set_payload(msg, nla_data(attr),
123 						 nla_len(attr));
124 		if (err < 0)
125 			goto errout;
126 	}
127 
128 	*result = msg;
129 	return 0;
130 
131 errout:
132 	nfnl_queue_msg_put(msg);
133 	return err;
134 }
135 
queue_msg_parser(struct nl_cache_ops * ops,struct sockaddr_nl * who,struct nlmsghdr * nlh,struct nl_parser_param * pp)136 static int queue_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
137 			    struct nlmsghdr *nlh, struct nl_parser_param *pp)
138 {
139 	struct nfnl_queue_msg *msg;
140 	int err;
141 
142 	if ((err = nfnlmsg_queue_msg_parse(nlh, &msg)) < 0)
143 		return err;
144 
145 	err = pp->pp_cb((struct nl_object *) msg, pp);
146 	nfnl_queue_msg_put(msg);
147 	return err;
148 }
149 
150 /** @} */
151 
152 static struct nl_msg *
__nfnl_queue_msg_build_verdict(const struct nfnl_queue_msg * msg,uint8_t type)153 __nfnl_queue_msg_build_verdict(const struct nfnl_queue_msg *msg,
154 							   uint8_t type)
155 {
156 	struct nl_msg *nlmsg;
157 	struct nfqnl_msg_verdict_hdr verdict;
158 
159 	nlmsg = nfnlmsg_alloc_simple(NFNL_SUBSYS_QUEUE, type, 0,
160 				     nfnl_queue_msg_get_family(msg),
161 				     nfnl_queue_msg_get_group(msg));
162 	if (nlmsg == NULL)
163 		return NULL;
164 
165 	verdict.id = htonl(nfnl_queue_msg_get_packetid(msg));
166 	verdict.verdict = htonl(nfnl_queue_msg_get_verdict(msg));
167 	if (nla_put(nlmsg, NFQA_VERDICT_HDR, sizeof(verdict), &verdict) < 0)
168 		goto nla_put_failure;
169 
170 	if (nfnl_queue_msg_test_mark(msg) &&
171 	    nla_put_u32(nlmsg, NFQA_MARK,
172 			ntohl(nfnl_queue_msg_get_mark(msg))) < 0)
173 		goto nla_put_failure;
174 
175 	return nlmsg;
176 
177 nla_put_failure:
178 	nlmsg_free(nlmsg);
179 	return NULL;
180 }
181 
182 struct nl_msg *
nfnl_queue_msg_build_verdict(const struct nfnl_queue_msg * msg)183 nfnl_queue_msg_build_verdict(const struct nfnl_queue_msg *msg)
184 {
185 	return __nfnl_queue_msg_build_verdict(msg, NFQNL_MSG_VERDICT);
186 }
187 
188 struct nl_msg *
nfnl_queue_msg_build_verdict_batch(const struct nfnl_queue_msg * msg)189 nfnl_queue_msg_build_verdict_batch(const struct nfnl_queue_msg *msg)
190 {
191 	return __nfnl_queue_msg_build_verdict(msg, NFQNL_MSG_VERDICT_BATCH);
192 }
193 
194 /**
195 * Send a message verdict/mark
196 * @arg nlh            netlink messsage header
197 * @arg msg            queue msg
198 * @return 0 on OK or error code
199 */
nfnl_queue_msg_send_verdict(struct nl_sock * nlh,const struct nfnl_queue_msg * msg)200 int nfnl_queue_msg_send_verdict(struct nl_sock *nlh,
201 				const struct nfnl_queue_msg *msg)
202 {
203 	struct nl_msg *nlmsg;
204 	int err;
205 
206 	nlmsg = nfnl_queue_msg_build_verdict(msg);
207 	if (nlmsg == NULL)
208 		return -NLE_NOMEM;
209 
210 	err = nl_send_auto_complete(nlh, nlmsg);
211 	nlmsg_free(nlmsg);
212 	if (err < 0)
213 		return err;
214 	return wait_for_ack(nlh);
215 }
216 
217 /**
218 * Send a message batched verdict/mark
219 * @arg nlh            netlink messsage header
220 * @arg msg            queue msg
221 * @return 0 on OK or error code
222 */
nfnl_queue_msg_send_verdict_batch(struct nl_sock * nlh,const struct nfnl_queue_msg * msg)223 int nfnl_queue_msg_send_verdict_batch(struct nl_sock *nlh,
224 									  const struct nfnl_queue_msg *msg)
225 {
226 	struct nl_msg *nlmsg;
227 	int err;
228 
229 	nlmsg = nfnl_queue_msg_build_verdict_batch(msg);
230 	if (nlmsg == NULL)
231 		return -NLE_NOMEM;
232 
233 	err = nl_send_auto_complete(nlh, nlmsg);
234 	nlmsg_free(nlmsg);
235 	if (err < 0)
236 		return err;
237 	return wait_for_ack(nlh);
238 }
239 
240 /**
241 * Send a message verdict including the payload
242 * @arg nlh            netlink messsage header
243 * @arg msg            queue msg
244 * @arg payload_data   packet payload data
245 * @arg payload_len    payload length
246 * @return 0 on OK or error code
247 */
nfnl_queue_msg_send_verdict_payload(struct nl_sock * nlh,const struct nfnl_queue_msg * msg,const void * payload_data,unsigned payload_len)248 int nfnl_queue_msg_send_verdict_payload(struct nl_sock *nlh,
249 				const struct nfnl_queue_msg *msg,
250 				const void *payload_data, unsigned payload_len)
251 {
252 	struct nl_msg *nlmsg;
253 	int err;
254 	struct iovec iov[3];
255 	struct nlattr nla;
256 
257 	nlmsg = nfnl_queue_msg_build_verdict(msg);
258 	if (nlmsg == NULL)
259 		return -NLE_NOMEM;
260 
261 	memset(iov, 0, sizeof(iov));
262 
263 	iov[0].iov_base = (void *) nlmsg_hdr(nlmsg);
264 	iov[0].iov_len = nlmsg_hdr(nlmsg)->nlmsg_len;
265 
266 	nla.nla_type = NFQA_PAYLOAD;
267 	nla.nla_len = payload_len + sizeof(nla);
268 	nlmsg_hdr(nlmsg)->nlmsg_len += nla.nla_len;
269 
270 	iov[1].iov_base = (void *) &nla;
271 	iov[1].iov_len = sizeof(nla);
272 
273 	iov[2].iov_base = (void *) payload_data;
274 	iov[2].iov_len = NLA_ALIGN(payload_len);
275 
276 	nl_complete_msg(nlh, nlmsg);
277 	err = nl_send_iovec(nlh, nlmsg, iov, 3);
278 
279 	nlmsg_free(nlmsg);
280 	if (err < 0)
281 		return err;
282 	return wait_for_ack(nlh);
283 }
284 
285 #define NFNLMSG_QUEUE_TYPE(type) NFNLMSG_TYPE(NFNL_SUBSYS_QUEUE, (type))
286 static struct nl_cache_ops nfnl_queue_msg_ops = {
287 	.co_name		= "netfilter/queue_msg",
288 	.co_hdrsize		= NFNL_HDRLEN,
289 	.co_msgtypes		= {
290 		{ NFNLMSG_QUEUE_TYPE(NFQNL_MSG_PACKET), NL_ACT_NEW, "new" },
291 		END_OF_MSGTYPES_LIST,
292 	},
293 	.co_protocol		= NETLINK_NETFILTER,
294 	.co_msg_parser		= queue_msg_parser,
295 	.co_obj_ops		= &queue_msg_obj_ops,
296 };
297 
nfnl_msg_queue_init(void)298 static void _nl_init nfnl_msg_queue_init(void)
299 {
300 	nl_cache_mngt_register(&nfnl_queue_msg_ops);
301 }
302 
nfnl_queue_msg_exit(void)303 static void _nl_exit nfnl_queue_msg_exit(void)
304 {
305 	nl_cache_mngt_unregister(&nfnl_queue_msg_ops);
306 }
307 
308 /** @} */
309