1 /*
2  *
3  * Copyright (C) 2000  Robert Olsson.
4  * Swedish University of Agricultural Sciences
5  *
6  * This file is part of GNU Zebra.
7  *
8  * GNU Zebra is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU General Public License as published by the
10  * Free Software Foundation; either version 2, or (at your option) any
11  * later version.
12  *
13  * GNU Zebra is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with GNU Zebra; see the file COPYING.  If not, write to the Free
20  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
21  * 02111-1307, USA.
22  */
23 
24 /*
25  * This work includes work with the following copywrite:
26  *
27  * Copyright (C) 1997, 2000 Kunihiro Ishiguro
28  *
29  */
30 
31 /*
32  * Thanks to Jens L��s at Swedish University of Agricultural Sciences
33  * for reviewing and tests.
34  */
35 
36 
37 #include <zebra.h>
38 
39 #ifdef HAVE_IRDP
40 
41 #include "if.h"
42 #include "vty.h"
43 #include "sockunion.h"
44 #include "sockopt.h"
45 #include "prefix.h"
46 #include "command.h"
47 #include "memory.h"
48 #include "stream.h"
49 #include "ioctl.h"
50 #include "connected.h"
51 #include "log.h"
52 #include "zclient.h"
53 #include "thread.h"
54 #include "privs.h"
55 #include "zebra/interface.h"
56 #include "zebra/rtadv.h"
57 #include "zebra/rib.h"
58 #include "zebra/zserv.h"
59 #include "zebra/redistribute.h"
60 #include "zebra/irdp.h"
61 #include <netinet/ip_icmp.h>
62 
63 #include "checksum.h"
64 #include "if.h"
65 #include "sockunion.h"
66 #include "log.h"
67 
68 /* GLOBAL VARS */
69 
70 extern struct zebra_privs_t zserv_privs;
71 
72 /* Master of threads. */
73 extern struct zebra_t zebrad;
74 struct thread *t_irdp_raw;
75 
76 /* Timer interval of irdp. */
77 int irdp_timer_interval = IRDP_DEFAULT_INTERVAL;
78 
79 int
irdp_sock_init(void)80 irdp_sock_init (void)
81 {
82   int ret, i;
83   int save_errno;
84   int sock;
85 
86   if ( zserv_privs.change (ZPRIVS_RAISE) )
87        zlog_err ("irdp_sock_init: could not raise privs, %s",
88                   safe_strerror (errno) );
89 
90   sock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
91   save_errno = errno;
92 
93   if ( zserv_privs.change (ZPRIVS_LOWER) )
94        zlog_err ("irdp_sock_init: could not lower privs, %s",
95              safe_strerror (errno) );
96 
97   if (sock < 0) {
98     zlog_warn ("IRDP: can't create irdp socket %s", safe_strerror(save_errno));
99     return sock;
100   };
101 
102   i = 1;
103   ret = setsockopt (sock, IPPROTO_IP, IP_TTL,
104                         (void *) &i, sizeof (i));
105   if (ret < 0) {
106     zlog_warn ("IRDP: can't do irdp sockopt %s", safe_strerror(errno));
107     close(sock);
108     return ret;
109   };
110 
111   ret = setsockopt_ifindex (AF_INET, sock, 1);
112   if (ret < 0) {
113     zlog_warn ("IRDP: can't do irdp sockopt %s", safe_strerror(errno));
114     close(sock);
115     return ret;
116   };
117 
118   t_irdp_raw = thread_add_read (zebrad.master, irdp_read_raw, NULL, sock);
119 
120   return sock;
121 }
122 
123 
124 static int
get_pref(struct irdp_interface * irdp,struct prefix * p)125 get_pref(struct irdp_interface *irdp, struct prefix *p)
126 {
127   struct listnode *node;
128   struct Adv *adv;
129 
130   /* Use default preference or use the override pref */
131 
132   if( irdp->AdvPrefList == NULL )
133     return irdp->Preference;
134 
135   for (ALL_LIST_ELEMENTS_RO (irdp->AdvPrefList, node, adv))
136     if( p->u.prefix4.s_addr == adv->ip.s_addr )
137       return adv->pref;
138 
139   return irdp->Preference;
140 }
141 
142 /* Make ICMP Router Advertisement Message. */
143 static int
make_advertisement_packet(struct interface * ifp,struct prefix * p,struct stream * s)144 make_advertisement_packet (struct interface *ifp,
145 			   struct prefix *p,
146 			   struct stream *s)
147 {
148   struct zebra_if *zi=ifp->info;
149   struct irdp_interface *irdp=&zi->irdp;
150   int size;
151   int pref;
152   u_int16_t checksum;
153 
154   pref =  get_pref(irdp, p);
155 
156   stream_putc (s, ICMP_ROUTERADVERT); /* Type. */
157   stream_putc (s, 0);		/* Code. */
158   stream_putw (s, 0);		/* Checksum. */
159   stream_putc (s, 1);		/* Num address. */
160   stream_putc (s, 2);		/* Address Entry Size. */
161 
162   if(irdp->flags & IF_SHUTDOWN)
163     stream_putw (s, 0);
164   else
165     stream_putw (s, irdp->Lifetime);
166 
167   stream_putl (s, htonl(p->u.prefix4.s_addr)); /* Router address. */
168   stream_putl (s, pref);
169 
170   /* in_cksum return network byte order value */
171   size = 16;
172   checksum = in_cksum (s->data, size);
173   stream_putw_at (s, 2, htons(checksum));
174 
175   return size;
176 }
177 
178 static void
irdp_send(struct interface * ifp,struct prefix * p,struct stream * s)179 irdp_send(struct interface *ifp, struct prefix *p, struct stream *s)
180 {
181   struct zebra_if *zi=ifp->info;
182   struct irdp_interface *irdp=&zi->irdp;
183   char buf[PREFIX_STRLEN];
184   u_int32_t dst;
185   u_int32_t ttl=1;
186 
187   if (! (ifp->flags & IFF_UP)) return;
188 
189   if (irdp->flags & IF_BROADCAST)
190     dst =INADDR_BROADCAST ;
191   else
192     dst = htonl(INADDR_ALLHOSTS_GROUP);
193 
194   if(irdp->flags & IF_DEBUG_MESSAGES)
195     zlog_debug("IRDP: TX Advert on %s %s Holdtime=%d Preference=%d",
196 	      ifp->name,
197 	      prefix2str(p, buf, sizeof buf),
198 	      irdp->flags & IF_SHUTDOWN? 0 : irdp->Lifetime,
199 	      get_pref(irdp, p));
200 
201   send_packet (ifp, s, dst, p, ttl);
202 }
203 
irdp_advertisement(struct interface * ifp,struct prefix * p)204 static void irdp_advertisement (struct interface *ifp, struct prefix *p)
205 {
206   struct stream *s;
207   s = stream_new (128);
208   make_advertisement_packet (ifp, p, s);
209   irdp_send(ifp, p, s);
210   stream_free (s);
211 }
212 
irdp_send_thread(struct thread * t_advert)213 int irdp_send_thread(struct thread *t_advert)
214 {
215   u_int32_t timer, tmp;
216   struct interface *ifp = THREAD_ARG (t_advert);
217   struct zebra_if *zi=ifp->info;
218   struct irdp_interface *irdp=&zi->irdp;
219   struct prefix *p;
220   struct listnode *node, *nnode;
221   struct connected *ifc;
222 
223   irdp->flags &= ~IF_SOLICIT;
224 
225   if(ifp->connected)
226     for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, ifc))
227       {
228         p = ifc->address;
229 
230         if (p->family != AF_INET)
231           continue;
232 
233         irdp_advertisement(ifp, p);
234         irdp->irdp_sent++;
235       }
236 
237   tmp = irdp->MaxAdvertInterval-irdp->MinAdvertInterval;
238   timer =  (random () % tmp ) + 1;
239   timer = irdp->MinAdvertInterval + timer;
240 
241   if(irdp->irdp_sent <  MAX_INITIAL_ADVERTISEMENTS &&
242      timer > MAX_INITIAL_ADVERT_INTERVAL )
243 	  timer= MAX_INITIAL_ADVERT_INTERVAL;
244 
245   if(irdp->flags & IF_DEBUG_MISC)
246     zlog_debug("IRDP: New timer for %s set to %u\n", ifp->name, timer);
247 
248   irdp->t_advertise = thread_add_timer(zebrad.master, irdp_send_thread, ifp, timer);
249   return 0;
250 }
251 
irdp_advert_off(struct interface * ifp)252 void irdp_advert_off(struct interface *ifp)
253 {
254   struct zebra_if *zi=ifp->info;
255   struct irdp_interface *irdp=&zi->irdp;
256   struct listnode *node, *nnode;
257   int i;
258   struct connected *ifc;
259   struct prefix *p;
260 
261   if(irdp->t_advertise)  thread_cancel(irdp->t_advertise);
262   irdp->t_advertise = NULL;
263 
264   if(ifp->connected)
265     for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, ifc))
266       {
267         p = ifc->address;
268 
269         /* Output some packets with Lifetime 0
270            we should add a wait...
271         */
272 
273         for(i=0; i< IRDP_LAST_ADVERT_MESSAGES; i++)
274           {
275             irdp->irdp_sent++;
276             irdp_advertisement(ifp, p);
277           }
278       }
279 }
280 
281 
process_solicit(struct interface * ifp)282 void process_solicit (struct interface *ifp)
283 {
284   struct zebra_if *zi=ifp->info;
285   struct irdp_interface *irdp=&zi->irdp;
286   u_int32_t timer;
287 
288   /* When SOLICIT is active we reject further incoming solicits
289      this keeps down the answering rate so we don't have think
290      about DoS attacks here. */
291 
292   if( irdp->flags & IF_SOLICIT) return;
293 
294   irdp->flags |= IF_SOLICIT;
295   if(irdp->t_advertise)  thread_cancel(irdp->t_advertise);
296   irdp->t_advertise = NULL;
297 
298   timer =  (random () % MAX_RESPONSE_DELAY) + 1;
299 
300   irdp->t_advertise = thread_add_timer(zebrad.master,
301 				       irdp_send_thread,
302 				       ifp,
303 				       timer);
304 }
305 
irdp_finish()306 void irdp_finish()
307 {
308 
309   struct listnode *node, *nnode;
310   struct interface *ifp;
311   struct zebra_if *zi;
312   struct irdp_interface *irdp;
313 
314   zlog_info("IRDP: Received shutdown notification.");
315 
316   for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
317     {
318       zi = ifp->info;
319 
320       if (!zi)
321         continue;
322       irdp = &zi->irdp;
323       if (!irdp)
324         continue;
325 
326       if (irdp->flags & IF_ACTIVE )
327         {
328 	  irdp->flags |= IF_SHUTDOWN;
329 	  irdp_advert_off(ifp);
330         }
331     }
332 }
333 
334 #endif /* HAVE_IRDP */
335