[LIBNL]: Add nfnetlink_queue support
Signed-off-by: Patrick McHardy <kaber@trash.net>
This commit is contained in:
parent
665b757809
commit
e72cb033f2
9 changed files with 1649 additions and 0 deletions
94
include/linux/netfilter/nfnetlink_queue.h
Normal file
94
include/linux/netfilter/nfnetlink_queue.h
Normal file
|
@ -0,0 +1,94 @@
|
|||
#ifndef _NFNETLINK_QUEUE_H
|
||||
#define _NFNETLINK_QUEUE_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/netfilter/nfnetlink.h>
|
||||
|
||||
#ifndef aligned_be64
|
||||
#define aligned_be64 u_int64_t __attribute__((aligned(8)))
|
||||
#endif
|
||||
|
||||
enum nfqnl_msg_types {
|
||||
NFQNL_MSG_PACKET, /* packet from kernel to userspace */
|
||||
NFQNL_MSG_VERDICT, /* verdict from userspace to kernel */
|
||||
NFQNL_MSG_CONFIG, /* connect to a particular queue */
|
||||
|
||||
NFQNL_MSG_MAX
|
||||
};
|
||||
|
||||
struct nfqnl_msg_packet_hdr {
|
||||
__be32 packet_id; /* unique ID of packet in queue */
|
||||
__be16 hw_protocol; /* hw protocol (network order) */
|
||||
u_int8_t hook; /* netfilter hook */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct nfqnl_msg_packet_hw {
|
||||
__be16 hw_addrlen;
|
||||
u_int16_t _pad;
|
||||
u_int8_t hw_addr[8];
|
||||
};
|
||||
|
||||
struct nfqnl_msg_packet_timestamp {
|
||||
aligned_be64 sec;
|
||||
aligned_be64 usec;
|
||||
};
|
||||
|
||||
enum nfqnl_attr_type {
|
||||
NFQA_UNSPEC,
|
||||
NFQA_PACKET_HDR,
|
||||
NFQA_VERDICT_HDR, /* nfqnl_msg_verdict_hrd */
|
||||
NFQA_MARK, /* u_int32_t nfmark */
|
||||
NFQA_TIMESTAMP, /* nfqnl_msg_packet_timestamp */
|
||||
NFQA_IFINDEX_INDEV, /* u_int32_t ifindex */
|
||||
NFQA_IFINDEX_OUTDEV, /* u_int32_t ifindex */
|
||||
NFQA_IFINDEX_PHYSINDEV, /* u_int32_t ifindex */
|
||||
NFQA_IFINDEX_PHYSOUTDEV, /* u_int32_t ifindex */
|
||||
NFQA_HWADDR, /* nfqnl_msg_packet_hw */
|
||||
NFQA_PAYLOAD, /* opaque data payload */
|
||||
|
||||
__NFQA_MAX
|
||||
};
|
||||
#define NFQA_MAX (__NFQA_MAX - 1)
|
||||
|
||||
struct nfqnl_msg_verdict_hdr {
|
||||
__be32 verdict;
|
||||
__be32 id;
|
||||
};
|
||||
|
||||
|
||||
enum nfqnl_msg_config_cmds {
|
||||
NFQNL_CFG_CMD_NONE,
|
||||
NFQNL_CFG_CMD_BIND,
|
||||
NFQNL_CFG_CMD_UNBIND,
|
||||
NFQNL_CFG_CMD_PF_BIND,
|
||||
NFQNL_CFG_CMD_PF_UNBIND,
|
||||
};
|
||||
|
||||
struct nfqnl_msg_config_cmd {
|
||||
u_int8_t command; /* nfqnl_msg_config_cmds */
|
||||
u_int8_t _pad;
|
||||
__be16 pf; /* AF_xxx for PF_[UN]BIND */
|
||||
};
|
||||
|
||||
enum nfqnl_config_mode {
|
||||
NFQNL_COPY_NONE,
|
||||
NFQNL_COPY_META,
|
||||
NFQNL_COPY_PACKET,
|
||||
};
|
||||
|
||||
struct nfqnl_msg_config_params {
|
||||
__be32 copy_range;
|
||||
u_int8_t copy_mode; /* enum nfqnl_config_mode */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
enum nfqnl_attr_config {
|
||||
NFQA_CFG_UNSPEC,
|
||||
NFQA_CFG_CMD, /* nfqnl_msg_config_cmd */
|
||||
NFQA_CFG_PARAMS, /* nfqnl_msg_config_params */
|
||||
NFQA_CFG_QUEUE_MAXLEN, /* u_int32_t */
|
||||
__NFQA_CFG_MAX
|
||||
};
|
||||
#define NFQA_CFG_MAX (__NFQA_CFG_MAX-1)
|
||||
|
||||
#endif /* _NFNETLINK_QUEUE_H */
|
|
@ -755,4 +755,34 @@ struct nfnl_log {
|
|||
uint32_t log_seq_global;
|
||||
};
|
||||
|
||||
struct nfnl_queue {
|
||||
NLHDR_COMMON
|
||||
|
||||
uint16_t queue_group;
|
||||
uint32_t queue_maxlen;
|
||||
uint32_t queue_copy_range;
|
||||
uint8_t queue_copy_mode;
|
||||
};
|
||||
|
||||
struct nfnl_queue_msg {
|
||||
NLHDR_COMMON
|
||||
|
||||
uint16_t queue_msg_group;
|
||||
uint8_t queue_msg_family;
|
||||
uint8_t queue_msg_hook;
|
||||
uint16_t queue_msg_hwproto;
|
||||
uint32_t queue_msg_packetid;
|
||||
uint32_t queue_msg_mark;
|
||||
struct timeval queue_msg_timestamp;
|
||||
uint32_t queue_msg_indev;
|
||||
uint32_t queue_msg_outdev;
|
||||
uint32_t queue_msg_physindev;
|
||||
uint32_t queue_msg_physoutdev;
|
||||
uint8_t queue_msg_hwaddr[8];
|
||||
int queue_msg_hwaddr_len;
|
||||
void * queue_msg_payload;
|
||||
int queue_msg_payload_len;
|
||||
uint32_t queue_msg_verdict;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
86
include/netlink/netfilter/queue.h
Normal file
86
include/netlink/netfilter/queue.h
Normal file
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* netlink/netfilter/queue.h 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>
|
||||
*/
|
||||
|
||||
#ifndef NETLINK_QUEUE_H_
|
||||
#define NETLINK_QUEUE_H_
|
||||
|
||||
#include <netlink/netlink.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct nl_handle;
|
||||
struct nlmsghdr;
|
||||
struct nfnl_queue;
|
||||
|
||||
extern struct nl_object_ops queue_obj_ops;
|
||||
|
||||
enum nfnl_queue_copy_mode {
|
||||
NFNL_QUEUE_COPY_NONE,
|
||||
NFNL_QUEUE_COPY_META,
|
||||
NFNL_QUEUE_COPY_PACKET,
|
||||
};
|
||||
|
||||
/* General */
|
||||
extern struct nfnl_queue * nfnl_queue_alloc(void);
|
||||
|
||||
extern void nfnl_queue_get(struct nfnl_queue *);
|
||||
extern void nfnl_queue_put(struct nfnl_queue *);
|
||||
|
||||
/* Attributes */
|
||||
extern void nfnl_queue_set_group(struct nfnl_queue *, uint16_t);
|
||||
extern int nfnl_queue_test_group(const struct nfnl_queue *);
|
||||
extern uint16_t nfnl_queue_get_group(const struct nfnl_queue *);
|
||||
|
||||
extern void nfnl_queue_set_maxlen(struct nfnl_queue *, uint32_t);
|
||||
extern int nfnl_queue_test_maxlen(const struct nfnl_queue *);
|
||||
extern uint32_t nfnl_queue_get_maxlen(const struct nfnl_queue *);
|
||||
|
||||
extern void nfnl_queue_set_copy_mode(struct nfnl_queue *,
|
||||
enum nfnl_queue_copy_mode);
|
||||
extern int nfnl_queue_test_copy_mode(const struct nfnl_queue *);
|
||||
extern enum nfnl_queue_copy_mode nfnl_queue_get_copy_mode(const struct nfnl_queue *);
|
||||
|
||||
extern char * nfnl_queue_copy_mode2str(enum nfnl_queue_copy_mode,
|
||||
char *, size_t);
|
||||
extern enum nfnl_queue_copy_mode nfnl_queue_str2copy_mode(const char *);
|
||||
|
||||
extern void nfnl_queue_set_copy_range(struct nfnl_queue *,
|
||||
uint32_t);
|
||||
extern int nfnl_queue_test_copy_range(const struct nfnl_queue *);
|
||||
extern uint32_t nfnl_queue_get_copy_range(const struct nfnl_queue *);
|
||||
|
||||
/* Message construction / sending */
|
||||
extern struct nl_msg * nfnl_queue_build_pf_bind(uint8_t);
|
||||
extern int nfnl_queue_pf_bind(struct nl_handle *, uint8_t);
|
||||
|
||||
extern struct nl_msg * nfnl_queue_build_pf_unbind(uint8_t);
|
||||
extern int nfnl_queue_pf_unbind(struct nl_handle *, uint8_t);
|
||||
|
||||
extern struct nl_msg * nfnl_queue_build_create_request(const struct nfnl_queue *);
|
||||
extern int nfnl_queue_create(struct nl_handle *,
|
||||
const struct nfnl_queue *);
|
||||
|
||||
extern struct nl_msg * nfnl_queue_build_change_request(const struct nfnl_queue *);
|
||||
extern int nfnl_queue_change(struct nl_handle *,
|
||||
const struct nfnl_queue *);
|
||||
|
||||
extern struct nl_msg * nfnl_queue_build_delete_request(const struct nfnl_queue *);
|
||||
extern int nfnl_queue_delete(struct nl_handle *,
|
||||
const struct nfnl_queue *);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
101
include/netlink/netfilter/queue_msg.h
Normal file
101
include/netlink/netfilter/queue_msg.h
Normal file
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* netlink/netfilter/queue_msg.h Netfilter Queue Messages
|
||||
*
|
||||
* 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>
|
||||
*/
|
||||
|
||||
#ifndef NETLINK_QUEUE_MSG_H_
|
||||
#define NETLINK_QUEUE_MSG_H_
|
||||
|
||||
#include <netlink/netlink.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct nl_handle;
|
||||
struct nlmsghdr;
|
||||
struct nfnl_queue_msg;
|
||||
|
||||
extern struct nl_object_ops queue_msg_obj_ops;
|
||||
|
||||
/* General */
|
||||
extern struct nfnl_queue_msg * nfnl_queue_msg_alloc(void);
|
||||
extern struct nfnl_queue_msg * nfnlmsg_queue_msg_parse(struct nlmsghdr *);
|
||||
|
||||
extern void nfnl_queue_msg_get(struct nfnl_queue_msg *);
|
||||
extern void nfnl_queue_msg_put(struct nfnl_queue_msg *);
|
||||
|
||||
extern void nfnl_queue_msg_set_group(struct nfnl_queue_msg *, uint16_t);
|
||||
extern int nfnl_queue_msg_test_group(const struct nfnl_queue_msg *);
|
||||
extern uint16_t nfnl_queue_msg_get_group(const struct nfnl_queue_msg *);
|
||||
|
||||
extern void nfnl_queue_msg_set_family(struct nfnl_queue_msg *, uint8_t);
|
||||
extern int nfnl_queue_msg_test_family(const struct nfnl_queue_msg *);
|
||||
extern uint8_t nfnl_queue_msg_get_family(const struct nfnl_queue_msg *);
|
||||
|
||||
extern void nfnl_queue_msg_set_packetid(struct nfnl_queue_msg *, uint32_t);
|
||||
extern int nfnl_queue_msg_test_packetid(const struct nfnl_queue_msg *);
|
||||
extern uint16_t nfnl_queue_msg_get_packetid(const struct nfnl_queue_msg *);
|
||||
|
||||
extern void nfnl_queue_msg_set_hwproto(struct nfnl_queue_msg *, uint16_t);
|
||||
extern int nfnl_queue_msg_test_hwproto(const struct nfnl_queue_msg *);
|
||||
extern uint16_t nfnl_queue_msg_get_hwproto(const struct nfnl_queue_msg *);
|
||||
|
||||
extern void nfnl_queue_msg_set_hook(struct nfnl_queue_msg *, uint8_t);
|
||||
extern int nfnl_queue_msg_test_hook(const struct nfnl_queue_msg *);
|
||||
extern uint8_t nfnl_queue_msg_get_hook(const struct nfnl_queue_msg *);
|
||||
|
||||
extern void nfnl_queue_msg_set_mark(struct nfnl_queue_msg *, uint32_t);
|
||||
extern int nfnl_queue_msg_test_mark(const struct nfnl_queue_msg *);
|
||||
extern uint32_t nfnl_queue_msg_get_mark(const struct nfnl_queue_msg *);
|
||||
|
||||
extern void nfnl_queue_msg_set_timestamp(struct nfnl_queue_msg *,
|
||||
struct timeval *);
|
||||
extern int nfnl_queue_msg_test_timestamp(const struct nfnl_queue_msg *);
|
||||
extern const struct timeval * nfnl_queue_msg_get_timestamp(const struct nfnl_queue_msg *);
|
||||
|
||||
extern void nfnl_queue_msg_set_indev(struct nfnl_queue_msg *, uint32_t);
|
||||
extern int nfnl_queue_msg_test_indev(const struct nfnl_queue_msg *);
|
||||
extern uint32_t nfnl_queue_msg_get_indev(const struct nfnl_queue_msg *);
|
||||
|
||||
extern void nfnl_queue_msg_set_outdev(struct nfnl_queue_msg *, uint32_t);
|
||||
extern int nfnl_queue_msg_test_outdev(const struct nfnl_queue_msg *);
|
||||
extern uint32_t nfnl_queue_msg_get_outdev(const struct nfnl_queue_msg *);
|
||||
|
||||
extern void nfnl_queue_msg_set_physindev(struct nfnl_queue_msg *, uint32_t);
|
||||
extern int nfnl_queue_msg_test_physindev(const struct nfnl_queue_msg *);
|
||||
extern uint32_t nfnl_queue_msg_get_physindev(const struct nfnl_queue_msg *);
|
||||
|
||||
extern void nfnl_queue_msg_set_physoutdev(struct nfnl_queue_msg *, uint32_t);
|
||||
extern int nfnl_queue_msg_test_physoutdev(const struct nfnl_queue_msg *);
|
||||
extern uint32_t nfnl_queue_msg_get_physoutdev(const struct nfnl_queue_msg *);
|
||||
|
||||
extern void nfnl_queue_msg_set_hwaddr(struct nfnl_queue_msg *, uint8_t *, int);
|
||||
extern int nfnl_queue_msg_test_hwaddr(const struct nfnl_queue_msg *);
|
||||
extern const uint8_t * nfnl_queue_msg_get_hwaddr(const struct nfnl_queue_msg *, int *);
|
||||
|
||||
extern int nfnl_queue_msg_set_payload(struct nfnl_queue_msg *, uint8_t *, int);
|
||||
extern int nfnl_queue_msg_test_payload(const struct nfnl_queue_msg *);
|
||||
extern const void * nfnl_queue_msg_get_payload(const struct nfnl_queue_msg *, int *);
|
||||
|
||||
extern void nfnl_queue_msg_set_verdict(struct nfnl_queue_msg *,
|
||||
unsigned int);
|
||||
extern int nfnl_queue_msg_test_verdict(const struct nfnl_queue_msg *);
|
||||
extern unsigned int nfnl_queue_msg_get_verdict(const struct nfnl_queue_msg *);
|
||||
|
||||
extern struct nl_msg * nfnl_queue_msg_build_verdict(const struct nfnl_queue_msg *);
|
||||
extern int nfnl_queue_msg_send_verdict(struct nl_handle *,
|
||||
const struct nfnl_queue_msg *);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
233
lib/netfilter/queue.c
Normal file
233
lib/netfilter/queue.c
Normal file
|
@ -0,0 +1,233 @@
|
|||
/*
|
||||
* 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,
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/** @} */
|
240
lib/netfilter/queue_msg.c
Normal file
240
lib/netfilter/queue_msg.c
Normal file
|
@ -0,0 +1,240 @@
|
|||
/*
|
||||
* lib/netfilter/queue_msg.c Netfilter Queue Messages
|
||||
*
|
||||
* 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_msg.h>
|
||||
|
||||
static struct nl_cache_ops nfnl_queue_msg_ops;
|
||||
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
static uint64_t ntohll(uint64_t x)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
#elif __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
static uint64_t ntohll(uint64_t x)
|
||||
{
|
||||
return __bswap_64(x);
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct nla_policy queue_policy[NFQA_MAX+1] = {
|
||||
[NFQA_PACKET_HDR] = {
|
||||
.minlen = sizeof(struct nfqnl_msg_packet_hdr),
|
||||
},
|
||||
[NFQA_VERDICT_HDR] = {
|
||||
.minlen = sizeof(struct nfqnl_msg_verdict_hdr),
|
||||
},
|
||||
[NFQA_MARK] = { .type = NLA_U32 },
|
||||
[NFQA_TIMESTAMP] = {
|
||||
.minlen = sizeof(struct nfqnl_msg_packet_timestamp),
|
||||
},
|
||||
[NFQA_IFINDEX_INDEV] = { .type = NLA_U32 },
|
||||
[NFQA_IFINDEX_OUTDEV] = { .type = NLA_U32 },
|
||||
[NFQA_IFINDEX_PHYSINDEV] = { .type = NLA_U32 },
|
||||
[NFQA_IFINDEX_PHYSOUTDEV] = { .type = NLA_U32 },
|
||||
[NFQA_HWADDR] = {
|
||||
.minlen = sizeof(struct nfqnl_msg_packet_timestamp),
|
||||
},
|
||||
};
|
||||
|
||||
struct nfnl_queue_msg *nfnlmsg_queue_msg_parse(struct nlmsghdr *nlh)
|
||||
{
|
||||
struct nfnl_queue_msg *msg;
|
||||
struct nlattr *tb[NFQA_MAX+1];
|
||||
struct nlattr *attr;
|
||||
int err;
|
||||
|
||||
msg = nfnl_queue_msg_alloc();
|
||||
if (!msg)
|
||||
return NULL;
|
||||
|
||||
msg->ce_msgtype = nlh->nlmsg_type;
|
||||
|
||||
err = nlmsg_parse(nlh, sizeof(struct nfgenmsg), tb, NFQA_MAX,
|
||||
queue_policy);
|
||||
if (err < 0)
|
||||
goto errout;
|
||||
|
||||
nfnl_queue_msg_set_group(msg, nfnlmsg_res_id(nlh));
|
||||
nfnl_queue_msg_set_family(msg, nfnlmsg_family(nlh));
|
||||
|
||||
attr = tb[NFQA_PACKET_HDR];
|
||||
if (attr) {
|
||||
struct nfqnl_msg_packet_hdr *hdr = nla_data(attr);
|
||||
|
||||
nfnl_queue_msg_set_packetid(msg, ntohl(hdr->packet_id));
|
||||
if (hdr->hw_protocol)
|
||||
nfnl_queue_msg_set_hwproto(msg, hdr->hw_protocol);
|
||||
nfnl_queue_msg_set_hook(msg, hdr->hook);
|
||||
}
|
||||
|
||||
attr = tb[NFQA_MARK];
|
||||
if (attr)
|
||||
nfnl_queue_msg_set_mark(msg, ntohl(nla_get_u32(attr)));
|
||||
|
||||
attr = tb[NFQA_TIMESTAMP];
|
||||
if (attr) {
|
||||
struct nfqnl_msg_packet_timestamp *timestamp = nla_data(attr);
|
||||
struct timeval tv;
|
||||
|
||||
tv.tv_sec = ntohll(timestamp->sec);
|
||||
tv.tv_usec = ntohll(timestamp->usec);
|
||||
nfnl_queue_msg_set_timestamp(msg, &tv);
|
||||
}
|
||||
|
||||
attr = tb[NFQA_IFINDEX_INDEV];
|
||||
if (attr)
|
||||
nfnl_queue_msg_set_indev(msg, ntohl(nla_get_u32(attr)));
|
||||
|
||||
attr = tb[NFQA_IFINDEX_OUTDEV];
|
||||
if (attr)
|
||||
nfnl_queue_msg_set_outdev(msg, ntohl(nla_get_u32(attr)));
|
||||
|
||||
attr = tb[NFQA_IFINDEX_PHYSINDEV];
|
||||
if (attr)
|
||||
nfnl_queue_msg_set_physindev(msg, ntohl(nla_get_u32(attr)));
|
||||
|
||||
attr = tb[NFQA_IFINDEX_PHYSOUTDEV];
|
||||
if (attr)
|
||||
nfnl_queue_msg_set_physoutdev(msg, ntohl(nla_get_u32(attr)));
|
||||
|
||||
attr = tb[NFQA_HWADDR];
|
||||
if (attr) {
|
||||
struct nfqnl_msg_packet_hw *hw = nla_data(attr);
|
||||
|
||||
nfnl_queue_msg_set_hwaddr(msg, hw->hw_addr,
|
||||
ntohs(hw->hw_addrlen));
|
||||
}
|
||||
|
||||
attr = tb[NFQA_PAYLOAD];
|
||||
if (attr) {
|
||||
err = nfnl_queue_msg_set_payload(msg, nla_data(attr),
|
||||
nla_len(attr));
|
||||
if (err < 0)
|
||||
goto errout;
|
||||
}
|
||||
|
||||
return msg;
|
||||
|
||||
errout:
|
||||
nfnl_queue_msg_put(msg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int queue_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
|
||||
struct nlmsghdr *nlh, struct nl_parser_param *pp)
|
||||
{
|
||||
struct nfnl_queue_msg *msg;
|
||||
int err;
|
||||
|
||||
msg = nfnlmsg_queue_msg_parse(nlh);
|
||||
if (msg == NULL)
|
||||
goto errout_errno;
|
||||
|
||||
err = pp->pp_cb((struct nl_object *) msg, pp);
|
||||
if (err < 0)
|
||||
goto errout;
|
||||
|
||||
err = P_ACCEPT;
|
||||
|
||||
errout:
|
||||
nfnl_queue_msg_put(msg);
|
||||
return err;
|
||||
|
||||
errout_errno:
|
||||
err = nl_get_errno();
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
struct nl_msg *nfnl_queue_msg_build_verdict(const struct nfnl_queue_msg *msg)
|
||||
{
|
||||
struct nl_msg *nlmsg;
|
||||
struct nfqnl_msg_verdict_hdr verdict;
|
||||
|
||||
nlmsg = nfnlmsg_alloc_simple(NFNL_SUBSYS_QUEUE, NFQNL_MSG_VERDICT, 0,
|
||||
nfnl_queue_msg_get_family(msg),
|
||||
nfnl_queue_msg_get_group(msg));
|
||||
if (nlmsg == NULL)
|
||||
return NULL;
|
||||
|
||||
verdict.id = htonl(nfnl_queue_msg_get_packetid(msg));
|
||||
verdict.verdict = htonl(nfnl_queue_msg_get_verdict(msg));
|
||||
if (nla_put(nlmsg, NFQA_VERDICT_HDR, sizeof(verdict), &verdict) < 0)
|
||||
goto nla_put_failure;
|
||||
|
||||
if (nfnl_queue_msg_test_mark(msg) &&
|
||||
nla_put_u32(nlmsg, NFQA_MARK,
|
||||
ntohl(nfnl_queue_msg_get_mark(msg))) < 0)
|
||||
goto nla_put_failure;
|
||||
|
||||
return nlmsg;
|
||||
|
||||
nla_put_failure:
|
||||
nlmsg_free(nlmsg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int nfnl_queue_msg_send_verdict(struct nl_handle *nlh,
|
||||
const struct nfnl_queue_msg *msg)
|
||||
{
|
||||
struct nl_msg *nlmsg;
|
||||
int err;
|
||||
|
||||
nlmsg = nfnl_queue_msg_build_verdict(msg);
|
||||
if (nlmsg == NULL)
|
||||
return nl_errno(ENOMEM);
|
||||
|
||||
err = nl_send_auto_complete(nlh, nlmsg);
|
||||
nlmsg_free(nlmsg);
|
||||
if (err < 0)
|
||||
return err;
|
||||
return nl_wait_for_ack(nlh);
|
||||
}
|
||||
|
||||
#define NFNLMSG_QUEUE_TYPE(type) NFNLMSG_TYPE(NFNL_SUBSYS_QUEUE, (type))
|
||||
static struct nl_cache_ops nfnl_queue_msg_ops = {
|
||||
.co_name = "netfilter/queue_msg",
|
||||
.co_hdrsize = NFNL_HDRLEN,
|
||||
.co_msgtypes = {
|
||||
{ NFNLMSG_QUEUE_TYPE(NFQNL_MSG_PACKET), NL_ACT_NEW, "new" },
|
||||
END_OF_MSGTYPES_LIST,
|
||||
},
|
||||
.co_protocol = NETLINK_NETFILTER,
|
||||
.co_msg_parser = queue_msg_parser,
|
||||
.co_obj_ops = &queue_msg_obj_ops,
|
||||
};
|
||||
|
||||
static void __init nfnl_msg_queue_init(void)
|
||||
{
|
||||
nl_cache_mngt_register(&nfnl_queue_msg_ops);
|
||||
}
|
||||
|
||||
static void __exit nfnl_queue_msg_exit(void)
|
||||
{
|
||||
nl_cache_mngt_unregister(&nfnl_queue_msg_ops);
|
||||
}
|
||||
|
||||
/** @} */
|
480
lib/netfilter/queue_msg_obj.c
Normal file
480
lib/netfilter/queue_msg_obj.c
Normal file
|
@ -0,0 +1,480 @@
|
|||
/*
|
||||
* lib/netfilter/queue_msg_obj.c Netfilter Queue Message Object
|
||||
*
|
||||
* 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>
|
||||
*/
|
||||
|
||||
#include <netlink-local.h>
|
||||
#include <netlink/netfilter/nfnl.h>
|
||||
#include <netlink/netfilter/netfilter.h>
|
||||
#include <netlink/netfilter/queue_msg.h>
|
||||
#include <linux/netfilter.h>
|
||||
|
||||
/** @cond SKIP */
|
||||
#define QUEUE_MSG_ATTR_GROUP (1UL << 0)
|
||||
#define QUEUE_MSG_ATTR_FAMILY (1UL << 1)
|
||||
#define QUEUE_MSG_ATTR_PACKETID (1UL << 2)
|
||||
#define QUEUE_MSG_ATTR_HWPROTO (1UL << 3)
|
||||
#define QUEUE_MSG_ATTR_HOOK (1UL << 4)
|
||||
#define QUEUE_MSG_ATTR_MARK (1UL << 5)
|
||||
#define QUEUE_MSG_ATTR_TIMESTAMP (1UL << 6)
|
||||
#define QUEUE_MSG_ATTR_INDEV (1UL << 7)
|
||||
#define QUEUE_MSG_ATTR_OUTDEV (1UL << 8)
|
||||
#define QUEUE_MSG_ATTR_PHYSINDEV (1UL << 9)
|
||||
#define QUEUE_MSG_ATTR_PHYSOUTDEV (1UL << 10)
|
||||
#define QUEUE_MSG_ATTR_HWADDR (1UL << 11)
|
||||
#define QUEUE_MSG_ATTR_PAYLOAD (1UL << 12)
|
||||
#define QUEUE_MSG_ATTR_VERDICT (1UL << 13)
|
||||
/** @endcond */
|
||||
|
||||
static void nfnl_queue_msg_free_data(struct nl_object *c)
|
||||
{
|
||||
struct nfnl_queue_msg *msg = (struct nfnl_queue_msg *) c;
|
||||
|
||||
if (msg == NULL)
|
||||
return;
|
||||
|
||||
free(msg->queue_msg_payload);
|
||||
}
|
||||
|
||||
static int nfnl_queue_msg_clone(struct nl_object *_dst, struct nl_object *_src)
|
||||
{
|
||||
struct nfnl_queue_msg *dst = (struct nfnl_queue_msg *) _dst;
|
||||
struct nfnl_queue_msg *src = (struct nfnl_queue_msg *) _src;
|
||||
int err;
|
||||
|
||||
if (src->queue_msg_payload) {
|
||||
err = nfnl_queue_msg_set_payload(dst, src->queue_msg_payload,
|
||||
src->queue_msg_payload_len);
|
||||
if (err < 0)
|
||||
goto errout;
|
||||
}
|
||||
|
||||
return 0;
|
||||
errout:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int nfnl_queue_msg_dump(struct nl_object *a, struct nl_dump_params *p)
|
||||
{
|
||||
struct nfnl_queue_msg *msg = (struct nfnl_queue_msg *) a;
|
||||
struct nl_cache *link_cache;
|
||||
char buf[64];
|
||||
|
||||
link_cache = nl_cache_mngt_require("route/link");
|
||||
|
||||
if (msg->ce_mask & QUEUE_MSG_ATTR_GROUP)
|
||||
dp_dump(p, "GROUP=%u ", msg->queue_msg_group);
|
||||
|
||||
if (msg->ce_mask & QUEUE_MSG_ATTR_INDEV) {
|
||||
if (link_cache)
|
||||
dp_dump(p, "IN=%s ",
|
||||
rtnl_link_i2name(link_cache,
|
||||
msg->queue_msg_indev,
|
||||
buf, sizeof(buf)));
|
||||
else
|
||||
dp_dump(p, "IN=%d ", msg->queue_msg_indev);
|
||||
}
|
||||
|
||||
if (msg->ce_mask & QUEUE_MSG_ATTR_PHYSINDEV) {
|
||||
if (link_cache)
|
||||
dp_dump(p, "PHYSIN=%s ",
|
||||
rtnl_link_i2name(link_cache,
|
||||
msg->queue_msg_physindev,
|
||||
buf, sizeof(buf)));
|
||||
else
|
||||
dp_dump(p, "IN=%d ", msg->queue_msg_physindev);
|
||||
}
|
||||
|
||||
if (msg->ce_mask & QUEUE_MSG_ATTR_OUTDEV) {
|
||||
if (link_cache)
|
||||
dp_dump(p, "OUT=%s ",
|
||||
rtnl_link_i2name(link_cache,
|
||||
msg->queue_msg_outdev,
|
||||
buf, sizeof(buf)));
|
||||
else
|
||||
dp_dump(p, "OUT=%d ", msg->queue_msg_outdev);
|
||||
}
|
||||
|
||||
if (msg->ce_mask & QUEUE_MSG_ATTR_PHYSOUTDEV) {
|
||||
if (link_cache)
|
||||
dp_dump(p, "PHYSOUT=%s ",
|
||||
rtnl_link_i2name(link_cache,
|
||||
msg->queue_msg_physoutdev,
|
||||
buf, sizeof(buf)));
|
||||
else
|
||||
dp_dump(p, "PHYSOUT=%d ", msg->queue_msg_physoutdev);
|
||||
}
|
||||
|
||||
if (msg->ce_mask & QUEUE_MSG_ATTR_HWADDR) {
|
||||
int i;
|
||||
|
||||
dp_dump(p, "MAC");
|
||||
for (i = 0; i < msg->queue_msg_hwaddr_len; i++)
|
||||
dp_dump(p, "%c%02x", i?':':'=',
|
||||
msg->queue_msg_hwaddr[i]);
|
||||
dp_dump(p, " ");
|
||||
}
|
||||
|
||||
if (msg->ce_mask & QUEUE_MSG_ATTR_FAMILY)
|
||||
dp_dump(p, "FAMILY=%s ",
|
||||
nl_af2str(msg->queue_msg_family, buf, sizeof(buf)));
|
||||
|
||||
if (msg->ce_mask & QUEUE_MSG_ATTR_HWPROTO)
|
||||
dp_dump(p, "HWPROTO=%s ",
|
||||
nl_ether_proto2str(ntohs(msg->queue_msg_hwproto),
|
||||
buf, sizeof(buf)));
|
||||
|
||||
if (msg->ce_mask & QUEUE_MSG_ATTR_HOOK)
|
||||
dp_dump(p, "HOOK=%s ",
|
||||
nfnl_inet_hook2str(msg->queue_msg_hook,
|
||||
buf, sizeof(buf)));
|
||||
|
||||
if (msg->ce_mask & QUEUE_MSG_ATTR_MARK)
|
||||
dp_dump(p, "MARK=%d ", msg->queue_msg_mark);
|
||||
|
||||
if (msg->ce_mask & QUEUE_MSG_ATTR_PAYLOAD)
|
||||
dp_dump(p, "PAYLOADLEN=%d ", msg->queue_msg_payload_len);
|
||||
|
||||
if (msg->ce_mask & QUEUE_MSG_ATTR_PACKETID)
|
||||
dp_dump(p, "PACKETID=%u ", msg->queue_msg_packetid);
|
||||
|
||||
if (msg->ce_mask & QUEUE_MSG_ATTR_VERDICT)
|
||||
dp_dump(p, "VERDICT=%s ",
|
||||
nfnl_verdict2str(msg->queue_msg_verdict,
|
||||
buf, sizeof(buf)));
|
||||
|
||||
dp_dump(p, "\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @name Allocation/Freeing
|
||||
* @{
|
||||
*/
|
||||
|
||||
struct nfnl_queue_msg *nfnl_queue_msg_alloc(void)
|
||||
{
|
||||
return (struct nfnl_queue_msg *) nl_object_alloc(&queue_msg_obj_ops);
|
||||
}
|
||||
|
||||
void nfnl_queue_msg_get(struct nfnl_queue_msg *msg)
|
||||
{
|
||||
nl_object_get((struct nl_object *) msg);
|
||||
}
|
||||
|
||||
void nfnl_queue_msg_put(struct nfnl_queue_msg *msg)
|
||||
{
|
||||
nl_object_put((struct nl_object *) msg);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Attributes
|
||||
* @{
|
||||
*/
|
||||
|
||||
void nfnl_queue_msg_set_group(struct nfnl_queue_msg *msg, uint16_t group)
|
||||
{
|
||||
msg->queue_msg_group = group;
|
||||
msg->ce_mask |= QUEUE_MSG_ATTR_GROUP;
|
||||
}
|
||||
|
||||
int nfnl_queue_msg_test_group(const struct nfnl_queue_msg *msg)
|
||||
{
|
||||
return !!(msg->ce_mask & QUEUE_MSG_ATTR_GROUP);
|
||||
}
|
||||
|
||||
uint16_t nfnl_queue_msg_get_group(const struct nfnl_queue_msg *msg)
|
||||
{
|
||||
return msg->queue_msg_group;
|
||||
}
|
||||
|
||||
void nfnl_queue_msg_set_family(struct nfnl_queue_msg *msg, uint8_t family)
|
||||
{
|
||||
msg->queue_msg_family = family;
|
||||
msg->ce_mask |= QUEUE_MSG_ATTR_FAMILY;
|
||||
}
|
||||
|
||||
int nfnl_queue_msg_test_family(const struct nfnl_queue_msg *msg)
|
||||
{
|
||||
return !!(msg->ce_mask & QUEUE_MSG_ATTR_FAMILY);
|
||||
}
|
||||
|
||||
uint8_t nfnl_queue_msg_get_family(const struct nfnl_queue_msg *msg)
|
||||
{
|
||||
if (msg->ce_mask & QUEUE_MSG_ATTR_FAMILY)
|
||||
return msg->queue_msg_family;
|
||||
else
|
||||
return AF_UNSPEC;
|
||||
}
|
||||
|
||||
void nfnl_queue_msg_set_packetid(struct nfnl_queue_msg *msg, uint32_t packetid)
|
||||
{
|
||||
msg->queue_msg_packetid = packetid;
|
||||
msg->ce_mask |= QUEUE_MSG_ATTR_PACKETID;
|
||||
}
|
||||
|
||||
int nfnl_queue_msg_test_packetid(const struct nfnl_queue_msg *msg)
|
||||
{
|
||||
return !!(msg->ce_mask & QUEUE_MSG_ATTR_PACKETID);
|
||||
}
|
||||
|
||||
uint16_t nfnl_queue_msg_get_packetid(const struct nfnl_queue_msg *msg)
|
||||
{
|
||||
return msg->queue_msg_packetid;
|
||||
}
|
||||
|
||||
void nfnl_queue_msg_set_hwproto(struct nfnl_queue_msg *msg, uint16_t hwproto)
|
||||
{
|
||||
msg->queue_msg_hwproto = hwproto;
|
||||
msg->ce_mask |= QUEUE_MSG_ATTR_HWPROTO;
|
||||
}
|
||||
|
||||
int nfnl_queue_msg_test_hwproto(const struct nfnl_queue_msg *msg)
|
||||
{
|
||||
return !!(msg->ce_mask & QUEUE_MSG_ATTR_HWPROTO);
|
||||
}
|
||||
|
||||
uint16_t nfnl_queue_msg_get_hwproto(const struct nfnl_queue_msg *msg)
|
||||
{
|
||||
return msg->queue_msg_hwproto;
|
||||
}
|
||||
|
||||
void nfnl_queue_msg_set_hook(struct nfnl_queue_msg *msg, uint8_t hook)
|
||||
{
|
||||
msg->queue_msg_hook = hook;
|
||||
msg->ce_mask |= QUEUE_MSG_ATTR_HOOK;
|
||||
}
|
||||
|
||||
int nfnl_queue_msg_test_hook(const struct nfnl_queue_msg *msg)
|
||||
{
|
||||
return !!(msg->ce_mask & QUEUE_MSG_ATTR_HOOK);
|
||||
}
|
||||
|
||||
uint8_t nfnl_queue_msg_get_hook(const struct nfnl_queue_msg *msg)
|
||||
{
|
||||
return msg->queue_msg_hook;
|
||||
}
|
||||
|
||||
void nfnl_queue_msg_set_mark(struct nfnl_queue_msg *msg, uint32_t mark)
|
||||
{
|
||||
msg->queue_msg_mark = mark;
|
||||
msg->ce_mask |= QUEUE_MSG_ATTR_MARK;
|
||||
}
|
||||
|
||||
int nfnl_queue_msg_test_mark(const struct nfnl_queue_msg *msg)
|
||||
{
|
||||
return !!(msg->ce_mask & QUEUE_MSG_ATTR_MARK);
|
||||
}
|
||||
|
||||
uint32_t nfnl_queue_msg_get_mark(const struct nfnl_queue_msg *msg)
|
||||
{
|
||||
return msg->queue_msg_mark;
|
||||
}
|
||||
|
||||
void nfnl_queue_msg_set_timestamp(struct nfnl_queue_msg *msg,
|
||||
struct timeval *tv)
|
||||
{
|
||||
msg->queue_msg_timestamp.tv_sec = tv->tv_sec;
|
||||
msg->queue_msg_timestamp.tv_usec = tv->tv_usec;
|
||||
msg->ce_mask |= QUEUE_MSG_ATTR_TIMESTAMP;
|
||||
}
|
||||
|
||||
int nfnl_queue_msg_test_timestamp(const struct nfnl_queue_msg *msg)
|
||||
{
|
||||
return !!(msg->ce_mask & QUEUE_MSG_ATTR_TIMESTAMP);
|
||||
}
|
||||
|
||||
const struct timeval *nfnl_queue_msg_get_timestamp(const struct nfnl_queue_msg *msg)
|
||||
{
|
||||
if (!(msg->ce_mask & QUEUE_MSG_ATTR_TIMESTAMP))
|
||||
return NULL;
|
||||
return &msg->queue_msg_timestamp;
|
||||
}
|
||||
|
||||
void nfnl_queue_msg_set_indev(struct nfnl_queue_msg *msg, uint32_t indev)
|
||||
{
|
||||
msg->queue_msg_indev = indev;
|
||||
msg->ce_mask |= QUEUE_MSG_ATTR_INDEV;
|
||||
}
|
||||
|
||||
int nfnl_queue_msg_test_indev(const struct nfnl_queue_msg *msg)
|
||||
{
|
||||
return !!(msg->ce_mask & QUEUE_MSG_ATTR_INDEV);
|
||||
}
|
||||
|
||||
uint32_t nfnl_queue_msg_get_indev(const struct nfnl_queue_msg *msg)
|
||||
{
|
||||
return msg->queue_msg_indev;
|
||||
}
|
||||
|
||||
void nfnl_queue_msg_set_outdev(struct nfnl_queue_msg *msg, uint32_t outdev)
|
||||
{
|
||||
msg->queue_msg_outdev = outdev;
|
||||
msg->ce_mask |= QUEUE_MSG_ATTR_OUTDEV;
|
||||
}
|
||||
|
||||
int nfnl_queue_msg_test_outdev(const struct nfnl_queue_msg *msg)
|
||||
{
|
||||
return !!(msg->ce_mask & QUEUE_MSG_ATTR_OUTDEV);
|
||||
}
|
||||
|
||||
uint32_t nfnl_queue_msg_get_outdev(const struct nfnl_queue_msg *msg)
|
||||
{
|
||||
return msg->queue_msg_outdev;
|
||||
}
|
||||
|
||||
void nfnl_queue_msg_set_physindev(struct nfnl_queue_msg *msg,
|
||||
uint32_t physindev)
|
||||
{
|
||||
msg->queue_msg_physindev = physindev;
|
||||
msg->ce_mask |= QUEUE_MSG_ATTR_PHYSINDEV;
|
||||
}
|
||||
|
||||
int nfnl_queue_msg_test_physindev(const struct nfnl_queue_msg *msg)
|
||||
{
|
||||
return !!(msg->ce_mask & QUEUE_MSG_ATTR_PHYSINDEV);
|
||||
}
|
||||
|
||||
uint32_t nfnl_queue_msg_get_physindev(const struct nfnl_queue_msg *msg)
|
||||
{
|
||||
return msg->queue_msg_physindev;
|
||||
}
|
||||
|
||||
void nfnl_queue_msg_set_physoutdev(struct nfnl_queue_msg *msg,
|
||||
uint32_t physoutdev)
|
||||
{
|
||||
msg->queue_msg_physoutdev = physoutdev;
|
||||
msg->ce_mask |= QUEUE_MSG_ATTR_PHYSOUTDEV;
|
||||
}
|
||||
|
||||
int nfnl_queue_msg_test_physoutdev(const struct nfnl_queue_msg *msg)
|
||||
{
|
||||
return !!(msg->ce_mask & QUEUE_MSG_ATTR_PHYSOUTDEV);
|
||||
}
|
||||
|
||||
uint32_t nfnl_queue_msg_get_physoutdev(const struct nfnl_queue_msg *msg)
|
||||
{
|
||||
return msg->queue_msg_physoutdev;
|
||||
}
|
||||
|
||||
void nfnl_queue_msg_set_hwaddr(struct nfnl_queue_msg *msg, uint8_t *hwaddr,
|
||||
int len)
|
||||
{
|
||||
if (len > sizeof(msg->queue_msg_hwaddr))
|
||||
len = sizeof(msg->queue_msg_hwaddr);
|
||||
|
||||
msg->queue_msg_hwaddr_len = len;
|
||||
memcpy(msg->queue_msg_hwaddr, hwaddr, len);
|
||||
msg->ce_mask |= QUEUE_MSG_ATTR_HWADDR;
|
||||
}
|
||||
|
||||
int nfnl_queue_msg_test_hwaddr(const struct nfnl_queue_msg *msg)
|
||||
{
|
||||
return !!(msg->ce_mask & QUEUE_MSG_ATTR_HWADDR);
|
||||
}
|
||||
|
||||
const uint8_t *nfnl_queue_msg_get_hwaddr(const struct nfnl_queue_msg *msg,
|
||||
int *len)
|
||||
{
|
||||
if (!(msg->ce_mask & QUEUE_MSG_ATTR_HWADDR)) {
|
||||
*len = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*len = msg->queue_msg_hwaddr_len;
|
||||
return msg->queue_msg_hwaddr;
|
||||
}
|
||||
|
||||
int nfnl_queue_msg_set_payload(struct nfnl_queue_msg *msg, uint8_t *payload,
|
||||
int len)
|
||||
{
|
||||
free(msg->queue_msg_payload);
|
||||
msg->queue_msg_payload = malloc(len);
|
||||
if (!msg->queue_msg_payload)
|
||||
return nl_errno(ENOMEM);
|
||||
|
||||
memcpy(msg->queue_msg_payload, payload, len);
|
||||
msg->queue_msg_payload_len = len;
|
||||
msg->ce_mask |= QUEUE_MSG_ATTR_PAYLOAD;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nfnl_queue_msg_test_payload(const struct nfnl_queue_msg *msg)
|
||||
{
|
||||
return !!(msg->ce_mask & QUEUE_MSG_ATTR_PAYLOAD);
|
||||
}
|
||||
|
||||
const void *nfnl_queue_msg_get_payload(const struct nfnl_queue_msg *msg, int *len)
|
||||
{
|
||||
if (!(msg->ce_mask & QUEUE_MSG_ATTR_PAYLOAD)) {
|
||||
*len = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*len = msg->queue_msg_payload_len;
|
||||
return msg->queue_msg_payload;
|
||||
}
|
||||
|
||||
void nfnl_queue_msg_set_verdict(struct nfnl_queue_msg *msg,
|
||||
unsigned int verdict)
|
||||
{
|
||||
msg->queue_msg_verdict = verdict;
|
||||
msg->ce_mask |= QUEUE_MSG_ATTR_VERDICT;
|
||||
}
|
||||
|
||||
int nfnl_queue_msg_test_verdict(const struct nfnl_queue_msg *msg)
|
||||
{
|
||||
return !!(msg->ce_mask & QUEUE_MSG_ATTR_VERDICT);
|
||||
}
|
||||
|
||||
unsigned int nfnl_queue_msg_get_verdict(const struct nfnl_queue_msg *msg)
|
||||
{
|
||||
return msg->queue_msg_verdict;
|
||||
}
|
||||
|
||||
static struct trans_tbl nfnl_queue_msg_attrs[] = {
|
||||
__ADD(QUEUE_MSG_ATTR_GROUP, group)
|
||||
__ADD(QUEUE_MSG_ATTR_FAMILY, family)
|
||||
__ADD(QUEUE_MSG_ATTR_PACKETID, packetid)
|
||||
__ADD(QUEUE_MSG_ATTR_HWPROTO, hwproto)
|
||||
__ADD(QUEUE_MSG_ATTR_HOOK, hook)
|
||||
__ADD(QUEUE_MSG_ATTR_MARK, mark)
|
||||
__ADD(QUEUE_MSG_ATTR_TIMESTAMP, timestamp)
|
||||
__ADD(QUEUE_MSG_ATTR_INDEV, indev)
|
||||
__ADD(QUEUE_MSG_ATTR_OUTDEV, outdev)
|
||||
__ADD(QUEUE_MSG_ATTR_PHYSINDEV, physindev)
|
||||
__ADD(QUEUE_MSG_ATTR_PHYSOUTDEV, physoutdev)
|
||||
__ADD(QUEUE_MSG_ATTR_HWADDR, hwaddr)
|
||||
__ADD(QUEUE_MSG_ATTR_PAYLOAD, payload)
|
||||
__ADD(QUEUE_MSG_ATTR_VERDICT, verdict)
|
||||
};
|
||||
|
||||
static char *nfnl_queue_msg_attrs2str(int attrs, char *buf, size_t len)
|
||||
{
|
||||
return __flags2str(attrs, buf, len, nfnl_queue_msg_attrs,
|
||||
ARRAY_SIZE(nfnl_queue_msg_attrs));
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
struct nl_object_ops queue_msg_obj_ops = {
|
||||
.oo_name = "netfilter/queuemsg",
|
||||
.oo_size = sizeof(struct nfnl_queue_msg),
|
||||
.oo_free_data = nfnl_queue_msg_free_data,
|
||||
.oo_clone = nfnl_queue_msg_clone,
|
||||
.oo_dump[NL_DUMP_BRIEF] = nfnl_queue_msg_dump,
|
||||
.oo_dump[NL_DUMP_FULL] = nfnl_queue_msg_dump,
|
||||
.oo_dump[NL_DUMP_STATS] = nfnl_queue_msg_dump,
|
||||
.oo_attrs2str = nfnl_queue_msg_attrs2str,
|
||||
};
|
||||
|
||||
/** @} */
|
213
lib/netfilter/queue_obj.c
Normal file
213
lib/netfilter/queue_obj.c
Normal file
|
@ -0,0 +1,213 @@
|
|||
/*
|
||||
* lib/netfilter/queue_obj.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 <netlink-local.h>
|
||||
#include <netlink/netfilter/nfnl.h>
|
||||
#include <netlink/netfilter/queue.h>
|
||||
|
||||
/** @cond SKIP */
|
||||
#define QUEUE_ATTR_GROUP (1UL << 0)
|
||||
#define QUEUE_ATTR_MAXLEN (1UL << 1)
|
||||
#define QUEUE_ATTR_COPY_MODE (1UL << 2)
|
||||
#define QUEUE_ATTR_COPY_RANGE (1UL << 3)
|
||||
/** @endcond */
|
||||
|
||||
|
||||
static int nfnl_queue_dump(struct nl_object *a, struct nl_dump_params *p)
|
||||
{
|
||||
struct nfnl_queue *queue = (struct nfnl_queue *) a;
|
||||
char buf[64];
|
||||
|
||||
if (queue->ce_mask & QUEUE_ATTR_GROUP)
|
||||
dp_dump(p, "group=%u ", queue->queue_group);
|
||||
|
||||
if (queue->ce_mask & QUEUE_ATTR_MAXLEN)
|
||||
dp_dump(p, "maxlen=%u ", queue->queue_maxlen);
|
||||
|
||||
if (queue->ce_mask & QUEUE_ATTR_COPY_MODE)
|
||||
dp_dump(p, "copy_mode=%s ",
|
||||
nfnl_queue_copy_mode2str(queue->queue_copy_mode,
|
||||
buf, sizeof(buf)));
|
||||
|
||||
if (queue->ce_mask & QUEUE_ATTR_COPY_RANGE)
|
||||
dp_dump(p, "copy_range=%u ", queue->queue_copy_range);
|
||||
|
||||
dp_dump(p, "\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct trans_tbl copy_modes[] = {
|
||||
__ADD(NFNL_QUEUE_COPY_NONE, none)
|
||||
__ADD(NFNL_QUEUE_COPY_META, meta)
|
||||
__ADD(NFNL_QUEUE_COPY_PACKET, packet)
|
||||
};
|
||||
|
||||
char *nfnl_queue_copy_mode2str(enum nfnl_queue_copy_mode copy_mode, char *buf,
|
||||
size_t len)
|
||||
{
|
||||
return __type2str(copy_mode, buf, len, copy_modes,
|
||||
ARRAY_SIZE(copy_modes));
|
||||
}
|
||||
|
||||
enum nfnl_queue_copy_mode nfnl_queue_str2copy_mode(const char *name)
|
||||
{
|
||||
return __str2type(name, copy_modes, ARRAY_SIZE(copy_modes));
|
||||
}
|
||||
|
||||
/**
|
||||
* @name Allocation/Freeing
|
||||
* @{
|
||||
*/
|
||||
|
||||
struct nfnl_queue *nfnl_queue_alloc(void)
|
||||
{
|
||||
return (struct nfnl_queue *) nl_object_alloc(&queue_obj_ops);
|
||||
}
|
||||
|
||||
void nfnl_queue_get(struct nfnl_queue *queue)
|
||||
{
|
||||
nl_object_get((struct nl_object *) queue);
|
||||
}
|
||||
|
||||
void nfnl_queue_put(struct nfnl_queue *queue)
|
||||
{
|
||||
nl_object_put((struct nl_object *) queue);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Attributes
|
||||
* @{
|
||||
*/
|
||||
|
||||
void nfnl_queue_set_group(struct nfnl_queue *queue, uint16_t group)
|
||||
{
|
||||
queue->queue_group = group;
|
||||
queue->ce_mask |= QUEUE_ATTR_GROUP;
|
||||
}
|
||||
|
||||
int nfnl_queue_test_group(const struct nfnl_queue *queue)
|
||||
{
|
||||
return !!(queue->ce_mask & QUEUE_ATTR_GROUP);
|
||||
}
|
||||
|
||||
uint16_t nfnl_queue_get_group(const struct nfnl_queue *queue)
|
||||
{
|
||||
return queue->queue_group;
|
||||
}
|
||||
|
||||
void nfnl_queue_set_maxlen(struct nfnl_queue *queue, uint32_t maxlen)
|
||||
{
|
||||
queue->queue_maxlen = maxlen;
|
||||
queue->ce_mask |= QUEUE_ATTR_MAXLEN;
|
||||
}
|
||||
|
||||
int nfnl_queue_test_maxlen(const struct nfnl_queue *queue)
|
||||
{
|
||||
return !!(queue->ce_mask & QUEUE_ATTR_MAXLEN);
|
||||
}
|
||||
|
||||
uint32_t nfnl_queue_get_maxlen(const struct nfnl_queue *queue)
|
||||
{
|
||||
return queue->queue_maxlen;
|
||||
}
|
||||
|
||||
void nfnl_queue_set_copy_mode(struct nfnl_queue *queue, enum nfnl_queue_copy_mode mode)
|
||||
{
|
||||
queue->queue_copy_mode = mode;
|
||||
queue->ce_mask |= QUEUE_ATTR_COPY_MODE;
|
||||
}
|
||||
|
||||
int nfnl_queue_test_copy_mode(const struct nfnl_queue *queue)
|
||||
{
|
||||
return !!(queue->ce_mask & QUEUE_ATTR_COPY_MODE);
|
||||
}
|
||||
|
||||
enum nfnl_queue_copy_mode nfnl_queue_get_copy_mode(const struct nfnl_queue *queue)
|
||||
{
|
||||
return queue->queue_copy_mode;
|
||||
}
|
||||
|
||||
void nfnl_queue_set_copy_range(struct nfnl_queue *queue, uint32_t copy_range)
|
||||
{
|
||||
queue->queue_copy_range = copy_range;
|
||||
queue->ce_mask |= QUEUE_ATTR_COPY_RANGE;
|
||||
}
|
||||
|
||||
int nfnl_queue_test_copy_range(const struct nfnl_queue *queue)
|
||||
{
|
||||
return !!(queue->ce_mask & QUEUE_ATTR_COPY_RANGE);
|
||||
}
|
||||
|
||||
uint32_t nfnl_queue_get_copy_range(const struct nfnl_queue *queue)
|
||||
{
|
||||
return queue->queue_copy_range;
|
||||
}
|
||||
|
||||
static int nfnl_queue_compare(struct nl_object *_a, struct nl_object *_b,
|
||||
uint32_t attrs, int flags)
|
||||
{
|
||||
struct nfnl_queue *a = (struct nfnl_queue *) _a;
|
||||
struct nfnl_queue *b = (struct nfnl_queue *) _b;
|
||||
int diff = 0;
|
||||
|
||||
#define NFNL_QUEUE_DIFF(ATTR, EXPR) \
|
||||
ATTR_DIFF(attrs, QUEUE_ATTR_##ATTR, a, b, EXPR)
|
||||
#define NFNL_QUEUE_DIFF_VAL(ATTR, FIELD) \
|
||||
NFNL_QUEUE_DIFF(ATTR, a->FIELD != b->FIELD)
|
||||
|
||||
diff |= NFNL_QUEUE_DIFF_VAL(GROUP, queue_group);
|
||||
diff |= NFNL_QUEUE_DIFF_VAL(MAXLEN, queue_maxlen);
|
||||
diff |= NFNL_QUEUE_DIFF_VAL(COPY_MODE, queue_copy_mode);
|
||||
diff |= NFNL_QUEUE_DIFF_VAL(COPY_RANGE, queue_copy_range);
|
||||
|
||||
#undef NFNL_QUEUE_DIFF
|
||||
#undef NFNL_QUEUE_DIFF_VAL
|
||||
|
||||
return diff;
|
||||
}
|
||||
|
||||
static struct trans_tbl nfnl_queue_attrs[] = {
|
||||
__ADD(QUEUE_ATTR_GROUP, group)
|
||||
__ADD(QUEUE_ATTR_MAXLEN, maxlen)
|
||||
__ADD(QUEUE_ATTR_COPY_MODE, copy_mode)
|
||||
__ADD(QUEUE_ATTR_COPY_RANGE, copy_range)
|
||||
};
|
||||
|
||||
static char *nfnl_queue_attrs2str(int attrs, char *buf, size_t len)
|
||||
{
|
||||
return __flags2str(attrs, buf, len, nfnl_queue_attrs,
|
||||
ARRAY_SIZE(nfnl_queue_attrs));
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
struct nl_object_ops queue_obj_ops = {
|
||||
.oo_name = "netfilter/queue",
|
||||
.oo_size = sizeof(struct nfnl_queue),
|
||||
.oo_dump[NL_DUMP_BRIEF] = nfnl_queue_dump,
|
||||
.oo_dump[NL_DUMP_FULL] = nfnl_queue_dump,
|
||||
.oo_dump[NL_DUMP_STATS] = nfnl_queue_dump,
|
||||
.oo_compare = nfnl_queue_compare,
|
||||
.oo_attrs2str = nfnl_queue_attrs2str,
|
||||
.oo_id_attrs = QUEUE_ATTR_GROUP,
|
||||
};
|
||||
|
||||
/** @} */
|
172
src/nf-queue.c
Normal file
172
src/nf-queue.c
Normal file
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
* src/nf-log.c Monitor netfilter queue events
|
||||
*
|
||||
* 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>
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/netfilter/nfnetlink_queue.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include <netlink/netfilter/nfnl.h>
|
||||
#include <netlink/netfilter/queue.h>
|
||||
#include <netlink/netfilter/queue_msg.h>
|
||||
|
||||
static struct nl_handle *nfnlh;
|
||||
|
||||
static void obj_input(struct nl_object *obj, void *arg)
|
||||
{
|
||||
struct nfnl_queue_msg *msg = (struct nfnl_queue_msg *) obj;
|
||||
struct nl_dump_params dp = {
|
||||
.dp_type = NL_DUMP_STATS,
|
||||
.dp_fd = stdout,
|
||||
.dp_dump_msgtype = 1,
|
||||
};
|
||||
|
||||
nfnl_queue_msg_set_verdict(msg, NF_ACCEPT);
|
||||
nl_object_dump(obj, &dp);
|
||||
nfnl_queue_msg_send_verdict(nfnlh, msg);
|
||||
}
|
||||
|
||||
static int event_input(struct nl_msg *msg, void *arg)
|
||||
{
|
||||
if (nl_msg_parse(msg, &obj_input, NULL) < 0)
|
||||
fprintf(stderr, "<<EVENT>> Unknown message type\n");
|
||||
|
||||
/* Exit nl_recvmsgs_def() and return to the main select() */
|
||||
return NL_STOP;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct nl_handle *rtnlh;
|
||||
struct nl_cache *link_cache;
|
||||
struct nfnl_queue *queue;
|
||||
enum nfnl_queue_copy_mode copy_mode;
|
||||
uint32_t copy_range;
|
||||
int err = 1;
|
||||
int family;
|
||||
|
||||
if (nltool_init(argc, argv) < 0)
|
||||
return -1;
|
||||
|
||||
nfnlh = nltool_alloc_handle();
|
||||
if (nfnlh == NULL)
|
||||
return -1;
|
||||
|
||||
nl_disable_sequence_check(nfnlh);
|
||||
|
||||
nl_socket_modify_cb(nfnlh, NL_CB_VALID, NL_CB_CUSTOM, event_input, NULL);
|
||||
|
||||
if ((argc > 1 && !strcasecmp(argv[1], "-h")) || argc < 3) {
|
||||
printf("Usage: nf-queue family group [ copy_mode ] "
|
||||
"[ copy_range ]\n");
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (nfnl_connect(nfnlh) < 0) {
|
||||
fprintf(stderr, "%s\n", nl_geterror());
|
||||
goto errout;
|
||||
}
|
||||
|
||||
family = nl_str2af(argv[1]);
|
||||
if (family == AF_UNSPEC) {
|
||||
fprintf(stderr, "Unknown family: %s\n", argv[1]);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
nfnl_queue_pf_unbind(nfnlh, family);
|
||||
if (nfnl_queue_pf_bind(nfnlh, family) < 0) {
|
||||
fprintf(stderr, "%s\n", nl_geterror());
|
||||
goto errout;
|
||||
}
|
||||
|
||||
queue = nfnl_queue_alloc();
|
||||
if (queue == NULL) {
|
||||
fprintf(stderr, "%s\n", nl_geterror());
|
||||
goto errout;
|
||||
}
|
||||
|
||||
nfnl_queue_set_group(queue, atoi(argv[2]));
|
||||
|
||||
copy_mode = NFNL_QUEUE_COPY_PACKET;
|
||||
if (argc > 3) {
|
||||
copy_mode = nfnl_queue_str2copy_mode(argv[3]);
|
||||
if (copy_mode < 0) {
|
||||
fprintf(stderr, "%s\n", nl_geterror());
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
nfnl_queue_set_copy_mode(queue, copy_mode);
|
||||
|
||||
copy_range = 0xFFFF;
|
||||
if (argc > 4)
|
||||
copy_range = atoi(argv[4]);
|
||||
nfnl_queue_set_copy_range(queue, copy_range);
|
||||
|
||||
if (nfnl_queue_create(nfnlh, queue) < 0) {
|
||||
fprintf(stderr, "%s\n", nl_geterror());
|
||||
goto errout;
|
||||
}
|
||||
|
||||
rtnlh = nltool_alloc_handle();
|
||||
if (rtnlh == NULL) {
|
||||
goto errout_close;
|
||||
}
|
||||
|
||||
if (nl_connect(rtnlh, NETLINK_ROUTE) < 0) {
|
||||
fprintf(stderr, "%s\n", nl_geterror());
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if ((link_cache = rtnl_link_alloc_cache(rtnlh)) == NULL) {
|
||||
fprintf(stderr, "%s\n", nl_geterror());
|
||||
goto errout_close;
|
||||
}
|
||||
|
||||
nl_cache_mngt_provide(link_cache);
|
||||
|
||||
while (1) {
|
||||
fd_set rfds;
|
||||
int nffd, rtfd, maxfd, retval;
|
||||
|
||||
FD_ZERO(&rfds);
|
||||
|
||||
maxfd = nffd = nl_socket_get_fd(nfnlh);
|
||||
FD_SET(nffd, &rfds);
|
||||
|
||||
rtfd = nl_socket_get_fd(rtnlh);
|
||||
FD_SET(rtfd, &rfds);
|
||||
if (maxfd < rtfd)
|
||||
maxfd = rtfd;
|
||||
|
||||
/* wait for an incoming message on the netlink socket */
|
||||
retval = select(maxfd+1, &rfds, NULL, NULL, NULL);
|
||||
|
||||
if (retval) {
|
||||
if (FD_ISSET(nffd, &rfds))
|
||||
nl_recvmsgs_default(nfnlh);
|
||||
if (FD_ISSET(rtfd, &rfds))
|
||||
nl_recvmsgs_default(rtnlh);
|
||||
}
|
||||
}
|
||||
|
||||
nl_cache_mngt_unprovide(link_cache);
|
||||
nl_cache_free(link_cache);
|
||||
|
||||
nfnl_queue_put(queue);
|
||||
|
||||
nl_close(rtnlh);
|
||||
nl_handle_destroy(rtnlh);
|
||||
errout_close:
|
||||
nl_close(nfnlh);
|
||||
nl_handle_destroy(nfnlh);
|
||||
errout:
|
||||
return err;
|
||||
}
|
Loading…
Add table
Reference in a new issue