Repo created
This commit is contained in:
parent
51cf8bb4f9
commit
ee0cddf35c
548 changed files with 93129 additions and 2 deletions
10
external/nflog/Android.mk
vendored
Normal file
10
external/nflog/Android.mk
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
# Build original nflog
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_CFLAGS += -fvisibility=default -fPIE
|
||||
LOCAL_LDFLAGS += -rdynamic -fPIE -pie
|
||||
LOCAL_MODULE := nflog
|
||||
LOCAL_SRC_FILES := attr.c callback.c nflog.c nlmsg.c socket.c
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
753
external/nflog/attr.c
vendored
Normal file
753
external/nflog/attr.c
vendored
Normal file
|
|
@ -0,0 +1,753 @@
|
|||
/*
|
||||
* (C) 2008-2012 by Pablo Neira Ayuso <pablo@netfilter.org>
|
||||
*
|
||||
* This program 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; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
#include <limits.h> /* for INT_MAX */
|
||||
#include <libmnl/libmnl.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "internal.h"
|
||||
|
||||
/**
|
||||
* \defgroup attr Netlink attribute helpers
|
||||
*
|
||||
* Netlink Type-Length-Value (TLV) attribute:
|
||||
* \verbatim
|
||||
|<-- 2 bytes -->|<-- 2 bytes -->|<-- variable -->|
|
||||
-------------------------------------------------
|
||||
| length | type | value |
|
||||
-------------------------------------------------
|
||||
|<--------- header ------------>|<-- payload --->|
|
||||
\endverbatim
|
||||
* The payload of the Netlink message contains sequences of attributes that are
|
||||
* expressed in TLV format.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* mnl_attr_get_type - get type of netlink attribute
|
||||
* \param attr pointer to netlink attribute
|
||||
*
|
||||
* This function returns the attribute type.
|
||||
*/
|
||||
uint16_t mnl_attr_get_type(const struct nlattr *attr)
|
||||
{
|
||||
return attr->nla_type & NLA_TYPE_MASK;
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_attr_get_type);
|
||||
|
||||
/**
|
||||
* mnl_attr_get_len - get length of netlink attribute
|
||||
* \param attr pointer to netlink attribute
|
||||
*
|
||||
* This function returns the attribute length that is the attribute header
|
||||
* plus the attribute payload.
|
||||
*/
|
||||
uint16_t mnl_attr_get_len(const struct nlattr *attr)
|
||||
{
|
||||
return attr->nla_len;
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_attr_get_len);
|
||||
|
||||
/**
|
||||
* mnl_attr_get_payload_len - get the attribute payload-value length
|
||||
* \param attr pointer to netlink attribute
|
||||
*
|
||||
* This function returns the attribute payload-value length.
|
||||
*/
|
||||
uint16_t mnl_attr_get_payload_len(const struct nlattr *attr)
|
||||
{
|
||||
return attr->nla_len - MNL_ATTR_HDRLEN;
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_attr_get_payload_len);
|
||||
|
||||
/**
|
||||
* mnl_attr_get_payload - get pointer to the attribute payload
|
||||
* \param attr pointer to netlink attribute
|
||||
*
|
||||
* This function return a pointer to the attribute payload.
|
||||
*/
|
||||
void *mnl_attr_get_payload(const struct nlattr *attr)
|
||||
{
|
||||
return (void *)attr + MNL_ATTR_HDRLEN;
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_attr_get_payload);
|
||||
|
||||
/**
|
||||
* mnl_attr_ok - check if there is room for an attribute in a buffer
|
||||
* \param attr attribute that we want to check if there is room for
|
||||
* \param len remaining bytes in a buffer that contains the attribute
|
||||
*
|
||||
* This function is used to check that a buffer, which is supposed to contain
|
||||
* an attribute, has enough room for the attribute that it stores, i.e. this
|
||||
* function can be used to verify that an attribute is neither malformed nor
|
||||
* truncated.
|
||||
*
|
||||
* This function does not set errno in case of error since it is intended
|
||||
* for iterations. Thus, it returns 1 on success and 0 on error.
|
||||
*
|
||||
* The len parameter may be negative in the case of malformed messages during
|
||||
* attribute iteration, that is why we use a signed integer.
|
||||
*/
|
||||
bool mnl_attr_ok(const struct nlattr *attr, int len)
|
||||
{
|
||||
return len >= (int)sizeof(struct nlattr) &&
|
||||
attr->nla_len >= sizeof(struct nlattr) &&
|
||||
(int)attr->nla_len <= len;
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_attr_ok);
|
||||
|
||||
/**
|
||||
* mnl_attr_next - get the next attribute in the payload of a netlink message
|
||||
* \param attr pointer to the current attribute
|
||||
* \param len length of the remaining bytes in the buffer (passed by reference).
|
||||
*
|
||||
* This function returns a pointer to the next attribute after the one passed
|
||||
* as parameter. You have to use mnl_attr_ok() to ensure that the next
|
||||
* attribute is valid.
|
||||
*/
|
||||
struct nlattr *mnl_attr_next(const struct nlattr *attr)
|
||||
{
|
||||
return (struct nlattr *)((void *)attr + MNL_ALIGN(attr->nla_len));
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_attr_next);
|
||||
|
||||
/**
|
||||
* mnl_attr_type_valid - check if the attribute type is valid
|
||||
* \param attr pointer to attribute to be checked
|
||||
* \param max maximum attribute type
|
||||
*
|
||||
* This function allows to check if the attribute type is higher than the
|
||||
* maximum supported type. If the attribute type is invalid, this function
|
||||
* returns -1 and errno is explicitly set. On success, this function returns 1.
|
||||
*
|
||||
* Strict attribute checking in user-space is not a good idea since you may
|
||||
* run an old application with a newer kernel that supports new attributes.
|
||||
* This leads to backward compatibility breakages in user-space. Better check
|
||||
* if you support an attribute, if not, skip it.
|
||||
*/
|
||||
int mnl_attr_type_valid(const struct nlattr *attr, uint16_t max)
|
||||
{
|
||||
if (mnl_attr_get_type(attr) > max) {
|
||||
errno = EOPNOTSUPP;
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_attr_type_valid);
|
||||
|
||||
static int __mnl_attr_validate(const struct nlattr *attr,
|
||||
enum mnl_attr_data_type type, size_t exp_len)
|
||||
{
|
||||
uint16_t attr_len = mnl_attr_get_payload_len(attr);
|
||||
const char *attr_data = mnl_attr_get_payload(attr);
|
||||
|
||||
if (attr_len < exp_len) {
|
||||
errno = ERANGE;
|
||||
return -1;
|
||||
}
|
||||
switch(type) {
|
||||
case MNL_TYPE_FLAG:
|
||||
if (attr_len > 0) {
|
||||
errno = ERANGE;
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case MNL_TYPE_NUL_STRING:
|
||||
if (attr_len == 0) {
|
||||
errno = ERANGE;
|
||||
return -1;
|
||||
}
|
||||
if (attr_data[attr_len-1] != '\0') {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case MNL_TYPE_STRING:
|
||||
if (attr_len == 0) {
|
||||
errno = ERANGE;
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case MNL_TYPE_NESTED:
|
||||
/* empty nested attributes are OK. */
|
||||
if (attr_len == 0)
|
||||
break;
|
||||
/* if not empty, they must contain one header, eg. flag */
|
||||
if (attr_len < MNL_ATTR_HDRLEN) {
|
||||
errno = ERANGE;
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* make gcc happy. */
|
||||
break;
|
||||
}
|
||||
if (exp_len && attr_len > exp_len) {
|
||||
errno = ERANGE;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const size_t mnl_attr_data_type_len[MNL_TYPE_MAX] = {
|
||||
[MNL_TYPE_U8] = sizeof(uint8_t),
|
||||
[MNL_TYPE_U16] = sizeof(uint16_t),
|
||||
[MNL_TYPE_U32] = sizeof(uint32_t),
|
||||
[MNL_TYPE_U64] = sizeof(uint64_t),
|
||||
};
|
||||
|
||||
/**
|
||||
* mnl_attr_validate - validate netlink attribute (simplified version)
|
||||
* \param attr pointer to netlink attribute that we want to validate
|
||||
* \param type data type (see enum mnl_attr_data_type)
|
||||
*
|
||||
* The validation is based on the data type. Specifically, it checks that
|
||||
* integers (u8, u16, u32 and u64) have enough room for them. This function
|
||||
* returns -1 in case of error, and errno is explicitly set.
|
||||
*/
|
||||
int mnl_attr_validate(const struct nlattr *attr, enum mnl_attr_data_type type)
|
||||
{
|
||||
int exp_len;
|
||||
|
||||
if (type >= MNL_TYPE_MAX) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
exp_len = mnl_attr_data_type_len[type];
|
||||
return __mnl_attr_validate(attr, type, exp_len);
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_attr_validate);
|
||||
|
||||
/**
|
||||
* mnl_attr_validate2 - validate netlink attribute (extended version)
|
||||
* \param attr pointer to netlink attribute that we want to validate
|
||||
* \param type attribute type (see enum mnl_attr_data_type)
|
||||
* \param exp_len expected attribute data size
|
||||
*
|
||||
* This function allows to perform a more accurate validation for attributes
|
||||
* whose size is variable. If the size of the attribute is not what we expect,
|
||||
* this functions returns -1 and errno is explicitly set.
|
||||
*/
|
||||
int
|
||||
mnl_attr_validate2(const struct nlattr *attr, enum mnl_attr_data_type type,
|
||||
size_t exp_len)
|
||||
{
|
||||
if (type >= MNL_TYPE_MAX) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
return __mnl_attr_validate(attr, type, exp_len);
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_attr_validate2);
|
||||
|
||||
/**
|
||||
* mnl_attr_parse - parse attributes
|
||||
* \param nlh pointer to netlink message
|
||||
* \param offset offset to start parsing from (if payload is after any header)
|
||||
* \param cb callback function that is called for each attribute
|
||||
* \param data pointer to data that is passed to the callback function
|
||||
*
|
||||
* This function allows to iterate over the sequence of attributes that compose
|
||||
* the Netlink message. You can then put the attribute in an array as it
|
||||
* usually happens at this stage or you can use any other data structure (such
|
||||
* as lists or trees).
|
||||
*
|
||||
* This function propagates the return value of the callback, which can be
|
||||
* MNL_CB_ERROR, MNL_CB_OK or MNL_CB_STOP.
|
||||
*/
|
||||
int
|
||||
mnl_attr_parse(const struct nlmsghdr *nlh, unsigned int offset,
|
||||
mnl_attr_cb_t cb, void *data)
|
||||
{
|
||||
int ret = MNL_CB_OK;
|
||||
const struct nlattr *attr;
|
||||
|
||||
mnl_attr_for_each(attr, nlh, offset)
|
||||
if ((ret = cb(attr, data)) <= MNL_CB_STOP)
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_attr_parse);
|
||||
|
||||
/**
|
||||
* mnl_attr_parse_nested - parse attributes inside a nest
|
||||
* \param nested pointer to netlink attribute that contains a nest
|
||||
* \param cb callback function that is called for each attribute in the nest
|
||||
* \param data pointer to data passed to the callback function
|
||||
*
|
||||
* This function allows to iterate over the sequence of attributes that compose
|
||||
* the Netlink message. You can then put the attribute in an array as it
|
||||
* usually happens at this stage or you can use any other data structure (such
|
||||
* as lists or trees).
|
||||
*
|
||||
* This function propagates the return value of the callback, which can be
|
||||
* MNL_CB_ERROR, MNL_CB_OK or MNL_CB_STOP.
|
||||
*/
|
||||
int
|
||||
mnl_attr_parse_nested(const struct nlattr *nested, mnl_attr_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
int ret = MNL_CB_OK;
|
||||
const struct nlattr *attr;
|
||||
|
||||
mnl_attr_for_each_nested(attr, nested)
|
||||
if ((ret = cb(attr, data)) <= MNL_CB_STOP)
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_attr_parse_nested);
|
||||
|
||||
/**
|
||||
* mnl_attr_parse_payload - parse attributes in payload of Netlink message
|
||||
* \param payload pointer to payload of the Netlink message
|
||||
* \param payload_len payload length that contains the attributes
|
||||
* \param cb callback function that is called for each attribute
|
||||
* \param data pointer to data that is passed to the callback function
|
||||
*
|
||||
* This function takes a pointer to the area that contains the attributes,
|
||||
* commonly known as the payload of the Netlink message. Thus, you have to
|
||||
* pass a pointer to the Netlink message payload, instead of the entire
|
||||
* message.
|
||||
*
|
||||
* This function allows you to iterate over the sequence of attributes that are
|
||||
* located at some payload offset. You can then put the attributes in one array
|
||||
* as usual, or you can use any other data structure (such as lists or trees).
|
||||
*
|
||||
* This function propagates the return value of the callback, which can be
|
||||
* MNL_CB_ERROR, MNL_CB_OK or MNL_CB_STOP.
|
||||
*/
|
||||
int
|
||||
mnl_attr_parse_payload(const void *payload, size_t payload_len,
|
||||
mnl_attr_cb_t cb, void *data)
|
||||
{
|
||||
int ret = MNL_CB_OK;
|
||||
const struct nlattr *attr;
|
||||
|
||||
mnl_attr_for_each_payload(payload, payload_len)
|
||||
if ((ret = cb(attr, data)) <= MNL_CB_STOP)
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_attr_parse_payload);
|
||||
|
||||
/**
|
||||
* mnl_attr_get_u8 - returns 8-bit unsigned integer attribute payload
|
||||
* \param attr pointer to netlink attribute
|
||||
*
|
||||
* This function returns the 8-bit value of the attribute payload.
|
||||
*/
|
||||
uint8_t mnl_attr_get_u8(const struct nlattr *attr)
|
||||
{
|
||||
return *((uint8_t *)mnl_attr_get_payload(attr));
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_attr_get_u8);
|
||||
|
||||
/**
|
||||
* mnl_attr_get_u16 - returns 16-bit unsigned integer attribute payload
|
||||
* \param attr pointer to netlink attribute
|
||||
*
|
||||
* This function returns the 16-bit value of the attribute payload.
|
||||
*/
|
||||
uint16_t mnl_attr_get_u16(const struct nlattr *attr)
|
||||
{
|
||||
return *((uint16_t *)mnl_attr_get_payload(attr));
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_attr_get_u16);
|
||||
|
||||
/**
|
||||
* mnl_attr_get_u32 - returns 32-bit unsigned integer attribute payload
|
||||
* \param attr pointer to netlink attribute
|
||||
*
|
||||
* This function returns the 32-bit value of the attribute payload.
|
||||
*/
|
||||
uint32_t mnl_attr_get_u32(const struct nlattr *attr)
|
||||
{
|
||||
return *((uint32_t *)mnl_attr_get_payload(attr));
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_attr_get_u32);
|
||||
|
||||
/**
|
||||
* mnl_attr_get_u64 - returns 64-bit unsigned integer attribute.
|
||||
* \param attr pointer to netlink attribute
|
||||
*
|
||||
* This function returns the 64-bit value of the attribute payload. This
|
||||
* function is align-safe, since accessing 64-bit Netlink attributes is a
|
||||
* common source of alignment issues.
|
||||
*/
|
||||
uint64_t mnl_attr_get_u64(const struct nlattr *attr)
|
||||
{
|
||||
uint64_t tmp;
|
||||
memcpy(&tmp, mnl_attr_get_payload(attr), sizeof(tmp));
|
||||
return tmp;
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_attr_get_u64);
|
||||
|
||||
/**
|
||||
* mnl_attr_get_str - returns pointer to string attribute.
|
||||
* \param attr pointer to netlink attribute
|
||||
*
|
||||
* This function returns the payload of string attribute value.
|
||||
*/
|
||||
const char *mnl_attr_get_str(const struct nlattr *attr)
|
||||
{
|
||||
return mnl_attr_get_payload(attr);
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_attr_get_str);
|
||||
|
||||
/**
|
||||
* mnl_attr_put - add an attribute to netlink message
|
||||
* \param nlh pointer to the netlink message
|
||||
* \param type netlink attribute type that you want to add
|
||||
* \param len netlink attribute payload length
|
||||
* \param data pointer to the data that will be stored by the new attribute
|
||||
*
|
||||
* This function updates the length field of the Netlink message (nlmsg_len)
|
||||
* by adding the size (header + payload) of the new attribute.
|
||||
*/
|
||||
void
|
||||
mnl_attr_put(struct nlmsghdr *nlh, uint16_t type, size_t len, const void *data)
|
||||
{
|
||||
struct nlattr *attr = mnl_nlmsg_get_payload_tail(nlh);
|
||||
uint16_t payload_len = MNL_ALIGN(sizeof(struct nlattr)) + len;
|
||||
|
||||
attr->nla_type = type;
|
||||
attr->nla_len = payload_len;
|
||||
memcpy(mnl_attr_get_payload(attr), data, len);
|
||||
nlh->nlmsg_len += MNL_ALIGN(payload_len);
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_attr_put);
|
||||
|
||||
/**
|
||||
* mnl_attr_put_u8 - add 8-bit unsigned integer attribute to netlink message
|
||||
* \param nlh pointer to the netlink message
|
||||
* \param type netlink attribute type
|
||||
* \param len netlink attribute payload size
|
||||
* \param data 8-bit unsigned integer data that is stored by the new attribute
|
||||
*
|
||||
* This function updates the length field of the Netlink message (nlmsg_len)
|
||||
* by adding the size (header + payload) of the new attribute.
|
||||
*/
|
||||
void mnl_attr_put_u8(struct nlmsghdr *nlh, uint16_t type, uint8_t data)
|
||||
{
|
||||
mnl_attr_put(nlh, type, sizeof(uint8_t), &data);
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_attr_put_u8);
|
||||
|
||||
/**
|
||||
* mnl_attr_put_u16 - add 16-bit unsigned integer attribute to netlink message
|
||||
* \param nlh pointer to the netlink message
|
||||
* \param type netlink attribute type
|
||||
* \param data 16-bit unsigned integer data that is stored by the new attribute
|
||||
*
|
||||
* This function updates the length field of the Netlink message (nlmsg_len)
|
||||
* by adding the size (header + payload) of the new attribute.
|
||||
*/
|
||||
void mnl_attr_put_u16(struct nlmsghdr *nlh, uint16_t type, uint16_t data)
|
||||
{
|
||||
mnl_attr_put(nlh, type, sizeof(uint16_t), &data);
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_attr_put_u16);
|
||||
|
||||
/**
|
||||
* mnl_attr_put_u32 - add 32-bit unsigned integer attribute to netlink message
|
||||
* \param nlh pointer to the netlink message
|
||||
* \param type netlink attribute type
|
||||
* \param data 32-bit unsigned integer data that is stored by the new attribute
|
||||
*
|
||||
* This function updates the length field of the Netlink message (nlmsg_len)
|
||||
* by adding the size (header + payload) of the new attribute.
|
||||
*/
|
||||
void mnl_attr_put_u32(struct nlmsghdr *nlh, uint16_t type, uint32_t data)
|
||||
{
|
||||
mnl_attr_put(nlh, type, sizeof(uint32_t), &data);
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_attr_put_u32);
|
||||
|
||||
/**
|
||||
* mnl_attr_put_u64 - add 64-bit unsigned integer attribute to netlink message
|
||||
* \param nlh pointer to the netlink message
|
||||
* \param type netlink attribute type
|
||||
* \param data 64-bit unsigned integer data that is stored by the new attribute
|
||||
*
|
||||
* This function updates the length field of the Netlink message (nlmsg_len)
|
||||
* by adding the size (header + payload) of the new attribute.
|
||||
*/
|
||||
void mnl_attr_put_u64(struct nlmsghdr *nlh, uint16_t type, uint64_t data)
|
||||
{
|
||||
mnl_attr_put(nlh, type, sizeof(uint64_t), &data);
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_attr_put_u64);
|
||||
|
||||
/**
|
||||
* mnl_attr_put_str - add string attribute to netlink message
|
||||
* \param nlh pointer to the netlink message
|
||||
* \param type netlink attribute type
|
||||
* \param data pointer to string data that is stored by the new attribute
|
||||
*
|
||||
* This function updates the length field of the Netlink message (nlmsg_len)
|
||||
* by adding the size (header + payload) of the new attribute.
|
||||
*/
|
||||
void mnl_attr_put_str(struct nlmsghdr *nlh, uint16_t type, const char *data)
|
||||
{
|
||||
mnl_attr_put(nlh, type, strlen(data), data);
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_attr_put_str);
|
||||
|
||||
/**
|
||||
* mnl_attr_put_strz - add string attribute to netlink message
|
||||
* \param nlh pointer to the netlink message
|
||||
* \param type netlink attribute type
|
||||
* \param data pointer to string data that is stored by the new attribute
|
||||
*
|
||||
* This function is similar to mnl_attr_put_str, but it includes the
|
||||
* NUL/zero ('\0') terminator at the end of the string.
|
||||
*
|
||||
* This function updates the length field of the Netlink message (nlmsg_len)
|
||||
* by adding the size (header + payload) of the new attribute.
|
||||
*/
|
||||
void mnl_attr_put_strz(struct nlmsghdr *nlh, uint16_t type, const char *data)
|
||||
{
|
||||
mnl_attr_put(nlh, type, strlen(data)+1, data);
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_attr_put_strz);
|
||||
|
||||
/**
|
||||
* mnl_attr_nest_start - start an attribute nest
|
||||
* \param nlh pointer to the netlink message
|
||||
* \param type netlink attribute type
|
||||
*
|
||||
* This function adds the attribute header that identifies the beginning of
|
||||
* an attribute nest. This function always returns a valid pointer to the
|
||||
* beginning of the nest.
|
||||
*/
|
||||
struct nlattr *mnl_attr_nest_start(struct nlmsghdr *nlh, uint16_t type)
|
||||
{
|
||||
struct nlattr *start = mnl_nlmsg_get_payload_tail(nlh);
|
||||
|
||||
/* set start->nla_len in mnl_attr_nest_end() */
|
||||
start->nla_type = NLA_F_NESTED | type;
|
||||
nlh->nlmsg_len += MNL_ALIGN(sizeof(struct nlattr));
|
||||
|
||||
return start;
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_attr_nest_start);
|
||||
|
||||
/**
|
||||
* mnl_attr_put_check - add an attribute to netlink message
|
||||
* \param nlh pointer to the netlink message
|
||||
* \param buflen size of buffer which stores the message
|
||||
* \param type netlink attribute type that you want to add
|
||||
* \param len netlink attribute payload length
|
||||
* \param data pointer to the data that will be stored by the new attribute
|
||||
*
|
||||
* This function first checks that the data can be added to the message
|
||||
* (fits into the buffer) and then updates the length field of the Netlink
|
||||
* message (nlmsg_len) by adding the size (header + payload) of the new
|
||||
* attribute. The function returns true if the attribute could be added
|
||||
* to the message, otherwise false is returned.
|
||||
*/
|
||||
bool
|
||||
mnl_attr_put_check(struct nlmsghdr *nlh, size_t buflen,
|
||||
uint16_t type, size_t len, const void *data)
|
||||
{
|
||||
if (nlh->nlmsg_len + MNL_ATTR_HDRLEN + MNL_ALIGN(len) > buflen)
|
||||
return false;
|
||||
mnl_attr_put(nlh, type, len, data);
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_attr_put_check);
|
||||
|
||||
/**
|
||||
* mnl_attr_put_u8_check - add 8-bit unsigned int attribute to netlink message
|
||||
* \param nlh pointer to the netlink message
|
||||
* \param buflen size of buffer which stores the message
|
||||
* \param type netlink attribute type
|
||||
* \param len netlink attribute payload size
|
||||
* \param data 8-bit unsigned integer data that is stored by the new attribute
|
||||
*
|
||||
* This function first checks that the data can be added to the message
|
||||
* (fits into the buffer) and then updates the length field of the Netlink
|
||||
* message (nlmsg_len) by adding the size (header + payload) of the new
|
||||
* attribute. The function returns true if the attribute could be added
|
||||
* to the message, otherwise false is returned.
|
||||
*/
|
||||
bool
|
||||
mnl_attr_put_u8_check(struct nlmsghdr *nlh, size_t buflen,
|
||||
uint16_t type, uint8_t data)
|
||||
{
|
||||
return mnl_attr_put_check(nlh, buflen, type, sizeof(uint8_t), &data);
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_attr_put_u8_check);
|
||||
|
||||
/**
|
||||
* mnl_attr_put_u16_check - add 16-bit unsigned int attribute to netlink message
|
||||
* \param nlh pointer to the netlink message
|
||||
* \param buflen size of buffer which stores the message
|
||||
* \param type netlink attribute type
|
||||
* \param data 16-bit unsigned integer data that is stored by the new attribute
|
||||
*
|
||||
* This function first checks that the data can be added to the message
|
||||
* (fits into the buffer) and then updates the length field of the Netlink
|
||||
* message (nlmsg_len) by adding the size (header + payload) of the new
|
||||
* attribute. The function returns true if the attribute could be added
|
||||
* to the message, otherwise false is returned.
|
||||
* This function updates the length field of the Netlink message (nlmsg_len)
|
||||
* by adding the size (header + payload) of the new attribute.
|
||||
*/
|
||||
bool
|
||||
mnl_attr_put_u16_check(struct nlmsghdr *nlh, size_t buflen,
|
||||
uint16_t type, uint16_t data)
|
||||
{
|
||||
return mnl_attr_put_check(nlh, buflen, type, sizeof(uint16_t), &data);
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_attr_put_u16_check);
|
||||
|
||||
/**
|
||||
* mnl_attr_put_u32_check - add 32-bit unsigned int attribute to netlink message
|
||||
* \param nlh pointer to the netlink message
|
||||
* \param buflen size of buffer which stores the message
|
||||
* \param type netlink attribute type
|
||||
* \param data 32-bit unsigned integer data that is stored by the new attribute
|
||||
*
|
||||
* This function first checks that the data can be added to the message
|
||||
* (fits into the buffer) and then updates the length field of the Netlink
|
||||
* message (nlmsg_len) by adding the size (header + payload) of the new
|
||||
* attribute. The function returns true if the attribute could be added
|
||||
* to the message, otherwise false is returned.
|
||||
* This function updates the length field of the Netlink message (nlmsg_len)
|
||||
* by adding the size (header + payload) of the new attribute.
|
||||
*/
|
||||
bool
|
||||
mnl_attr_put_u32_check(struct nlmsghdr *nlh, size_t buflen,
|
||||
uint16_t type, uint32_t data)
|
||||
{
|
||||
return mnl_attr_put_check(nlh, buflen, type, sizeof(uint32_t), &data);
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_attr_put_u32_check);
|
||||
|
||||
/**
|
||||
* mnl_attr_put_u64_check - add 64-bit unsigned int attribute to netlink message
|
||||
* \param nlh pointer to the netlink message
|
||||
* \param buflen size of buffer which stores the message
|
||||
* \param type netlink attribute type
|
||||
* \param data 64-bit unsigned integer data that is stored by the new attribute
|
||||
*
|
||||
* This function first checks that the data can be added to the message
|
||||
* (fits into the buffer) and then updates the length field of the Netlink
|
||||
* message (nlmsg_len) by adding the size (header + payload) of the new
|
||||
* attribute. The function returns true if the attribute could be added
|
||||
* to the message, otherwise false is returned.
|
||||
* This function updates the length field of the Netlink message (nlmsg_len)
|
||||
* by adding the size (header + payload) of the new attribute.
|
||||
*/
|
||||
bool
|
||||
mnl_attr_put_u64_check(struct nlmsghdr *nlh, size_t buflen,
|
||||
uint16_t type, uint64_t data)
|
||||
{
|
||||
return mnl_attr_put_check(nlh, buflen, type, sizeof(uint64_t), &data);
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_attr_put_u64_check);
|
||||
|
||||
/**
|
||||
* mnl_attr_put_str_check - add string attribute to netlink message
|
||||
* \param nlh pointer to the netlink message
|
||||
* \param buflen size of buffer which stores the message
|
||||
* \param type netlink attribute type
|
||||
* \param data pointer to string data that is stored by the new attribute
|
||||
*
|
||||
* This function first checks that the data can be added to the message
|
||||
* (fits into the buffer) and then updates the length field of the Netlink
|
||||
* message (nlmsg_len) by adding the size (header + payload) of the new
|
||||
* attribute. The function returns true if the attribute could be added
|
||||
* to the message, otherwise false is returned.
|
||||
* This function updates the length field of the Netlink message (nlmsg_len)
|
||||
* by adding the size (header + payload) of the new attribute.
|
||||
*/
|
||||
bool
|
||||
mnl_attr_put_str_check(struct nlmsghdr *nlh, size_t buflen,
|
||||
uint16_t type, const char *data)
|
||||
{
|
||||
return mnl_attr_put_check(nlh, buflen, type, strlen(data), data);
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_attr_put_str_check);
|
||||
|
||||
/**
|
||||
* mnl_attr_put_strz_check - add string attribute to netlink message
|
||||
* \param nlh pointer to the netlink message
|
||||
* \param buflen size of buffer which stores the message
|
||||
* \param type netlink attribute type
|
||||
* \param data pointer to string data that is stored by the new attribute
|
||||
*
|
||||
* This function is similar to mnl_attr_put_str, but it includes the
|
||||
* NUL/zero ('\0') terminator at the end of the string.
|
||||
*
|
||||
* This function first checks that the data can be added to the message
|
||||
* (fits into the buffer) and then updates the length field of the Netlink
|
||||
* message (nlmsg_len) by adding the size (header + payload) of the new
|
||||
* attribute. The function returns true if the attribute could be added
|
||||
* to the message, otherwise false is returned.
|
||||
*/
|
||||
bool
|
||||
mnl_attr_put_strz_check(struct nlmsghdr *nlh, size_t buflen,
|
||||
uint16_t type, const char *data)
|
||||
{
|
||||
return mnl_attr_put_check(nlh, buflen, type, strlen(data)+1, data);
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_attr_put_strz_check);
|
||||
|
||||
/**
|
||||
* mnl_attr_nest_start_check - start an attribute nest
|
||||
* \param buflen size of buffer which stores the message
|
||||
* \param nlh pointer to the netlink message
|
||||
* \param type netlink attribute type
|
||||
*
|
||||
* This function adds the attribute header that identifies the beginning of
|
||||
* an attribute nest. If the nested attribute cannot be added then NULL,
|
||||
* otherwise valid pointer to the beginning of the nest is returned.
|
||||
*/
|
||||
struct nlattr *
|
||||
mnl_attr_nest_start_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type)
|
||||
{
|
||||
if (nlh->nlmsg_len + MNL_ATTR_HDRLEN > buflen)
|
||||
return NULL;
|
||||
return mnl_attr_nest_start(nlh, type);
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_attr_nest_start_check);
|
||||
|
||||
/**
|
||||
* mnl_attr_nest_end - end an attribute nest
|
||||
* \param nlh pointer to the netlink message
|
||||
* \param start pointer to the attribute nest returned by mnl_attr_nest_start()
|
||||
*
|
||||
* This function updates the attribute header that identifies the nest.
|
||||
*/
|
||||
void
|
||||
mnl_attr_nest_end(struct nlmsghdr *nlh, struct nlattr *start)
|
||||
{
|
||||
start->nla_len = mnl_nlmsg_get_payload_tail(nlh) - (void *)start;
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_attr_nest_end);
|
||||
|
||||
/**
|
||||
* mnl_attr_nest_cancel - cancel an attribute nest
|
||||
* \param nlh pointer to the netlink message
|
||||
* \param start pointer to the attribute nest returned by mnl_attr_nest_start()
|
||||
*
|
||||
* This function updates the attribute header that identifies the nest.
|
||||
*/
|
||||
void
|
||||
mnl_attr_nest_cancel(struct nlmsghdr *nlh, struct nlattr *start)
|
||||
{
|
||||
nlh->nlmsg_len -= mnl_nlmsg_get_payload_tail(nlh) - (void *)start;
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_attr_nest_cancel);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
161
external/nflog/callback.c
vendored
Normal file
161
external/nflog/callback.c
vendored
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* (C) 2008-2010 by Pablo Neira Ayuso <pablo@netfilter.org>
|
||||
*
|
||||
* This program 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; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <libmnl/libmnl.h>
|
||||
#include "internal.h"
|
||||
|
||||
static int mnl_cb_noop(const struct nlmsghdr *nlh, void *data)
|
||||
{
|
||||
return MNL_CB_OK;
|
||||
}
|
||||
|
||||
static int mnl_cb_error(const struct nlmsghdr *nlh, void *data)
|
||||
{
|
||||
const struct nlmsgerr *err = mnl_nlmsg_get_payload(nlh);
|
||||
|
||||
if (nlh->nlmsg_len < mnl_nlmsg_size(sizeof(struct nlmsgerr))) {
|
||||
errno = EBADMSG;
|
||||
return MNL_CB_ERROR;
|
||||
}
|
||||
/* Netlink subsystems returns the errno value with different signess */
|
||||
if (err->error < 0)
|
||||
errno = -err->error;
|
||||
else
|
||||
errno = err->error;
|
||||
|
||||
return err->error == 0 ? MNL_CB_STOP : MNL_CB_ERROR;
|
||||
}
|
||||
|
||||
static int mnl_cb_stop(const struct nlmsghdr *nlh, void *data)
|
||||
{
|
||||
return MNL_CB_STOP;
|
||||
}
|
||||
|
||||
static const mnl_cb_t default_cb_array[NLMSG_MIN_TYPE] = {
|
||||
[NLMSG_NOOP] = mnl_cb_noop,
|
||||
[NLMSG_ERROR] = mnl_cb_error,
|
||||
[NLMSG_DONE] = mnl_cb_stop,
|
||||
[NLMSG_OVERRUN] = mnl_cb_noop,
|
||||
};
|
||||
|
||||
static inline int
|
||||
__mnl_cb_run(const void *buf, size_t numbytes, unsigned int seq,
|
||||
unsigned int portid, mnl_cb_t cb_data, void *data,
|
||||
mnl_cb_t *cb_ctl_array, unsigned int cb_ctl_array_len)
|
||||
{
|
||||
int ret = MNL_CB_OK, len = numbytes;
|
||||
const struct nlmsghdr *nlh = buf;
|
||||
|
||||
while (mnl_nlmsg_ok(nlh, len)) {
|
||||
/* check message source */
|
||||
if (!mnl_nlmsg_portid_ok(nlh, portid)) {
|
||||
errno = ESRCH;
|
||||
return -1;
|
||||
}
|
||||
/* perform sequence tracking */
|
||||
if (!mnl_nlmsg_seq_ok(nlh, seq)) {
|
||||
errno = EPROTO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* netlink data message handling */
|
||||
if (nlh->nlmsg_type >= NLMSG_MIN_TYPE) {
|
||||
if (cb_data){
|
||||
ret = cb_data(nlh, data);
|
||||
if (ret <= MNL_CB_STOP)
|
||||
goto out;
|
||||
}
|
||||
} else if (nlh->nlmsg_type < cb_ctl_array_len) {
|
||||
if (cb_ctl_array && cb_ctl_array[nlh->nlmsg_type]) {
|
||||
ret = cb_ctl_array[nlh->nlmsg_type](nlh, data);
|
||||
if (ret <= MNL_CB_STOP)
|
||||
goto out;
|
||||
}
|
||||
} else if (default_cb_array[nlh->nlmsg_type]) {
|
||||
ret = default_cb_array[nlh->nlmsg_type](nlh, data);
|
||||
if (ret <= MNL_CB_STOP)
|
||||
goto out;
|
||||
}
|
||||
nlh = mnl_nlmsg_next(nlh, &len);
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* \defgroup callback Callback helpers
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* mnl_cb_run2 - callback runqueue for netlink messages
|
||||
* \param buf buffer that contains the netlink messages
|
||||
* \param numbytes number of bytes stored in the buffer
|
||||
* \param seq sequence number that we expect to receive
|
||||
* \param portid Netlink PortID that we expect to receive
|
||||
* \param cb_data callback handler for data messages
|
||||
* \param data pointer to data that will be passed to the data callback handler
|
||||
* \param cb_ctl_array array of custom callback handlers from control messages
|
||||
* \param cb_ctl_array_len array length of custom control callback handlers
|
||||
*
|
||||
* You can set the cb_ctl_array to NULL if you want to use the default control
|
||||
* callback handlers, in that case, the parameter cb_ctl_array_len is not
|
||||
* checked.
|
||||
*
|
||||
* Your callback may return three possible values:
|
||||
* - MNL_CB_ERROR (<=-1): an error has occurred. Stop callback runqueue.
|
||||
* - MNL_CB_STOP (=0): stop callback runqueue.
|
||||
* - MNL_CB_OK (>=1): no problem has occurred.
|
||||
*
|
||||
* This function propagates the callback return value. On error, it returns
|
||||
* -1 and errno is explicitly set. If the portID is not the expected, errno
|
||||
* is set to ESRCH. If the sequence number is not the expected, errno is set
|
||||
* to EPROTO.
|
||||
*/
|
||||
int
|
||||
mnl_cb_run2(const void *buf, size_t numbytes, unsigned int seq,
|
||||
unsigned int portid, mnl_cb_t cb_data, void *data,
|
||||
mnl_cb_t *cb_ctl_array, unsigned int cb_ctl_array_len)
|
||||
{
|
||||
return __mnl_cb_run(buf, numbytes, seq, portid, cb_data, data,
|
||||
cb_ctl_array, cb_ctl_array_len);
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_cb_run2);
|
||||
|
||||
/**
|
||||
* mnl_cb_run - callback runqueue for netlink messages (simplified version)
|
||||
* \param buf buffer that contains the netlink messages
|
||||
* \param numbytes number of bytes stored in the buffer
|
||||
* \param seq sequence number that we expect to receive
|
||||
* \param portid Netlink PortID that we expect to receive
|
||||
* \param cb_data callback handler for data messages
|
||||
* \param data pointer to data that will be passed to the data callback handler
|
||||
*
|
||||
* This function is like mnl_cb_run2() but it does not allow you to set
|
||||
* the control callback handlers.
|
||||
*
|
||||
* Your callback may return three possible values:
|
||||
* - MNL_CB_ERROR (<=-1): an error has occurred. Stop callback runqueue.
|
||||
* - MNL_CB_STOP (=0): stop callback runqueue.
|
||||
* - MNL_CB_OK (>=1): no problems has occurred.
|
||||
*
|
||||
* This function propagates the callback return value.
|
||||
*/
|
||||
int
|
||||
mnl_cb_run(const void *buf, size_t numbytes, unsigned int seq,
|
||||
unsigned int portid, mnl_cb_t cb_data, void *data)
|
||||
{
|
||||
return __mnl_cb_run(buf, numbytes, seq, portid, cb_data, data, NULL, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_cb_run);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
69
external/nflog/config.h
vendored
Normal file
69
external/nflog/config.h
vendored
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
/* config.h. Generated from config.h.in by configure. */
|
||||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#define HAVE_DLFCN_H 1
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#define HAVE_INTTYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#define HAVE_MEMORY_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#define HAVE_STDINT_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#define HAVE_STDLIB_H 1
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#define HAVE_STRINGS_H 1
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#define HAVE_STRING_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#define HAVE_SYS_STAT_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#define HAVE_SYS_TYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#define HAVE_UNISTD_H 1
|
||||
|
||||
/* True if compiler supports -fvisibility=hidden */
|
||||
#define HAVE_VISIBILITY_HIDDEN 1
|
||||
|
||||
/* Define to the sub-directory in which libtool stores uninstalled libraries.
|
||||
*/
|
||||
#define LT_OBJDIR ".libs/"
|
||||
|
||||
/* Define to 1 if your C compiler doesn't accept -c and -o together. */
|
||||
/* #undef NO_MINUS_C_MINUS_O */
|
||||
|
||||
/* Name of package */
|
||||
#define PACKAGE "libmnl"
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#define PACKAGE_BUGREPORT ""
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#define PACKAGE_NAME "libmnl"
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#define PACKAGE_STRING "libmnl 1.0.3"
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#define PACKAGE_TARNAME "libmnl"
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#define PACKAGE_URL ""
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#define PACKAGE_VERSION "1.0.3"
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#define STDC_HEADERS 1
|
||||
|
||||
/* Version number of package */
|
||||
#define VERSION "1.0.3"
|
||||
12
external/nflog/internal.h
vendored
Normal file
12
external/nflog/internal.h
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#ifndef INTERNAL_H
|
||||
#define INTERNAL_H 1
|
||||
|
||||
#include "config.h"
|
||||
#ifdef HAVE_VISIBILITY_HIDDEN
|
||||
# define __visible __attribute__((visibility("default")))
|
||||
# define EXPORT_SYMBOL(x) typeof(x) (x) __visible
|
||||
#else
|
||||
# define EXPORT_SYMBOL
|
||||
#endif
|
||||
|
||||
#endif
|
||||
203
external/nflog/libmnl/libmnl.h
vendored
Normal file
203
external/nflog/libmnl/libmnl.h
vendored
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
#ifndef _LIBMNL_H_
|
||||
#define _LIBMNL_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
# include <cstdio>
|
||||
# include <cstdint>
|
||||
#else
|
||||
# include <stdbool.h> /* not in C++ */
|
||||
# include <stdio.h>
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h> /* for sa_family_t */
|
||||
#include <linux/netlink.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Netlink socket API
|
||||
*/
|
||||
|
||||
#define MNL_SOCKET_AUTOPID 0
|
||||
#define MNL_SOCKET_BUFFER_SIZE (getpagesize() < 8192L ? getpagesize() : 8192L)
|
||||
|
||||
struct mnl_socket;
|
||||
|
||||
extern struct mnl_socket *mnl_socket_open(int type);
|
||||
extern int mnl_socket_bind(struct mnl_socket *nl, unsigned int groups, pid_t pid);
|
||||
extern int mnl_socket_close(struct mnl_socket *nl);
|
||||
extern int mnl_socket_get_fd(const struct mnl_socket *nl);
|
||||
extern unsigned int mnl_socket_get_portid(const struct mnl_socket *nl);
|
||||
extern ssize_t mnl_socket_sendto(const struct mnl_socket *nl, const void *req, size_t siz);
|
||||
extern ssize_t mnl_socket_recvfrom(const struct mnl_socket *nl, void *buf, size_t siz);
|
||||
extern int mnl_socket_setsockopt(const struct mnl_socket *nl, int type, void *buf, socklen_t len);
|
||||
extern int mnl_socket_getsockopt(const struct mnl_socket *nl, int type, void *buf, socklen_t *len);
|
||||
|
||||
/*
|
||||
* Netlink message API
|
||||
*/
|
||||
|
||||
#define MNL_ALIGNTO 4
|
||||
#define MNL_ALIGN(len) (((len)+MNL_ALIGNTO-1) & ~(MNL_ALIGNTO-1))
|
||||
#define MNL_NLMSG_HDRLEN MNL_ALIGN(sizeof(struct nlmsghdr))
|
||||
|
||||
extern size_t mnl_nlmsg_size(size_t len);
|
||||
extern size_t mnl_nlmsg_get_payload_len(const struct nlmsghdr *nlh);
|
||||
|
||||
/* Netlink message header builder */
|
||||
extern struct nlmsghdr *mnl_nlmsg_put_header(void *buf);
|
||||
extern void *mnl_nlmsg_put_extra_header(struct nlmsghdr *nlh, size_t size);
|
||||
|
||||
/* Netlink message iterators */
|
||||
extern bool mnl_nlmsg_ok(const struct nlmsghdr *nlh, int len);
|
||||
extern struct nlmsghdr *mnl_nlmsg_next(const struct nlmsghdr *nlh, int *len);
|
||||
|
||||
/* Netlink sequence tracking */
|
||||
extern bool mnl_nlmsg_seq_ok(const struct nlmsghdr *nlh, unsigned int seq);
|
||||
|
||||
/* Netlink portID checking */
|
||||
extern bool mnl_nlmsg_portid_ok(const struct nlmsghdr *nlh, unsigned int portid);
|
||||
|
||||
/* Netlink message getters */
|
||||
extern void *mnl_nlmsg_get_payload(const struct nlmsghdr *nlh);
|
||||
extern void *mnl_nlmsg_get_payload_offset(const struct nlmsghdr *nlh, size_t offset);
|
||||
extern void *mnl_nlmsg_get_payload_tail(const struct nlmsghdr *nlh);
|
||||
|
||||
/* Netlink message printer */
|
||||
extern void mnl_nlmsg_fprintf(FILE *fd, const void *data, size_t datalen, size_t extra_header_size);
|
||||
|
||||
/* Message batch helpers */
|
||||
struct mnl_nlmsg_batch;
|
||||
extern struct mnl_nlmsg_batch *mnl_nlmsg_batch_start(void *buf, size_t bufsiz);
|
||||
extern bool mnl_nlmsg_batch_next(struct mnl_nlmsg_batch *b);
|
||||
extern void mnl_nlmsg_batch_stop(struct mnl_nlmsg_batch *b);
|
||||
extern size_t mnl_nlmsg_batch_size(struct mnl_nlmsg_batch *b);
|
||||
extern void mnl_nlmsg_batch_reset(struct mnl_nlmsg_batch *b);
|
||||
extern void *mnl_nlmsg_batch_head(struct mnl_nlmsg_batch *b);
|
||||
extern void *mnl_nlmsg_batch_current(struct mnl_nlmsg_batch *b);
|
||||
extern bool mnl_nlmsg_batch_is_empty(struct mnl_nlmsg_batch *b);
|
||||
|
||||
/*
|
||||
* Netlink attributes API
|
||||
*/
|
||||
#define MNL_ATTR_HDRLEN MNL_ALIGN(sizeof(struct nlattr))
|
||||
|
||||
/* TLV attribute getters */
|
||||
extern uint16_t mnl_attr_get_type(const struct nlattr *attr);
|
||||
extern uint16_t mnl_attr_get_len(const struct nlattr *attr);
|
||||
extern uint16_t mnl_attr_get_payload_len(const struct nlattr *attr);
|
||||
extern void *mnl_attr_get_payload(const struct nlattr *attr);
|
||||
extern uint8_t mnl_attr_get_u8(const struct nlattr *attr);
|
||||
extern uint16_t mnl_attr_get_u16(const struct nlattr *attr);
|
||||
extern uint32_t mnl_attr_get_u32(const struct nlattr *attr);
|
||||
extern uint64_t mnl_attr_get_u64(const struct nlattr *attr);
|
||||
extern const char *mnl_attr_get_str(const struct nlattr *attr);
|
||||
|
||||
/* TLV attribute putters */
|
||||
extern void mnl_attr_put(struct nlmsghdr *nlh, uint16_t type, size_t len, const void *data);
|
||||
extern void mnl_attr_put_u8(struct nlmsghdr *nlh, uint16_t type, uint8_t data);
|
||||
extern void mnl_attr_put_u16(struct nlmsghdr *nlh, uint16_t type, uint16_t data);
|
||||
extern void mnl_attr_put_u32(struct nlmsghdr *nlh, uint16_t type, uint32_t data);
|
||||
extern void mnl_attr_put_u64(struct nlmsghdr *nlh, uint16_t type, uint64_t data);
|
||||
extern void mnl_attr_put_str(struct nlmsghdr *nlh, uint16_t type, const char *data);
|
||||
extern void mnl_attr_put_strz(struct nlmsghdr *nlh, uint16_t type, const char *data);
|
||||
|
||||
/* TLV attribute putters with buffer boundary checkings */
|
||||
extern bool mnl_attr_put_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type, size_t len, const void *data);
|
||||
extern bool mnl_attr_put_u8_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type, uint8_t data);
|
||||
extern bool mnl_attr_put_u16_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type, uint16_t data);
|
||||
extern bool mnl_attr_put_u32_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type, uint32_t data);
|
||||
extern bool mnl_attr_put_u64_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type, uint64_t data);
|
||||
extern bool mnl_attr_put_str_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type, const char *data);
|
||||
extern bool mnl_attr_put_strz_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type, const char *data);
|
||||
|
||||
/* TLV attribute nesting */
|
||||
extern struct nlattr *mnl_attr_nest_start(struct nlmsghdr *nlh, uint16_t type);
|
||||
extern struct nlattr *mnl_attr_nest_start_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type);
|
||||
extern void mnl_attr_nest_end(struct nlmsghdr *nlh, struct nlattr *start);
|
||||
extern void mnl_attr_nest_cancel(struct nlmsghdr *nlh, struct nlattr *start);
|
||||
|
||||
/* TLV validation */
|
||||
extern int mnl_attr_type_valid(const struct nlattr *attr, uint16_t maxtype);
|
||||
|
||||
enum mnl_attr_data_type {
|
||||
MNL_TYPE_UNSPEC,
|
||||
MNL_TYPE_U8,
|
||||
MNL_TYPE_U16,
|
||||
MNL_TYPE_U32,
|
||||
MNL_TYPE_U64,
|
||||
MNL_TYPE_STRING,
|
||||
MNL_TYPE_FLAG,
|
||||
MNL_TYPE_MSECS,
|
||||
MNL_TYPE_NESTED,
|
||||
MNL_TYPE_NESTED_COMPAT,
|
||||
MNL_TYPE_NUL_STRING,
|
||||
MNL_TYPE_BINARY,
|
||||
MNL_TYPE_MAX,
|
||||
};
|
||||
|
||||
extern int mnl_attr_validate(const struct nlattr *attr, enum mnl_attr_data_type type);
|
||||
extern int mnl_attr_validate2(const struct nlattr *attr, enum mnl_attr_data_type type, size_t len);
|
||||
|
||||
/* TLV iterators */
|
||||
extern bool mnl_attr_ok(const struct nlattr *attr, int len);
|
||||
extern struct nlattr *mnl_attr_next(const struct nlattr *attr);
|
||||
|
||||
#define mnl_attr_for_each(attr, nlh, offset) \
|
||||
for ((attr) = mnl_nlmsg_get_payload_offset((nlh), (offset)); \
|
||||
mnl_attr_ok((attr), (char *)mnl_nlmsg_get_payload_tail(nlh) - (char *)(attr)); \
|
||||
(attr) = mnl_attr_next(attr))
|
||||
|
||||
#define mnl_attr_for_each_nested(attr, nest) \
|
||||
for ((attr) = mnl_attr_get_payload(nest); \
|
||||
mnl_attr_ok((attr), (char *)mnl_attr_get_payload(nest) + mnl_attr_get_payload_len(nest) - (char *)(attr)); \
|
||||
(attr) = mnl_attr_next(attr))
|
||||
|
||||
#define mnl_attr_for_each_payload(payload, payload_size) \
|
||||
for ((attr) = (payload); \
|
||||
mnl_attr_ok((attr), (char *)(payload) + payload_size - (char *)(attr)); \
|
||||
(attr) = mnl_attr_next(attr))
|
||||
|
||||
/* TLV callback-based attribute parsers */
|
||||
typedef int (*mnl_attr_cb_t)(const struct nlattr *attr, void *data);
|
||||
|
||||
extern int mnl_attr_parse(const struct nlmsghdr *nlh, unsigned int offset, mnl_attr_cb_t cb, void *data);
|
||||
extern int mnl_attr_parse_nested(const struct nlattr *attr, mnl_attr_cb_t cb, void *data);
|
||||
extern int mnl_attr_parse_payload(const void *payload, size_t payload_len, mnl_attr_cb_t cb, void *data);
|
||||
|
||||
/*
|
||||
* callback API
|
||||
*/
|
||||
#define MNL_CB_ERROR -1
|
||||
#define MNL_CB_STOP 0
|
||||
#define MNL_CB_OK 1
|
||||
|
||||
typedef int (*mnl_cb_t)(const struct nlmsghdr *nlh, void *data);
|
||||
|
||||
extern int mnl_cb_run(const void *buf, size_t numbytes, unsigned int seq,
|
||||
unsigned int portid, mnl_cb_t cb_data, void *data);
|
||||
|
||||
extern int mnl_cb_run2(const void *buf, size_t numbytes, unsigned int seq,
|
||||
unsigned int portid, mnl_cb_t cb_data, void *data,
|
||||
mnl_cb_t *cb_ctl_array, unsigned int cb_ctl_array_len);
|
||||
|
||||
/*
|
||||
* other declarations
|
||||
*/
|
||||
|
||||
#ifndef SOL_NETLINK
|
||||
#define SOL_NETLINK 270
|
||||
#endif
|
||||
|
||||
#ifndef MNL_ARRAY_SIZE
|
||||
#define MNL_ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif
|
||||
99
external/nflog/linux/netfilter/nfnetlink_log.h
vendored
Normal file
99
external/nflog/linux/netfilter/nfnetlink_log.h
vendored
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
/* Android NDK r8d is missing nfnetlink_log.h */
|
||||
|
||||
#ifndef _NFNETLINK_LOG_H
|
||||
#define _NFNETLINK_LOG_H
|
||||
|
||||
/* This file describes the netlink messages (i.e. 'protocol packets'),
|
||||
* and not any kind of function definitions. It is shared between kernel and
|
||||
* userspace. Don't put kernel specific stuff in here */
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/netfilter/nfnetlink.h>
|
||||
|
||||
enum nfulnl_msg_types {
|
||||
NFULNL_MSG_PACKET, /* packet from kernel to userspace */
|
||||
NFULNL_MSG_CONFIG, /* connect to a particular queue */
|
||||
|
||||
NFULNL_MSG_MAX
|
||||
};
|
||||
|
||||
struct nfulnl_msg_packet_hdr {
|
||||
__be16 hw_protocol; /* hw protocol (network order) */
|
||||
__u8 hook; /* netfilter hook */
|
||||
__u8 _pad;
|
||||
};
|
||||
|
||||
struct nfulnl_msg_packet_hw {
|
||||
__be16 hw_addrlen;
|
||||
__u16 _pad;
|
||||
__u8 hw_addr[8];
|
||||
};
|
||||
|
||||
struct nfulnl_msg_packet_timestamp {
|
||||
aligned_be64 sec;
|
||||
aligned_be64 usec;
|
||||
};
|
||||
|
||||
enum nfulnl_attr_type {
|
||||
NFULA_UNSPEC,
|
||||
NFULA_PACKET_HDR,
|
||||
NFULA_MARK, /* __u32 nfmark */
|
||||
NFULA_TIMESTAMP, /* nfulnl_msg_packet_timestamp */
|
||||
NFULA_IFINDEX_INDEV, /* __u32 ifindex */
|
||||
NFULA_IFINDEX_OUTDEV, /* __u32 ifindex */
|
||||
NFULA_IFINDEX_PHYSINDEV, /* __u32 ifindex */
|
||||
NFULA_IFINDEX_PHYSOUTDEV, /* __u32 ifindex */
|
||||
NFULA_HWADDR, /* nfulnl_msg_packet_hw */
|
||||
NFULA_PAYLOAD, /* opaque data payload */
|
||||
NFULA_PREFIX, /* string prefix */
|
||||
NFULA_UID, /* user id of socket */
|
||||
NFULA_SEQ, /* instance-local sequence number */
|
||||
NFULA_SEQ_GLOBAL, /* global sequence number */
|
||||
NFULA_GID, /* group id of socket */
|
||||
NFULA_HWTYPE, /* hardware type */
|
||||
NFULA_HWHEADER, /* hardware header */
|
||||
NFULA_HWLEN, /* hardware header length */
|
||||
|
||||
__NFULA_MAX
|
||||
};
|
||||
#define NFULA_MAX (__NFULA_MAX - 1)
|
||||
|
||||
enum nfulnl_msg_config_cmds {
|
||||
NFULNL_CFG_CMD_NONE,
|
||||
NFULNL_CFG_CMD_BIND,
|
||||
NFULNL_CFG_CMD_UNBIND,
|
||||
NFULNL_CFG_CMD_PF_BIND,
|
||||
NFULNL_CFG_CMD_PF_UNBIND,
|
||||
};
|
||||
|
||||
struct nfulnl_msg_config_cmd {
|
||||
__u8 command; /* nfulnl_msg_config_cmds */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct nfulnl_msg_config_mode {
|
||||
__be32 copy_range;
|
||||
__u8 copy_mode;
|
||||
__u8 _pad;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
enum nfulnl_attr_config {
|
||||
NFULA_CFG_UNSPEC,
|
||||
NFULA_CFG_CMD, /* nfulnl_msg_config_cmd */
|
||||
NFULA_CFG_MODE, /* nfulnl_msg_config_mode */
|
||||
NFULA_CFG_NLBUFSIZ, /* __u32 buffer size */
|
||||
NFULA_CFG_TIMEOUT, /* __u32 in 1/100 s */
|
||||
NFULA_CFG_QTHRESH, /* __u32 */
|
||||
NFULA_CFG_FLAGS, /* __u16 */
|
||||
__NFULA_CFG_MAX
|
||||
};
|
||||
#define NFULA_CFG_MAX (__NFULA_CFG_MAX -1)
|
||||
|
||||
#define NFULNL_COPY_NONE 0x00
|
||||
#define NFULNL_COPY_META 0x01
|
||||
#define NFULNL_COPY_PACKET 0x02
|
||||
/* 0xff is reserved, don't use it for new copy modes. */
|
||||
|
||||
#define NFULNL_CFG_F_SEQ 0x0001
|
||||
#define NFULNL_CFG_F_SEQ_GLOBAL 0x0002
|
||||
|
||||
#endif /* _NFNETLINK_LOG_H */
|
||||
148
external/nflog/linux/netlink.h
vendored
Normal file
148
external/nflog/linux/netlink.h
vendored
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
#ifndef __LINUX_NETLINK_H
|
||||
#define __LINUX_NETLINK_H
|
||||
|
||||
#include <linux/socket.h> /* for sa_family_t */
|
||||
#include <linux/types.h>
|
||||
|
||||
#define NETLINK_ROUTE 0 /* Routing/device hook */
|
||||
#define NETLINK_UNUSED 1 /* Unused number */
|
||||
#define NETLINK_USERSOCK 2 /* Reserved for user mode socket protocols */
|
||||
#define NETLINK_FIREWALL 3 /* Firewalling hook */
|
||||
#define NETLINK_INET_DIAG 4 /* INET socket monitoring */
|
||||
#define NETLINK_NFLOG 5 /* netfilter/iptables ULOG */
|
||||
#define NETLINK_XFRM 6 /* ipsec */
|
||||
#define NETLINK_SELINUX 7 /* SELinux event notifications */
|
||||
#define NETLINK_ISCSI 8 /* Open-iSCSI */
|
||||
#define NETLINK_AUDIT 9 /* auditing */
|
||||
#define NETLINK_FIB_LOOKUP 10
|
||||
#define NETLINK_CONNECTOR 11
|
||||
#define NETLINK_NETFILTER 12 /* netfilter subsystem */
|
||||
#define NETLINK_IP6_FW 13
|
||||
#define NETLINK_DNRTMSG 14 /* DECnet routing messages */
|
||||
#define NETLINK_KOBJECT_UEVENT 15 /* Kernel messages to userspace */
|
||||
#define NETLINK_GENERIC 16
|
||||
/* leave room for NETLINK_DM (DM Events) */
|
||||
#define NETLINK_SCSITRANSPORT 18 /* SCSI Transports */
|
||||
#define NETLINK_ECRYPTFS 19
|
||||
|
||||
#define MAX_LINKS 32
|
||||
|
||||
struct sockaddr_nl {
|
||||
sa_family_t nl_family; /* AF_NETLINK */
|
||||
unsigned short nl_pad; /* zero */
|
||||
__u32 nl_pid; /* port ID */
|
||||
__u32 nl_groups; /* multicast groups mask */
|
||||
};
|
||||
|
||||
struct nlmsghdr {
|
||||
__u32 nlmsg_len; /* Length of message including header */
|
||||
__u16 nlmsg_type; /* Message content */
|
||||
__u16 nlmsg_flags; /* Additional flags */
|
||||
__u32 nlmsg_seq; /* Sequence number */
|
||||
__u32 nlmsg_pid; /* Sending process port ID */
|
||||
};
|
||||
|
||||
/* Flags values */
|
||||
|
||||
#define NLM_F_REQUEST 1 /* It is request message. */
|
||||
#define NLM_F_MULTI 2 /* Multipart message, terminated by NLMSG_DONE */
|
||||
#define NLM_F_ACK 4 /* Reply with ack, with zero or error code */
|
||||
#define NLM_F_ECHO 8 /* Echo this request */
|
||||
|
||||
/* Modifiers to GET request */
|
||||
#define NLM_F_ROOT 0x100 /* specify tree root */
|
||||
#define NLM_F_MATCH 0x200 /* return all matching */
|
||||
#define NLM_F_ATOMIC 0x400 /* atomic GET */
|
||||
#define NLM_F_DUMP (NLM_F_ROOT|NLM_F_MATCH)
|
||||
|
||||
/* Modifiers to NEW request */
|
||||
#define NLM_F_REPLACE 0x100 /* Override existing */
|
||||
#define NLM_F_EXCL 0x200 /* Do not touch, if it exists */
|
||||
#define NLM_F_CREATE 0x400 /* Create, if it does not exist */
|
||||
#define NLM_F_APPEND 0x800 /* Add to end of list */
|
||||
|
||||
/*
|
||||
4.4BSD ADD NLM_F_CREATE|NLM_F_EXCL
|
||||
4.4BSD CHANGE NLM_F_REPLACE
|
||||
|
||||
True CHANGE NLM_F_CREATE|NLM_F_REPLACE
|
||||
Append NLM_F_CREATE
|
||||
Check NLM_F_EXCL
|
||||
*/
|
||||
|
||||
#define NLMSG_ALIGNTO 4U
|
||||
#define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) )
|
||||
#define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr)))
|
||||
#define NLMSG_LENGTH(len) ((len)+NLMSG_ALIGN(NLMSG_HDRLEN))
|
||||
#define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len))
|
||||
#define NLMSG_DATA(nlh) ((void*)(((char*)nlh) + NLMSG_LENGTH(0)))
|
||||
#define NLMSG_NEXT(nlh,len) ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \
|
||||
(struct nlmsghdr*)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len)))
|
||||
#define NLMSG_OK(nlh,len) ((len) >= (int)sizeof(struct nlmsghdr) && \
|
||||
(nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && \
|
||||
(nlh)->nlmsg_len <= (len))
|
||||
#define NLMSG_PAYLOAD(nlh,len) ((nlh)->nlmsg_len - NLMSG_SPACE((len)))
|
||||
|
||||
#define NLMSG_NOOP 0x1 /* Nothing. */
|
||||
#define NLMSG_ERROR 0x2 /* Error */
|
||||
#define NLMSG_DONE 0x3 /* End of a dump */
|
||||
#define NLMSG_OVERRUN 0x4 /* Data lost */
|
||||
|
||||
#define NLMSG_MIN_TYPE 0x10 /* < 0x10: reserved control messages */
|
||||
|
||||
struct nlmsgerr {
|
||||
int error;
|
||||
struct nlmsghdr msg;
|
||||
};
|
||||
|
||||
#define NETLINK_ADD_MEMBERSHIP 1
|
||||
#define NETLINK_DROP_MEMBERSHIP 2
|
||||
#define NETLINK_PKTINFO 3
|
||||
#define NETLINK_BROADCAST_ERROR 4
|
||||
#define NETLINK_NO_ENOBUFS 5
|
||||
|
||||
struct nl_pktinfo {
|
||||
__u32 group;
|
||||
};
|
||||
|
||||
#define NET_MAJOR 36 /* Major 36 is reserved for networking */
|
||||
|
||||
enum {
|
||||
NETLINK_UNCONNECTED = 0,
|
||||
NETLINK_CONNECTED,
|
||||
};
|
||||
|
||||
/*
|
||||
* <------- NLA_HDRLEN ------> <-- NLA_ALIGN(payload)-->
|
||||
* +---------------------+- - -+- - - - - - - - - -+- - -+
|
||||
* | Header | Pad | Payload | Pad |
|
||||
* | (struct nlattr) | ing | | ing |
|
||||
* +---------------------+- - -+- - - - - - - - - -+- - -+
|
||||
* <-------------- nlattr->nla_len -------------->
|
||||
*/
|
||||
|
||||
struct nlattr {
|
||||
__u16 nla_len;
|
||||
__u16 nla_type;
|
||||
};
|
||||
|
||||
/*
|
||||
* nla_type (16 bits)
|
||||
* +---+---+-------------------------------+
|
||||
* | N | O | Attribute Type |
|
||||
* +---+---+-------------------------------+
|
||||
* N := Carries nested attributes
|
||||
* O := Payload stored in network byte order
|
||||
*
|
||||
* Note: The N and O flag are mutually exclusive.
|
||||
*/
|
||||
#define NLA_F_NESTED (1 << 15)
|
||||
#define NLA_F_NET_BYTEORDER (1 << 14)
|
||||
#define NLA_TYPE_MASK ~(NLA_F_NESTED | NLA_F_NET_BYTEORDER)
|
||||
|
||||
#define NLA_ALIGNTO 4
|
||||
#define NLA_ALIGN(len) (((len) + NLA_ALIGNTO - 1) & ~(NLA_ALIGNTO - 1))
|
||||
#define NLA_HDRLEN ((int) NLA_ALIGN(sizeof(struct nlattr)))
|
||||
|
||||
|
||||
#endif /* __LINUX_NETLINK_H */
|
||||
672
external/nflog/nflog.c
vendored
Normal file
672
external/nflog/nflog.c
vendored
Normal file
|
|
@ -0,0 +1,672 @@
|
|||
/* Enhanced NFLOG implementation for AFWall+
|
||||
* (C) 2012 Pragmatic Software - Original implementation
|
||||
* (C) 2025 AFWall+ Project - Enhancements and optimizations
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/
|
||||
*
|
||||
* Enhanced features:
|
||||
* - Improved memory management and leak prevention
|
||||
* - Better error handling and recovery
|
||||
* - Optimized interface name caching
|
||||
* - Enhanced buffer management
|
||||
* - Signal handling for graceful shutdown
|
||||
* - Backward compatibility maintained
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <fcntl.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <libmnl/libmnl.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/netfilter/nfnetlink.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/ipv6.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/udp.h>
|
||||
#include <linux/icmp.h>
|
||||
#include <linux/icmpv6.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/select.h>
|
||||
|
||||
#ifndef aligned_be64
|
||||
#define aligned_be64 u_int64_t __attribute__((aligned(8)))
|
||||
#endif
|
||||
|
||||
#include <linux/netfilter/nfnetlink_log.h>
|
||||
|
||||
// Enhanced configuration constants
|
||||
#define MAX_NETDEVICES 64 // Increased from 32 for better device support
|
||||
#define INTERFACE_CACHE_TTL 300 // Cache interfaces for 5 minutes
|
||||
#define DEFAULT_BUFFER_SIZE (32 * 1024) // 32KB default buffer
|
||||
|
||||
// Enhanced structures for interface caching
|
||||
struct interface_cache_entry {
|
||||
int ifindex;
|
||||
char ifname[IFNAMSIZ];
|
||||
time_t timestamp;
|
||||
int valid;
|
||||
};
|
||||
|
||||
// Global state with better organization
|
||||
static struct interface_cache_entry device_cache[MAX_NETDEVICES] = {{0}};
|
||||
static struct mnl_socket *nl = NULL;
|
||||
static int shutdown_requested = 0;
|
||||
static char *recv_buffer = NULL;
|
||||
static size_t recv_buffer_size = DEFAULT_BUFFER_SIZE;
|
||||
|
||||
// Function declarations
|
||||
char *enhanced_if_indextoname(unsigned int ifindex, char *ifname);
|
||||
void cleanup_enhanced(void);
|
||||
void signal_handler(int sig);
|
||||
static int parse_attr_cb(const struct nlattr *attr, void *data);
|
||||
static int log_cb(const struct nlmsghdr *nlh, void *data);
|
||||
|
||||
// Enhanced interface name resolution with caching and proper error handling
|
||||
char *enhanced_if_indextoname(unsigned int ifindex, char *ifname) {
|
||||
if (ifindex == 0 || ifindex >= MAX_NETDEVICES || !ifname) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
time_t now = time(NULL);
|
||||
struct interface_cache_entry *entry = &device_cache[ifindex];
|
||||
|
||||
// Check cache validity
|
||||
if (entry->valid && entry->ifindex == ifindex &&
|
||||
(now - entry->timestamp) < INTERFACE_CACHE_TTL) {
|
||||
strncpy(ifname, entry->ifname, IFNAMSIZ - 1);
|
||||
ifname[IFNAMSIZ - 1] = '\0';
|
||||
return ifname;
|
||||
}
|
||||
|
||||
// Cache miss or expired - lookup interface name
|
||||
struct ifreq ifr;
|
||||
int fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (fd < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
ifr.ifr_ifindex = ifindex;
|
||||
int status = ioctl(fd, SIOCGIFNAME, &ifr);
|
||||
close(fd);
|
||||
|
||||
if (status < 0) {
|
||||
if (errno == ENODEV) {
|
||||
errno = ENXIO;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Update cache with proper bounds checking
|
||||
entry->ifindex = ifindex;
|
||||
strncpy(entry->ifname, ifr.ifr_name, IFNAMSIZ - 1);
|
||||
entry->ifname[IFNAMSIZ - 1] = '\0';
|
||||
entry->timestamp = now;
|
||||
entry->valid = 1;
|
||||
|
||||
// Return the cached name
|
||||
strncpy(ifname, entry->ifname, IFNAMSIZ - 1);
|
||||
ifname[IFNAMSIZ - 1] = '\0';
|
||||
return ifname;
|
||||
}
|
||||
|
||||
// Original function maintained for compatibility
|
||||
char *netlog_if_indextoname(unsigned int ifindex, char *ifname) {
|
||||
return enhanced_if_indextoname(ifindex, ifname);
|
||||
}
|
||||
|
||||
// Enhanced cleanup function
|
||||
void cleanup_enhanced(void) {
|
||||
shutdown_requested = 1;
|
||||
|
||||
if (nl) {
|
||||
mnl_socket_close(nl);
|
||||
nl = NULL;
|
||||
}
|
||||
|
||||
if (recv_buffer) {
|
||||
free(recv_buffer);
|
||||
recv_buffer = NULL;
|
||||
}
|
||||
|
||||
// Clear interface cache
|
||||
memset(device_cache, 0, sizeof(device_cache));
|
||||
|
||||
fprintf(stderr, "Enhanced NFLOG shutdown complete\n");
|
||||
}
|
||||
|
||||
// Original cleanup function maintained for compatibility
|
||||
void cleanup(void) {
|
||||
cleanup_enhanced();
|
||||
}
|
||||
|
||||
// Free net devices function maintained for compatibility
|
||||
void free_net_devices(void) {
|
||||
// In enhanced version, we use static cache, so just clear it
|
||||
memset(device_cache, 0, sizeof(device_cache));
|
||||
}
|
||||
|
||||
// Signal handler for graceful shutdown
|
||||
void signal_handler(int sig) {
|
||||
fprintf(stderr, "Received signal %d, shutting down gracefully...\n", sig);
|
||||
shutdown_requested = 1;
|
||||
}
|
||||
|
||||
// Enhanced attribute parsing with better error handling
|
||||
static int parse_attr_cb(const struct nlattr *attr, void *data) {
|
||||
const struct nlattr **tb = data;
|
||||
int type = mnl_attr_get_type(attr);
|
||||
|
||||
/* skip unsupported attribute in user-space */
|
||||
if (mnl_attr_type_valid(attr, NFULA_MAX) < 0) {
|
||||
return MNL_CB_OK;
|
||||
}
|
||||
|
||||
switch(type) {
|
||||
case NFULA_HWTYPE:
|
||||
if (mnl_attr_validate(attr, MNL_TYPE_U16) < 0) {
|
||||
perror("mnl_attr_validate HWTYPE");
|
||||
return MNL_CB_ERROR;
|
||||
}
|
||||
break;
|
||||
case NFULA_MARK:
|
||||
case NFULA_IFINDEX_INDEV:
|
||||
case NFULA_IFINDEX_OUTDEV:
|
||||
case NFULA_IFINDEX_PHYSINDEV:
|
||||
case NFULA_IFINDEX_PHYSOUTDEV:
|
||||
if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
|
||||
perror("mnl_attr_validate U32");
|
||||
return MNL_CB_ERROR;
|
||||
}
|
||||
break;
|
||||
case NFULA_TIMESTAMP:
|
||||
if (mnl_attr_validate2(attr, MNL_TYPE_UNSPEC,
|
||||
sizeof(struct nfulnl_msg_packet_timestamp)) < 0) {
|
||||
perror("mnl_attr_validate TIMESTAMP");
|
||||
return MNL_CB_ERROR;
|
||||
}
|
||||
break;
|
||||
case NFULA_HWADDR:
|
||||
if (mnl_attr_validate2(attr, MNL_TYPE_UNSPEC,
|
||||
sizeof(struct nfulnl_msg_packet_hw)) < 0) {
|
||||
perror("mnl_attr_validate HWADDR");
|
||||
return MNL_CB_ERROR;
|
||||
}
|
||||
break;
|
||||
case NFULA_PACKET_HDR:
|
||||
if (mnl_attr_validate2(attr, MNL_TYPE_UNSPEC,
|
||||
sizeof(struct nfulnl_msg_packet_hdr)) < 0) {
|
||||
perror("mnl_attr_validate PACKET_HDR");
|
||||
return MNL_CB_ERROR;
|
||||
}
|
||||
break;
|
||||
case NFULA_PREFIX:
|
||||
if (mnl_attr_validate(attr, MNL_TYPE_NUL_STRING) < 0) {
|
||||
perror("mnl_attr_validate PREFIX");
|
||||
return MNL_CB_ERROR;
|
||||
}
|
||||
break;
|
||||
case NFULA_PAYLOAD:
|
||||
// Payload doesn't need validation
|
||||
break;
|
||||
default:
|
||||
// Unknown attribute type, skip
|
||||
break;
|
||||
}
|
||||
|
||||
tb[type] = attr;
|
||||
return MNL_CB_OK;
|
||||
}
|
||||
|
||||
// Enhanced log callback with improved error handling and memory safety
|
||||
static int log_cb(const struct nlmsghdr *nlh, void *data) {
|
||||
struct nlattr *tb[NFULA_MAX+1] = {};
|
||||
char ifname_buf[IFNAMSIZ];
|
||||
|
||||
if (!nlh) {
|
||||
return MNL_CB_ERROR;
|
||||
}
|
||||
|
||||
if (mnl_attr_parse(nlh, sizeof(struct nfgenmsg), parse_attr_cb, tb) < 0) {
|
||||
return MNL_CB_ERROR;
|
||||
}
|
||||
|
||||
// Print prefix if available
|
||||
if (tb[NFULA_PREFIX]) {
|
||||
const char *prefix = mnl_attr_get_str(tb[NFULA_PREFIX]);
|
||||
if (prefix) {
|
||||
printf("%s ", prefix);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle input interface
|
||||
if (tb[NFULA_IFINDEX_INDEV]) {
|
||||
uint32_t indev = ntohl(mnl_attr_get_u32(tb[NFULA_IFINDEX_INDEV]));
|
||||
char *instr = enhanced_if_indextoname(indev, ifname_buf);
|
||||
printf("IN=%s ", instr ? instr : "");
|
||||
} else {
|
||||
printf("IN= ");
|
||||
}
|
||||
|
||||
// Handle output interface
|
||||
if (tb[NFULA_IFINDEX_OUTDEV]) {
|
||||
uint32_t outdev = ntohl(mnl_attr_get_u32(tb[NFULA_IFINDEX_OUTDEV]));
|
||||
char *outstr = enhanced_if_indextoname(outdev, ifname_buf);
|
||||
printf("OUT=%s ", outstr ? outstr : "");
|
||||
} else {
|
||||
printf("OUT= ");
|
||||
}
|
||||
|
||||
// Process packet payload
|
||||
uint16_t hwProtocol = 0;
|
||||
if (tb[NFULA_PACKET_HDR]) {
|
||||
struct nfulnl_msg_packet_hdr* pktHdr =
|
||||
(struct nfulnl_msg_packet_hdr*)mnl_attr_get_payload(tb[NFULA_PACKET_HDR]);
|
||||
if (pktHdr) {
|
||||
hwProtocol = ntohs(pktHdr->hw_protocol);
|
||||
}
|
||||
}
|
||||
|
||||
if (tb[NFULA_PAYLOAD]) {
|
||||
switch (hwProtocol) {
|
||||
case ETH_P_IP: {
|
||||
struct iphdr *iph = (struct iphdr *) mnl_attr_get_payload(tb[NFULA_PAYLOAD]);
|
||||
if (iph && mnl_attr_get_payload_len(tb[NFULA_PAYLOAD]) >= sizeof(struct iphdr)) {
|
||||
char addressStr[INET_ADDRSTRLEN];
|
||||
|
||||
// Source address
|
||||
if (inet_ntop(AF_INET, &iph->saddr, addressStr, sizeof(addressStr))) {
|
||||
printf("SRC=%s ", addressStr);
|
||||
}
|
||||
|
||||
// Destination address
|
||||
if (inet_ntop(AF_INET, &iph->daddr, addressStr, sizeof(addressStr))) {
|
||||
printf("DST=%s ", addressStr);
|
||||
}
|
||||
|
||||
printf("LEN=%u ", ntohs(iph->tot_len));
|
||||
|
||||
// Protocol-specific processing with bounds checking
|
||||
int header_len = iph->ihl * 4;
|
||||
if (header_len >= sizeof(struct iphdr) &&
|
||||
mnl_attr_get_payload_len(tb[NFULA_PAYLOAD]) >= header_len) {
|
||||
|
||||
switch(iph->protocol) {
|
||||
case IPPROTO_TCP: {
|
||||
if (mnl_attr_get_payload_len(tb[NFULA_PAYLOAD]) >=
|
||||
header_len + sizeof(struct tcphdr)) {
|
||||
struct tcphdr *th = (struct tcphdr *)
|
||||
((uint8_t*)iph + header_len);
|
||||
printf("PROTO=TCP SPT=%u DPT=%u ",
|
||||
ntohs(th->source), ntohs(th->dest));
|
||||
} else {
|
||||
printf("PROTO=TCP ");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IPPROTO_UDP: {
|
||||
if (mnl_attr_get_payload_len(tb[NFULA_PAYLOAD]) >=
|
||||
header_len + sizeof(struct udphdr)) {
|
||||
struct udphdr *uh = (struct udphdr *)
|
||||
((uint8_t*)iph + header_len);
|
||||
printf("PROTO=UDP SPT=%u DPT=%u LEN=%u ",
|
||||
ntohs(uh->source), ntohs(uh->dest), ntohs(uh->len));
|
||||
} else {
|
||||
printf("PROTO=UDP ");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IPPROTO_ICMP: {
|
||||
if (mnl_attr_get_payload_len(tb[NFULA_PAYLOAD]) >=
|
||||
header_len + sizeof(struct icmphdr)) {
|
||||
struct icmphdr *ich = (struct icmphdr *)
|
||||
((uint8_t*)iph + header_len);
|
||||
printf("PROTO=ICMP TYPE=%u CODE=%u ",
|
||||
ich->type, ich->code);
|
||||
} else {
|
||||
printf("PROTO=ICMP ");
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printf("PROTO=%u ", iph->protocol);
|
||||
}
|
||||
} else {
|
||||
printf("PROTO=%u ", iph->protocol);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ETH_P_IPV6: {
|
||||
struct ipv6hdr *iph = (struct ipv6hdr *) mnl_attr_get_payload(tb[NFULA_PAYLOAD]);
|
||||
if (iph && mnl_attr_get_payload_len(tb[NFULA_PAYLOAD]) >= sizeof(struct ipv6hdr)) {
|
||||
char addressStr[INET6_ADDRSTRLEN];
|
||||
|
||||
// Source address
|
||||
if (inet_ntop(AF_INET6, &iph->saddr, addressStr, sizeof(addressStr))) {
|
||||
printf("SRC=%s ", addressStr);
|
||||
}
|
||||
|
||||
// Destination address
|
||||
if (inet_ntop(AF_INET6, &iph->daddr, addressStr, sizeof(addressStr))) {
|
||||
printf("DST=%s ", addressStr);
|
||||
}
|
||||
|
||||
// Protocol-specific processing with bounds checking
|
||||
if (mnl_attr_get_payload_len(tb[NFULA_PAYLOAD]) >=
|
||||
sizeof(struct ipv6hdr) + 4) { // At least IPv6 header + some payload
|
||||
|
||||
switch (iph->nexthdr) {
|
||||
case IPPROTO_TCP: {
|
||||
if (mnl_attr_get_payload_len(tb[NFULA_PAYLOAD]) >=
|
||||
sizeof(struct ipv6hdr) + sizeof(struct tcphdr)) {
|
||||
struct tcphdr *th = (struct tcphdr *)
|
||||
((uint8_t*) iph + sizeof(*iph));
|
||||
printf("PROTO=TCP SPT=%u DPT=%u ",
|
||||
ntohs(th->source), ntohs(th->dest));
|
||||
} else {
|
||||
printf("PROTO=TCP ");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IPPROTO_UDP: {
|
||||
if (mnl_attr_get_payload_len(tb[NFULA_PAYLOAD]) >=
|
||||
sizeof(struct ipv6hdr) + sizeof(struct udphdr)) {
|
||||
struct udphdr *uh = (struct udphdr *)
|
||||
((uint8_t *) iph + sizeof(*iph));
|
||||
printf("PROTO=UDP SPT=%u DPT=%u LEN=%u ",
|
||||
ntohs(uh->source), ntohs(uh->dest), ntohs(uh->len));
|
||||
} else {
|
||||
printf("PROTO=UDP ");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IPPROTO_ICMPV6: {
|
||||
if (mnl_attr_get_payload_len(tb[NFULA_PAYLOAD]) >=
|
||||
sizeof(struct ipv6hdr) + sizeof(struct icmp6hdr)) {
|
||||
struct icmp6hdr *icmpv6h = (struct icmp6hdr *)
|
||||
((uint8_t *) iph + sizeof(*iph));
|
||||
printf("PROTO=ICMP6 TYPE=%u CODE=%u ",
|
||||
icmpv6h->icmp6_type, icmpv6h->icmp6_code);
|
||||
} else {
|
||||
printf("PROTO=ICMP6 ");
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printf("PROTO=%d ", iph->nexthdr);
|
||||
}
|
||||
} else {
|
||||
printf("PROTO=%d ", iph->nexthdr);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// Unknown or unsupported protocol
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// UID information
|
||||
if (tb[NFULA_UID]) {
|
||||
uint32_t uid = ntohl(mnl_attr_get_u32(tb[NFULA_UID]));
|
||||
printf("UID=%u ", uid);
|
||||
}
|
||||
|
||||
// End the log line
|
||||
puts("");
|
||||
fflush(stdout);
|
||||
|
||||
return MNL_CB_OK;
|
||||
}
|
||||
|
||||
// Configuration helper functions (enhanced with error checking)
|
||||
static struct nlmsghdr *nflog_build_cfg_pf_request(char *buf, uint8_t command) {
|
||||
if (!buf) return NULL;
|
||||
|
||||
struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf);
|
||||
nlh->nlmsg_type = (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_CONFIG;
|
||||
nlh->nlmsg_flags = NLM_F_REQUEST;
|
||||
|
||||
struct nfgenmsg *nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
|
||||
nfg->nfgen_family = AF_INET;
|
||||
nfg->version = NFNETLINK_V0;
|
||||
|
||||
struct nfulnl_msg_config_cmd cmd = {
|
||||
.command = command,
|
||||
};
|
||||
mnl_attr_put(nlh, NFULA_CFG_CMD, sizeof(cmd), &cmd);
|
||||
|
||||
return nlh;
|
||||
}
|
||||
|
||||
static struct nlmsghdr *nflog_build_cfg_request(char *buf, uint8_t command, int qnum) {
|
||||
if (!buf || qnum < 0 || qnum > 65535) return NULL;
|
||||
|
||||
struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf);
|
||||
nlh->nlmsg_type = (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_CONFIG;
|
||||
nlh->nlmsg_flags = NLM_F_REQUEST;
|
||||
|
||||
struct nfgenmsg *nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
|
||||
nfg->nfgen_family = AF_INET;
|
||||
nfg->version = NFNETLINK_V0;
|
||||
nfg->res_id = htons(qnum);
|
||||
|
||||
struct nfulnl_msg_config_cmd cmd = {
|
||||
.command = command,
|
||||
};
|
||||
mnl_attr_put(nlh, NFULA_CFG_CMD, sizeof(cmd), &cmd);
|
||||
|
||||
return nlh;
|
||||
}
|
||||
|
||||
static struct nlmsghdr *nflog_build_cfg_params(char *buf, uint8_t mode, int range, int qnum) {
|
||||
if (!buf || qnum < 0 || qnum > 65535 || range < 0) return NULL;
|
||||
|
||||
struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf);
|
||||
nlh->nlmsg_type = (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_CONFIG;
|
||||
nlh->nlmsg_flags = NLM_F_REQUEST;
|
||||
|
||||
struct nfgenmsg *nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
|
||||
nfg->nfgen_family = AF_UNSPEC;
|
||||
nfg->version = NFNETLINK_V0;
|
||||
nfg->res_id = htons(qnum);
|
||||
|
||||
struct nfulnl_msg_config_mode params = {
|
||||
.copy_range = htonl(range),
|
||||
.copy_mode = mode,
|
||||
};
|
||||
mnl_attr_put(nlh, NFULA_CFG_MODE, sizeof(params), ¶ms);
|
||||
|
||||
return nlh;
|
||||
}
|
||||
|
||||
// Enhanced main function with better error handling and resource management
|
||||
int main(int argc, char *argv[]) {
|
||||
char buf[MNL_SOCKET_BUFFER_SIZE];
|
||||
struct nlmsghdr *nlh;
|
||||
int ret, nfds, sock_fd, stdin_fd;
|
||||
unsigned int portid, qnum;
|
||||
|
||||
// Install signal handlers for graceful shutdown
|
||||
signal(SIGINT, signal_handler);
|
||||
signal(SIGTERM, signal_handler);
|
||||
signal(SIGPIPE, SIG_IGN); // Ignore broken pipe
|
||||
|
||||
atexit(cleanup_enhanced);
|
||||
|
||||
// Validate command line arguments
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "Usage: %s [queue_num]\n", argv[0]);
|
||||
fprintf(stderr, "Enhanced NFLOG implementation with improved reliability\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Parse and validate queue number
|
||||
char *endptr;
|
||||
long qnum_long = strtol(argv[1], &endptr, 10);
|
||||
if (*endptr != '\0' || qnum_long < 0 || qnum_long > 65535) {
|
||||
fprintf(stderr, "Error: Invalid queue number. Must be 0-65535\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
qnum = (unsigned int)qnum_long;
|
||||
|
||||
// Allocate enhanced receive buffer
|
||||
recv_buffer = malloc(recv_buffer_size);
|
||||
if (!recv_buffer) {
|
||||
perror("Failed to allocate receive buffer");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Initialize netlink socket
|
||||
nl = mnl_socket_open(NETLINK_NETFILTER);
|
||||
if (nl == NULL) {
|
||||
perror("mnl_socket_open");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
|
||||
perror("mnl_socket_bind");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
portid = mnl_socket_get_portid(nl);
|
||||
|
||||
// Set socket buffer size for better performance
|
||||
int sock_buffer_size = recv_buffer_size * 2;
|
||||
if (setsockopt(mnl_socket_get_fd(nl), SOL_SOCKET, SO_RCVBUF,
|
||||
&sock_buffer_size, sizeof(sock_buffer_size)) < 0) {
|
||||
perror("Warning: setsockopt SO_RCVBUF failed");
|
||||
// Continue anyway - not fatal
|
||||
}
|
||||
|
||||
// Configure NFLOG with enhanced error checking
|
||||
nlh = nflog_build_cfg_pf_request(buf, NFULNL_CFG_CMD_PF_UNBIND);
|
||||
if (!nlh) {
|
||||
fprintf(stderr, "Error: Failed to build PF unbind request\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
|
||||
perror("mnl_socket_send PF unbind");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
nlh = nflog_build_cfg_pf_request(buf, NFULNL_CFG_CMD_PF_BIND);
|
||||
if (!nlh) {
|
||||
fprintf(stderr, "Error: Failed to build PF bind request\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
|
||||
perror("mnl_socket_send PF bind");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
nlh = nflog_build_cfg_request(buf, NFULNL_CFG_CMD_BIND, qnum);
|
||||
if (!nlh) {
|
||||
fprintf(stderr, "Error: Failed to build queue bind request\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
|
||||
perror("mnl_socket_send queue bind");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
nlh = nflog_build_cfg_params(buf, NFULNL_COPY_PACKET, 0xFFFF, qnum);
|
||||
if (!nlh) {
|
||||
fprintf(stderr, "Error: Failed to build config params request\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
|
||||
perror("mnl_socket_send config params");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
sock_fd = mnl_socket_get_fd(nl);
|
||||
stdin_fd = fileno(stdin);
|
||||
nfds = (sock_fd > stdin_fd ? sock_fd : stdin_fd) + 1;
|
||||
|
||||
if (fcntl(sock_fd, F_SETFL, O_NONBLOCK) < 0 ||
|
||||
fcntl(stdin_fd, F_SETFL, O_NONBLOCK) < 0) {
|
||||
perror("fcntl");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
fprintf(stderr, "Enhanced NFLOG started on queue %u\n", qnum);
|
||||
|
||||
// Enhanced main loop with better error handling
|
||||
while (!shutdown_requested) {
|
||||
fd_set fds;
|
||||
char c;
|
||||
int select_result;
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(sock_fd, &fds);
|
||||
FD_SET(stdin_fd, &fds);
|
||||
|
||||
select_result = select(nfds, &fds, NULL, NULL, NULL);
|
||||
|
||||
if (select_result < 0) {
|
||||
if (errno == EINTR) {
|
||||
// Interrupted by signal, check shutdown flag
|
||||
continue;
|
||||
}
|
||||
perror("select");
|
||||
break;
|
||||
}
|
||||
|
||||
if (FD_ISSET(stdin_fd, &fds)) {
|
||||
// Check for stdin closure or input
|
||||
if (read(stdin_fd, &c, 1) <= 0) {
|
||||
fprintf(stderr, "stdin closed, shutting down...\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!FD_ISSET(sock_fd, &fds)) {
|
||||
// No data on socket
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = mnl_socket_recvfrom(nl, recv_buffer, recv_buffer_size);
|
||||
if (ret == -1) {
|
||||
if (errno == ENOSPC || errno == ENOBUFS) {
|
||||
// Buffer overrun - usually recoverable
|
||||
fprintf(stderr, "Warning: Buffer overrun, some packets may be lost\n");
|
||||
continue;
|
||||
} else if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
// No data available - normal with O_NONBLOCK
|
||||
continue;
|
||||
} else {
|
||||
perror("mnl_socket_recvfrom");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
fprintf(stderr, "Socket closed by remote end\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (mnl_cb_run(recv_buffer, ret, 0, portid, log_cb, NULL) < 0) {
|
||||
perror("mnl_cb_run");
|
||||
// Don't exit on callback errors - try to continue
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "Enhanced NFLOG shutting down gracefully\n");
|
||||
return 0;
|
||||
}
|
||||
573
external/nflog/nlmsg.c
vendored
Normal file
573
external/nflog/nlmsg.c
vendored
Normal file
|
|
@ -0,0 +1,573 @@
|
|||
/*
|
||||
* (C) 2008-2010 by Pablo Neira Ayuso <pablo@netfilter.org>
|
||||
*
|
||||
* This program 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; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <libmnl/libmnl.h>
|
||||
#include "internal.h"
|
||||
|
||||
/**
|
||||
* \defgroup nlmsg Netlink message helpers
|
||||
*
|
||||
* Netlink message:
|
||||
* \verbatim
|
||||
|<----------------- 4 bytes ------------------->|
|
||||
|<----- 2 bytes ------>|<------- 2 bytes ------>|
|
||||
|-----------------------------------------------|
|
||||
| Message length (including header) |
|
||||
|-----------------------------------------------|
|
||||
| Message type | Message flags |
|
||||
|-----------------------------------------------|
|
||||
| Message sequence number |
|
||||
|-----------------------------------------------|
|
||||
| Netlink PortID |
|
||||
|-----------------------------------------------|
|
||||
| |
|
||||
. Payload .
|
||||
|_______________________________________________|
|
||||
\endverbatim
|
||||
*
|
||||
* There is usually an extra header after the the Netlink header (at the
|
||||
* beginning of the payload). This extra header is specific of the Netlink
|
||||
* subsystem. After this extra header, it comes the sequence of attributes
|
||||
* that are expressed in Type-Length-Value (TLV) format.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_size - calculate the size of Netlink message (without alignment)
|
||||
* \param len length of the Netlink payload
|
||||
*
|
||||
* This function returns the size of a netlink message (header plus payload)
|
||||
* without alignment.
|
||||
*/
|
||||
size_t mnl_nlmsg_size(size_t len)
|
||||
{
|
||||
return len + MNL_NLMSG_HDRLEN;
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_nlmsg_size);
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_get_payload_len - get the length of the Netlink payload
|
||||
* \param nlh pointer to the header of the Netlink message
|
||||
*
|
||||
* This function returns the Length of the netlink payload, ie. the length
|
||||
* of the full message minus the size of the Netlink header.
|
||||
*/
|
||||
size_t mnl_nlmsg_get_payload_len(const struct nlmsghdr *nlh)
|
||||
{
|
||||
return nlh->nlmsg_len - MNL_NLMSG_HDRLEN;
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_nlmsg_get_payload_len);
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_put_header - reserve and prepare room for Netlink header
|
||||
* \param buf memory already allocated to store the Netlink header
|
||||
*
|
||||
* This function sets to zero the room that is required to put the Netlink
|
||||
* header in the memory buffer passed as parameter. This function also
|
||||
* initializes the nlmsg_len field to the size of the Netlink header. This
|
||||
* function returns a pointer to the Netlink header structure.
|
||||
*/
|
||||
struct nlmsghdr *mnl_nlmsg_put_header(void *buf)
|
||||
{
|
||||
int len = MNL_ALIGN(sizeof(struct nlmsghdr));
|
||||
struct nlmsghdr *nlh = buf;
|
||||
|
||||
memset(buf, 0, len);
|
||||
nlh->nlmsg_len = len;
|
||||
return nlh;
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_nlmsg_put_header);
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_put_extra_header - reserve and prepare room for an extra header
|
||||
* \param nlh pointer to Netlink header
|
||||
* \param size size of the extra header that we want to put
|
||||
*
|
||||
* This function sets to zero the room that is required to put the extra
|
||||
* header after the initial Netlink header. This function also increases
|
||||
* the nlmsg_len field. You have to invoke mnl_nlmsg_put_header() before
|
||||
* you call this function. This function returns a pointer to the extra
|
||||
* header.
|
||||
*/
|
||||
void *
|
||||
mnl_nlmsg_put_extra_header(struct nlmsghdr *nlh, size_t size)
|
||||
{
|
||||
char *ptr = (char *)nlh + nlh->nlmsg_len;
|
||||
size_t len = MNL_ALIGN(size);
|
||||
nlh->nlmsg_len += len;
|
||||
memset(ptr, 0, len);
|
||||
return ptr;
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_nlmsg_put_extra_header);
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_get_payload - get a pointer to the payload of the netlink message
|
||||
* \param nlh pointer to a netlink header
|
||||
*
|
||||
* This function returns a pointer to the payload of the netlink message.
|
||||
*/
|
||||
void *mnl_nlmsg_get_payload(const struct nlmsghdr *nlh)
|
||||
{
|
||||
return (void *)nlh + MNL_NLMSG_HDRLEN;
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_nlmsg_get_payload);
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_get_payload_offset - get a pointer to the payload of the message
|
||||
* \param nlh pointer to a netlink header
|
||||
* \param offset offset to the payload of the attributes TLV set
|
||||
*
|
||||
* This function returns a pointer to the payload of the netlink message plus
|
||||
* a given offset.
|
||||
*/
|
||||
void *
|
||||
mnl_nlmsg_get_payload_offset(const struct nlmsghdr *nlh, size_t offset)
|
||||
{
|
||||
return (void *)nlh + MNL_NLMSG_HDRLEN + MNL_ALIGN(offset);
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_nlmsg_get_payload_offset);
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_ok - check a there is room for netlink message
|
||||
* \param nlh netlink message that we want to check
|
||||
* \param len remaining bytes in a buffer that contains the netlink message
|
||||
*
|
||||
* This function is used to check that a buffer that contains a netlink
|
||||
* message has enough room for the netlink message that it stores, ie. this
|
||||
* function can be used to verify that a netlink message is not malformed nor
|
||||
* truncated.
|
||||
*
|
||||
* This function does not set errno in case of error since it is intended
|
||||
* for iterations. Thus, it returns 1 on success and 0 on error.
|
||||
*
|
||||
* The len parameter may become negative in malformed messages during message
|
||||
* iteration, that is why we use a signed integer.
|
||||
*/
|
||||
bool mnl_nlmsg_ok(const struct nlmsghdr *nlh, int len)
|
||||
{
|
||||
return len >= (int)sizeof(struct nlmsghdr) &&
|
||||
nlh->nlmsg_len >= sizeof(struct nlmsghdr) &&
|
||||
(int)nlh->nlmsg_len <= len;
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_nlmsg_ok);
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_next - get the next netlink message in a multipart message
|
||||
* \param nlh current netlink message that we are handling
|
||||
* \param len length of the remaining bytes in the buffer (passed by reference).
|
||||
*
|
||||
* This function returns a pointer to the next netlink message that is part
|
||||
* of a multi-part netlink message. Netlink can batch several messages into
|
||||
* one buffer so that the receiver has to iterate over the whole set of
|
||||
* Netlink messages.
|
||||
*
|
||||
* You have to use mnl_nlmsg_ok() to check if the next Netlink message is
|
||||
* valid.
|
||||
*/
|
||||
struct nlmsghdr *
|
||||
mnl_nlmsg_next(const struct nlmsghdr *nlh, int *len)
|
||||
{
|
||||
*len -= MNL_ALIGN(nlh->nlmsg_len);
|
||||
return (struct nlmsghdr *)((void *)nlh + MNL_ALIGN(nlh->nlmsg_len));
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_nlmsg_next);
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_get_payload_tail - get the ending of the netlink message
|
||||
* \param nlh pointer to netlink message
|
||||
*
|
||||
* This function returns a pointer to the netlink message tail. This is useful
|
||||
* to build a message since we continue adding attributes at the end of the
|
||||
* message.
|
||||
*/
|
||||
void *mnl_nlmsg_get_payload_tail(const struct nlmsghdr *nlh)
|
||||
{
|
||||
return (void *)nlh + MNL_ALIGN(nlh->nlmsg_len);
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_nlmsg_get_payload_tail);
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_seq_ok - perform sequence tracking
|
||||
* \param nlh current netlink message that we are handling
|
||||
* \param seq last sequence number used to send a message
|
||||
*
|
||||
* This functions returns true if the sequence tracking is fulfilled, otherwise
|
||||
* false is returned. We skip the tracking for netlink messages whose sequence
|
||||
* number is zero since it is usually reserved for event-based kernel
|
||||
* notifications. On the other hand, if seq is set but the message sequence
|
||||
* number is not set (i.e. this is an event message coming from kernel-space),
|
||||
* then we also skip the tracking. This approach is good if we use the same
|
||||
* socket to send commands to kernel-space (that we want to track) and to
|
||||
* listen to events (that we do not track).
|
||||
*/
|
||||
bool
|
||||
mnl_nlmsg_seq_ok(const struct nlmsghdr *nlh, unsigned int seq)
|
||||
{
|
||||
return nlh->nlmsg_seq && seq ? nlh->nlmsg_seq == seq : true;
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_nlmsg_seq_ok);
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_portid_ok - perform portID origin check
|
||||
* \param nlh current netlink message that we are handling
|
||||
* \param seq netlink portid that we want to check
|
||||
*
|
||||
* This functions returns true if the origin is fulfilled, otherwise
|
||||
* false is returned. We skip the tracking for netlink message whose portID
|
||||
* is zero since it is reserved for event-based kernel notifications. On the
|
||||
* other hand, if portid is set but the message PortID is not (i.e. this
|
||||
* is an event message coming from kernel-space), then we also skip the
|
||||
* tracking. This approach is good if we use the same socket to send commands
|
||||
* to kernel-space (that we want to track) and to listen to events (that we
|
||||
* do not track).
|
||||
*/
|
||||
bool
|
||||
mnl_nlmsg_portid_ok(const struct nlmsghdr *nlh, unsigned int portid)
|
||||
{
|
||||
return nlh->nlmsg_pid && portid ? nlh->nlmsg_pid == portid : true;
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_nlmsg_portid_ok);
|
||||
|
||||
static void mnl_nlmsg_fprintf_header(FILE *fd, const struct nlmsghdr *nlh)
|
||||
{
|
||||
fprintf(fd, "----------------\t------------------\n");
|
||||
fprintf(fd, "| %.010u |\t| message length |\n", nlh->nlmsg_len);
|
||||
fprintf(fd, "| %.05u | %c%c%c%c |\t| type | flags |\n",
|
||||
nlh->nlmsg_type,
|
||||
nlh->nlmsg_flags & NLM_F_REQUEST ? 'R' : '-',
|
||||
nlh->nlmsg_flags & NLM_F_MULTI ? 'M' : '-',
|
||||
nlh->nlmsg_flags & NLM_F_ACK ? 'A' : '-',
|
||||
nlh->nlmsg_flags & NLM_F_ECHO ? 'E' : '-');
|
||||
fprintf(fd, "| %.010u |\t| sequence number|\n", nlh->nlmsg_seq);
|
||||
fprintf(fd, "| %.010u |\t| port ID |\n", nlh->nlmsg_pid);
|
||||
fprintf(fd, "----------------\t------------------\n");
|
||||
}
|
||||
|
||||
static void
|
||||
mnl_nlmsg_fprintf_payload(FILE *fd, const struct nlmsghdr *nlh,
|
||||
size_t extra_header_size)
|
||||
{
|
||||
int rem = 0;
|
||||
unsigned int i;
|
||||
|
||||
for (i=sizeof(struct nlmsghdr); i<nlh->nlmsg_len; i+=4) {
|
||||
char *b = (char *) nlh;
|
||||
struct nlattr *attr = (struct nlattr *) (b+i);
|
||||
|
||||
/* netlink control message. */
|
||||
if (nlh->nlmsg_type < NLMSG_MIN_TYPE) {
|
||||
fprintf(fd, "| %.2x %.2x %.2x %.2x |\t",
|
||||
0xff & b[i], 0xff & b[i+1],
|
||||
0xff & b[i+2], 0xff & b[i+3]);
|
||||
fprintf(fd, "| |\n");
|
||||
/* special handling for the extra header. */
|
||||
} else if (extra_header_size > 0) {
|
||||
extra_header_size -= 4;
|
||||
fprintf(fd, "| %.2x %.2x %.2x %.2x |\t",
|
||||
0xff & b[i], 0xff & b[i+1],
|
||||
0xff & b[i+2], 0xff & b[i+3]);
|
||||
fprintf(fd, "| extra header |\n");
|
||||
/* this seems like an attribute header. */
|
||||
} else if (rem == 0 && (attr->nla_type & NLA_TYPE_MASK) != 0) {
|
||||
fprintf(fd, "|%c[%d;%dm"
|
||||
"%.5u"
|
||||
"%c[%dm"
|
||||
"|"
|
||||
"%c[%d;%dm"
|
||||
"%c%c"
|
||||
"%c[%dm"
|
||||
"|"
|
||||
"%c[%d;%dm"
|
||||
"%.5u"
|
||||
"%c[%dm|\t",
|
||||
27, 1, 31,
|
||||
attr->nla_len,
|
||||
27, 0,
|
||||
27, 1, 32,
|
||||
attr->nla_type & NLA_F_NESTED ? 'N' : '-',
|
||||
attr->nla_type &
|
||||
NLA_F_NET_BYTEORDER ? 'B' : '-',
|
||||
27, 0,
|
||||
27, 1, 34,
|
||||
attr->nla_type & NLA_TYPE_MASK,
|
||||
27, 0);
|
||||
fprintf(fd, "|len |flags| type|\n");
|
||||
|
||||
if (!(attr->nla_type & NLA_F_NESTED)) {
|
||||
rem = NLA_ALIGN(attr->nla_len) -
|
||||
sizeof(struct nlattr);
|
||||
}
|
||||
/* this is the attribute payload. */
|
||||
} else if (rem > 0) {
|
||||
rem -= 4;
|
||||
fprintf(fd, "| %.2x %.2x %.2x %.2x |\t",
|
||||
0xff & b[i], 0xff & b[i+1],
|
||||
0xff & b[i+2], 0xff & b[i+3]);
|
||||
fprintf(fd, "| data |");
|
||||
fprintf(fd, "\t %c %c %c %c\n",
|
||||
isalnum(b[i]) ? b[i] : 0,
|
||||
isalnum(b[i+1]) ? b[i+1] : 0,
|
||||
isalnum(b[i+2]) ? b[i+2] : 0,
|
||||
isalnum(b[i+3]) ? b[i+3] : 0);
|
||||
}
|
||||
}
|
||||
fprintf(fd, "----------------\t------------------\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_fprintf - print netlink message to file
|
||||
* \param fd pointer to file type
|
||||
* \param data pointer to the buffer that contains messages to be printed
|
||||
* \param datalen length of data stored in the buffer
|
||||
* \param extra_header_size size of the extra header (if any)
|
||||
*
|
||||
* This function prints the netlink header to a file handle.
|
||||
* It may be useful for debugging purposes. One example of the output
|
||||
* is the following:
|
||||
*
|
||||
*\verbatim
|
||||
---------------- ------------------
|
||||
| 0000000040 | | message length |
|
||||
| 00016 | R-A- | | type | flags |
|
||||
| 1289148991 | | sequence number|
|
||||
| 0000000000 | | port ID |
|
||||
---------------- ------------------
|
||||
| 00 00 00 00 | | extra header |
|
||||
| 00 00 00 00 | | extra header |
|
||||
| 01 00 00 00 | | extra header |
|
||||
| 01 00 00 00 | | extra header |
|
||||
|00008|--|00003| |len |flags| type|
|
||||
| 65 74 68 30 | | data | e t h 0
|
||||
---------------- ------------------
|
||||
\endverbatim
|
||||
*
|
||||
* This example above shows the netlink message that is send to kernel-space
|
||||
* to set up the link interface eth0. The netlink and attribute header data
|
||||
* are displayed in base 10 whereas the extra header and the attribute payload
|
||||
* are expressed in base 16. The possible flags in the netlink header are:
|
||||
*
|
||||
* - R, that indicates that NLM_F_REQUEST is set.
|
||||
* - M, that indicates that NLM_F_MULTI is set.
|
||||
* - A, that indicates that NLM_F_ACK is set.
|
||||
* - E, that indicates that NLM_F_ECHO is set.
|
||||
*
|
||||
* The lack of one flag is displayed with '-'. On the other hand, the possible
|
||||
* attribute flags available are:
|
||||
*
|
||||
* - N, that indicates that NLA_F_NESTED is set.
|
||||
* - B, that indicates that NLA_F_NET_BYTEORDER is set.
|
||||
*/
|
||||
void
|
||||
mnl_nlmsg_fprintf(FILE *fd, const void *data, size_t datalen,
|
||||
size_t extra_header_size)
|
||||
{
|
||||
const struct nlmsghdr *nlh = data;
|
||||
int len = datalen;
|
||||
|
||||
while (mnl_nlmsg_ok(nlh, len)) {
|
||||
mnl_nlmsg_fprintf_header(fd, nlh);
|
||||
mnl_nlmsg_fprintf_payload(fd, nlh, extra_header_size);
|
||||
nlh = mnl_nlmsg_next(nlh, &len);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_nlmsg_fprintf);
|
||||
|
||||
/**
|
||||
* \defgroup batch Netlink message batch helpers
|
||||
*
|
||||
* This library provides helpers to batch several messages into one single
|
||||
* datagram. These helpers do not perform strict memory boundary checkings.
|
||||
*
|
||||
* The following figure represents a Netlink message batch:
|
||||
*
|
||||
* |<-------------- MNL_SOCKET_BUFFER_SIZE ------------->|
|
||||
* |<-------------------- batch ------------------>| |
|
||||
* |-----------|-----------|-----------|-----------|-----------|
|
||||
* |<- nlmsg ->|<- nlmsg ->|<- nlmsg ->|<- nlmsg ->|<- nlmsg ->|
|
||||
* |-----------|-----------|-----------|-----------|-----------|
|
||||
* ^ ^
|
||||
* | |
|
||||
* message N message N+1
|
||||
*
|
||||
* To start the batch, you have to call mnl_nlmsg_batch_start() and you can
|
||||
* use mnl_nlmsg_batch_stop() to release it.
|
||||
*
|
||||
* You have to invoke mnl_nlmsg_batch_next() to get room for a new message
|
||||
* in the batch. If this function returns NULL, it means that the last
|
||||
* message that was added (message N+1 in the figure above) does not fit the
|
||||
* batch. Thus, you have to send the batch (which includes until message N)
|
||||
* and, then, you have to call mnl_nlmsg_batch_reset() to re-initialize
|
||||
* the batch (this moves message N+1 to the head of the buffer). For that
|
||||
* reason, the buffer that you have to use to store the batch must be double
|
||||
* of MNL_SOCKET_BUFFER_SIZE to ensure that the last message (message N+1)
|
||||
* that did not fit into the batch is written inside valid memory boundaries.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
struct mnl_nlmsg_batch {
|
||||
/* the buffer that is used to store the batch. */
|
||||
void *buf;
|
||||
size_t limit;
|
||||
size_t buflen;
|
||||
/* the current netlink message in the batch. */
|
||||
void *cur;
|
||||
bool overflow;
|
||||
};
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_batch_start - initialize a batch
|
||||
* \param buf pointer to the buffer that will store this batch
|
||||
* \param limit maximum size of the batch (should be MNL_SOCKET_BUFFER_SIZE).
|
||||
*
|
||||
* The buffer that you pass must be double of MNL_SOCKET_BUFFER_SIZE. The
|
||||
* limit must be half of the buffer size, otherwise expect funny memory
|
||||
* corruptions 8-).
|
||||
*
|
||||
* You can allocate the buffer that you use to store the batch in the stack or
|
||||
* the heap, no restrictions in this regard. This function returns NULL on
|
||||
* error.
|
||||
*/
|
||||
struct mnl_nlmsg_batch *mnl_nlmsg_batch_start(void *buf, size_t limit)
|
||||
{
|
||||
struct mnl_nlmsg_batch *b;
|
||||
|
||||
b = malloc(sizeof(struct mnl_nlmsg_batch));
|
||||
if (b == NULL)
|
||||
return NULL;
|
||||
|
||||
b->buf = buf;
|
||||
b->limit = limit;
|
||||
b->buflen = 0;
|
||||
b->cur = buf;
|
||||
b->overflow = false;
|
||||
|
||||
return b;
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_nlmsg_batch_start);
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_batch_stop - release a batch
|
||||
* \param b pointer to batch
|
||||
*
|
||||
* This function returns the amount of data that is part of this batch.
|
||||
*/
|
||||
void mnl_nlmsg_batch_stop(struct mnl_nlmsg_batch *b)
|
||||
{
|
||||
free(b);
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_nlmsg_batch_stop);
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_batch_next - get room for the next message in the batch
|
||||
* \param b pointer to batch
|
||||
*
|
||||
* This function returns false if the last message did not fit into the
|
||||
* batch. Otherwise, it prepares the batch to provide room for the new
|
||||
* Netlink message in the batch and returns true.
|
||||
*
|
||||
* You have to put at least one message in the batch before calling this
|
||||
* function, otherwise your application is likely to crash.
|
||||
*/
|
||||
bool mnl_nlmsg_batch_next(struct mnl_nlmsg_batch *b)
|
||||
{
|
||||
struct nlmsghdr *nlh = b->cur;
|
||||
|
||||
if (b->buflen + nlh->nlmsg_len > b->limit) {
|
||||
b->overflow = true;
|
||||
return false;
|
||||
}
|
||||
b->cur = b->buf + b->buflen + nlh->nlmsg_len;
|
||||
b->buflen += nlh->nlmsg_len;
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_nlmsg_batch_next);
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_batch_reset - reset the batch
|
||||
* \param b pointer to batch
|
||||
*
|
||||
* This function allows to reset a batch, so you can reuse it to create a
|
||||
* new one. This function moves the last message which does not fit the
|
||||
* batch to the head of the buffer, if any.
|
||||
*/
|
||||
void mnl_nlmsg_batch_reset(struct mnl_nlmsg_batch *b)
|
||||
{
|
||||
if (b->overflow) {
|
||||
struct nlmsghdr *nlh = b->cur;
|
||||
memcpy(b->buf, b->cur, nlh->nlmsg_len);
|
||||
b->buflen = nlh->nlmsg_len;
|
||||
b->cur = b->buf + b->buflen;
|
||||
b->overflow = false;
|
||||
} else {
|
||||
b->buflen = 0;
|
||||
b->cur = b->buf;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_nlmsg_batch_reset);
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_batch_size - get current size of the batch
|
||||
* \param b pointer to batch
|
||||
*
|
||||
* This function returns the current size of the batch.
|
||||
*/
|
||||
size_t mnl_nlmsg_batch_size(struct mnl_nlmsg_batch *b)
|
||||
{
|
||||
return b->buflen;
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_nlmsg_batch_size);
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_batch_head - get head of this batch
|
||||
* \param b pointer to batch
|
||||
*
|
||||
* This function returns a pointer to the head of the batch, which is the
|
||||
* beginning of the buffer that is used.
|
||||
*/
|
||||
void *mnl_nlmsg_batch_head(struct mnl_nlmsg_batch *b)
|
||||
{
|
||||
return b->buf;
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_nlmsg_batch_head);
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_batch_current - returns current position in the batch
|
||||
* \param b pointer to batch
|
||||
*
|
||||
* This function returns a pointer to the current position in the buffer
|
||||
* that is used to store the batch.
|
||||
*/
|
||||
void *mnl_nlmsg_batch_current(struct mnl_nlmsg_batch *b)
|
||||
{
|
||||
return b->cur;
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_nlmsg_batch_current);
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_batch_is_empty - check if there is any message in the batch
|
||||
* \param b pointer to batch
|
||||
*
|
||||
* This function returns true if the batch is empty.
|
||||
*/
|
||||
bool mnl_nlmsg_batch_is_empty(struct mnl_nlmsg_batch *b)
|
||||
{
|
||||
return b->buflen == 0;
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_nlmsg_batch_is_empty);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
304
external/nflog/socket.c
vendored
Normal file
304
external/nflog/socket.c
vendored
Normal file
|
|
@ -0,0 +1,304 @@
|
|||
/*
|
||||
* (C) 2008-2010 by Pablo Neira Ayuso <pablo@netfilter.org>
|
||||
*
|
||||
* This program 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; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <libmnl/libmnl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include "internal.h"
|
||||
|
||||
/**
|
||||
* \mainpage
|
||||
*
|
||||
* libmnl is a minimalistic user-space library oriented to Netlink developers.
|
||||
* There are a lot of common tasks in parsing, validating, constructing of
|
||||
* both the Netlink header and TLVs that are repetitive and easy to get wrong.
|
||||
* This library aims to provide simple helpers that allows you to avoid
|
||||
* re-inventing the wheel in common Netlink tasks.
|
||||
*
|
||||
* \verbatim
|
||||
"Simplify, simplify" -- Henry David Thoureau. Walden (1854)
|
||||
\endverbatim
|
||||
*
|
||||
* The acronym libmnl stands for LIBrary Minimalistic NetLink.
|
||||
*
|
||||
* libmnl homepage is:
|
||||
* http://www.netfilter.org/projects/libmnl/
|
||||
*
|
||||
* \section features Main Features
|
||||
* - Small: the shared library requires around 30KB for an x86-based computer.
|
||||
* - Simple: this library avoids complex abstractions that tend to hide Netlink
|
||||
* details. It avoids elaborated object-oriented infrastructure and complex
|
||||
* callback-based workflow.
|
||||
* - Easy to use: the library simplifies the work for Netlink-wise developers.
|
||||
* It provides functions to make socket handling, message building,
|
||||
* validating, parsing and sequence tracking, easier.
|
||||
* - Easy to re-use: you can use this library to build your own abstraction
|
||||
* layer upon this library, if you want to provide another library that
|
||||
* hides Netlink details to your users.
|
||||
* - Decoupling: the interdependency of the main bricks that compose this
|
||||
* library is reduced, i.e. the library provides many helpers, but the
|
||||
* programmer is not forced to use them.
|
||||
*
|
||||
* \section licensing Licensing terms
|
||||
* This library is released under the LGPLv2.1 or any later (at your option).
|
||||
*
|
||||
* \section Dependencies
|
||||
* You have to install the Linux kernel headers that you want to use to develop
|
||||
* your application. Moreover, this library requires that you have some basics
|
||||
* on Netlink.
|
||||
*
|
||||
* \section scm Git Tree
|
||||
* The current development version of libmnl can be accessed at:
|
||||
* http://git.netfilter.org/cgi-bin/gitweb.cgi?p=libmnl.git;a=summary
|
||||
*
|
||||
* \section using Using libmnl
|
||||
* You can access several example files under examples/ in the libmnl source
|
||||
* code tree.
|
||||
*/
|
||||
|
||||
struct mnl_socket {
|
||||
int fd;
|
||||
struct sockaddr_nl addr;
|
||||
};
|
||||
|
||||
/**
|
||||
* \defgroup socket Netlink socket helpers
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* mnl_socket_get_fd - obtain file descriptor from netlink socket
|
||||
* \param nl netlink socket obtained via mnl_socket_open()
|
||||
*
|
||||
* This function returns the file descriptor of a given netlink socket.
|
||||
*/
|
||||
int mnl_socket_get_fd(const struct mnl_socket *nl)
|
||||
{
|
||||
return nl->fd;
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_socket_get_fd);
|
||||
|
||||
/**
|
||||
* mnl_socket_get_portid - obtain Netlink PortID from netlink socket
|
||||
* \param nl netlink socket obtained via mnl_socket_open()
|
||||
*
|
||||
* This function returns the Netlink PortID of a given netlink socket.
|
||||
* It's a common mistake to assume that this PortID equals the process ID
|
||||
* which is not always true. This is the case if you open more than one
|
||||
* socket that is binded to the same Netlink subsystem from the same process.
|
||||
*/
|
||||
unsigned int mnl_socket_get_portid(const struct mnl_socket *nl)
|
||||
{
|
||||
return nl->addr.nl_pid;
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_socket_get_portid);
|
||||
|
||||
/**
|
||||
* mnl_socket_open - open a netlink socket
|
||||
* \param bus the netlink socket bus ID (see NETLINK_* constants)
|
||||
*
|
||||
* On error, it returns -1 and errno is appropriately set. Otherwise, it
|
||||
* returns a valid pointer to the mnl_socket structure.
|
||||
*/
|
||||
struct mnl_socket *mnl_socket_open(int bus)
|
||||
{
|
||||
struct mnl_socket *nl;
|
||||
|
||||
nl = calloc(sizeof(struct mnl_socket), 1);
|
||||
if (nl == NULL)
|
||||
return NULL;
|
||||
|
||||
nl->fd = socket(AF_NETLINK, SOCK_RAW, bus);
|
||||
if (nl->fd == -1) {
|
||||
free(nl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return nl;
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_socket_open);
|
||||
|
||||
/**
|
||||
* mnl_socket_bind - bind netlink socket
|
||||
* \param nl netlink socket obtained via mnl_socket_open()
|
||||
* \param groups the group of message you're interested in
|
||||
* \param pid the port ID you want to use (use zero for automatic selection)
|
||||
*
|
||||
* On error, this function returns -1 and errno is appropriately set. On
|
||||
* success, 0 is returned. You can use MNL_SOCKET_AUTOPID which is 0 for
|
||||
* automatic port ID selection.
|
||||
*/
|
||||
int mnl_socket_bind(struct mnl_socket *nl, unsigned int groups, pid_t pid)
|
||||
{
|
||||
int ret;
|
||||
socklen_t addr_len;
|
||||
|
||||
nl->addr.nl_family = AF_NETLINK;
|
||||
nl->addr.nl_groups = groups;
|
||||
nl->addr.nl_pid = pid;
|
||||
|
||||
ret = bind(nl->fd, (struct sockaddr *) &nl->addr, sizeof (nl->addr));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
addr_len = sizeof(nl->addr);
|
||||
ret = getsockname(nl->fd, (struct sockaddr *) &nl->addr, &addr_len);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (addr_len != sizeof(nl->addr)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (nl->addr.nl_family != AF_NETLINK) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_socket_bind);
|
||||
|
||||
/**
|
||||
* mnl_socket_sendto - send a netlink message of a certain size
|
||||
* \param nl netlink socket obtained via mnl_socket_open()
|
||||
* \param buf buffer containing the netlink message to be sent
|
||||
* \param len number of bytes in the buffer that you want to send
|
||||
*
|
||||
* On error, it returns -1 and errno is appropriately set. Otherwise, it
|
||||
* returns the number of bytes sent.
|
||||
*/
|
||||
ssize_t
|
||||
mnl_socket_sendto(const struct mnl_socket *nl, const void *buf, size_t len)
|
||||
{
|
||||
static const struct sockaddr_nl snl = {
|
||||
.nl_family = AF_NETLINK
|
||||
};
|
||||
return sendto(nl->fd, buf, len, 0,
|
||||
(struct sockaddr *) &snl, sizeof(snl));
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_socket_sendto);
|
||||
|
||||
/**
|
||||
* mnl_socket_recvfrom - receive a netlink message
|
||||
* \param nl netlink socket obtained via mnl_socket_open()
|
||||
* \param buf buffer that you want to use to store the netlink message
|
||||
* \param bufsiz size of the buffer passed to store the netlink message
|
||||
*
|
||||
* On error, it returns -1 and errno is appropriately set. If errno is set
|
||||
* to ENOSPC, it means that the buffer that you have passed to store the
|
||||
* netlink message is too small, so you have received a truncated message.
|
||||
* To avoid this, you have to allocate a buffer of MNL_SOCKET_BUFFER_SIZE
|
||||
* (which is 8KB, see linux/netlink.h for more information). Using this
|
||||
* buffer size ensures that your buffer is big enough to store the netlink
|
||||
* message without truncating it.
|
||||
*/
|
||||
ssize_t
|
||||
mnl_socket_recvfrom(const struct mnl_socket *nl, void *buf, size_t bufsiz)
|
||||
{
|
||||
ssize_t ret;
|
||||
struct sockaddr_nl addr;
|
||||
struct iovec iov = {
|
||||
.iov_base = buf,
|
||||
.iov_len = bufsiz,
|
||||
};
|
||||
struct msghdr msg = {
|
||||
.msg_name = &addr,
|
||||
.msg_namelen = sizeof(struct sockaddr_nl),
|
||||
.msg_iov = &iov,
|
||||
.msg_iovlen = 1,
|
||||
.msg_control = NULL,
|
||||
.msg_controllen = 0,
|
||||
.msg_flags = 0,
|
||||
};
|
||||
ret = recvmsg(nl->fd, &msg, 0);
|
||||
if (ret == -1)
|
||||
return ret;
|
||||
|
||||
if (msg.msg_flags & MSG_TRUNC) {
|
||||
errno = ENOSPC;
|
||||
return -1;
|
||||
}
|
||||
if (msg.msg_namelen != sizeof(struct sockaddr_nl)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_socket_recvfrom);
|
||||
|
||||
/**
|
||||
* mnl_socket_close - close a given netlink socket
|
||||
* \param nl netlink socket obtained via mnl_socket_open()
|
||||
*
|
||||
* On error, this function returns -1 and errno is appropriately set.
|
||||
* On success, it returns 0.
|
||||
*/
|
||||
int mnl_socket_close(struct mnl_socket *nl)
|
||||
{
|
||||
int ret = close(nl->fd);
|
||||
free(nl);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_socket_close);
|
||||
|
||||
/**
|
||||
* mnl_socket_setsockopt - set Netlink socket option
|
||||
* \param nl netlink socket obtained via mnl_socket_open()
|
||||
* \param type type of Netlink socket options
|
||||
* \param buf the buffer that contains the data about this option
|
||||
* \param len the size of the buffer passed
|
||||
*
|
||||
* This function allows you to set some Netlink socket option. As of writing
|
||||
* this (see linux/netlink.h), the existing options are:
|
||||
*
|
||||
* - \#define NETLINK_ADD_MEMBERSHIP 1
|
||||
* - \#define NETLINK_DROP_MEMBERSHIP 2
|
||||
* - \#define NETLINK_PKTINFO 3
|
||||
* - \#define NETLINK_BROADCAST_ERROR 4
|
||||
* - \#define NETLINK_NO_ENOBUFS 5
|
||||
*
|
||||
* In the early days, Netlink only supported 32 groups expressed in a
|
||||
* 32-bits mask. However, since 2.6.14, Netlink may have up to 2^32 multicast
|
||||
* groups but you have to use setsockopt() with NETLINK_ADD_MEMBERSHIP to
|
||||
* join a given multicast group. This function internally calls setsockopt()
|
||||
* to join a given netlink multicast group. You can still use mnl_bind()
|
||||
* and the 32-bit mask to join a set of Netlink multicast groups.
|
||||
*
|
||||
* On error, this function returns -1 and errno is appropriately set.
|
||||
*/
|
||||
int mnl_socket_setsockopt(const struct mnl_socket *nl, int type,
|
||||
void *buf, socklen_t len)
|
||||
{
|
||||
return setsockopt(nl->fd, SOL_NETLINK, type, buf, len);
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_socket_setsockopt);
|
||||
|
||||
/**
|
||||
* mnl_socket_getsockopt - get a Netlink socket option
|
||||
* \param nl netlink socket obtained via mnl_socket_open()
|
||||
* \param type type of Netlink socket options
|
||||
* \param buf pointer to the buffer to store the value of this option
|
||||
* \param len size of the information written in the buffer
|
||||
*
|
||||
* On error, this function returns -1 and errno is appropriately set.
|
||||
*/
|
||||
int mnl_socket_getsockopt(const struct mnl_socket *nl, int type,
|
||||
void *buf, socklen_t *len)
|
||||
{
|
||||
return getsockopt(nl->fd, SOL_NETLINK, type, buf, len);
|
||||
}
|
||||
EXPORT_SYMBOL(mnl_socket_getsockopt);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
Loading…
Add table
Add a link
Reference in a new issue