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