df5d8e7c2aefa44ab5479327f63d326a80294d6a
[project/luci.git] / contrib / fwd / src / fwd_addr.c
1 /*
2  * fwd - OpenWrt firewall daemon - rtnetlink communication
3  *
4  *   Copyright (C) 2009 Jo-Philipp Wich <xm@subsignal.org>
5  *
6  * The fwd program is free software: you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License version 2
8  * as published by the Free Software Foundation.
9  *
10  * The fwd program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13  * See the GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with the fwd program. If not, see http://www.gnu.org/licenses/.
17  */
18
19
20 #include "fwd.h"
21 #include "fwd_addr.h"
22
23 struct fwd_addr_list * fwd_get_addrs(int fd, int family)
24 {
25         struct {
26                   struct nlmsghdr n;
27                   struct ifaddrmsg r;
28         } req;
29
30         int offlen;
31         int rtattrlen;
32         int dump_done;
33         char buf[16384];
34
35         struct rtattr *rta;
36         struct rtattr *rtatp;
37         struct nlmsghdr *nlmp;
38         struct ifaddrmsg *rtmp;
39
40         struct fwd_addr_list *head, *entry;
41
42         /* Build request */
43         memset(&req, 0, sizeof(req));
44         req.n.nlmsg_len   = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
45         req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
46         req.n.nlmsg_type  = RTM_GETADDR;
47         req.r.ifa_family  = family;
48
49         rta = (struct rtattr *)(((char *)&req) + NLMSG_ALIGN(req.n.nlmsg_len));
50         rta->rta_len = RTA_LENGTH(family == AF_INET ? 4 : 16);
51
52         head = entry = NULL;
53
54         /* Send request */
55         if( send(fd, &req, sizeof(req), 0) <= 0 )
56                 goto error;
57
58         /* Receive responses */
59         for( dump_done = 0; !dump_done; )
60         {
61                 if( (offlen = recv(fd, buf, sizeof(buf), 0)) <= 0 )
62                         goto error;
63
64                 /* Parse message */
65                 for(nlmp = (struct nlmsghdr *)buf; offlen > sizeof(*nlmp);)
66                 {
67                         /* Dump finished? */
68                         if( nlmp->nlmsg_type == NLMSG_DONE )
69                         {
70                                 dump_done = 1;
71                                 break;
72                         }
73
74                         int len = nlmp->nlmsg_len;
75                         int req_len = len - sizeof(*nlmp);
76
77                         if( req_len<0 || len>offlen )
78                                 goto error;
79
80                         if( !NLMSG_OK(nlmp, offlen) )
81                                 goto error;
82
83                         rtmp  = (struct ifaddrmsg *) NLMSG_DATA(nlmp);
84                         rtatp = (struct rtattr *) IFA_RTA(rtmp);
85
86                         if( !(entry = fwd_alloc_ptr(struct fwd_addr_list)) )
87                                 goto error;
88
89                         entry->index = rtmp->ifa_index;
90                         if_indextoname(rtmp->ifa_index, (char *)&entry->ifname);
91
92                         rtattrlen = IFA_PAYLOAD(nlmp);
93
94                         for( ; RTA_OK(rtatp, rtattrlen); rtatp = RTA_NEXT(rtatp, rtattrlen) )
95                         {
96                                 if( rtatp->rta_type == IFA_ADDRESS )
97                                 {
98                                         memcpy(&entry->ipaddr, (char *) RTA_DATA(rtatp), rtatp->rta_len);
99                                         entry->prefix = rtmp->ifa_prefixlen;
100                                         entry->family = family;
101                                 }
102                                 else if( rtatp->rta_type == IFA_LABEL)
103                                 {
104                                         memcpy(&entry->label, (char *) RTA_DATA(rtatp), rtatp->rta_len);
105                                 }
106                         }
107
108                         entry->next = head;
109                         head = entry;
110
111                         offlen -= NLMSG_ALIGN(len);
112                         nlmp = (struct nlmsghdr*)((char*)nlmp + NLMSG_ALIGN(len));
113                 }
114         }
115
116         return head;
117
118
119         error:
120
121         fwd_free_addrs(head);
122         head = entry = NULL;
123
124         return NULL;
125 }
126
127 void fwd_free_addrs(struct fwd_addr_list *head)
128 {
129         struct fwd_addr_list *entry = head;
130
131         while( entry != NULL )
132         {
133                 head = entry->next;
134                 free(entry);
135                 entry = head;
136         }
137
138         head = entry = NULL;
139 }
140
141 struct fwd_addr_list * fwd_append_addrs(struct fwd_addr_list *head, struct fwd_addr_list *add)
142 {
143         struct fwd_addr_list *entry = head;
144
145         while( entry->next != NULL )
146                 entry = entry->next;
147
148         return (entry->next = add);
149 }
150