Here is my MMAP adapted code that extends a previous NFLOG userspace daemon. Note that I used libmnl nl-mmap branch for my libmnl library & I also used Linux Kernel 3.12.5.
-
/**
-
* @copy (C) 2012 Pragmatic Software
-
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/
-
*
-
* @author [email protected] || www.pacificsimplicity.ca
-
* @note Modified source to use MMAP I/O which is available in the
-
* more recent Linux kernels 3.10+.
-
* gcc -g -I/usr/local/include/libmnl/ -L/usr/local/lib/ -o nflogd main.c -lmnl
-
* https://www.kernel.org/doc/Documentation/networking/netlink_mmap.txt
-
* https://git.netfilter.org/libmnl/tree/examples/netfilter/nf-queue.c?h=nl-mmap
-
*
-
* @author Original src https://code.google.com/p/iptableslog/
-
*/
-
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <unistd.h>
-
#include <string.h>
-
#include <time.h>
-
#include <arpa/inet.h>
-
-
#include <libmnl/libmnl.h>
-
#include <linux/netfilter.h>
-
#include <linux/netfilter/nfnetlink.h>
-
#include <linux/netlink.h>
-
#include <linux/ip.h>
-
#include <linux/tcp.h>
-
#include <linux/udp.h>
-
#include <linux/icmp.h>
-
#include <net/if.h>
-
#include <sys/ioctl.h>
-
#include <sys/socket.h>
-
#include <errno.h>
-
#include <poll.h>
-
#include <errno.h>
-
-
#ifndef aligned_be64
-
#define aligned_be64 u_int64_t __attribute__((aligned(8)))
-
#endif
-
-
#include <linux/netfilter/nfnetlink_log.h>
-
-
char *netlog_if_indextoname(unsigned int ifindex, char *ifname);
-
void free_net_devices(void);
-
void cleanup(void);
-
-
#define MAX_NETDEVICES 32
-
static char *devices[MAX_NETDEVICES] = { 0 };
-
-
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_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");
-
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");
-
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");
-
return MNL_CB_ERROR;
-
}
-
break;
-
case NFULA_PREFIX:
-
if (mnl_attr_validate(attr, MNL_TYPE_NUL_STRING) < 0) {
-
perror("mnl_attr_validate");
-
return MNL_CB_ERROR;
-
}
-
break;
-
case NFULA_PAYLOAD:
-
break;
-
}
-
tb[type] = attr;
-
return MNL_CB_OK;
-
}
-
-
char *netlog_if_indextoname(unsigned int ifindex, char *ifname)
-
{
-
/* We may be able to do the conversion directly, rather than searching a
-
* list. This ioctl is not present in kernels before version 2.1.50. */
-
struct ifreq ifr;
-
int fd;
-
int status;
-
-
fd = socket(AF_INET, SOCK_DGRAM, 0);
-
-
if (fd < 0)
-
return NULL;
-
-
ifr.ifr_ifindex = ifindex;
-
status = ioctl(fd, SIOCGIFNAME, &ifr);
-
-
close(fd);
-
-
if (status < 0) {
-
if (errno == ENODEV)
-
/* POSIX requires ENXIO. */
-
errno = ENXIO;
-
-
return NULL;
-
} else
-
return strncpy(ifname, ifr.ifr_name, IFNAMSIZ);
-
}
-
-
static inline char *get_net_device_name_by_index(int ifindex)
-
{
-
if (ifindex < 0 || ifindex > MAX_NETDEVICES - 1) {
-
return NULL;
-
}
-
-
if (!devices[ifindex]) {
-
devices[ifindex] = malloc(IFNAMSIZ);
-
if (!devices[ifindex]) {
-
perror("malloc");
-
exit(EXIT_FAILURE);
-
}
-
-
netlog_if_indextoname(ifindex, devices[ifindex]);
-
if (!devices[ifindex]) {
-
perror("if_indextoname");
-
exit(EXIT_FAILURE);
-
}
-
}
-
-
return devices[ifindex];
-
}
-
-
void free_net_devices(void)
-
{
-
int i;
-
for (i = 0; i < MAX_NETDEVICES - 1; i++) {
-
if (devices[i]) {
-
free(devices[i]);
-
}
-
}
-
}
-
-
static int log_cb(const struct nlmsghdr *nlh, void *data)
-
{
-
printf("here \n");
-
struct nlattr *tb[NFULA_MAX + 1] = { };
-
-
mnl_attr_parse(nlh, sizeof(struct nfgenmsg), parse_attr_cb, tb);
-
-
if (tb[NFULA_PREFIX]) {
-
const char *prefix = mnl_attr_get_str(tb[NFULA_PREFIX]);
-
printf("%s ", prefix);
-
}
-
-
if (tb[NFULA_IFINDEX_INDEV]) {
-
uint32_t indev = ntohl(mnl_attr_get_u32(tb[NFULA_IFINDEX_INDEV]));
-
char *instr = get_net_device_name_by_index(indev);
-
printf("IN=%s ", instr ? instr : "");
-
} else {
-
printf("IN= ");
-
}
-
-
if (tb[NFULA_IFINDEX_OUTDEV]) {
-
uint32_t outdev = ntohl(mnl_attr_get_u32(tb[NFULA_IFINDEX_OUTDEV]));
-
char *outstr = get_net_device_name_by_index(outdev);
-
printf("OUT=%s ", outstr ? outstr : "");
-
} else {
-
printf("OUT= ");
-
}
-
-
if (tb[NFULA_PAYLOAD]) {
-
struct iphdr *iph = (struct iphdr *)mnl_attr_get_payload(tb[NFULA_PAYLOAD]);
-
-
printf("SRC=%u.%u.%u.%u DST=%u.%u.%u.%u ",
-
((unsigned char *)&iph->saddr)[0],
-
((unsigned char *)&iph->saddr)[1],
-
((unsigned char *)&iph->saddr)[2],
-
((unsigned char *)&iph->saddr)[3],
-
((unsigned char *)&iph->daddr)[0],
-
((unsigned char *)&iph->daddr)[1],
-
((unsigned char *)&iph->daddr)[2], ((unsigned char *)&iph->daddr)[3]);
-
-
printf("LEN=%u ", ntohs(iph->tot_len));
-
-
switch (iph->protocol) {
-
case IPPROTO_TCP:
-
{
-
struct tcphdr *th = (struct tcphdr *)((__u32 *) iph + iph->ihl);
-
printf("PROTO=TCP SPT=%u DPT=%u ", ntohs(th->source), ntohs(th->dest));
-
break;
-
}
-
case IPPROTO_UDP:
-
{
-
struct udphdr *uh = (struct udphdr *)((__u32 *) iph + iph->ihl);
-
printf("PROTO=UDP SPT=%u DPT=%u LEN=%u ",
-
ntohs(uh->source), ntohs(uh->dest), ntohs(uh->len));
-
break;
-
}
-
case IPPROTO_ICMP:
-
{
-
struct icmphdr *ich = (struct icmphdr *)((__u32 *) iph + iph->ihl);
-
printf("PROTO=ICMP TYPE=%u CODE=%u ", ich->type, ich->code);
-
break;
-
}
-
default:
-
{
-
printf("PROTO=%u ", iph->protocol);
-
}
-
}
-
}
-
-
if (tb[NFULA_UID]) {
-
uint32_t uid = ntohl(mnl_attr_get_u32(tb[NFULA_UID]));
-
printf("UID=%u ", uid);
-
}
-
-
puts("");
-
fflush(stdout); // apparently this is necessary for some devices
-
-
return MNL_CB_OK;
-
}
-
-
static struct nlmsghdr *nflog_build_cfg_pf_request(struct mnl_socket *nl, uint8_t command)
-
{
-
struct nl_mmap_hdr *hdr;
-
-
hdr = mnl_socket_get_frame(nl, MNL_RING_TX);
-
if (hdr->nm_status != NL_MMAP_STATUS_UNUSED)
-
return NULL;
-
mnl_socket_advance_ring(nl, MNL_RING_TX);
-
-
struct nlmsghdr *nlh = mnl_nlmsg_put_header((void *)hdr + NL_MMAP_HDRLEN);
-
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);
-
-
hdr->nm_len = nlh->nlmsg_len;
-
hdr->nm_status = NL_MMAP_STATUS_VALID;
-
return nlh;
-
}
-
-
static struct nlmsghdr *nflog_build_cfg_request(struct mnl_socket *nl, uint8_t command, int nflognum)
-
{
-
struct nl_mmap_hdr *hdr;
-
-
hdr = mnl_socket_get_frame(nl, MNL_RING_TX);
-
if (hdr->nm_status != NL_MMAP_STATUS_UNUSED)
-
return NULL;
-
mnl_socket_advance_ring(nl, MNL_RING_TX);
-
-
struct nlmsghdr *nlh = mnl_nlmsg_put_header((void *)hdr + NL_MMAP_HDRLEN);
-
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(nflognum);
-
-
struct nfulnl_msg_config_cmd cmd = {
-
.command = command,
-
};
-
mnl_attr_put(nlh, NFULA_CFG_CMD, sizeof(cmd), &cmd);
-
-
hdr->nm_len = nlh->nlmsg_len;
-
hdr->nm_status = NL_MMAP_STATUS_VALID;
-
return nlh;
-
}
-
-
static struct nlmsghdr *nflog_build_cfg_params(struct mnl_socket *nl, uint8_t mode, int range, int nflognum)
-
{
-
struct nl_mmap_hdr *hdr;
-
-
hdr = mnl_socket_get_frame(nl, MNL_RING_TX);
-
if (hdr->nm_status != NL_MMAP_STATUS_UNUSED)
-
return NULL;
-
mnl_socket_advance_ring(nl, MNL_RING_TX);
-
-
struct nlmsghdr *nlh = mnl_nlmsg_put_header((void *)hdr + NL_MMAP_HDRLEN);
-
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(nflognum);
-
-
struct nfulnl_msg_config_mode params = {
-
.copy_range = htonl(range),
-
.copy_mode = mode,
-
};
-
mnl_attr_put(nlh, NFULA_CFG_MODE, sizeof(params), ¶ms);
-
-
hdr->nm_len = nlh->nlmsg_len;
-
hdr->nm_status = NL_MMAP_STATUS_VALID;
-
return nlh;
-
}
-
-
struct mnl_socket *nl = 0;
-
-
void cleanup(void)
-
{
-
if (nl != 0)
-
mnl_socket_close(nl);
-
free_net_devices();
-
}
-
-
static int mnl_socket_poll(struct mnl_socket *nl)
-
{
-
struct pollfd pfds[1];
-
-
while (1) {
-
pfds[0].fd = mnl_socket_get_fd(nl);
-
pfds[0].events = POLLIN | POLLERR;
-
pfds[0].revents = 0;
-
-
if (poll(pfds, 1, -1) < 0 && errno != -EINTR)
-
return -1;
-
-
if (pfds[0].revents & POLLIN)
-
return 0;
-
if (pfds[0].revents & POLLERR)
-
return -1;
-
}
-
}
-
-
int main(int argc, char *argv[])
-
{
-
char buf[MNL_SOCKET_BUFFER_SIZE];
-
struct mnl_socket *nl;
-
struct nlmsghdr *nlh;
-
struct nl_mmap_hdr *hdr;
-
ssize_t len;
-
void *ptr;
-
int ret, buffersize = MNL_SOCKET_BUFFER_SIZE;
-
unsigned int portid, nflognum;
-
-
atexit(cleanup);
-
-
if (argc != 2) {
-
printf("Usage: %s [nflog_group_num]\n", argv[0]);
-
exit(EXIT_FAILURE);
-
}
-
nflognum = atoi(argv[1]);
-
-
nl = mnl_socket_open(NETLINK_NETFILTER);
-
if (nl == NULL) {
-
perror("mnl_socket_open");
-
exit(EXIT_FAILURE);
-
}
-
-
setsockopt(mnl_socket_get_fd(nl), SOL_SOCKET, SO_RCVBUFFORCE, &buffersize, sizeof(socklen_t));
-
-
mnl_socket_setsockopt(nl, NETLINK_BROADCAST_ERROR, 0, sizeof(int));
-
mnl_socket_setsockopt(nl, NETLINK_NO_ENOBUFS, 0, sizeof(int));
-
-
if (mnl_socket_set_ring(nl, 0, 0) < 0) {
-
perror("mnl_socket_set_ring");
-
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);
-
-
nlh = nflog_build_cfg_pf_request(nl, NFULNL_CFG_CMD_PF_UNBIND);
-
-
if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
-
perror("mnl_socket_send");
-
exit(EXIT_FAILURE);
-
}
-
-
nlh = nflog_build_cfg_pf_request(nl, NFULNL_CFG_CMD_PF_BIND);
-
-
if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
-
perror("mnl_socket_send");
-
exit(EXIT_FAILURE);
-
}
-
-
nlh = nflog_build_cfg_request(nl, NFULNL_CFG_CMD_BIND, nflognum);
-
-
if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
-
perror("mnl_socket_send");
-
exit(EXIT_FAILURE);
-
}
-
-
nlh = nflog_build_cfg_params(nl, NFULNL_COPY_PACKET, 0xFFFF, nflognum);
-
-
if (mnl_socket_sendto(nl, NULL, 0) < 0) {
-
perror("mnl_socket_send");
-
exit(EXIT_FAILURE);
-
}
-
-
while (1) {
-
ret = mnl_socket_poll(nl);
-
if (ret < 0) {
-
perror("mnl_socket_poll");
-
exit(EXIT_FAILURE);
-
}
-
-
while (1) {
-
hdr = mnl_socket_get_frame(nl, MNL_RING_RX);
-
if (hdr->nm_status == NL_MMAP_STATUS_VALID) {
-
ptr = (void *)hdr + NL_MMAP_HDRLEN;
-
len = hdr->nm_len;
-
if (len == 0) {
-
goto next;
-
}
-
} else if (hdr->nm_status == NL_MMAP_STATUS_COPY) {
-
len = recv(mnl_socket_get_fd(nl), buf, sizeof(buf), MSG_DONTWAIT);
-
if (len <= 0) {
-
break;
-
}
-
ptr = buf;
-
} else {
-
break;
-
}
-
-
ret = mnl_cb_run(ptr, len, 0, portid, log_cb, NULL);
-
-
next:
-
hdr->nm_status = NL_MMAP_STATUS_UNUSED;
-
mnl_socket_advance_ring(nl, MNL_RING_RX);
-
-
}
-
-
}
-
-
return 0;
-
}
Blog tags:
Attachment | Size |
---|---|
nflogd-libmnl-mmap.c | 11.07 KB |
Add new comment