• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3  * lib/netfilter/queue.c	Netfilter Queue
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  */
12 
13 /**
14  * @ingroup nfnl
15  * @defgroup queue Queue
16  * @brief
17  * @{
18  */
19 
20 #include <sys/types.h>
21 #include <linux/netfilter/nfnetlink_queue.h>
22 
23 #include <netlink-private/netlink.h>
24 #include <netlink/attr.h>
25 #include <netlink/netfilter/nfnl.h>
26 #include <netlink/netfilter/queue.h>
27 
nfnl_queue_socket_alloc(void)28 struct nl_sock *nfnl_queue_socket_alloc(void)
29 {
30 	struct nl_sock *nlsk;
31 
32 	nlsk = nl_socket_alloc();
33 	if (nlsk)
34 		nl_socket_disable_auto_ack(nlsk);
35 	return nlsk;
36 }
37 
send_queue_request(struct nl_sock * sk,struct nl_msg * msg)38 static int send_queue_request(struct nl_sock *sk, struct nl_msg *msg)
39 {
40 	int err;
41 
42 	err = nl_send_auto_complete(sk, msg);
43 	nlmsg_free(msg);
44 	if (err < 0)
45 		return err;
46 
47 	return wait_for_ack(sk);
48 }
49 
50 /**
51  * @name Queue Commands
52  * @{
53  */
54 
build_queue_cmd_request(uint8_t family,uint16_t queuenum,uint8_t command,struct nl_msg ** result)55 static int build_queue_cmd_request(uint8_t family, uint16_t queuenum,
56 				   uint8_t command, struct nl_msg **result)
57 {
58 	struct nl_msg *msg;
59 	struct nfqnl_msg_config_cmd cmd;
60 
61 	msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_QUEUE, NFQNL_MSG_CONFIG, 0,
62 				   family, queuenum);
63 	if (msg == NULL)
64 		return -NLE_NOMEM;
65 
66 	cmd.pf = htons(family);
67 	cmd._pad = 0;
68 	cmd.command = command;
69 	if (nla_put(msg, NFQA_CFG_CMD, sizeof(cmd), &cmd) < 0)
70 		goto nla_put_failure;
71 
72 	*result = msg;
73 	return 0;
74 
75 nla_put_failure:
76 	nlmsg_free(msg);
77 	return -NLE_MSGSIZE;
78 }
79 
nfnl_queue_build_pf_bind(uint8_t pf,struct nl_msg ** result)80 int nfnl_queue_build_pf_bind(uint8_t pf, struct nl_msg **result)
81 {
82 	return build_queue_cmd_request(pf, 0, NFQNL_CFG_CMD_PF_BIND, result);
83 }
84 
nfnl_queue_pf_bind(struct nl_sock * nlh,uint8_t pf)85 int nfnl_queue_pf_bind(struct nl_sock *nlh, uint8_t pf)
86 {
87 	struct nl_msg *msg;
88 	int err;
89 
90 	if ((err = nfnl_queue_build_pf_bind(pf, &msg)) < 0)
91 		return err;
92 
93 	return send_queue_request(nlh, msg);
94 }
95 
nfnl_queue_build_pf_unbind(uint8_t pf,struct nl_msg ** result)96 int nfnl_queue_build_pf_unbind(uint8_t pf, struct nl_msg **result)
97 {
98 	return build_queue_cmd_request(pf, 0, NFQNL_CFG_CMD_PF_UNBIND, result);
99 }
100 
nfnl_queue_pf_unbind(struct nl_sock * nlh,uint8_t pf)101 int nfnl_queue_pf_unbind(struct nl_sock *nlh, uint8_t pf)
102 {
103 	struct nl_msg *msg;
104 	int err;
105 
106 	if ((err = nfnl_queue_build_pf_unbind(pf, &msg)) < 0)
107 		return err;
108 
109 	return send_queue_request(nlh, msg);
110 }
111 
nfnl_queue_build_request(const struct nfnl_queue * queue,struct nl_msg ** result)112 static int nfnl_queue_build_request(const struct nfnl_queue *queue,
113 				    struct nl_msg **result)
114 {
115 	struct nl_msg *msg;
116 
117 	if (!nfnl_queue_test_group(queue))
118 		return -NLE_MISSING_ATTR;
119 
120 	msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_QUEUE, NFQNL_MSG_CONFIG, 0,
121 				   0, nfnl_queue_get_group(queue));
122 	if (msg == NULL)
123 		return -NLE_NOMEM;
124 
125 	if (nfnl_queue_test_maxlen(queue) &&
126 	    nla_put_u32(msg, NFQA_CFG_QUEUE_MAXLEN,
127 			htonl(nfnl_queue_get_maxlen(queue))) < 0)
128 		goto nla_put_failure;
129 
130 	/* This sucks, the nfnetlink_queue interface always expects both
131 	 * parameters to be present. Needs to be done properly.
132 	 */
133 	if (nfnl_queue_test_copy_mode(queue)) {
134 		struct nfqnl_msg_config_params params;
135 
136 		switch (nfnl_queue_get_copy_mode(queue)) {
137 		case NFNL_QUEUE_COPY_NONE:
138 			params.copy_mode = NFQNL_COPY_NONE;
139 			break;
140 		case NFNL_QUEUE_COPY_META:
141 			params.copy_mode = NFQNL_COPY_META;
142 			break;
143 		case NFNL_QUEUE_COPY_PACKET:
144 			params.copy_mode = NFQNL_COPY_PACKET;
145 			break;
146 		}
147 		params.copy_range = htonl(nfnl_queue_get_copy_range(queue));
148 
149 		if (nla_put(msg, NFQA_CFG_PARAMS, sizeof(params), &params) < 0)
150 			goto nla_put_failure;
151 	}
152 
153 	*result = msg;
154 	return 0;
155 
156 nla_put_failure:
157 	nlmsg_free(msg);
158 	return -NLE_MSGSIZE;
159 }
160 
nfnl_queue_build_create_request(const struct nfnl_queue * queue,struct nl_msg ** result)161 int nfnl_queue_build_create_request(const struct nfnl_queue *queue,
162 				    struct nl_msg **result)
163 {
164 	struct nfqnl_msg_config_cmd cmd;
165 	int err;
166 
167 	if ((err = nfnl_queue_build_request(queue, result)) < 0)
168 		return err;
169 
170 	cmd.pf = 0;
171 	cmd._pad = 0;
172 	cmd.command = NFQNL_CFG_CMD_BIND;
173 
174 	NLA_PUT(*result, NFQA_CFG_CMD, sizeof(cmd), &cmd);
175 
176 	return 0;
177 
178 nla_put_failure:
179 	nlmsg_free(*result);
180 	return -NLE_MSGSIZE;
181 }
182 
nfnl_queue_create(struct nl_sock * nlh,const struct nfnl_queue * queue)183 int nfnl_queue_create(struct nl_sock *nlh, const struct nfnl_queue *queue)
184 {
185 	struct nl_msg *msg;
186 	int err;
187 
188 	if ((err = nfnl_queue_build_create_request(queue, &msg)) < 0)
189 		return err;
190 
191 	return send_queue_request(nlh, msg);
192 }
193 
nfnl_queue_build_change_request(const struct nfnl_queue * queue,struct nl_msg ** result)194 int nfnl_queue_build_change_request(const struct nfnl_queue *queue,
195 				    struct nl_msg **result)
196 {
197 	return nfnl_queue_build_request(queue, result);
198 }
199 
nfnl_queue_change(struct nl_sock * nlh,const struct nfnl_queue * queue)200 int nfnl_queue_change(struct nl_sock *nlh, const struct nfnl_queue *queue)
201 {
202 	struct nl_msg *msg;
203 	int err;
204 
205 	if ((err = nfnl_queue_build_change_request(queue, &msg)) < 0)
206 		return err;
207 
208 	return send_queue_request(nlh, msg);
209 }
210 
nfnl_queue_build_delete_request(const struct nfnl_queue * queue,struct nl_msg ** result)211 int nfnl_queue_build_delete_request(const struct nfnl_queue *queue,
212 				    struct nl_msg **result)
213 {
214 	if (!nfnl_queue_test_group(queue))
215 		return -NLE_MISSING_ATTR;
216 
217 	return build_queue_cmd_request(0, nfnl_queue_get_group(queue),
218 				       NFQNL_CFG_CMD_UNBIND, result);
219 }
220 
nfnl_queue_delete(struct nl_sock * nlh,const struct nfnl_queue * queue)221 int nfnl_queue_delete(struct nl_sock *nlh, const struct nfnl_queue *queue)
222 {
223 	struct nl_msg *msg;
224 	int err;
225 
226 	if ((err = nfnl_queue_build_delete_request(queue, &msg)) < 0)
227 		return err;
228 
229 	return send_queue_request(nlh, msg);
230 }
231 
232 /** @} */
233 
234 static struct nl_cache_ops nfnl_queue_ops = {
235 	.co_name		= "netfilter/queue",
236 	.co_obj_ops		= &queue_obj_ops,
237 	.co_msgtypes		= {
238 		END_OF_MSGTYPES_LIST,
239 	},
240 };
241 
nfnl_queue_init(void)242 static void __init nfnl_queue_init(void)
243 {
244 	nl_cache_mngt_register(&nfnl_queue_ops);
245 }
246 
nfnl_queue_exit(void)247 static void __exit nfnl_queue_exit(void)
248 {
249 	nl_cache_mngt_unregister(&nfnl_queue_ops);
250 }
251 
252 /** @} */
253