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