From a0092d15955f23b0f32506a5666db365dfa56510 Mon Sep 17 00:00:00 2001 From: "/C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=pablo/emailAddress=pablo@netfilter.org" Date: Fri, 26 Jan 2007 02:35:30 +0000 Subject: - Initial commit of index2interface API (Eric Leblond), still work to do - added a test file to utils/iftest.c --- src/Makefile.am | 4 +- src/iftable.c | 204 +++++++++++++++++++++++++++++++++++++++----------------- src/rtnl.c | 114 +++++++++++++++++-------------- src/rtnl.h | 22 ++++-- 4 files changed, 224 insertions(+), 120 deletions(-) (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 3e25c76..def8175 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -8,4 +8,6 @@ lib_LTLIBRARIES = libnfnetlink.la libnfnetlink_la_LDFLAGS = -Wc,-nostartfiles \ -version-info $(LIBVERSION) -libnfnetlink_la_SOURCES = libnfnetlink.c +libnfnetlink_la_SOURCES = libnfnetlink.c iftable.c rtnl.c + +noinst_HEADERS = iftable.h rtnl.c diff --git a/src/iftable.c b/src/iftable.c index 9c28a36..e97d2ba 100644 --- a/src/iftable.c +++ b/src/iftable.c @@ -19,6 +19,7 @@ #include +#include #include "rtnl.h" #define iftb_log(x, ...) @@ -34,27 +35,12 @@ struct ifindex_map { char name[16]; }; -static struct ifindex_map *ifindex_map[16]; - -/* iftable_dump - Dump the interface table to a given file stream - * @outfd: file stream to which table should be dumped - */ -int iftable_dump(FILE *outfd) -{ - int i; - - for (i = 0; i < 16; i++) { - struct ifindex_map *im; - for (im = ifindex_map[i]; im; im = im->next) { - fprintf(outfd, "%u %s", im->index, im->name); - if (!(im->flags & IFF_UP)) - fputs(" DOWN", outfd); - fputc('\n', outfd); - } - } - fflush(outfd); - return 0; -} +struct nlif_handle { + struct ifindex_map *ifindex_map[16]; + struct rtnl_handle *rtnl_handle; + struct rtnl_handler *ifadd_handler; + struct rtnl_handler *ifdel_handler; +}; /* iftable_add - Add/Update an entry to/in the interface table * @n: netlink message header of a RTM_NEWLINK message @@ -69,6 +55,7 @@ int iftable_add(struct nlmsghdr *n, void *arg) struct ifinfomsg *ifi_msg = NLMSG_DATA(n); struct ifindex_map *im, **imp; struct rtattr *cb[IFLA_MAX+1]; + struct nlif_handle *nlif_handle = (struct nlif_handle *)arg; if (n->nlmsg_type != RTM_NEWLINK) return -1; @@ -87,7 +74,8 @@ int iftable_add(struct nlmsghdr *n, void *arg) } hash = ifi_msg->ifi_index&0xF; - for (imp = &ifindex_map[hash]; (im=*imp)!=NULL; imp = &im->next) { + for (imp = &((nlif_handle->ifindex_map)[hash]); + (im=*imp)!=NULL; imp = &im->next) { if (im->index == ifi_msg->ifi_index) { iftb_log(LOG_DEBUG, "updating iftable (ifindex=%u)", im->index); @@ -136,7 +124,9 @@ int iftable_del(struct nlmsghdr *n, void *arg) { struct ifinfomsg *ifi_msg = NLMSG_DATA(n); struct rtattr *cb[IFLA_MAX+1]; - struct ifindex_map *im; + struct nlif_handle *nlif_handle = (struct nlif_handle *)arg; + struct ifindex_map *im, *ima, **imp; + unsigned int hash; if (n->nlmsg_type != RTM_DELLINK) { iftb_log(LOG_ERROR, @@ -153,27 +143,53 @@ int iftable_del(struct nlmsghdr *n, void *arg) memset(&cb, 0, sizeof(cb)); rtnl_parse_rtattr(cb, IFLA_MAX, IFLA_RTA(ifi_msg), IFLA_PAYLOAD(n)); - /* FIXME */ + /* \todo Really suppress entry */ + hash = ifi_msg->ifi_index&0xF; + for (ima = NULL, imp = &((nlif_handle->ifindex_map)[hash]); + (im=*imp)!=NULL; imp = &im->next, ima=im) { + if (im->index == ifi_msg->ifi_index) { + iftb_log(LOG_DEBUG, + "deleting iftable (ifindex=%u)", im->index); + break; + } + } + + if (!im) + return 0; + + if (ima) + ima->next = *imp; + else + (nlif_handle->ifindex_map)[hash] = *imp; + free(im); return 1; } - -/* ifindex_2name - get the name for an ifindex - * @index: ifindex to be resolved + +/** Get the name for an ifindex * - * Return value: character string containing name of interface + * \param nlif_handle A pointer to a ::nlif_handle created + * \param index ifindex to be resolved + * \param name interface name, pass a buffer of IFNAMSIZ size + * \return -1 on error, 1 on success */ -char *ifindex_2name(unsigned int index) +int nlif_index2name(struct nlif_handle *nlif_handle, + unsigned int index, + char *name) { struct ifindex_map *im; - if (index == 0) - return "*"; - for (im = ifindex_map[index&0xF]; im; im = im->next) - if (im->index == index) - return im->name; + if (index == 0) { + strcpy(name, "*"); + return 1; + } + for (im = (nlif_handle->ifindex_map)[index&0xF]; im; im = im->next) + if (im->index == index) { + strcpy(name, im->name); + return 1; + } - return NULL; + return -1; } /* iftable_up - Determine whether a given interface is UP @@ -181,11 +197,11 @@ char *ifindex_2name(unsigned int index) * * Return value: -1 if interface unknown, 1 if interface up, 0 if not. */ -int iftable_up(unsigned int index) +int iftable_up(struct nlif_handle *nlif_handle, unsigned int index) { struct ifindex_map *im; - for (im = ifindex_map[index&0xF]; im; im = im->next) { + for (im = nlif_handle->ifindex_map[index&0xF]; im; im = im->next) { if (im->index == index) { if (im->flags & IFF_UP) return 1; @@ -196,34 +212,49 @@ int iftable_up(unsigned int index) return -1; } -static struct rtnl_handler handlers[] = { - { .nlmsg_type = RTM_NEWLINK, .handlefn = &iftable_add }, - { .nlmsg_type = RTM_DELLINK, .handlefn = &iftable_del }, -}; - -static int init_or_fini(int fini) +static struct nlif_handle *init_or_fini(struct nlif_handle *orig) { + struct nlif_handle *nlif_handle; int ret = 0; - if (fini) + if (orig) { + nlif_handle = orig; goto cleanup; + } + + + nlif_handle = calloc(1, sizeof(struct nlif_handle)); + if (!nlif_handle) + goto cleanup_none; - if (rtnl_handler_register(&handlers[0]) < 0) { + nlif_handle->ifadd_handler = calloc(1, sizeof(struct rtnl_handler)); + nlif_handle->ifadd_handler->nlmsg_type = RTM_NEWLINK; + nlif_handle->ifadd_handler->handlefn = &iftable_add; + nlif_handle->ifadd_handler->arg = nlif_handle; + nlif_handle->ifdel_handler = calloc(1, sizeof(struct rtnl_handler)); + nlif_handle->ifdel_handler->nlmsg_type = RTM_DELLINK; + nlif_handle->ifdel_handler->handlefn = &iftable_del; + nlif_handle->ifdel_handler->arg = nlif_handle; + + nlif_handle->rtnl_handle = rtnl_init(); + + if (! nlif_handle->rtnl_handle) + goto cleanup_none; + + if (rtnl_handler_register(nlif_handle->rtnl_handle, + nlif_handle->ifadd_handler) < 0) { ret = -1; goto cleanup_none; } - if (rtnl_handler_register(&handlers[1]) < 0) { + if (rtnl_handler_register(nlif_handle->rtnl_handle, + nlif_handle->ifdel_handler) < 0) { ret = -1; goto cleanup_0; } - if (rtnl_dump_type(RTM_GETLINK) < 0) { - ret = -1; - goto cleanup_1; - } - return 0; + return nlif_handle; #if 0 if (rtnl_wilddump_requet(rtnl_fd, AF_UNSPEC, RTM_GETLINK) < 0) { @@ -234,28 +265,77 @@ static int init_or_fini(int fini) #endif cleanup: - -cleanup_1: - rtnl_handler_unregister(&handlers[1]); + rtnl_handler_unregister(nlif_handle->rtnl_handle, + nlif_handle->ifadd_handler); + free(nlif_handle->ifadd_handler); cleanup_0: - rtnl_handler_unregister(&handlers[0]); + rtnl_handler_unregister(nlif_handle->rtnl_handle, + nlif_handle->ifdel_handler); + free(nlif_handle->ifdel_handler); + rtnl_fini(nlif_handle->rtnl_handle); + free(nlif_handle); + cleanup_none: - return ret; + return nlif_handle; } -/* iftable_init - Initialize interface table +/** Initialize interface table + * + * Initialize rtnl interface and interface table + * Call this before any nlif_* function + * + * \return file descriptor to netlink socket */ -int iftable_init(void) +struct nlif_handle *nlif_open(void) { iftb_log(LOG_DEBUG, "%s", __FUNCTION__); - return init_or_fini(0); + return init_or_fini(NULL); } -/* iftable_fini - Destructor of interface table +/** Destructor of interface table + * + * \param nlif_handle A pointer to a ::nlif_handle created + * via nlif_open() */ -void iftable_fini(void) +void nlif_close(struct nlif_handle *nlif_handle) { - init_or_fini(1); + init_or_fini(nlif_handle); } +/** Receive message from netlink and update interface table + * + * \param nlif_handle A pointer to a ::nlif_handle created + * \return 0 if OK + */ +int nlif_catch(struct nlif_handle *nlif_handle) +{ + if (nlif_handle && nlif_handle->rtnl_handle) + return rtnl_receive(nlif_handle->rtnl_handle); + else + return -1; +} +/** + * nlif_query - request a dump of interfaces available in the system + * @h: pointer to a valid nlif_handler + */ +int nlif_query(struct nlif_handle *h) +{ + if (rtnl_dump_type(h->rtnl_handle, RTM_GETLINK) < 0) + return -1; + + return nlif_catch(h); +} + +/** Returns socket descriptor for the netlink socket + * + * \param nlif_handle A pointer to a ::nlif_handle created + * \return The fd or -1 if there's an error + */ +int nlif_fd(struct nlif_handle *nlif_handle) +{ + if (nlif_handle && nlif_handle->rtnl_handle) + return nlif_handle->rtnl_handle->rtnl_fd; + else + return -1; +} diff --git a/src/rtnl.c b/src/rtnl.c index 50c3d42..be1e77e 100644 --- a/src/rtnl.c +++ b/src/rtnl.c @@ -1,6 +1,8 @@ /* rtnl - rtnetlink utility functions * * (C) 2004 by Astaro AG, written by Harald Welte + * + * Adapted to nfnetlink by Eric Leblond * * This software is free software and licensed under GNU GPLv2. * @@ -26,26 +28,22 @@ #define rtnl_log(x, ...) -static int rtnl_fd; -static int rtnl_seq = 0; -static int rtnl_dump; -static struct sockaddr_nl rtnl_local; - -static struct rtnl_handler *handlers = NULL; - -static inline struct rtnl_handler *find_handler(u_int16_t type) +static inline struct rtnl_handler * +find_handler(struct rtnl_handle *rtnl_handle, u_int16_t type) { struct rtnl_handler *h; - for (h = handlers; h; h = h->next) { + for (h = rtnl_handle->handlers; h; h = h->next) { if (h->nlmsg_type == type) return h; } return NULL; } -static int call_handler(u_int16_t type, struct nlmsghdr *hdr) +static int call_handler(struct rtnl_handle *rtnl_handle, + u_int16_t type, + struct nlmsghdr *hdr) { - struct rtnl_handler *h = find_handler(type); + struct rtnl_handler *h = find_handler(rtnl_handle, type); if (!h) { rtnl_log(LOG_DEBUG, "no registered handler for type %u", @@ -59,31 +57,33 @@ static int call_handler(u_int16_t type, struct nlmsghdr *hdr) /* rtnl_handler_register - register handler for given nlmsg type * @hdlr: handler structure */ -int rtnl_handler_register(struct rtnl_handler *hdlr) +int rtnl_handler_register(struct rtnl_handle *rtnl_handle, + struct rtnl_handler *hdlr) { rtnl_log(LOG_DEBUG, "registering handler for type %u", hdlr->nlmsg_type); - hdlr->next = handlers; - handlers = hdlr; + hdlr->next = rtnl_handle->handlers; + rtnl_handle->handlers = hdlr; return 1; } /* rtnl_handler_unregister - unregister handler for given nlmst type * @hdlr: handler structure */ -int rtnl_handler_unregister(struct rtnl_handler *hdlr) +int rtnl_handler_unregister(struct rtnl_handle *rtnl_handle, + struct rtnl_handler *hdlr) { struct rtnl_handler *h, *prev = NULL; rtnl_log(LOG_DEBUG, "unregistering handler for type %u", hdlr->nlmsg_type); - for (h = handlers; h; h = h->next) { + for (h = rtnl_handle->handlers; h; h = h->next) { if (h == hdlr) { if (prev) prev->next = h->next; else - handlers = h->next; + rtnl_handle->handlers = h->next; return 1; } prev = h; @@ -107,7 +107,7 @@ int rtnl_parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) /* rtnl_dump_type - ask rtnetlink to dump a specific table * @type: type of table to be dumped */ -int rtnl_dump_type(unsigned int type) +int rtnl_dump_type(struct rtnl_handle *rtnl_handle, unsigned int type) { struct { struct nlmsghdr nlh; @@ -123,15 +123,15 @@ int rtnl_dump_type(unsigned int type) req.nlh.nlmsg_type = type; req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST; req.nlh.nlmsg_pid = 0; - req.nlh.nlmsg_seq = rtnl_dump = ++rtnl_seq; + req.nlh.nlmsg_seq = rtnl_handle->rtnl_dump = ++(rtnl_handle->rtnl_seq); req.g.rtgen_family = AF_INET; - return sendto(rtnl_fd, (void*)&req, sizeof(req), 0, + return sendto(rtnl_handle->rtnl_fd, (void*)&req, sizeof(req), 0, (struct sockaddr*)&nladdr, sizeof(nladdr)); } /* rtnl_receive - receive netlink packets from rtnetlink socket */ -int rtnl_receive() +int rtnl_receive(struct rtnl_handle *rtnl_handle) { int status; char buf[8192]; @@ -146,7 +146,7 @@ int rtnl_receive() 0 }; - status = recvmsg(rtnl_fd, &msg, 0); + status = recvmsg(rtnl_handle->rtnl_fd, &msg, 0); if (status < 0) { if (errno == EINTR) return 0; @@ -184,7 +184,7 @@ int rtnl_receive() return -1; } - if (call_handler(h->nlmsg_type, h) == 0) + if (call_handler(rtnl_handle, h->nlmsg_type, h) == 0) rtnl_log(LOG_NOTICE, "unhandled nlmsg_type %u", h->nlmsg_type); h = NLMSG_NEXT(h, status); @@ -193,54 +193,68 @@ int rtnl_receive() } /* rtnl_init - constructor of rtnetlink module */ -int rtnl_init(void) +struct rtnl_handle *rtnl_init(void) { - int addr_len; + unsigned int addr_len; + struct rtnl_handle *rtnl_handle = calloc(1, sizeof(struct rtnl_handle)); + + if (! rtnl_handle) + return NULL; + + rtnl_handle->rtnl_seq = 0; + rtnl_handle->handlers = NULL; - rtnl_local.nl_pid = getpid(); - rtnl_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); - if (rtnl_fd < 0) { + rtnl_handle->rtnl_local.nl_pid = getpid(); + rtnl_handle->rtnl_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (rtnl_handle->rtnl_fd < 0) { rtnl_log(LOG_ERROR, "unable to create rtnetlink socket"); - return -1; + free(rtnl_handle); + return NULL; } - memset(&rtnl_local, 0, sizeof(rtnl_local)); - rtnl_local.nl_family = AF_NETLINK; - rtnl_local.nl_groups = RTMGRP_IPV4_ROUTE|RTMGRP_IPV4_IFADDR|RTMGRP_LINK; - - if (bind(rtnl_fd, (struct sockaddr *)&rtnl_local, sizeof(rtnl_local)) < 0) { + memset(&(rtnl_handle->rtnl_local), 0, sizeof(rtnl_handle->rtnl_local)); + rtnl_handle->rtnl_local.nl_family = AF_NETLINK; + rtnl_handle->rtnl_local.nl_groups = + RTMGRP_IPV4_ROUTE|RTMGRP_IPV4_IFADDR|RTMGRP_LINK; + if (bind(rtnl_handle->rtnl_fd, + (struct sockaddr *)&(rtnl_handle->rtnl_local), + sizeof(rtnl_handle->rtnl_local)) < 0) { rtnl_log(LOG_ERROR, "unable to bind rtnetlink socket"); - return -1; + free(rtnl_handle); + return NULL; } - addr_len = sizeof(rtnl_local); - if (getsockname(rtnl_fd, (struct sockaddr *)&rtnl_local, + addr_len = sizeof(rtnl_handle->rtnl_local); + if (getsockname(rtnl_handle->rtnl_fd, + (struct sockaddr *)&(rtnl_handle->rtnl_local), &addr_len) < 0) { rtnl_log(LOG_ERROR, "cannot gescockname(rtnl_socket)"); - return -1; + free(rtnl_handle); + return NULL; } - if (addr_len != sizeof(rtnl_local)) { + if (addr_len != sizeof(rtnl_handle->rtnl_local)) { rtnl_log(LOG_ERROR, "invalid address size %u", addr_len); - return -1; + free(rtnl_handle); + return NULL; } - if (rtnl_local.nl_family != AF_NETLINK) { - rtnl_log(LOG_ERROR, "invalid AF %u", rtnl_local.nl_family); - return -1; + if (rtnl_handle->rtnl_local.nl_family != AF_NETLINK) { + rtnl_log(LOG_ERROR, "invalid AF %u", + rtnl_handle->rtnl_local.nl_family); + free(rtnl_handle); + return NULL; } - rtnl_seq = time(NULL); + rtnl_handle->rtnl_seq = time(NULL); - return rtnl_fd; + return rtnl_handle; } /* rtnl_fini - destructor of rtnetlink module */ -void rtnl_fini(void) +void rtnl_fini(struct rtnl_handle *rtnl_handle) { - close(rtnl_fd); + close(rtnl_handle->rtnl_fd); + free(rtnl_handle); return; } - - - diff --git a/src/rtnl.h b/src/rtnl.h index 5eeb043..b6644e6 100644 --- a/src/rtnl.h +++ b/src/rtnl.h @@ -12,17 +12,25 @@ struct rtnl_handler { void *arg; }; +struct rtnl_handle { + int rtnl_fd; + int rtnl_seq; + int rtnl_dump; + struct sockaddr_nl rtnl_local; + struct rtnl_handler *handlers; +}; /* api for handler plugins */ -int rtnl_handler_register(struct rtnl_handler *hdlr); -int rtnl_handler_unregister(struct rtnl_handler *hdlr); +int rtnl_handler_register(struct rtnl_handle *rtnl_handle, + struct rtnl_handler *hdlr); +int rtnl_handler_unregister(struct rtnl_handle *rtnl_handle, + struct rtnl_handler *hdlr); int rtnl_parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len); -int rtnl_dump_type(unsigned int type); +int rtnl_dump_type(struct rtnl_handle *rtnl_handle, unsigned int type); /* api for core program */ -int rtnl_init(void); -void rtnl_fini(void); -int rtnl_receive(); - +struct rtnl_handle *rtnl_init(void); +void rtnl_fini(struct rtnl_handle *rtnl_handle); +int rtnl_receive(struct rtnl_handle *rtnl_handle); #endif -- cgit v1.2.3