libipulog_compat.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <libnfnetlink/libnfnetlink.h>
#include <libnetfilter_log/libnetfilter_log.h>
#include <libnetfilter_log/libipulog.h>
/* private */
#define PAYLOAD_SIZE 0xffff
struct ipulog_handle
{
struct nflog_handle *nfulh;
struct nflog_g_handle *nful_gh;
struct nlmsghdr *last_nlh;
#if 0
int fd;
uint8_t blocking;
struct sockaddr_nl local;
struct sockaddr_nl peer;
#endif
struct ulog_packet_msg upmsg; /* has to be last in structure */
};
static const struct ipulog_errmap_t
{
int errcode;
const char *message;
} ipulog_errmap[] =
{
{ IPULOG_ERR_NONE, "No error" },
{ IPULOG_ERR_IMPL, "Not implemented yet" },
{ IPULOG_ERR_HANDLE, "Unable to create netlink handle" },
{ IPULOG_ERR_SOCKET, "Unable to create netlink socket" },
{ IPULOG_ERR_BIND, "Unable to bind netlink socket" },
{ IPULOG_ERR_RECVBUF, "Receive buffer size invalid" },
{ IPULOG_ERR_RECV, "Error during netlink receive" },
{ IPULOG_ERR_NLEOF, "Received EOF on netlink socket" },
{ IPULOG_ERR_TRUNC, "Receive message truncated" },
{ IPULOG_ERR_INVGR, "Invalid group specified" },
{ IPULOG_ERR_INVNL, "Invalid netlink message" },
};
/* obviously this only finds the highest group in the mask */
static unsigned int gmask2group(unsigned int gmask)
{
int bit;
for (bit = sizeof(gmask)*4 -1; bit >= 0; bit--) {
if (gmask & (1 << bit))
return bit+1;
}
return 0;
}
/* public */
int ipulog_errno = IPULOG_ERR_NONE;
const char *ipulog_strerror(int errcode)
{
if (errcode < 0 || errcode > IPULOG_MAXERR)
errcode = IPULOG_ERR_IMPL;
return ipulog_errmap[errcode].message;
}
/* convert a netlink group (1-32) to a group_mask suitable for create_handle */
uint32_t ipulog_group2gmask(uint32_t group)
{
if (group < 1 || group > 32)
{
ipulog_errno = IPULOG_ERR_INVGR;
return 0;
}
return (1 << (group - 1));
}
/* create a ipulog handle for the reception of packets sent to gmask */
struct ipulog_handle *ipulog_create_handle(uint32_t gmask,
uint32_t rcvbufsize)
{
int rv;
struct ipulog_handle *h;
unsigned int group = gmask2group(gmask);
h = calloc(1, sizeof(*h)+PAYLOAD_SIZE);
if (! h) {
ipulog_errno = IPULOG_ERR_HANDLE;
return NULL;
}
h->nfulh = nflog_open();
if (!h->nfulh)
goto out_free;
/* bind_pf returns EEXIST if we are already registered */
rv = nflog_bind_pf(h->nfulh, AF_INET);
if (rv < 0 && rv != -EEXIST)
goto out_free;
h->nful_gh = nflog_bind_group(h->nfulh, group);
if (!h->nful_gh)
goto out_free;
return h;
out_free:
ipulog_errno = IPULOG_ERR_HANDLE;
free(h);
return NULL;
}
void ipulog_destroy_handle(struct ipulog_handle *h)
{
nflog_unbind_group(h->nful_gh);
nflog_close(h->nfulh);
free(h);
}
ulog_packet_msg_t *ipulog_get_packet(struct ipulog_handle *h,
const unsigned char *buf,
size_t len)
{
struct nlmsghdr *nlh;
struct nfattr *tb[NFULA_MAX];
struct nfulnl_msg_packet_hdr *hdr;
if (!h->last_nlh) {
printf("first\n");
nlh = nfnl_get_msg_first(nflog_nfnlh(h->nfulh), buf, len);
}else {
next_msg: printf("next\n");
nlh = nfnl_get_msg_next(nflog_nfnlh(h->nfulh), buf, len);
}
h->last_nlh = nlh;
if (!nlh)
return NULL;
nfnl_parse_attr(tb, NFULA_MAX, NFM_NFA(NLMSG_DATA(nlh)),
NFM_PAYLOAD(nlh));
if (!tb[NFULA_PACKET_HDR-1])
goto next_msg;
/* now build the fake ulog_packet_msg */
hdr = NFA_DATA(tb[NFULA_PACKET_HDR-1]);
h->upmsg.hook = hdr->hook;
if (tb[NFULA_MARK-1])
h->upmsg.mark = ntohl(*(uint32_t *)NFA_DATA(tb[NFULA_MARK-1]));
else
h->upmsg.mark = 0;
if (tb[NFULA_TIMESTAMP-1]) {
struct nfulnl_msg_packet_timestamp *ts;
ts = NFA_DATA(tb[NFULA_TIMESTAMP-1]);
h->upmsg.timestamp_sec = __be64_to_cpu(ts->sec);
h->upmsg.timestamp_usec = __be64_to_cpu(ts->usec);
} else
h->upmsg.timestamp_sec = h->upmsg.timestamp_usec = 0;
if (tb[NFULA_IFINDEX_INDEV-1]) {
void *indev_ptr = NFA_DATA(tb[NFULA_IFINDEX_INDEV-1]);
uint32_t indev_idx = ntohl(*(uint32_t *)indev_ptr);
if (!if_indextoname(indev_idx, h->upmsg.indev_name))
h->upmsg.indev_name[0] = '\0';
} else
h->upmsg.indev_name[0] = '\0';
if (tb[NFULA_IFINDEX_OUTDEV-1]) {
void *outdev_ptr = NFA_DATA(tb[NFULA_IFINDEX_OUTDEV-1]);
uint32_t outdev_idx = ntohl(*(uint32_t *)outdev_ptr);
if (!if_indextoname(outdev_idx, h->upmsg.outdev_name))
h->upmsg.outdev_name[0] = '\0';
} else
h->upmsg.outdev_name[0] = '\0';
if (tb[NFULA_HWADDR-1]) {
struct nfulnl_msg_packet_hw *phw = NFA_DATA(tb[NFULA_HWADDR-1]);
h->upmsg.mac_len = ntohs(phw->hw_addrlen);
memcpy(h->upmsg.mac, phw->hw_addr, 8);
} else
h->upmsg.mac_len = 0;
if (tb[NFULA_PREFIX-1]) {
int plen = NFA_PAYLOAD(tb[NFULA_PREFIX-1]);
if (ULOG_PREFIX_LEN < plen)
plen = ULOG_PREFIX_LEN;
memcpy(h->upmsg.prefix, NFA_DATA(tb[NFULA_PREFIX-1]), plen);
h->upmsg.prefix[ULOG_PREFIX_LEN-1] = '\0';
}
if (tb[NFULA_PAYLOAD-1]) {
memcpy(h->upmsg.payload, NFA_DATA(tb[NFULA_PAYLOAD-1]),
NFA_PAYLOAD(tb[NFULA_PAYLOAD-1]));
h->upmsg.data_len = NFA_PAYLOAD(tb[NFULA_PAYLOAD-1]);
} else
h->upmsg.data_len = 0;
return &h->upmsg;
}
ssize_t ipulog_read(struct ipulog_handle *h, unsigned char *buf,
size_t len, int timeout)
{
/* 'timeout' was never implemented in the original libipulog,
* so we don't bother emulating it */
return nfnl_recv(nflog_nfnlh(h->nfulh), buf, len);
}
/* print a human readable description of the last error to stderr */
void ipulog_perror(const char *s)
{
if (s)
fputs(s, stderr);
else
fputs("ERROR", stderr);
if (ipulog_errno)
fprintf(stderr, ": %s", ipulog_strerror(ipulog_errno));
if (errno)
fprintf(stderr, ": %s", strerror(errno));
fputc('\n', stderr);
}
nflog_open
struct nflog_handle * nflog_open(void)
Definition libnetfilter_log.c:304
nflog_bind_pf
int nflog_bind_pf(struct nflog_handle *h, uint16_t pf)
Definition libnetfilter_log.c:420
nflog_close
int nflog_close(struct nflog_handle *h)
Definition libnetfilter_log.c:401
nflog_bind_group
struct nflog_g_handle * nflog_bind_group(struct nflog_handle *h, uint16_t num)
Definition libnetfilter_log.c:464
nflog_unbind_group
int nflog_unbind_group(struct nflog_g_handle *gh)
Definition libnetfilter_log.c:506