summaryrefslogtreecommitdiffhomepage
path: root/contrib/fwd/src/fwd_addr.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/fwd/src/fwd_addr.c')
-rw-r--r--contrib/fwd/src/fwd_addr.c150
1 files changed, 150 insertions, 0 deletions
diff --git a/contrib/fwd/src/fwd_addr.c b/contrib/fwd/src/fwd_addr.c
new file mode 100644
index 0000000000..df5d8e7c2a
--- /dev/null
+++ b/contrib/fwd/src/fwd_addr.c
@@ -0,0 +1,150 @@
+/*
+ * fwd - OpenWrt firewall daemon - rtnetlink communication
+ *
+ * Copyright (C) 2009 Jo-Philipp Wich <xm@subsignal.org>
+ *
+ * The fwd program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * The fwd program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with the fwd program. If not, see http://www.gnu.org/licenses/.
+ */
+
+
+#include "fwd.h"
+#include "fwd_addr.h"
+
+struct fwd_addr_list * fwd_get_addrs(int fd, int family)
+{
+ struct {
+ struct nlmsghdr n;
+ struct ifaddrmsg r;
+ } req;
+
+ int offlen;
+ int rtattrlen;
+ int dump_done;
+ char buf[16384];
+
+ struct rtattr *rta;
+ struct rtattr *rtatp;
+ struct nlmsghdr *nlmp;
+ struct ifaddrmsg *rtmp;
+
+ struct fwd_addr_list *head, *entry;
+
+ /* Build request */
+ memset(&req, 0, sizeof(req));
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
+ req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
+ req.n.nlmsg_type = RTM_GETADDR;
+ req.r.ifa_family = family;
+
+ rta = (struct rtattr *)(((char *)&req) + NLMSG_ALIGN(req.n.nlmsg_len));
+ rta->rta_len = RTA_LENGTH(family == AF_INET ? 4 : 16);
+
+ head = entry = NULL;
+
+ /* Send request */
+ if( send(fd, &req, sizeof(req), 0) <= 0 )
+ goto error;
+
+ /* Receive responses */
+ for( dump_done = 0; !dump_done; )
+ {
+ if( (offlen = recv(fd, buf, sizeof(buf), 0)) <= 0 )
+ goto error;
+
+ /* Parse message */
+ for(nlmp = (struct nlmsghdr *)buf; offlen > sizeof(*nlmp);)
+ {
+ /* Dump finished? */
+ if( nlmp->nlmsg_type == NLMSG_DONE )
+ {
+ dump_done = 1;
+ break;
+ }
+
+ int len = nlmp->nlmsg_len;
+ int req_len = len - sizeof(*nlmp);
+
+ if( req_len<0 || len>offlen )
+ goto error;
+
+ if( !NLMSG_OK(nlmp, offlen) )
+ goto error;
+
+ rtmp = (struct ifaddrmsg *) NLMSG_DATA(nlmp);
+ rtatp = (struct rtattr *) IFA_RTA(rtmp);
+
+ if( !(entry = fwd_alloc_ptr(struct fwd_addr_list)) )
+ goto error;
+
+ entry->index = rtmp->ifa_index;
+ if_indextoname(rtmp->ifa_index, (char *)&entry->ifname);
+
+ rtattrlen = IFA_PAYLOAD(nlmp);
+
+ for( ; RTA_OK(rtatp, rtattrlen); rtatp = RTA_NEXT(rtatp, rtattrlen) )
+ {
+ if( rtatp->rta_type == IFA_ADDRESS )
+ {
+ memcpy(&entry->ipaddr, (char *) RTA_DATA(rtatp), rtatp->rta_len);
+ entry->prefix = rtmp->ifa_prefixlen;
+ entry->family = family;
+ }
+ else if( rtatp->rta_type == IFA_LABEL)
+ {
+ memcpy(&entry->label, (char *) RTA_DATA(rtatp), rtatp->rta_len);
+ }
+ }
+
+ entry->next = head;
+ head = entry;
+
+ offlen -= NLMSG_ALIGN(len);
+ nlmp = (struct nlmsghdr*)((char*)nlmp + NLMSG_ALIGN(len));
+ }
+ }
+
+ return head;
+
+
+ error:
+
+ fwd_free_addrs(head);
+ head = entry = NULL;
+
+ return NULL;
+}
+
+void fwd_free_addrs(struct fwd_addr_list *head)
+{
+ struct fwd_addr_list *entry = head;
+
+ while( entry != NULL )
+ {
+ head = entry->next;
+ free(entry);
+ entry = head;
+ }
+
+ head = entry = NULL;
+}
+
+struct fwd_addr_list * fwd_append_addrs(struct fwd_addr_list *head, struct fwd_addr_list *add)
+{
+ struct fwd_addr_list *entry = head;
+
+ while( entry->next != NULL )
+ entry = entry->next;
+
+ return (entry->next = add);
+}
+