mirror of
https://git.netfilter.org/libmnl
synced 2026-01-26 10:34:28 +00:00
initial libmnl import
This commit is contained in:
commit
74e7bb8b03
7
Make_global.am
Normal file
7
Make_global.am
Normal file
@ -0,0 +1,7 @@
|
||||
# This is _NOT_ the library release version, it's an API version.
|
||||
# Please read Chapter 6 "Library interface versions" of the libtool
|
||||
# documentation before making any modification
|
||||
# http://sources.redhat.com/autobook/autobook/autobook_91.html
|
||||
LIBVERSION=0:0:0
|
||||
|
||||
INCLUDES=$(all_includes) -I$(top_srcdir)/include
|
||||
14
Makefile.am
Normal file
14
Makefile.am
Normal file
@ -0,0 +1,14 @@
|
||||
include $(top_srcdir)/Make_global.am
|
||||
|
||||
AUTOMAKE_OPTIONS = foreign dist-bzip2 1.6
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
SUBDIRS = src include examples
|
||||
DIST_SUBDIRS = src include examples
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = libmnl.pc
|
||||
|
||||
$(OBJECTS): libtool
|
||||
libtool: $(LIBTOOL_DEPS)
|
||||
$(SHELL) ./config.status --recheck
|
||||
9
README
Normal file
9
README
Normal file
@ -0,0 +1,9 @@
|
||||
libmnl
|
||||
|
||||
Features:
|
||||
- Minimalistic Netlink library
|
||||
- Low-level: you have to know how Netlink works.
|
||||
- Simplicity: as opposed to complexity.
|
||||
- Very low abstraction: try to leak as less Netlink details as possible.
|
||||
- Decoupling: the main bricks are decoupled to avoid inter-dependencies
|
||||
(eg. socket handling and callbacks are not attached).
|
||||
53
autogen.sh
Executable file
53
autogen.sh
Executable file
@ -0,0 +1,53 @@
|
||||
#!/bin/sh
|
||||
|
||||
include ()
|
||||
{
|
||||
# If we keep a copy of the kernel header in the SVN tree, we'll have
|
||||
# to worry about synchronization issues forever. Instead, we just copy
|
||||
# the headers that we need from the lastest kernel version at autogen
|
||||
# stage.
|
||||
|
||||
INCLUDEDIR=${KERNEL_DIR:-/lib/modules/`uname -r`/build}/include/linux
|
||||
|
||||
if [ -f $INCLUDEDIR/netfilter/nfnetlink.h ]
|
||||
then
|
||||
TARGET=include/libnfnetlink/linux_nfnetlink.h
|
||||
echo "Copying nfnetlink.h to linux_nfnetlink.h"
|
||||
cp $INCLUDEDIR/netfilter/nfnetlink.h $TARGET
|
||||
TMP=`mktemp`
|
||||
sed 's/__be16/u_int16_t/g' $TARGET > $TMP
|
||||
cp $TMP $TARGET
|
||||
sed 's/#include <linux\/netfilter\/nfnetlink_compat\.h>/#include <libnfnetlink\/linux_nfnetlink_compat\.h>/g' $TARGET > $TMP
|
||||
cp $TMP $TARGET
|
||||
else
|
||||
echo "can't find nfnetlink.h kernel file in $INCLUDEDIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -f $INCLUDEDIR/netfilter/nfnetlink_compat.h ]
|
||||
then
|
||||
TARGET=include/libnfnetlink/linux_nfnetlink_compat.h
|
||||
echo "Copying nfnetlink_compat.h to linux_nfnetlink_compat.h"
|
||||
cp $INCLUDEDIR/netfilter/nfnetlink_compat.h $TARGET
|
||||
else
|
||||
echo "can't find nfnetlink.h kernel file in $INCLUDEDIR, ignoring"
|
||||
fi
|
||||
}
|
||||
|
||||
run ()
|
||||
{
|
||||
echo "running: $*"
|
||||
eval $*
|
||||
|
||||
if test $? != 0 ; then
|
||||
echo "error: while running '$*'"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
[ "x$1" = "xdistrib" ] && include
|
||||
run aclocal
|
||||
#run autoheader
|
||||
run libtoolize -f
|
||||
run automake -a
|
||||
run autoconf
|
||||
18
configure.in
Normal file
18
configure.in
Normal file
@ -0,0 +1,18 @@
|
||||
dnl Process this file with autoconf to create configure.
|
||||
|
||||
AC_INIT
|
||||
AC_CANONICAL_SYSTEM
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AM_INIT_AUTOMAKE(libmnl, 1.0.0-beta0)
|
||||
|
||||
AC_PROG_CC
|
||||
AC_EXEEXT
|
||||
AM_PROG_LIBTOOL
|
||||
AC_SUBST(LIBTOOL_DEPS)
|
||||
|
||||
case $target in
|
||||
*-*-linux*) ;;
|
||||
*) AC_MSG_ERROR([Linux only, dude!]);;
|
||||
esac
|
||||
|
||||
AC_OUTPUT(Makefile src/Makefile include/Makefile include/libmnl/Makefile examples/Makefile libmnl.pc)
|
||||
24
examples/Makefile.am
Normal file
24
examples/Makefile.am
Normal file
@ -0,0 +1,24 @@
|
||||
include $(top_srcdir)/Make_global.am
|
||||
|
||||
check_PROGRAMS = rtnl-link-dump rtnl-link-event rtnl-link-set \
|
||||
rtnl-route-dump genl-family-get
|
||||
|
||||
rtnl_link_dump_SOURCES = rtnl-link-dump.c
|
||||
rtnl_link_dump_LDADD = ../src/libmnl.la
|
||||
rtnl_link_dump_LDFLAGS = -dynamic -ldl
|
||||
|
||||
rtnl_link_event_SOURCES = rtnl-link-event.c
|
||||
rtnl_link_event_LDADD = ../src/libmnl.la
|
||||
rtnl_link_event_LDFLAGS = -dynamic -ldl
|
||||
|
||||
rtnl_link_set_SOURCES = rtnl-link-set.c
|
||||
rtnl_link_set_LDADD = ../src/libmnl.la
|
||||
rtnl_link_set_LDFLAGS = -dynamic -ldl
|
||||
|
||||
rtnl_route_dump_SOURCES = rtnl-route-dump.c
|
||||
rtnl_route_dump_LDADD = ../src/libmnl.la
|
||||
rtnl_route_dump_LDFLAGS = -dynamic -ldl
|
||||
|
||||
genl_family_get_SOURCES = genl-family-get.c
|
||||
genl_family_get_LDADD = ../src/libmnl.la
|
||||
genl_family_get_LDFLAGS = -dynamic -ldl
|
||||
143
examples/genl-family-get.c
Normal file
143
examples/genl-family-get.c
Normal file
@ -0,0 +1,143 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <libmnl/libmnl.h>
|
||||
#include <linux/genetlink.h>
|
||||
|
||||
static void parse_genl_mc_grps(struct nlattr *nested)
|
||||
{
|
||||
struct nlattr *pos;
|
||||
int len;
|
||||
|
||||
mnl_attr_for_each_nested(pos, nested, len) {
|
||||
struct nlattr *tb[CTRL_ATTR_MCAST_GRP_MAX+1];
|
||||
|
||||
mnl_attr_parse_nested(pos, tb, CTRL_ATTR_MCAST_GRP_MAX);
|
||||
if (tb[CTRL_ATTR_MCAST_GRP_ID]) {
|
||||
printf("id-0x%x ",
|
||||
mnl_attr_get_u32(tb[CTRL_ATTR_MCAST_GRP_ID]));
|
||||
}
|
||||
if (tb[CTRL_ATTR_MCAST_GRP_NAME]) {
|
||||
printf("name: %s ",
|
||||
mnl_attr_get_str(tb[CTRL_ATTR_MCAST_GRP_NAME]));
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_genl_family_ops(struct nlattr *nested)
|
||||
{
|
||||
struct nlattr *pos;
|
||||
int len;
|
||||
|
||||
mnl_attr_for_each_nested(pos, nested, len) {
|
||||
struct nlattr *tb[CTRL_ATTR_OP_MAX+1];
|
||||
|
||||
mnl_attr_parse_nested(pos, tb, CTRL_ATTR_OP_MAX);
|
||||
if (tb[CTRL_ATTR_OP_ID]) {
|
||||
printf("id-0x%x ",
|
||||
mnl_attr_get_u32(tb[CTRL_ATTR_OP_ID]));
|
||||
}
|
||||
if (tb[CTRL_ATTR_OP_MAX]) {
|
||||
printf("flags ");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
static int data_cb(const struct nlmsghdr *nlh, void *data)
|
||||
{
|
||||
struct nlattr *tb[CTRL_ATTR_MAX+1];
|
||||
struct genlmsghdr *genl = mnl_nlmsg_get_data(nlh);
|
||||
|
||||
mnl_attr_parse_at_offset(nlh, sizeof(*genl), tb, CTRL_ATTR_MAX);
|
||||
if (tb[CTRL_ATTR_FAMILY_NAME]) {
|
||||
printf("name=%s\t",
|
||||
mnl_attr_get_str(tb[CTRL_ATTR_FAMILY_NAME]));
|
||||
}
|
||||
if (tb[CTRL_ATTR_FAMILY_ID]) {
|
||||
printf("id=%u\t",
|
||||
mnl_attr_get_u16(tb[CTRL_ATTR_FAMILY_ID]));
|
||||
}
|
||||
if (tb[CTRL_ATTR_VERSION]) {
|
||||
printf("version=%u\t",
|
||||
mnl_attr_get_u32(tb[CTRL_ATTR_VERSION]));
|
||||
}
|
||||
if (tb[CTRL_ATTR_HDRSIZE]) {
|
||||
printf("hdrsize=%u\t",
|
||||
mnl_attr_get_u32(tb[CTRL_ATTR_HDRSIZE]));
|
||||
}
|
||||
if (tb[CTRL_ATTR_MAXATTR]) {
|
||||
printf("maxattr=%u\t",
|
||||
mnl_attr_get_u32(tb[CTRL_ATTR_MAXATTR]));
|
||||
}
|
||||
if (tb[CTRL_ATTR_OPS]) {
|
||||
printf("\nops:\n");
|
||||
parse_genl_family_ops(tb[CTRL_ATTR_OPS]);
|
||||
}
|
||||
if (tb[CTRL_ATTR_MCAST_GROUPS]) {
|
||||
printf("\ngrps:\n");
|
||||
parse_genl_mc_grps(tb[CTRL_ATTR_MCAST_GROUPS]);
|
||||
}
|
||||
return MNL_CB_OK;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct mnl_socket *nl;
|
||||
char buf[getpagesize()];
|
||||
struct nlmsghdr *nlh;
|
||||
struct genlmsghdr *genl;
|
||||
int ret;
|
||||
unsigned int seq;
|
||||
|
||||
if (argc != 2) {
|
||||
printf("%s [family name]\n", argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
nlh = mnl_nlmsg_put_header(buf);
|
||||
nlh->nlmsg_type = GENL_ID_CTRL;
|
||||
nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
|
||||
nlh->nlmsg_seq = seq = time(NULL);
|
||||
|
||||
genl = mnl_nlmsg_put_extra_header(nlh, sizeof(struct genlmsghdr));
|
||||
genl->cmd = CTRL_CMD_GETFAMILY;
|
||||
genl->version = 1;
|
||||
|
||||
mnl_attr_put_u32(nlh, CTRL_ATTR_FAMILY_ID, GENL_ID_CTRL);
|
||||
mnl_attr_put_str_null(nlh, CTRL_ATTR_FAMILY_NAME, argv[1]);
|
||||
|
||||
nl = mnl_socket_open(NETLINK_GENERIC);
|
||||
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);
|
||||
}
|
||||
|
||||
if (mnl_socket_sendto(nl, nlh, mnl_nlmsg_get_len(nlh)) < 0) {
|
||||
perror("mnl_socket_send");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
|
||||
while (ret > 0) {
|
||||
ret = mnl_cb_run(buf, ret, seq, data_cb, NULL);
|
||||
if (ret <= 0)
|
||||
break;
|
||||
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
|
||||
}
|
||||
if (ret == -1) {
|
||||
perror("error");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
mnl_socket_close(nl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
84
examples/rtnl-link-dump.c
Normal file
84
examples/rtnl-link-dump.c
Normal file
@ -0,0 +1,84 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <libmnl/libmnl.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/if_link.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
|
||||
static int data_cb(const struct nlmsghdr *nlh, void *data)
|
||||
{
|
||||
struct nlattr *tb[IFLA_MAX+1];
|
||||
struct ifinfomsg *ifm = mnl_nlmsg_get_data(nlh);
|
||||
int len = mnl_nlmsg_get_len(nlh);
|
||||
struct nlattr *attr;
|
||||
|
||||
printf("index=%d type=%d flags=%d family=%d ",
|
||||
ifm->ifi_index, ifm->ifi_type,
|
||||
ifm->ifi_flags, ifm->ifi_family);
|
||||
|
||||
if (ifm->ifi_flags & IFF_RUNNING)
|
||||
printf("[RUNNING] ");
|
||||
else
|
||||
printf("[NOT RUNNING] ");
|
||||
|
||||
mnl_attr_parse_at_offset(nlh, sizeof(*ifm), tb, IFLA_MAX);
|
||||
if (tb[IFLA_MTU]) {
|
||||
printf("mtu=%d ", mnl_attr_get_u32(tb[IFLA_MTU]));
|
||||
}
|
||||
if (tb[IFLA_IFNAME]) {
|
||||
printf("name=%s", mnl_attr_get_str(tb[IFLA_IFNAME]));
|
||||
}
|
||||
printf("\n");
|
||||
return MNL_CB_OK;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
struct mnl_socket *nl;
|
||||
char buf[getpagesize()];
|
||||
struct nlmsghdr *nlh;
|
||||
struct rtgenmsg *rt;
|
||||
int ret;
|
||||
unsigned int seq;
|
||||
|
||||
nlh = mnl_nlmsg_put_header(buf);
|
||||
nlh->nlmsg_type = RTM_GETLINK;
|
||||
nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
|
||||
nlh->nlmsg_seq = seq = time(NULL);
|
||||
rt = mnl_nlmsg_put_extra_header(nlh, sizeof(struct rtgenmsg));
|
||||
rt->rtgen_family = AF_PACKET;
|
||||
|
||||
nl = mnl_socket_open(NETLINK_ROUTE);
|
||||
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);
|
||||
}
|
||||
|
||||
if (mnl_socket_sendto(nl, nlh, mnl_nlmsg_get_len(nlh)) < 0) {
|
||||
perror("mnl_socket_send");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
|
||||
while (ret > 0) {
|
||||
ret = mnl_cb_run(buf, ret, seq, data_cb, NULL);
|
||||
if (ret <= MNL_CB_STOP)
|
||||
break;
|
||||
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
|
||||
}
|
||||
if (ret == -1) {
|
||||
perror("error");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
mnl_socket_close(nl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
70
examples/rtnl-link-event.c
Normal file
70
examples/rtnl-link-event.c
Normal file
@ -0,0 +1,70 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <libmnl/libmnl.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/if_link.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
|
||||
static int data_cb(const struct nlmsghdr *nlh, void *data)
|
||||
{
|
||||
struct nlattr *tb[IFLA_MAX+1];
|
||||
struct ifinfomsg *ifm = mnl_nlmsg_get_data(nlh);
|
||||
int len = mnl_nlmsg_get_len(nlh);
|
||||
struct nlattr *attr;
|
||||
|
||||
printf("index=%d type=%d flags=%d family=%d ",
|
||||
ifm->ifi_index, ifm->ifi_type,
|
||||
ifm->ifi_flags, ifm->ifi_family);
|
||||
|
||||
if (ifm->ifi_flags & IFF_RUNNING)
|
||||
printf("[RUNNING] ");
|
||||
else
|
||||
printf("[NOT RUNNING] ");
|
||||
|
||||
mnl_attr_parse_at_offset(nlh, sizeof(*ifm), tb, IFLA_MAX);
|
||||
if (tb[IFLA_MTU]) {
|
||||
printf("mtu=%d ", mnl_attr_get_u32(tb[IFLA_MTU]));
|
||||
}
|
||||
if (tb[IFLA_IFNAME]) {
|
||||
printf("name=%s", mnl_attr_get_str(tb[IFLA_IFNAME]));
|
||||
}
|
||||
printf("\n");
|
||||
return MNL_CB_OK;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
struct mnl_socket *nl;
|
||||
char buf[getpagesize()];
|
||||
struct nlmsghdr *nlh = (struct nlmsghdr *) buf;
|
||||
int ret;
|
||||
|
||||
nl = mnl_socket_open(NETLINK_ROUTE);
|
||||
if (nl == NULL) {
|
||||
perror("mnl_socket_open");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (mnl_socket_bind(nl, RTMGRP_LINK, MNL_SOCKET_AUTOPID) < 0) {
|
||||
perror("mnl_socket_bind");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
|
||||
while (ret > 0) {
|
||||
ret = mnl_cb_run(buf, ret, 0, data_cb, NULL);
|
||||
if (ret <= 0)
|
||||
break;
|
||||
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
|
||||
}
|
||||
if (ret == -1) {
|
||||
perror("error");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
mnl_socket_close(nl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
76
examples/rtnl-link-set.c
Normal file
76
examples/rtnl-link-set.c
Normal file
@ -0,0 +1,76 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <libmnl/libmnl.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/if_link.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct mnl_socket *nl;
|
||||
char buf[getpagesize()];
|
||||
struct nlmsghdr *nlh;
|
||||
struct ifinfomsg *ifm;
|
||||
int ret;
|
||||
unsigned int seq, oper;
|
||||
|
||||
if (argc != 3) {
|
||||
printf("Usage: %s [ifname] [up|down]\n", argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (strncasecmp(argv[2], "up") == 0)
|
||||
oper = IF_OPER_UP;
|
||||
else if (strncasecmp(argv[2], "down") == 0)
|
||||
oper = IF_OPER_DOWN;
|
||||
else {
|
||||
fprintf(stderr, "%s is not `up' nor `down'\n", argv[2]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
nlh = mnl_nlmsg_put_header(buf);
|
||||
nlh->nlmsg_type = RTM_SETLINK;
|
||||
nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
|
||||
nlh->nlmsg_seq = seq = time(NULL);
|
||||
ifm = mnl_nlmsg_put_extra_header(nlh, sizeof(*ifm));
|
||||
ifm->ifi_family = AF_PACKET;
|
||||
|
||||
mnl_attr_put_u8(nlh, IFLA_OPERSTATE, oper);
|
||||
mnl_attr_put_str(nlh, IFLA_IFNAME, argv[1]);
|
||||
|
||||
nl = mnl_socket_open(NETLINK_ROUTE);
|
||||
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);
|
||||
}
|
||||
|
||||
mnl_nlmsg_print(nlh);
|
||||
|
||||
if (mnl_socket_sendto(nl, nlh, mnl_nlmsg_get_len(nlh)) < 0) {
|
||||
perror("mnl_socket_send");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
|
||||
if (ret == -1) {
|
||||
perror("read");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
ret = mnl_cb_run(buf, ret, seq, NULL, NULL);
|
||||
if (ret == -1){
|
||||
perror("callback");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
mnl_socket_close(nl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
192
examples/rtnl-route-dump.c
Normal file
192
examples/rtnl-route-dump.c
Normal file
@ -0,0 +1,192 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <libmnl/libmnl.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/if_link.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
|
||||
static void attributes_show_ipv4(struct nlattr *tb[])
|
||||
{
|
||||
if (tb[RTA_TABLE]) {
|
||||
printf("table=%u ", mnl_attr_get_u32(tb[RTA_TABLE]));
|
||||
}
|
||||
if (tb[RTA_DST]) {
|
||||
printf("dst=%s ", inet_ntoa(mnl_attr_get_u32(tb[RTA_DST])));
|
||||
}
|
||||
if (tb[RTA_SRC]) {
|
||||
printf("src=%s ", inet_ntoa(mnl_attr_get_u32(tb[RTA_SRC])));
|
||||
}
|
||||
if (tb[RTA_OIF]) {
|
||||
printf("oif=%u ", mnl_attr_get_u32(tb[RTA_OIF]));
|
||||
}
|
||||
if (tb[RTA_FLOW]) {
|
||||
printf("flow=%u ", mnl_attr_get_u32(tb[RTA_FLOW]));
|
||||
}
|
||||
if (tb[RTA_PREFSRC]) {
|
||||
printf("prefsrc=%s ",
|
||||
inet_ntoa(mnl_attr_get_u32(tb[RTA_PREFSRC])));
|
||||
}
|
||||
if (tb[RTA_GATEWAY]) {
|
||||
printf("gw=%s ", inet_ntoa(mnl_attr_get_u32(tb[RTA_GATEWAY])));
|
||||
}
|
||||
if (tb[RTA_METRICS]) {
|
||||
int i;
|
||||
struct nlattr *tbx[RTAX_MAX+1] = {};
|
||||
|
||||
mnl_attr_parse_nested(tb[RTA_METRICS], tbx, RTAX_MAX);
|
||||
|
||||
for (i=0; i<RTAX_MAX; i++) {
|
||||
if (tbx[i]) {
|
||||
printf("metrics[%d]=%u ",
|
||||
mnl_attr_get_u32(tbx[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static int data_cb(const struct nlmsghdr *nlh, void *data)
|
||||
{
|
||||
/* parse() ya está inicializando este array, qué hacer ? */
|
||||
struct nlattr *tb[RTA_MAX+1] = {};
|
||||
struct rtmsg *rm = mnl_nlmsg_get_data(nlh);
|
||||
int len = mnl_nlmsg_get_len(nlh);
|
||||
struct nlattr *attr;
|
||||
|
||||
/* protocol family = AF_INET | AF_INET6 */
|
||||
printf("family=%u ", rm->rtm_family);
|
||||
|
||||
/* destination CIDR, eg. 24 or 32 for IPv4 */
|
||||
printf("dst_len=%u ", rm->rtm_dst_len);
|
||||
|
||||
/* source CIDR */
|
||||
printf("src_len=%u ", rm->rtm_src_len);
|
||||
|
||||
/* type of service (TOS), eg. 0 */
|
||||
printf("tos=%u ", rm->rtm_tos);
|
||||
|
||||
/* table id:
|
||||
* RT_TABLE_UNSPEC = 0
|
||||
*
|
||||
* ... user defined values ...
|
||||
*
|
||||
* RT_TABLE_COMPAT = 252
|
||||
* RT_TABLE_DEFAULT = 253
|
||||
* RT_TABLE_MAIN = 254
|
||||
* RT_TABLE_LOCAL = 255
|
||||
* RT_TABLE_MAX = 0xFFFFFFFF
|
||||
*
|
||||
* Synonimous attribute: RTA_TABLE.
|
||||
*/
|
||||
printf("table=%u ", rm->rtm_table);
|
||||
|
||||
/* type:
|
||||
* RTN_UNSPEC = 0
|
||||
* RTN_UNICAST = 1
|
||||
* RTN_LOCAL = 2
|
||||
* RTN_BROADCAST = 3
|
||||
* RTN_ANYCAST = 4
|
||||
* RTN_MULTICAST = 5
|
||||
* RTN_BLACKHOLE = 6
|
||||
* RTN_UNREACHABLE = 7
|
||||
* RTN_PROHIBIT = 8
|
||||
* RTN_THROW = 9
|
||||
* RTN_NAT = 10
|
||||
* RTN_XRESOLVE = 11
|
||||
* __RTN_MAX = 12
|
||||
*/
|
||||
printf("type=%u ", rm->rtm_type);
|
||||
|
||||
/* scope:
|
||||
* RT_SCOPE_UNIVERSE = 0 : everywhere in the universe
|
||||
*
|
||||
* ... user defined values ...
|
||||
*
|
||||
* RT_SCOPE_SITE = 200
|
||||
* RT_SCOPE_LINK = 253 : destination attached to link
|
||||
* RT_SCOPE_HOST = 254 : local address
|
||||
* RT_SCOPE_NOWHERE = 255 : not existing destination
|
||||
*/
|
||||
printf("scope=%u ", rm->rtm_scope);
|
||||
|
||||
/* protocol:
|
||||
* RTPROT_UNSPEC = 0
|
||||
* RTPROT_REDIRECT = 1
|
||||
* RTPROT_KERNEL = 2 : route installed by kernel
|
||||
* RTPROT_BOOT = 3 : route installed during boot
|
||||
* RTPROT_STATIC = 4 : route installed by administrator
|
||||
*
|
||||
* Values >= RTPROT_STATIC are not interpreted by kernel, they are
|
||||
* just user-defined.
|
||||
*/
|
||||
printf("proto=%u ", rm->rtm_protocol);
|
||||
|
||||
/* flags:
|
||||
* RTM_F_NOTIFY = 0x100: notify user of route change
|
||||
* RTM_F_CLONED = 0x200: this route is cloned
|
||||
* RTM_F_EQUALIZE = 0x400: Multipath equalizer: NI
|
||||
* RTM_F_PREFIX = 0x800: Prefix addresses
|
||||
*/
|
||||
printf("flags=%x\n", rm->rtm_flags);
|
||||
|
||||
mnl_attr_parse_at_offset(nlh, sizeof(*rm), tb, RTA_MAX);
|
||||
|
||||
switch(rm->rtm_family) {
|
||||
case AF_INET:
|
||||
attributes_show_ipv4(tb);
|
||||
break;
|
||||
}
|
||||
|
||||
return MNL_CB_OK;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
struct mnl_socket *nl;
|
||||
char buf[getpagesize()];
|
||||
struct nlmsghdr *nlh;
|
||||
struct rtmsg *rtm;
|
||||
int ret;
|
||||
unsigned int seq;
|
||||
|
||||
nlh = mnl_nlmsg_put_header(buf);
|
||||
nlh->nlmsg_type = RTM_GETROUTE;
|
||||
nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
|
||||
nlh->nlmsg_seq = seq = time(NULL);
|
||||
rtm = mnl_nlmsg_put_extra_header(nlh, sizeof(struct rtmsg));
|
||||
rtm->rtm_family = AF_INET;
|
||||
|
||||
nl = mnl_socket_open(NETLINK_ROUTE);
|
||||
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);
|
||||
}
|
||||
|
||||
if (mnl_socket_sendto(nl, nlh, mnl_nlmsg_get_len(nlh)) < 0) {
|
||||
perror("mnl_socket_send");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
|
||||
while (ret > 0) {
|
||||
ret = mnl_cb_run(buf, ret, 0, data_cb, NULL);
|
||||
if (ret <= MNL_CB_STOP)
|
||||
break;
|
||||
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
|
||||
}
|
||||
if (ret == -1) {
|
||||
perror("error");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
mnl_socket_close(nl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
1
include/Makefile.am
Normal file
1
include/Makefile.am
Normal file
@ -0,0 +1 @@
|
||||
SUBDIRS = libmnl
|
||||
1
include/libmnl/Makefile.am
Normal file
1
include/libmnl/Makefile.am
Normal file
@ -0,0 +1 @@
|
||||
pkginclude_HEADERS = libmnl.h
|
||||
120
include/libmnl/libmnl.h
Normal file
120
include/libmnl/libmnl.h
Normal file
@ -0,0 +1,120 @@
|
||||
#ifndef _LIBMNL_H_
|
||||
#define _LIBMNL_H_
|
||||
|
||||
#include <sys/socket.h> /* for sa_family_t */
|
||||
#include <linux/netlink.h>
|
||||
|
||||
/*
|
||||
* generic netlink socket API
|
||||
*/
|
||||
|
||||
#define MNL_SOCKET_AUTOPID 0
|
||||
|
||||
struct mnl_socket;
|
||||
|
||||
extern struct mnl_socket *mnl_socket_open(int type);
|
||||
extern int mnl_socket_bind(struct mnl_socket *nl, int groups, int 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 int mnl_socket_sendto(struct mnl_socket *nl, const void *req, int siz);
|
||||
extern int mnl_socket_sendmsg(struct mnl_socket *nl, struct msghdr *msg, int flags);
|
||||
extern int mnl_socket_recvfrom(struct mnl_socket *nl, void *buf, int siz);
|
||||
extern int mnl_socket_recvmsg(const struct mnl_socket *nl, struct msghdr *msg, int flags);
|
||||
extern int mnl_socket_setsockopt(struct mnl_socket *nl, int type, void *buf, socklen_t len);
|
||||
extern int mnl_socket_getsockopt(struct mnl_socket *nl, int type, void *buf, socklen_t *len);
|
||||
|
||||
/*
|
||||
* generic netlink message API
|
||||
*/
|
||||
|
||||
#define MNL_ALIGNTO 4
|
||||
#define MNL_NLMSG_HDRLEN mnl_align(sizeof(struct nlmsghdr))
|
||||
|
||||
extern int mnl_align(int len);
|
||||
extern size_t mnl_nlmsg_size(int len);
|
||||
extern size_t mnl_nlmsg_total_size(int len);
|
||||
extern size_t mnl_nlmsg_payload_size(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, int size);
|
||||
|
||||
/* Netlink message iterators */
|
||||
extern int 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 int mnl_nlmsg_seq_ok(const struct nlmsghdr *nlh, unsigned int seq);
|
||||
|
||||
/* Netlink header getters */
|
||||
extern u_int16_t mnl_nlmsg_get_len(const struct nlmsghdr *nlh);
|
||||
extern void *mnl_nlmsg_get_data(const struct nlmsghdr *nlh);
|
||||
extern void *mnl_nlmsg_get_data_offset(const struct nlmsghdr *nlh, int offset);
|
||||
extern void *mnl_nlmsg_get_tail(const struct nlmsghdr *nlh);
|
||||
|
||||
/* Netlink dump message */
|
||||
extern void mnl_nlmsg_print(const struct nlmsghdr *nlh);
|
||||
|
||||
/*
|
||||
* generic netlink attributes API
|
||||
*/
|
||||
#define MNL_ATTR_HDRLEN mnl_align(sizeof(struct nlattr))
|
||||
|
||||
/* TLV attribute getters */
|
||||
extern u_int16_t mnl_attr_get_type(const struct nlattr *attr);
|
||||
extern u_int16_t mnl_attr_get_len(const struct nlattr *attr);
|
||||
extern u_int16_t mnl_attr_get_payload_len(const struct nlattr *attr);
|
||||
extern void *mnl_attr_get_data(const struct nlattr *attr);
|
||||
extern u_int8_t mnl_attr_get_u8(const struct nlattr *attr);
|
||||
extern u_int16_t mnl_attr_get_u16(const struct nlattr *attr);
|
||||
extern u_int32_t mnl_attr_get_u32(const struct nlattr *attr);
|
||||
extern u_int64_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, int type, size_t len, const void *data);
|
||||
extern void mnl_attr_put_u8(struct nlmsghdr *nlh, int type, u_int8_t data);
|
||||
extern void mnl_attr_put_u16(struct nlmsghdr *nlh, int type, u_int16_t data);
|
||||
extern void mnl_attr_put_u32(struct nlmsghdr *nlh, int type, u_int32_t data);
|
||||
extern void mnl_attr_put_u64(struct nlmsghdr *nlh, int type, u_int64_t data);
|
||||
extern void mnl_attr_put_str(struct nlmsghdr *nlh, int type, const void *data);
|
||||
extern void mnl_attr_put_str_null(struct nlmsghdr *nlh, int type, const void *data);
|
||||
|
||||
/* TLV attribute parsers */
|
||||
extern int mnl_attr_parse(const struct nlmsghdr *nlh, struct nlattr *tb[], int max);
|
||||
extern int mnl_attr_parse_at_offset(const struct nlmsghdr *nlh, int offset, struct nlattr *tb[], int max);
|
||||
extern int mnl_attr_parse_nested(const struct nlattr *attr, struct nlattr *tb[], int max);
|
||||
extern int mnl_attr_ok(const struct nlattr *attr, int len);
|
||||
extern struct nlattr *mnl_attr_next(const struct nlattr *attr, int *len);
|
||||
|
||||
#define mnl_attr_for_each_nested(pos, head, len) \
|
||||
for (pos = mnl_attr_get_data(head), len = mnl_attr_get_len(head); \
|
||||
mnl_attr_ok(pos, len); \
|
||||
pos = mnl_attr_next(pos, &(len)))
|
||||
|
||||
/*
|
||||
* 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 char *buf, int numbytes, unsigned int seq,
|
||||
mnl_cb_t cb_data, void *data);
|
||||
|
||||
extern int mnl_cb_run2(const char *buf, int numbytes, unsigned int seq,
|
||||
mnl_cb_t cb_data, void *data,
|
||||
mnl_cb_t *cb_ctl_array, int cb_ctl_array_len);
|
||||
|
||||
/*
|
||||
* other declarations
|
||||
*/
|
||||
|
||||
#ifndef SOL_NETLINK
|
||||
#define SOL_NETLINK 270
|
||||
#endif
|
||||
|
||||
#endif
|
||||
15
libmnl.pc.in
Normal file
15
libmnl.pc.in
Normal file
@ -0,0 +1,15 @@
|
||||
# libmnl pkg-config file
|
||||
|
||||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
libdir=@libdir@
|
||||
includedir=@includedir@
|
||||
|
||||
Name: libmnl
|
||||
Description: Minimalistic Netlink communication library
|
||||
URL: http://netfilter.org/projects/libmnl/
|
||||
Version: @VERSION@
|
||||
Requires:
|
||||
Conflicts:
|
||||
Libs: -L${libdir} -lmnl
|
||||
Cflags: -I${includedir}
|
||||
9
src/Makefile.am
Normal file
9
src/Makefile.am
Normal file
@ -0,0 +1,9 @@
|
||||
include $(top_srcdir)/Make_global.am
|
||||
|
||||
AM_CFLAGS=-fPIC -Wall
|
||||
LIBS=
|
||||
|
||||
lib_LTLIBRARIES = libmnl.la
|
||||
|
||||
libmnl_la_LDFLAGS = -Wc,-nostartfiles -version-info $(LIBVERSION)
|
||||
libmnl_la_SOURCES = socket.c callback.c msg.c attr.c
|
||||
212
src/attr.c
Normal file
212
src/attr.c
Normal file
@ -0,0 +1,212 @@
|
||||
/*
|
||||
* (C) 2008-2010 by Pablo Neira Ayuso <pablo@netfilter.org>
|
||||
*
|
||||
* This software may be used and distributed according to the terms
|
||||
* of the GNU General Public License, incorporated herein by reference.
|
||||
*/
|
||||
|
||||
#include <libmnl/libmnl.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* Netlink attribute:
|
||||
*
|
||||
* |<-- 2 bytes -->|<-- 2 bytes -->|<-- variable -->|
|
||||
* -------------------------------------------------
|
||||
* | length | type | value |
|
||||
* -------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* mnl_attr_get_type - get the attribute type of a netlink message
|
||||
*
|
||||
* This function returns the attribute type.
|
||||
*/
|
||||
u_int16_t mnl_attr_get_type(const struct nlattr *attr)
|
||||
{
|
||||
return attr->nla_type & NLA_TYPE_MASK;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_attr_get_len - get the attribute length
|
||||
*
|
||||
* This function returns the attribute length.
|
||||
*/
|
||||
u_int16_t mnl_attr_get_len(const struct nlattr *attr)
|
||||
{
|
||||
return attr->nla_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_attr_get_payload_len - get the attribute payload length
|
||||
*
|
||||
* This function returns the attribute payload length.
|
||||
*/
|
||||
u_int16_t mnl_attr_get_payload_len(const struct nlattr *attr)
|
||||
{
|
||||
return attr->nla_len - MNL_ATTR_HDRLEN;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_attr_get_data - get pointer to the attribute payload
|
||||
*
|
||||
* This function return a pointer to the attribute payload
|
||||
*/
|
||||
void *mnl_attr_get_data(const struct nlattr *attr)
|
||||
{
|
||||
return (void *)attr + MNL_ATTR_HDRLEN;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_attr_ok - check a there is room for an attribute
|
||||
* @nlh: attribute that we want to check
|
||||
* @len: remaining bytes in a buffer that contains the attribute
|
||||
*
|
||||
* This function is used to check that a buffer that contains an attribute
|
||||
* has enough room for the attribute that it stores, ie. this function can
|
||||
* be used to verify that an attribute is not malformed nor truncated.
|
||||
*/
|
||||
int mnl_attr_ok(const struct nlattr *attr, int len)
|
||||
{
|
||||
return len >= sizeof(struct nlattr) &&
|
||||
attr->nla_len >= sizeof(struct nlattr) &&
|
||||
attr->nla_len <= len;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_attr_next - get the next attribute in the payload of a netlink message
|
||||
* @attr: pointer to the current attribute
|
||||
* @len: pointer to the current remaining bytes in the buffer
|
||||
*
|
||||
* This function returns a pointer to the next attribute that is in the
|
||||
* payload of a netlink message.
|
||||
*/
|
||||
struct nlattr *mnl_attr_next(const struct nlattr *attr, int *len)
|
||||
{
|
||||
*len -= mnl_align(attr->nla_len);
|
||||
return (struct nlattr *)((void *)attr + mnl_align(attr->nla_len));
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_attr_parse - returns an array with the attributes in a message
|
||||
* @tb: array of pointers to the attribute found
|
||||
* @tb_size: size of the attribute array
|
||||
* @attr: first attribute in the stream
|
||||
* @len: remaining bytes in the buffer that contain attributes
|
||||
*
|
||||
* This function returns a table of pointers to the attributes that has been
|
||||
* found in a netlink payload. This function return 0 on sucess, and >0 to
|
||||
* indicate the number of bytes the remaining bytes.
|
||||
*/
|
||||
int mnl_attr_parse_at_offset(const struct nlmsghdr *nlh, int offset,
|
||||
struct nlattr *tb[], int max)
|
||||
{
|
||||
struct nlattr *attr = mnl_nlmsg_get_data_offset(nlh, offset);
|
||||
int len = mnl_nlmsg_get_len(nlh);
|
||||
|
||||
memset(tb, 0, sizeof(struct nlattr *) * (max + 1));
|
||||
|
||||
while (mnl_attr_ok(attr, len)) {
|
||||
if (mnl_attr_get_type(attr) <= max)
|
||||
tb[mnl_attr_get_type(attr)] = attr;
|
||||
attr = mnl_attr_next(attr, &len);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
int mnl_attr_parse(const struct nlmsghdr *nlh, struct nlattr *tb[], int max)
|
||||
{
|
||||
return mnl_attr_parse_at_offset(nlh, 0, tb, max);
|
||||
}
|
||||
|
||||
int mnl_attr_parse_nested(const struct nlattr *nested,
|
||||
struct nlattr *tb[], int max)
|
||||
{
|
||||
struct nlattr *attr = mnl_attr_get_data(nested);
|
||||
int len = mnl_attr_get_payload_len(nested);
|
||||
|
||||
memset(tb, 0, sizeof(struct nlattr *) * (max + 1));
|
||||
|
||||
while (mnl_attr_ok(attr, len)) {
|
||||
if (mnl_attr_get_type(attr) <= max)
|
||||
tb[mnl_attr_get_type(attr)] = attr;
|
||||
attr = mnl_attr_next(attr, &len);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
u_int8_t mnl_attr_get_u8(const struct nlattr *attr)
|
||||
{
|
||||
return *((u_int8_t *)mnl_attr_get_data(attr));
|
||||
}
|
||||
|
||||
u_int16_t mnl_attr_get_u16(const struct nlattr *attr)
|
||||
{
|
||||
return *((u_int16_t *)mnl_attr_get_data(attr));
|
||||
}
|
||||
|
||||
u_int32_t mnl_attr_get_u32(const struct nlattr *attr)
|
||||
{
|
||||
return *((u_int32_t *)mnl_attr_get_data(attr));
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_attr_get_u64 - returns an arra
|
||||
* @attr: netlink attribute
|
||||
*
|
||||
* This function returns the payload of a 64-bits attribute. This function
|
||||
* is align-safe since accessing 64-bits Netlink attributes is a common
|
||||
* source of alignment issues.
|
||||
*/
|
||||
u_int64_t mnl_attr_get_u64(const struct nlattr *attr)
|
||||
{
|
||||
u_int64_t tmp;
|
||||
memcpy(&tmp, mnl_attr_get_data(attr), sizeof(tmp));
|
||||
return tmp;
|
||||
}
|
||||
|
||||
const char *mnl_attr_get_str(const struct nlattr *attr)
|
||||
{
|
||||
return (const char *)mnl_attr_get_data(attr);
|
||||
}
|
||||
|
||||
void mnl_attr_put(struct nlmsghdr *nlh, int type, size_t len, const void *data)
|
||||
{
|
||||
struct nlattr *attr = mnl_nlmsg_get_tail(nlh);
|
||||
int payload_len = mnl_align(sizeof(struct nlattr)) + len;
|
||||
|
||||
attr->nla_type = type;
|
||||
attr->nla_len = payload_len;
|
||||
memcpy(mnl_attr_get_data(attr), data, len);
|
||||
nlh->nlmsg_len += mnl_align(payload_len);
|
||||
}
|
||||
|
||||
void mnl_attr_put_u8(struct nlmsghdr *nlh, int type, u_int8_t data)
|
||||
{
|
||||
mnl_attr_put(nlh, type, sizeof(u_int8_t), &data);
|
||||
}
|
||||
|
||||
void mnl_attr_put_u16(struct nlmsghdr *nlh, int type, u_int16_t data)
|
||||
{
|
||||
mnl_attr_put(nlh, type, sizeof(u_int16_t), &data);
|
||||
}
|
||||
|
||||
void mnl_attr_put_u32(struct nlmsghdr *nlh, int type, u_int32_t data)
|
||||
{
|
||||
mnl_attr_put(nlh, type, sizeof(u_int32_t), &data);
|
||||
}
|
||||
|
||||
void mnl_attr_put_u64(struct nlmsghdr *nlh, int type, u_int64_t data)
|
||||
{
|
||||
mnl_attr_put(nlh, type, sizeof(u_int64_t), &data);
|
||||
}
|
||||
|
||||
void mnl_attr_put_str(struct nlmsghdr *nlh, int type, const void *data)
|
||||
{
|
||||
mnl_attr_put(nlh, type, strlen(data), data);
|
||||
}
|
||||
|
||||
void mnl_attr_put_str_null(struct nlmsghdr *nlh, int type, const void *data)
|
||||
{
|
||||
mnl_attr_put(nlh, type, strlen(data)+1, data);
|
||||
}
|
||||
119
src/callback.c
Normal file
119
src/callback.c
Normal file
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* (C) 2008-2010 by Pablo Neira Ayuso <pablo@netfilter.org>
|
||||
*
|
||||
* This software may be used and distributed according to the terms
|
||||
* of the GNU General Public License, incorporated herein by reference.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <libmnl/libmnl.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_data(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 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,
|
||||
};
|
||||
|
||||
/**
|
||||
* mnl_cb_run2 - callback runqueue for netlink messages
|
||||
* @buf: buffer that contains the netlink messages
|
||||
* @numbytes: number of bytes stored in the buffer
|
||||
* @seq: sequence number that we expect to receive (use zero to skip)
|
||||
* @cb_data: callback handler for data messages
|
||||
* @data: pointer to data that will be passed to the data callback handler
|
||||
* @cb_ctl_array: array of custom callback handlers from control messages
|
||||
* @cb_ctl_array_len: length of the array 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.
|
||||
*
|
||||
* This function returns -1 in case of error, 0 if we have received a
|
||||
* NLMSG_DONE message or the callback has explicitly returned MNL_CB_STOP.
|
||||
*/
|
||||
int mnl_cb_run2(const char *buf, int numbytes, unsigned int seq,
|
||||
mnl_cb_t cb_data, void *data,
|
||||
mnl_cb_t *cb_ctl_array, int cb_ctl_array_len)
|
||||
{
|
||||
int ret = MNL_CB_OK;
|
||||
struct nlmsghdr *nlh = (struct nlmsghdr *)buf;
|
||||
|
||||
while (mnl_nlmsg_ok(nlh, numbytes)) {
|
||||
/* perform sequence tracking */
|
||||
if (!mnl_nlmsg_seq_ok(nlh, seq)) {
|
||||
errno = EILSEQ;
|
||||
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, &numbytes);
|
||||
}
|
||||
out:
|
||||
return ret <= MNL_CB_ERROR ? -1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_cb_run - callback runqueue for netlink messages (simplified version)
|
||||
* @buf: buffer that contains the netlink messages
|
||||
* @numbytes: number of bytes stored in the buffer
|
||||
* @seq: sequence number that we expect to receive (use zero to skip)
|
||||
* @cb_data: callback handler for data messages
|
||||
* @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.
|
||||
*
|
||||
* This function returns -1 in case of error, 0 if we have received a
|
||||
* NLMSG_DONE message or the callback has explicitly returned MNL_CB_STOP.
|
||||
*/
|
||||
|
||||
int mnl_cb_run(const char *buf, int numbytes, unsigned int seq,
|
||||
mnl_cb_t cb_data, void *data)
|
||||
{
|
||||
return mnl_cb_run2(buf, numbytes, seq, cb_data, data, NULL, 0);
|
||||
}
|
||||
213
src/msg.c
Normal file
213
src/msg.c
Normal file
@ -0,0 +1,213 @@
|
||||
/*
|
||||
* (C) 2008-2010 by Pablo Neira Ayuso <pablo@netfilter.org>
|
||||
*
|
||||
* This software may be used and distributed according to the terms
|
||||
* of the GNU General Public License, incorporated herein by reference.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <libmnl/libmnl.h>
|
||||
|
||||
/**
|
||||
* mnl_align - align a value to four bytes
|
||||
* @value: the value that we want to get aligned
|
||||
*
|
||||
* This function returns the value passed aligned to four bytes. Netlink
|
||||
* message headers and its attributes are always aligned to four bytes.
|
||||
*/
|
||||
int mnl_align(int value)
|
||||
{
|
||||
return (value + MNL_ALIGNTO - 1) & ~(MNL_ALIGNTO - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_size - get size of the netlink messages (without alignment)
|
||||
* @len: length of the netlink message
|
||||
*
|
||||
* This function returns the size of a netlink message (header plus payload)
|
||||
* without alignment.
|
||||
*/
|
||||
size_t mnl_nlmsg_size(int len)
|
||||
{
|
||||
return len + mnl_align(MNL_NLMSG_HDRLEN);
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_aligned_size - get size of the netlink messages (with alignment)
|
||||
* @len: length of the netlink message
|
||||
*
|
||||
* This function returns the size of a netlink message (header plus payload)
|
||||
* with alignment.
|
||||
*/
|
||||
size_t mnl_nlmsg_aligned_size(int len)
|
||||
{
|
||||
return mnl_align(mnl_nlmsg_size(len));
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_payload_size - get the size of the payload
|
||||
* @nlh: pointer to the header of the netlink message
|
||||
*
|
||||
* This function returns the size of the netlink payload
|
||||
*/
|
||||
size_t mnl_nlmsg_payload_size(const struct nlmsghdr *nlh)
|
||||
{
|
||||
return nlh->nlmsg_len - MNL_NLMSG_HDRLEN;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_put_header - prepare room for Netlink header
|
||||
* @buf: memory already allocated to store the Netlink message
|
||||
*
|
||||
* This function sets to zero the room that is required to put a Netlink
|
||||
* header in the memory buffer passed as parameter. This function also
|
||||
* initializes the nlmsg_len field. 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_put_extra_header - prepare room for an extra header
|
||||
* @nlh: pointer to Netlink header
|
||||
* @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. This function returns a pointer to the extra
|
||||
* header.
|
||||
*/
|
||||
void *mnl_nlmsg_put_extra_header(struct nlmsghdr *nlh, int size)
|
||||
{
|
||||
char *ptr = (char *)nlh + nlh->nlmsg_len;
|
||||
nlh->nlmsg_len += mnl_align(size);
|
||||
memset(ptr, 0, size);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_get_len - get the length field from the netlink message
|
||||
* @nlh: pointer to a netlink header
|
||||
*
|
||||
* This function returns the length of the netlink message by return the field
|
||||
* nlmsg_len of the message.
|
||||
*/
|
||||
u_int16_t mnl_nlmsg_get_len(const struct nlmsghdr *nlh)
|
||||
{
|
||||
return nlh->nlmsg_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_get_data - get a pointer to the payload of the netlink message
|
||||
* @nlh: pointer to a netlink header
|
||||
*
|
||||
* This function returns a pointer to the payload of the netlink message.
|
||||
*/
|
||||
void *mnl_nlmsg_get_data(const struct nlmsghdr *nlh)
|
||||
{
|
||||
return (void *)nlh + MNL_NLMSG_HDRLEN;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_get_data_offset - get a pointer to the payload of the message
|
||||
* @nlh: pointer to a netlink header
|
||||
* @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_data_offset(const struct nlmsghdr *nlh, int offset)
|
||||
{
|
||||
return (void *)nlh + MNL_NLMSG_HDRLEN + mnl_align(offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_ok - check a there is room for netlink message
|
||||
* @nlh: netlink message that we want to check
|
||||
* @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.
|
||||
*/
|
||||
int mnl_nlmsg_ok(const struct nlmsghdr *nlh, int len)
|
||||
{
|
||||
return len >= sizeof(struct nlmsghdr) &&
|
||||
nlh->nlmsg_len >= sizeof(struct nlmsghdr) &&
|
||||
nlh->nlmsg_len <= len;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_next - get the next netlink message in a multipart message
|
||||
* @nlh: current netlink message that we are handling
|
||||
* @len: pointer to the current remaining bytes in the buffer
|
||||
*
|
||||
* This function returns a pointer to the next netlink message that is part
|
||||
* of a multi-part netlink message. Netlink can batches messages into a buffer
|
||||
* so that the receiver has to iterate over the whole set of netlink
|
||||
* messages.
|
||||
*/
|
||||
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));
|
||||
}
|
||||
|
||||
void *mnl_nlmsg_get_tail(const struct nlmsghdr *nlh)
|
||||
{
|
||||
return (struct nlmsghdr *)((void *)nlh + mnl_align(nlh->nlmsg_len));
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_seq_ok - perform sequence tracking
|
||||
* @nlh: current netlink message that we are handling
|
||||
* @seq: last sequence number used to send a message
|
||||
*
|
||||
* This functions returns 1 if the sequence tracking is fulfilled, otherwise
|
||||
* 0 is returned. If seq is 0, then the sequence tracking is skipped. This
|
||||
* value is generally used by the kernel for asynchronous notifications,
|
||||
* for that reason, this library consider that it is reserved.
|
||||
*/
|
||||
int mnl_nlmsg_seq_ok(const struct nlmsghdr *nlh, unsigned int seq)
|
||||
{
|
||||
return seq ? nlh->nlmsg_seq == seq : 1;
|
||||
}
|
||||
|
||||
/* XXX: rework this, please */
|
||||
void mnl_nlmsg_print(const struct nlmsghdr *nlh)
|
||||
{
|
||||
int i;
|
||||
|
||||
printf("========= netlink header ==========\n");
|
||||
printf("length(32 bits)=%.08u\n", nlh->nlmsg_len);
|
||||
printf("type(16 bits)=%.04u flags(16 bits)=%.04x\n",
|
||||
nlh->nlmsg_type, nlh->nlmsg_flags);
|
||||
printf("sequence number(32 bits)=%.08x\n", nlh->nlmsg_seq);
|
||||
printf("port ID(32 bits)=%.08u\n", nlh->nlmsg_pid);
|
||||
printf("===================================\n");
|
||||
|
||||
for (i=sizeof(struct nlmsghdr); i<mnl_nlmsg_get_len(nlh); i+=4) {
|
||||
char *b = (char *) nlh;
|
||||
|
||||
printf("(%.3d) %.2x %.2x %.2x %.2x | ", i,
|
||||
0xff & b[i], 0xff & b[i+1],
|
||||
0xff & b[i+2], 0xff & b[i+3]);
|
||||
|
||||
printf("%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);
|
||||
}
|
||||
}
|
||||
255
src/socket.c
Normal file
255
src/socket.c
Normal file
@ -0,0 +1,255 @@
|
||||
/*
|
||||
* (C) 2008-2010 by Pablo Neira Ayuso <pablo@netfilter.org>
|
||||
*
|
||||
* This software may be used and distributed according to the terms
|
||||
* of the GNU General Public License, incorporated herein by reference.
|
||||
*/
|
||||
|
||||
#include <libmnl/libmnl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
|
||||
struct mnl_socket {
|
||||
int fd;
|
||||
struct sockaddr_nl addr;
|
||||
};
|
||||
|
||||
/**
|
||||
* mnl_socket_get_fd - obtain file descriptor from netlink socket
|
||||
* @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;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_socket_get_portid - obtain Netlink PortID from netlink socket
|
||||
* @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.
|
||||
*/
|
||||
unsigned int mnl_socket_get_portid(const struct mnl_socket *nl)
|
||||
{
|
||||
return nl->addr.nl_pid;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_socket_open - open a netlink socket
|
||||
* @unit: the netlink socket unit (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 unit)
|
||||
{
|
||||
struct mnl_socket *nl;
|
||||
|
||||
nl = calloc(sizeof(struct mnl_socket), 1);
|
||||
if (nl == NULL)
|
||||
return NULL;
|
||||
|
||||
nl->fd = socket(AF_NETLINK, SOCK_RAW, unit);
|
||||
if (nl->fd == -1)
|
||||
return NULL;
|
||||
|
||||
return nl;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_socket_bind - bind netlink socket
|
||||
* @nl: netlink socket obtained via mnl_socket_open()
|
||||
* @groups: the group of message you're interested in
|
||||
* @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.
|
||||
*/
|
||||
int mnl_socket_bind(struct mnl_socket *nl, int groups, int pid)
|
||||
{
|
||||
int ret;
|
||||
socklen_t addr_len;
|
||||
|
||||
nl->addr.nl_family = AF_NETLINK;
|
||||
nl->addr.nl_groups = groups;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_socket_sendto - send a netlink message of a certain size
|
||||
* @nl: netlink socket obtained via mnl_socket_open()
|
||||
* @buf: buffer containing the netlink message to be sent
|
||||
* @bufsiz: 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.
|
||||
*/
|
||||
int mnl_socket_sendto(struct mnl_socket *nl, const void *buf, int len)
|
||||
{
|
||||
struct sockaddr_nl snl = {
|
||||
.nl_family = AF_NETLINK
|
||||
};
|
||||
return sendto(nl->fd, buf, len, 0,
|
||||
(struct sockaddr *) &snl, sizeof(snl));
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_socket_sendmsg - send a netlink message of a certain size
|
||||
* @nl: netlink socket obtained via mnl_socket_open()
|
||||
* @msg: pointer to struct msghdr (must be initialized appropriately)
|
||||
* @flags: flags passed to sendmsg()
|
||||
*
|
||||
* On error, it returns -1 and errno is appropriately set. Otherwise, it
|
||||
* returns the number of bytes sent.
|
||||
*/
|
||||
int
|
||||
mnl_socket_sendmsg(struct mnl_socket *nl, struct msghdr *msg, int flags)
|
||||
{
|
||||
return sendmsg(nl->fd, msg, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_socket_recvfrom - receive a netlink message
|
||||
* @nl: netlink socket obtained via mnl_socket_open()
|
||||
* @buf: buffer that you want to use to store the netlink message
|
||||
* @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 small so you have received a truncated message. Make
|
||||
* sure your program set a buffer big enough to store the netlink message.
|
||||
*/
|
||||
int mnl_socket_recvfrom(struct mnl_socket *nl, void *buf, int bufsiz)
|
||||
{
|
||||
int ret;
|
||||
struct sockaddr_nl addr;
|
||||
struct iovec iov = {
|
||||
.iov_base = buf,
|
||||
.iov_len = bufsiz,
|
||||
};
|
||||
struct msghdr msg = {
|
||||
.msg_name = (void *)&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;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_socket_recvmsg- receive a netlink message
|
||||
* @nl: netlink socket obtained via mnl_socket_open()
|
||||
* @msg: pointer to struct msghdr (must be initialized appropriately)
|
||||
* @flags: flags passed to recvmsg()
|
||||
*
|
||||
* On error, this function returns -1 and errno is appropriately set.
|
||||
* On sucess, this function returns the number of bytes received.
|
||||
*/
|
||||
int
|
||||
mnl_socket_recvmsg(const struct mnl_socket *nl, struct msghdr *msg, int flags)
|
||||
{
|
||||
return recvmsg(nl->fd, msg, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_socket_close - close a given netlink socket
|
||||
* @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);
|
||||
nl = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_socket_setsockopt - set Netlink socket option
|
||||
* @nl: netlink socket obtained via mnl_socket_open()
|
||||
* @type: type of Netlink socket options
|
||||
* @buf: the buffer that contains the data about this option
|
||||
* @len: the size of the buffer passed
|
||||
*
|
||||
* This function allows you to set some Netlink socket option. As of writing
|
||||
* this, 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(struct mnl_socket *nl, int type,
|
||||
void *buf, socklen_t len)
|
||||
{
|
||||
return setsockopt(nl->fd, SOL_NETLINK, type, buf, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_socket_getsockopt - get a Netlink socket option
|
||||
* @nl: netlink socket obtained via mnl_socket_open()
|
||||
* @type: type of Netlink socket options
|
||||
* @buf: pointer to the buffer to store the value of this option
|
||||
* @len: size of the information written in the buffer
|
||||
*
|
||||
* On error, this function returns -1 and errno is appropriately set.
|
||||
*/
|
||||
int mnl_socket_getsockopt(struct mnl_socket *nl, int type,
|
||||
void *buf, socklen_t *len)
|
||||
{
|
||||
return getsockopt(nl->fd, SOL_NETLINK, type, buf, len);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user