Skip to content

Instantly share code, notes, and snippets.

@netskink

netskink/stats.c Secret

Last active February 15, 2017 21:13
Show Gist options
  • Save netskink/6f712a9a0a2beccc8504fdf625825762 to your computer and use it in GitHub Desktop.
Save netskink/6f712a9a0a2beccc8504fdf625825762 to your computer and use it in GitHub Desktop.
trying to get this netlink version 3 library code to work
/* ipchange.c
*
* Netlink based IP monitor on specific interface.
* Executes command on new IPv4 address.
*
* Sebastian Kricner
* tuxwave.net
* June 2014
*
*/
#include <libnl3/netlink/netlink.h>
#include <libnl3/netlink/socket.h>
#include <libnl3/netlink/msg.h>
#include <libnl3/netlink/errno.h>
#include <libnl3/netlink/route/link.h>
#include <libnl3/netlink/route/addr.h>
#include <libnl3/netlink/route/qdisc.h>
#include <net/if.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <syslog.h>
#include <sys/types.h>
#include <string.h>
/*
gcc ipchange.c -o ipchange $(pkg-config --cflags --libs libnl-3.0 libnl-route-3.0)
*/
static char *interface;
struct rtnl_link* m_link;
static void parse_notification(struct nl_object *obj, void *arg) {
struct rtnl_addr *addr;
char s_addr[128];
int flags;
char s_flags[128];
unsigned int ifindex;
char s_ifname[16];
char pchBuf[80];
addr = (struct rtnl_addr *) obj;
flags = rtnl_addr_get_flags(addr);
ifindex = rtnl_addr_get_ifindex(addr);
if_indextoname(ifindex, s_ifname);
nl_addr2str(rtnl_addr_get_local(addr), s_addr, sizeof(s_addr));
rtnl_addr_flags2str(flags, s_flags, sizeof(s_flags));
setenv("S_INTERFACE", s_ifname, 0);
setenv("S_ADDRESS", s_addr, 0);
setenv("S_FLAGS", s_flags, 0);
if(strcmp(s_ifname, interface) == 0) {
sprintf(pchBuf,"%s %s","echo",s_ifname);
system(pchBuf);
syslog(LOG_NOTICE, "command executed");
}
return;
}
static int process_notification(struct nl_msg *msg, void *arg) {
struct nlmsghdr *msghdr = nlmsg_hdr(msg);
// These def/enums are defined in linux/rtnetlink.h
if(msghdr->nlmsg_type == RTM_NEWADDR) {
// hits when a second address is added to the interface
nl_msg_parse(msg, &parse_notification, arg);
} else if(msghdr->nlmsg_type == RTM_DELADDR) {
// hits when ip addr is removed.
printf("addr removed\n");
} else if(msghdr->nlmsg_type == RTM_NEWLINK) {
// If in the add membership group, I RTNLGRP_LINK,
// hits when ethernet cable is inserted/removed
printf("network cable inserted/removed\n");
} else if(msghdr->nlmsg_type == RTM_DELLINK) {
// this never hits
printf("network cable removed\n");
} else {
// this never hits
printf("some other msg\n");
}
return NL_OK;
}
static int start_monitor(char *interface) {
struct nl_sock *sk;
int err;
// This entire code seems to be based upon the example given
// in section 3.3.1 Multicast Example
// https://www.infradead.org/~tgr/libnl/doc/core.html#core_sk_multicast
// https://www.infradead.org/~tgr/libnl/doc/core.html#core_sockets
// allocate a new socket
sk = nl_socket_alloc();
if(!sk) {
fprintf(stderr, "Could not allocate netlink socket.\n");
exit(ENOMEM);
}
// https://www.infradead.org/~tgr/libnl/doc/core.html#core_sk_seq_num
// Notifications do not use sequence numbers, disable sequence number checking
nl_socket_disable_seq_check(sk);
// Define a callback function, which will be called for each notification received
nl_socket_modify_cb(sk, NL_CB_VALID, NL_CB_CUSTOM, process_notification, NULL);
// Connect to a routing netlink protocol
if(err = nl_connect(sk, NETLINK_ROUTE)) {
fprintf(stderr, "netlink error: %s\n", nl_geterror(err));
nl_socket_free(sk);
sk = NULL;
exit(err);
}
// Subscribe to link notifications group.
// The example code use RTNLGRP_LINK.
//nl_socket_add_memberships(sk, RTNLGRP_IPV4_IFADDR|RTNLGRP_LINK, 0);
// to add multiple groups, seperate them with , instead of |
// These groups are defined in linux/rtnetlink.h
//nl_socket_add_memberships(sk, RTNLGRP_IPV4_IFADDR, RTNLGRP_LINK, RTNLGRP_NOTIFY,0);
nl_socket_add_memberships(sk, RTNLGRP_IPV4_IFADDR, RTNLGRP_LINK, RTNLGRP_NOTIFY,RTNLGRP_IPV4_RULE,0);
while (1) {
nl_recvmsgs_default(sk);
// Everytime I get a message, I also get a callback
//printf("recv msg\n");
}
// Never reached
return 0;
}
int main(int argc, char **argv, char **envp) {
int err;
struct nl_cache *cache;
struct rtnl_link *link;
struct nl_addr *addr;
struct addrinfo *addr_info;
char *name;
uint64_t count;
struct rtnl_qdisc *qdisc;
struct nl_sock *sk;
interface = "enp6s0";
sk = nl_socket_alloc();
if (!sk) {
fprintf(stderr, "Could not allocate netlink socket.\n");
exit(ENOMEM);
}
// https://www.infradead.org/~tgr/libnl/doc/core.html#core_sk_seq_num
// Notifications do not use sequence numbers, disable sequence number checking
nl_socket_disable_seq_check(sk);
// Connect to a routing netlink protocol
//if(err = nl_connect(sk, NETLINK_SOCK_DIAG)) {
if(err = nl_connect(sk, NETLINK_ROUTE)) {
fprintf(stderr, "netlink error: %s\n", nl_geterror(err));
nl_socket_free(sk);
sk = NULL;
exit(err);
}
err = rtnl_link_alloc_cache(sk, AF_UNSPEC, &cache);
if (0 != err) {
/* error */
printf("rtnl_link_alloc_cache failed with %d: %s\n", err, nl_geterror(err));
return(EXIT_FAILURE);
}
// returns a link object or NULL is no match found
link = rtnl_link_get_by_name(cache, interface);
if (NULL == link) {
/* link does not exist */
printf("rtnl_link_get_by_name for interface %s does not exist\n",interface);
return(EXIT_FAILURE);
}
/* do something with link */
addr = rtnl_link_get_addr(link);
if (NULL == addr) {
/* failure to get mac address */
printf("rtnl_link_get_addr failed\n");
return(EXIT_FAILURE);
}
name = rtnl_link_get_name(link);
printf("name is %s\n",name);
// allocation of qdisc object
qdisc = rtnl_qdisc_alloc();
// Get some counts
count = rtnl_tc_get_stat(TC_CAST(qdisc), RTNL_TC_PACKETS);
printf("Total # of packets transmitted is %ld\n",count); // is zero.
// how to specify this is the link for my desired network interface?
err = nl_addr_info(addr, &addr_info);
if (0 != err) {
/* failure to get mac address */
//printf("nl_addr_info failed. %s\n",strerror(errno));
printf("nl_addr_info failed with %d: %s\n", err, nl_geterror(err));
return(EXIT_FAILURE);
}
// free the qdisc object
rtnl_qdisc_put(qdisc);
// put releases the reference to the link struct
rtnl_link_put(link);
// i'm guessing this releases the reference to the cache struct
nl_cache_put(cache);
//start_monitor(interface);
return(EXIT_SUCCESS);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment