/* * fwd - OpenWrt firewall daemon - rtnetlink communication * * Copyright (C) 2009 Jo-Philipp Wich * * 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" #include "fwd_utils.h" struct fwd_addr * 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 *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)) ) 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.addr, (char *) RTA_DATA(rtatp), rtatp->rta_len); entry->ipaddr.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; } struct fwd_cidr * fwd_lookup_addr(struct fwd_addr *head, const char *ifname) { struct fwd_addr *entry; for( entry = head; entry; entry = entry->next ) if( !strncmp(entry->ifname, ifname, IFNAMSIZ) ) return &entry->ipaddr; return NULL; } void fwd_free_addrs(struct fwd_addr *head) { struct fwd_addr *entry = head; while( entry != NULL ) { head = entry->next; free(entry); entry = head; } head = entry = NULL; } struct fwd_addr * fwd_append_addrs(struct fwd_addr *head, struct fwd_addr *add) { struct fwd_addr *entry = head; while( entry->next != NULL ) entry = entry->next; return (entry->next = add); }