blob: e80c2a33bc928900bd49e63b258c6218533d60d2 [file] [log] [blame]
Brian Waters13d96012017-12-08 16:53:31 -06001/*********************************************************************************************************
2* Software License Agreement (BSD License) *
3* Author: Sebastien Decugis <sdecugis@freediameter.net> *
4* *
5* Copyright (c) 2013, WIDE Project and NICT *
6* All rights reserved. *
7* *
8* Redistribution and use of this software in source and binary forms, with or without modification, are *
9* permitted provided that the following conditions are met: *
10* *
11* * Redistributions of source code must retain the above *
12* copyright notice, this list of conditions and the *
13* following disclaimer. *
14* *
15* * Redistributions in binary form must reproduce the above *
16* copyright notice, this list of conditions and the *
17* following disclaimer in the documentation and/or other *
18* materials provided with the distribution. *
19* *
20* * Neither the name of the WIDE Project or NICT nor the *
21* names of its contributors may be used to endorse or *
22* promote products derived from this software without *
23* specific prior written permission of WIDE Project and *
24* NICT. *
25* *
26* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
27* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
28* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
29* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
30* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
31* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
32* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
33* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
34*********************************************************************************************************/
35
36#include "fdcore-internal.h"
37
38
39/* Add an endpoint information in a list */
40int fd_ep_add_merge( struct fd_list * list, sSA * sa, socklen_t sl, uint32_t flags )
41{
42 struct fd_endpoint * ep;
43 struct fd_list * li;
44 union {
45 sSA * sa;
46 sSA4 *sin;
47 sSA6 *sin6;
48 } ptr;
49 in_port_t * port;
50 int cmp = -1;
51
52 TRACE_ENTRY("%p %p %u %x", list, sa, sl, flags);
53 CHECK_PARAMS( list && sa && (sl <= sizeof(sSS)) );
54
55 if (list->next == NULL) {
56 /* the list is not initialized yet, do it */
57 fd_list_init(list, NULL);
58 }
59
60 ptr.sa = sa;
61
62 /* Filter out a bunch of invalid addresses */
63 switch (sa->sa_family) {
64 case AF_INET:
65 if (! (flags & EP_ACCEPTALL)) {
66 if (IN_IS_ADDR_UNSPECIFIED(&ptr.sin->sin_addr)
67 || IN_IS_ADDR_LOOPBACK(&ptr.sin->sin_addr)
68 /* the next one filters both EXPERIMENTAL, BADCLASS and MULTICAST. */
69 || ((ntohl(ptr.sin->sin_addr.s_addr) & 0xe0000000) == 0xe0000000)
70 || (ptr.sin->sin_addr.s_addr == INADDR_BROADCAST)) {
71 LOG_A(" DEBUG:fd_ep_add_merge Address was ignored, not added.");
72 return 0;
73 }
74 }
75 port = &ptr.sin->sin_port;
76 break;
77
78 case AF_INET6:
79 if (! (flags & EP_ACCEPTALL)) {
80 if (IN6_IS_ADDR_UNSPECIFIED(&ptr.sin6->sin6_addr)
81 || IN6_IS_ADDR_LOOPBACK(&ptr.sin6->sin6_addr)
82 || IN6_IS_ADDR_MULTICAST(&ptr.sin6->sin6_addr)
83 || IN6_IS_ADDR_LINKLOCAL(&ptr.sin6->sin6_addr)
84 || IN6_IS_ADDR_SITELOCAL(&ptr.sin6->sin6_addr)) {
85 LOG_A(" DEBUG:fd_ep_add_merge Address was ignored, not added.");
86 return 0;
87 }
88 }
89 port = &ptr.sin6->sin6_port;
90 break;
91
92 default:
93 LOG_A(" DEBUG:fd_ep_add_merge Address family was unknown, not added.");
94 return 0;
95 }
96
97 /* remove the ACCEPTALL flag */
98 flags &= ~EP_ACCEPTALL;
99
100 /* Search place in the list */
101 for (li = list->next; li != list; li = li->next) {
102 ep = (struct fd_endpoint *)li;
103 in_port_t * ep_port;
104
105 /* First, compare the address family */
106 if (ep->sa.sa_family < sa->sa_family)
107 continue;
108 if (ep->sa.sa_family > sa->sa_family)
109 break;
110
111 /* Then compare the address field */
112 switch (sa->sa_family) {
113 case AF_INET:
114 cmp = memcmp(&ep->sin.sin_addr, &ptr.sin->sin_addr, sizeof(struct in_addr));
115 ep_port = &ep->sin.sin_port;
116 break;
117 case AF_INET6:
118 cmp = memcmp(&ep->sin6.sin6_addr, &ptr.sin6->sin6_addr, sizeof(struct in6_addr));
119 ep_port = &ep->sin6.sin6_port;
120 break;
121 default:
122 ASSERT( 0 ); /* we got a different value previously in this same function */
123 }
124 if (cmp < 0)
125 continue;
126 if (cmp > 0)
127 break;
128
129 /* Finally compare the port, only if not 0 */
130 if (*port == 0)
131 break;
132 if (*ep_port == 0) {
133 /* save the port information in the list, and break */
134 *ep_port = *port;
135 break;
136 }
137 if (*ep_port < *port) {
138 cmp = -1;
139 continue;
140 }
141 if (*ep_port > *port)
142 cmp = 1;
143 break;
144 }
145
146 if (cmp) {
147 /* new item to be added */
148 CHECK_MALLOC( ep = malloc(sizeof(struct fd_endpoint)) );
149 memset(ep, 0, sizeof(struct fd_endpoint));
150 fd_list_init(&ep->chain, NULL);
151 memcpy(&ep->ss, sa, sl);
152
153 /* Insert in the list */
154 fd_list_insert_before(li, &ep->chain);
155 }
156
157 /* Merge the flags */
158 ep->flags |= flags;
159
160 return 0;
161}
162
163/* Delete endpoints that do not have a matching flag from a list (0: delete all endpoints) */
164int fd_ep_filter( struct fd_list * list, uint32_t flags )
165{
166 struct fd_list * li;
167
168 TRACE_ENTRY("%p %x", list, flags);
169 CHECK_PARAMS(list);
170
171 for (li = list->next; li != list; li = li->next) {
172 struct fd_endpoint * ep = (struct fd_endpoint *)li;
173
174 if (! (ep->flags & flags)) {
175 li = li->prev;
176 fd_list_unlink(&ep->chain);
177 free(ep);
178 }
179 }
180
181 return 0;
182}
183
184/* Keep only endpoints of the same family as af */
185int fd_ep_filter_family( struct fd_list * list, int af )
186{
187 struct fd_list * li;
188
189 TRACE_ENTRY("%p %d", list, af);
190 CHECK_PARAMS(list);
191
192 for (li = list->next; li != list; li = li->next) {
193 struct fd_endpoint * ep = (struct fd_endpoint *)li;
194
195 if (ep->sa.sa_family != af) {
196 li = li->prev;
197 fd_list_unlink(&ep->chain);
198 free(ep);
199 }
200 }
201
202 return 0;
203}
204
205/* Reset the given flag(s) from all items in the list */
206int fd_ep_clearflags( struct fd_list * list, uint32_t flags )
207{
208 struct fd_list * li;
209
210 TRACE_ENTRY("%p %x", list, flags);
211 CHECK_PARAMS(list);
212
213 for (li = list->next; li != list; li = li->next) {
214 struct fd_endpoint * ep = (struct fd_endpoint *)li;
215 ep->flags &= ~flags;
216 if (ep->flags == 0) {
217 li = li->prev;
218 fd_list_unlink(&ep->chain);
219 free(ep);
220 }
221 }
222
223 return 0;
224}
225
226DECLARE_FD_DUMP_PROTOTYPE(fd_ep_dump_one, int preamble, struct fd_endpoint * ep )
227{
228 FD_DUMP_HANDLE_OFFSET();
229
230 if (preamble) {
231 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{ep}(@%p): ", ep), return NULL);
232 }
233
234 if (!ep) {
235 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "INVALID/NULL"), return NULL);
236 return *buf;
237 }
238
239 CHECK_MALLOC_DO( fd_sa_dump( FD_DUMP_STD_PARAMS, &ep->sa, NI_NUMERICHOST | NI_NUMERICSERV ), return NULL);
240 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{%s%s%s%s%s}",
241 (ep->flags & EP_FL_CONF) ? "C" : "-",
242 (ep->flags & EP_FL_DISC) ? "D" : "-",
243 (ep->flags & EP_FL_ADV) ? "A" : "-",
244 (ep->flags & EP_FL_LL) ? "L" : "-",
245 (ep->flags & EP_FL_PRIMARY) ? "P" : "-"), return NULL);
246 return *buf;
247}
248
249DECLARE_FD_DUMP_PROTOTYPE(fd_ep_dump, int preamble, int indent, struct fd_list * eps )
250{
251 struct fd_list * li;
252
253 FD_DUMP_HANDLE_OFFSET();
254
255 if (preamble) {
256 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "%*s{eps}(@%p):", indent, "", eps), return NULL);
257 }
258 if (eps) {
259 for (li = eps->next; li != eps; li = li->next) {
260 struct fd_endpoint * ep = (struct fd_endpoint *)li;
261 if (preamble) {
262 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n%*s", indent+1, ""), return NULL);
263 } else if (li->prev != eps) {
264 CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\t"), return NULL);
265 }
266 CHECK_MALLOC_DO( fd_ep_dump_one( FD_DUMP_STD_PARAMS, preamble, ep ), return NULL);
267 }
268 }
269 return *buf;
270}
271