1 /*
2  * EIGRP Filter Functions.
3  * Copyright (C) 2013-2015
4  * Authors:
5  *   Donnie Savage
6  *   Jan Janovic
7  *   Matej Perina
8  *   Peter Orsag
9  *   Peter Paluch
10  *   Frantisek Gazo
11  *   Tomas Hvorkovy
12  *   Martin Kontsek
13  *   Lukas Koribsky
14  *
15  *
16  * This file is part of GNU Zebra.
17  *
18  * GNU Zebra is free software; you can redistribute it and/or modify it
19  * under the terms of the GNU General Public License as published by the
20  * Free Software Foundation; either version 2, or (at your option) any
21  * later version.
22  *
23  * GNU Zebra is distributed in the hope that it will be useful, but
24  * WITHOUT ANY WARRANTY; without even the implied warranty of
25  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
26  * General Public License for more details.
27  *
28  * You should have received a copy of the GNU General Public License along
29  * with this program; see the file COPYING; if not, write to the Free Software
30  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
31  */
32 
33 #include <zebra.h>
34 
35 #include "if.h"
36 #include "command.h"
37 #include "prefix.h"
38 #include "table.h"
39 #include "thread.h"
40 #include "memory.h"
41 #include "log.h"
42 #include "stream.h"
43 #include "filter.h"
44 #include "sockunion.h"
45 #include "sockopt.h"
46 #include "routemap.h"
47 #include "if_rmap.h"
48 #include "plist.h"
49 #include "distribute.h"
50 #include "md5.h"
51 #include "keychain.h"
52 #include "privs.h"
53 #include "vrf.h"
54 
55 #include "eigrpd/eigrp_structs.h"
56 #include "eigrpd/eigrpd.h"
57 #include "eigrpd/eigrp_const.h"
58 #include "eigrpd/eigrp_filter.h"
59 #include "eigrpd/eigrp_packet.h"
60 #include "eigrpd/eigrp_memory.h"
61 
62 /*
63  * Distribute-list update functions.
64  */
eigrp_distribute_update(struct distribute_ctx * ctx,struct distribute * dist)65 void eigrp_distribute_update(struct distribute_ctx *ctx,
66 			     struct distribute *dist)
67 {
68 	struct eigrp *e = eigrp_lookup(ctx->vrf->vrf_id);
69 	struct interface *ifp;
70 	struct eigrp_interface *ei = NULL;
71 	struct access_list *alist;
72 	struct prefix_list *plist;
73 	// struct route_map *routemap;
74 
75 	/* if no interface address is present, set list to eigrp process struct
76 	 */
77 
78 	/* Check if distribute-list was set for process or interface */
79 	if (!dist->ifname) {
80 		/* access list IN for whole process */
81 		if (dist->list[DISTRIBUTE_V4_IN]) {
82 			alist = access_list_lookup(
83 				AFI_IP, dist->list[DISTRIBUTE_V4_IN]);
84 			if (alist)
85 				e->list[EIGRP_FILTER_IN] = alist;
86 			else
87 				e->list[EIGRP_FILTER_IN] = NULL;
88 		} else {
89 			e->list[EIGRP_FILTER_IN] = NULL;
90 		}
91 
92 		/* access list OUT for whole process */
93 		if (dist->list[DISTRIBUTE_V4_OUT]) {
94 			alist = access_list_lookup(
95 				AFI_IP, dist->list[DISTRIBUTE_V4_OUT]);
96 			if (alist)
97 				e->list[EIGRP_FILTER_OUT] = alist;
98 			else
99 				e->list[EIGRP_FILTER_OUT] = NULL;
100 		} else {
101 			e->list[EIGRP_FILTER_OUT] = NULL;
102 		}
103 
104 		/* PREFIX_LIST IN for process */
105 		if (dist->prefix[DISTRIBUTE_V4_IN]) {
106 			plist = prefix_list_lookup(
107 				AFI_IP, dist->prefix[DISTRIBUTE_V4_IN]);
108 			if (plist) {
109 				e->prefix[EIGRP_FILTER_IN] = plist;
110 			} else
111 				e->prefix[EIGRP_FILTER_IN] = NULL;
112 		} else
113 			e->prefix[EIGRP_FILTER_IN] = NULL;
114 
115 		/* PREFIX_LIST OUT for process */
116 		if (dist->prefix[DISTRIBUTE_V4_OUT]) {
117 			plist = prefix_list_lookup(
118 				AFI_IP, dist->prefix[DISTRIBUTE_V4_OUT]);
119 			if (plist) {
120 				e->prefix[EIGRP_FILTER_OUT] = plist;
121 
122 			} else
123 				e->prefix[EIGRP_FILTER_OUT] = NULL;
124 		} else
125 			e->prefix[EIGRP_FILTER_OUT] = NULL;
126 
127 // This is commented out, because the distribute.[ch] code
128 // changes looked poorly written from first glance
129 // commit was 133bdf2d
130 // TODO: DBS
131 #if 0
132       /* route-map IN for whole process */
133       if (dist->route[DISTRIBUTE_V4_IN])
134         {
135           routemap = route_map_lookup_by_name (dist->route[DISTRIBUTE_V4_IN]);
136           if (routemap)
137             e->routemap[EIGRP_FILTER_IN] = routemap;
138           else
139             e->routemap[EIGRP_FILTER_IN] = NULL;
140         }
141       else
142         {
143           e->routemap[EIGRP_FILTER_IN] = NULL;
144         }
145 
146       /* route-map OUT for whole process */
147       if (dist->route[DISTRIBUTE_V4_OUT])
148         {
149           routemap = route_map_lookup_by_name (dist->route[DISTRIBUTE_V4_OUT]);
150           if (routemap)
151             e->routemap[EIGRP_FILTER_OUT] = routemap;
152           else
153             e->routemap[EIGRP_FILTER_OUT] = NULL;
154         }
155       else
156         {
157           e->routemap[EIGRP_FILTER_OUT] = NULL;
158         }
159 #endif
160 		// TODO: check Graceful restart after 10sec
161 
162 		/* check if there is already GR scheduled */
163 		if (e->t_distribute != NULL) {
164 			/* if is, cancel schedule */
165 			thread_cancel(e->t_distribute);
166 		}
167 		/* schedule Graceful restart for whole process in 10sec */
168 		e->t_distribute = NULL;
169 		thread_add_timer(master, eigrp_distribute_timer_process, e,
170 				 (10), &e->t_distribute);
171 
172 		return;
173 	}
174 
175 	ifp = if_lookup_by_name(dist->ifname, e->vrf_id);
176 	if (ifp == NULL)
177 		return;
178 
179 	/*struct eigrp_if_info * info = ifp->info;
180 	ei = info->eigrp_interface;*/
181 	struct listnode *node, *nnode;
182 	struct eigrp_interface *ei2;
183 	/* Find proper interface */
184 	for (ALL_LIST_ELEMENTS(e->eiflist, node, nnode, ei2)) {
185 		if (strcmp(ei2->ifp->name, ifp->name) == 0) {
186 			ei = ei2;
187 			break;
188 		}
189 	}
190 	assert(ei != NULL);
191 
192 	/* Access-list for interface in */
193 	if (dist->list[DISTRIBUTE_V4_IN]) {
194 		alist = access_list_lookup(AFI_IP,
195 					   dist->list[DISTRIBUTE_V4_IN]);
196 		if (alist) {
197 			ei->list[EIGRP_FILTER_IN] = alist;
198 		} else
199 			ei->list[EIGRP_FILTER_IN] = NULL;
200 	} else {
201 		ei->list[EIGRP_FILTER_IN] = NULL;
202 	}
203 
204 	/* Access-list for interface in */
205 	if (dist->list[DISTRIBUTE_V4_OUT]) {
206 		alist = access_list_lookup(AFI_IP,
207 					   dist->list[DISTRIBUTE_V4_OUT]);
208 		if (alist)
209 			ei->list[EIGRP_FILTER_OUT] = alist;
210 		else
211 			ei->list[EIGRP_FILTER_OUT] = NULL;
212 
213 	} else
214 		ei->list[EIGRP_FILTER_OUT] = NULL;
215 
216 	/* Prefix-list for interface in */
217 	if (dist->prefix[DISTRIBUTE_V4_IN]) {
218 		plist = prefix_list_lookup(AFI_IP,
219 					   dist->prefix[DISTRIBUTE_V4_IN]);
220 		if (plist)
221 			ei->prefix[EIGRP_FILTER_IN] = plist;
222 		else
223 			ei->prefix[EIGRP_FILTER_IN] = NULL;
224 	} else
225 		ei->prefix[EIGRP_FILTER_IN] = NULL;
226 
227 	/* Prefix-list for interface out */
228 	if (dist->prefix[DISTRIBUTE_V4_OUT]) {
229 		plist = prefix_list_lookup(AFI_IP,
230 					   dist->prefix[DISTRIBUTE_V4_OUT]);
231 		if (plist)
232 			ei->prefix[EIGRP_FILTER_OUT] = plist;
233 		else
234 			ei->prefix[EIGRP_FILTER_OUT] = NULL;
235 	} else
236 		ei->prefix[EIGRP_FILTER_OUT] = NULL;
237 
238 #if 0
239   /* route-map IN for whole process */
240   if (dist->route[DISTRIBUTE_V4_IN])
241     {
242       zlog_info("<DEBUG ACL ALL in");
243       routemap = route_map_lookup_by_name (dist->route[DISTRIBUTE_V4_IN]);
244       if (routemap)
245         ei->routemap[EIGRP_FILTER_IN] = routemap;
246       else
247         ei->routemap[EIGRP_FILTER_IN] = NULL;
248     }
249   else
250     {
251       ei->routemap[EIGRP_FILTER_IN] = NULL;
252     }
253 
254   /* route-map OUT for whole process */
255   if (dist->route[DISTRIBUTE_V4_OUT])
256     {
257       routemap = route_map_lookup_by_name (dist->route[DISTRIBUTE_V4_OUT]);
258       if (routemap)
259         ei->routemap[EIGRP_FILTER_OUT] = routemap;
260       else
261         ei->routemap[EIGRP_FILTER_OUT] = NULL;
262     }
263   else
264     {
265       ei->routemap[EIGRP_FILTER_OUT] = NULL;
266     }
267 #endif
268 	// TODO: check Graceful restart after 10sec
269 
270 	/* check if there is already GR scheduled */
271 	if (ei->t_distribute != NULL) {
272 		/* if is, cancel schedule */
273 		thread_cancel(ei->t_distribute);
274 	}
275 	/* schedule Graceful restart for interface in 10sec */
276 	e->t_distribute = NULL;
277 	thread_add_timer(master, eigrp_distribute_timer_interface, ei, 10,
278 			 &e->t_distribute);
279 }
280 
281 /*
282  * Function called by prefix-list and access-list update
283  */
eigrp_distribute_update_interface(struct interface * ifp)284 void eigrp_distribute_update_interface(struct interface *ifp)
285 {
286 	struct distribute *dist;
287 	struct eigrp *eigrp;
288 
289 	eigrp = eigrp_lookup(ifp->vrf_id);
290 	if (!eigrp)
291 		return;
292 	dist = distribute_lookup(eigrp->distribute_ctx, ifp->name);
293 	if (dist)
294 		eigrp_distribute_update(eigrp->distribute_ctx,
295 					dist);
296 }
297 
298 /* Update all interface's distribute list.
299  * Function used in hook for prefix-list
300  */
eigrp_distribute_update_all(struct prefix_list * notused)301 void eigrp_distribute_update_all(struct prefix_list *notused)
302 {
303 	struct vrf *vrf;
304 	struct interface *ifp;
305 
306 	RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
307 		FOR_ALL_INTERFACES (vrf, ifp)
308 			eigrp_distribute_update_interface(ifp);
309 	}
310 }
311 
312 /*
313  * Function used in hook for acces-list
314  */
eigrp_distribute_update_all_wrapper(struct access_list * notused)315 void eigrp_distribute_update_all_wrapper(struct access_list *notused)
316 {
317 	eigrp_distribute_update_all(NULL);
318 }
319 
320 /*
321  * @fn eigrp_distribute_timer_process
322  *
323  * @param[in]   thread  current execution thread timer is associated with
324  *
325  * @return int  always returns 0
326  *
327  * @par
328  * Called when 10sec waiting time expire and
329  * executes Graceful restart for whole process
330  */
eigrp_distribute_timer_process(struct thread * thread)331 int eigrp_distribute_timer_process(struct thread *thread)
332 {
333 	struct eigrp *eigrp;
334 
335 	eigrp = THREAD_ARG(thread);
336 	eigrp->t_distribute = NULL;
337 
338 	/* execute GR for whole process */
339 	eigrp_update_send_process_GR(eigrp, EIGRP_GR_FILTER, NULL);
340 
341 	return 0;
342 }
343 
344 /*
345  * @fn eigrp_distribute_timer_interface
346  *
347  * @param[in]   thread  current execution thread timer is associated with
348  *
349  * @return int  always returns 0
350  *
351  * @par
352  * Called when 10sec waiting time expire and
353  * executes Graceful restart for interface
354  */
eigrp_distribute_timer_interface(struct thread * thread)355 int eigrp_distribute_timer_interface(struct thread *thread)
356 {
357 	struct eigrp_interface *ei;
358 
359 	ei = THREAD_ARG(thread);
360 	ei->t_distribute = NULL;
361 
362 	/* execute GR for interface */
363 	eigrp_update_send_interface_GR(ei, EIGRP_GR_FILTER, NULL);
364 
365 	return 0;
366 }
367