Home | History | Annotate | Download | only in netfilter
      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 (at) 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-private/netlink.h>
     23 #include <netlink/attr.h>
     24 #include <netlink/netfilter/nfnl.h>
     25 #include <netlink/netfilter/queue.h>
     26 
     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 
     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 
     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 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    241 static void __init nfnl_queue_init(void)
    242 {
    243 	nl_cache_mngt_register(&nfnl_queue_ops);
    244 }
    245 
    246 static void __exit nfnl_queue_exit(void)
    247 {
    248 	nl_cache_mngt_unregister(&nfnl_queue_ops);
    249 }
    250 
    251 /** @} */
    252