236 lines
4.9 KiB
C
236 lines
4.9 KiB
C
/*
|
|
* lib/netfilter/queue.c Netfilter Queue
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation version 2.1
|
|
* of the License.
|
|
*
|
|
* Copyright (c) 2007, 2008 Patrick McHardy <kaber@trash.net>
|
|
*/
|
|
|
|
/**
|
|
* @ingroup nfnl
|
|
* @defgroup queue Queue
|
|
* @brief
|
|
* @{
|
|
*/
|
|
|
|
#include <sys/types.h>
|
|
#include <linux/netfilter/nfnetlink_queue.h>
|
|
|
|
#include <netlink-local.h>
|
|
#include <netlink/attr.h>
|
|
#include <netlink/netfilter/nfnl.h>
|
|
#include <netlink/netfilter/queue.h>
|
|
|
|
static int send_queue_request(struct nl_handle *handle, struct nl_msg *msg)
|
|
{
|
|
int err;
|
|
|
|
err = nl_send_auto_complete(handle, msg);
|
|
nlmsg_free(msg);
|
|
if (err < 0)
|
|
return err;
|
|
|
|
return nl_wait_for_ack(handle);
|
|
}
|
|
|
|
/**
|
|
* @name Queue Commands
|
|
* @{
|
|
*/
|
|
|
|
static struct nl_msg *build_queue_cmd_request(uint8_t family, uint16_t queuenum,
|
|
uint8_t command)
|
|
{
|
|
struct nl_msg *msg;
|
|
struct nfqnl_msg_config_cmd cmd;
|
|
|
|
msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_QUEUE, NFQNL_MSG_CONFIG, 0,
|
|
family, queuenum);
|
|
if (msg == NULL)
|
|
return NULL;
|
|
|
|
cmd.pf = htons(family);
|
|
cmd._pad = 0;
|
|
cmd.command = command;
|
|
if (nla_put(msg, NFQA_CFG_CMD, sizeof(cmd), &cmd) < 0)
|
|
goto nla_put_failure;
|
|
|
|
return msg;
|
|
|
|
nla_put_failure:
|
|
nlmsg_free(msg);
|
|
return NULL;
|
|
}
|
|
|
|
struct nl_msg *nfnl_queue_build_pf_bind(uint8_t pf)
|
|
{
|
|
return build_queue_cmd_request(pf, 0, NFQNL_CFG_CMD_PF_BIND);
|
|
}
|
|
|
|
int nfnl_queue_pf_bind(struct nl_handle *nlh, uint8_t pf)
|
|
{
|
|
struct nl_msg *msg;
|
|
|
|
msg = nfnl_queue_build_pf_bind(pf);
|
|
if (!msg)
|
|
return nl_get_errno();
|
|
|
|
return send_queue_request(nlh, msg);
|
|
}
|
|
|
|
struct nl_msg *nfnl_queue_build_pf_unbind(uint8_t pf)
|
|
{
|
|
return build_queue_cmd_request(pf, 0, NFQNL_CFG_CMD_PF_UNBIND);
|
|
}
|
|
|
|
int nfnl_queue_pf_unbind(struct nl_handle *nlh, uint8_t pf)
|
|
{
|
|
struct nl_msg *msg;
|
|
|
|
msg = nfnl_queue_build_pf_unbind(pf);
|
|
if (!msg)
|
|
return nl_get_errno();
|
|
|
|
return send_queue_request(nlh, msg);
|
|
}
|
|
|
|
static struct nl_msg *nfnl_queue_build_request(const struct nfnl_queue *queue)
|
|
{
|
|
struct nl_msg *msg;
|
|
|
|
if (!nfnl_queue_test_group(queue))
|
|
return NULL;
|
|
|
|
msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_QUEUE, NFQNL_MSG_CONFIG, 0,
|
|
0, nfnl_queue_get_group(queue));
|
|
if (msg == NULL)
|
|
return NULL;
|
|
|
|
if (nfnl_queue_test_maxlen(queue) &&
|
|
nla_put_u32(msg, NFQA_CFG_QUEUE_MAXLEN,
|
|
htonl(nfnl_queue_get_maxlen(queue))) < 0)
|
|
goto nla_put_failure;
|
|
|
|
/* This sucks, the nfnetlink_queue interface always expects both
|
|
* parameters to be present. Needs to be done properly.
|
|
*/
|
|
if (nfnl_queue_test_copy_mode(queue)) {
|
|
struct nfqnl_msg_config_params params;
|
|
|
|
switch (nfnl_queue_get_copy_mode(queue)) {
|
|
case NFNL_QUEUE_COPY_NONE:
|
|
params.copy_mode = NFQNL_COPY_NONE;
|
|
break;
|
|
case NFNL_QUEUE_COPY_META:
|
|
params.copy_mode = NFQNL_COPY_META;
|
|
break;
|
|
case NFNL_QUEUE_COPY_PACKET:
|
|
params.copy_mode = NFQNL_COPY_PACKET;
|
|
break;
|
|
}
|
|
params.copy_range = htonl(nfnl_queue_get_copy_range(queue));
|
|
|
|
if (nla_put(msg, NFQA_CFG_PARAMS, sizeof(params), ¶ms) < 0)
|
|
goto nla_put_failure;
|
|
}
|
|
return msg;
|
|
|
|
nla_put_failure:
|
|
nlmsg_free(msg);
|
|
return NULL;
|
|
}
|
|
|
|
struct nl_msg *nfnl_queue_build_create_request(const struct nfnl_queue *queue)
|
|
{
|
|
struct nl_msg *msg;
|
|
struct nfqnl_msg_config_cmd cmd;
|
|
|
|
msg = nfnl_queue_build_request(queue);
|
|
if (msg == NULL)
|
|
return NULL;
|
|
|
|
cmd.pf = 0;
|
|
cmd._pad = 0;
|
|
cmd.command = NFQNL_CFG_CMD_BIND;
|
|
|
|
if (nla_put(msg, NFQA_CFG_CMD, sizeof(cmd), &cmd) < 0)
|
|
goto nla_put_failure;
|
|
|
|
return msg;
|
|
|
|
nla_put_failure:
|
|
nlmsg_free(msg);
|
|
return NULL;
|
|
}
|
|
|
|
int nfnl_queue_create(struct nl_handle *nlh, const struct nfnl_queue *queue)
|
|
{
|
|
struct nl_msg *msg;
|
|
|
|
msg = nfnl_queue_build_create_request(queue);
|
|
if (msg == NULL)
|
|
return nl_errno(ENOMEM);
|
|
|
|
return send_queue_request(nlh, msg);
|
|
}
|
|
|
|
struct nl_msg *nfnl_queue_build_change_request(const struct nfnl_queue *queue)
|
|
{
|
|
return nfnl_queue_build_request(queue);
|
|
}
|
|
|
|
int nfnl_queue_change(struct nl_handle *nlh, const struct nfnl_queue *queue)
|
|
{
|
|
struct nl_msg *msg;
|
|
|
|
msg = nfnl_queue_build_change_request(queue);
|
|
if (msg == NULL)
|
|
return nl_errno(ENOMEM);
|
|
|
|
return send_queue_request(nlh, msg);
|
|
}
|
|
|
|
struct nl_msg *nfnl_queue_build_delete_request(const struct nfnl_queue *queue)
|
|
{
|
|
if (!nfnl_queue_test_group(queue))
|
|
return NULL;
|
|
|
|
return build_queue_cmd_request(0, nfnl_queue_get_group(queue),
|
|
NFQNL_CFG_CMD_UNBIND);
|
|
}
|
|
|
|
int nfnl_queue_delete(struct nl_handle *nlh, const struct nfnl_queue *queue)
|
|
{
|
|
struct nl_msg *msg;
|
|
|
|
msg = nfnl_queue_build_delete_request(queue);
|
|
if (msg == NULL)
|
|
return nl_errno(ENOMEM);
|
|
|
|
return send_queue_request(nlh, msg);
|
|
}
|
|
|
|
/** @} */
|
|
|
|
static struct nl_cache_ops nfnl_queue_ops = {
|
|
.co_name = "netfilter/queue",
|
|
.co_obj_ops = &queue_obj_ops,
|
|
.co_msgtypes = {
|
|
END_OF_MSGTYPES_LIST,
|
|
},
|
|
};
|
|
|
|
static void __init nfnl_queue_init(void)
|
|
{
|
|
nl_cache_mngt_register(&nfnl_queue_ops);
|
|
}
|
|
|
|
static void __exit nfnl_queue_exit(void)
|
|
{
|
|
nl_cache_mngt_unregister(&nfnl_queue_ops);
|
|
}
|
|
|
|
/** @} */
|