Line data Source code
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
80 0 : irdp_sock_init (void)
81 : {
82 : int ret, i;
83 : int save_errno;
84 : int sock;
85 :
86 0 : if ( zserv_privs.change (ZPRIVS_RAISE) )
87 0 : zlog_err ("irdp_sock_init: could not raise privs, %s",
88 0 : safe_strerror (errno) );
89 :
90 0 : sock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
91 0 : save_errno = errno;
92 :
93 0 : if ( zserv_privs.change (ZPRIVS_LOWER) )
94 0 : zlog_err ("irdp_sock_init: could not lower privs, %s",
95 0 : safe_strerror (errno) );
96 :
97 0 : if (sock < 0) {
98 0 : zlog_warn ("IRDP: can't create irdp socket %s", safe_strerror(save_errno));
99 0 : return sock;
100 : };
101 :
102 0 : i = 1;
103 0 : ret = setsockopt (sock, IPPROTO_IP, IP_TTL,
104 : (void *) &i, sizeof (i));
105 0 : if (ret < 0) {
106 0 : zlog_warn ("IRDP: can't do irdp sockopt %s", safe_strerror(errno));
107 0 : close(sock);
108 0 : return ret;
109 : };
110 :
111 0 : ret = setsockopt_ifindex (AF_INET, sock, 1);
112 0 : if (ret < 0) {
113 0 : zlog_warn ("IRDP: can't do irdp sockopt %s", safe_strerror(errno));
114 0 : close(sock);
115 0 : return ret;
116 : };
117 :
118 0 : t_irdp_raw = thread_add_read (zebrad.master, irdp_read_raw, NULL, sock);
119 :
120 0 : return sock;
121 : }
122 :
123 :
124 : static int
125 0 : 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 0 : if( irdp->AdvPrefList == NULL )
133 0 : return irdp->Preference;
134 :
135 0 : for (ALL_LIST_ELEMENTS_RO (irdp->AdvPrefList, node, adv))
136 0 : if( p->u.prefix4.s_addr == adv->ip.s_addr )
137 0 : return adv->pref;
138 :
139 0 : return irdp->Preference;
140 : }
141 :
142 : /* Make ICMP Router Advertisement Message. */
143 : static int
144 0 : make_advertisement_packet (struct interface *ifp,
145 : struct prefix *p,
146 : struct stream *s)
147 : {
148 0 : struct zebra_if *zi=ifp->info;
149 0 : struct irdp_interface *irdp=&zi->irdp;
150 : int size;
151 : int pref;
152 : u_int16_t checksum;
153 :
154 0 : pref = get_pref(irdp, p);
155 :
156 0 : stream_putc (s, ICMP_ROUTERADVERT); /* Type. */
157 0 : stream_putc (s, 0); /* Code. */
158 0 : stream_putw (s, 0); /* Checksum. */
159 0 : stream_putc (s, 1); /* Num address. */
160 0 : stream_putc (s, 2); /* Address Entry Size. */
161 :
162 0 : if(irdp->flags & IF_SHUTDOWN)
163 0 : stream_putw (s, 0);
164 : else
165 0 : stream_putw (s, irdp->Lifetime);
166 :
167 0 : stream_putl (s, htonl(p->u.prefix4.s_addr)); /* Router address. */
168 0 : stream_putl (s, pref);
169 :
170 : /* in_cksum return network byte order value */
171 0 : size = 16;
172 0 : checksum = in_cksum (s->data, size);
173 0 : stream_putw_at (s, 2, htons(checksum));
174 :
175 0 : return size;
176 : }
177 :
178 : static void
179 0 : irdp_send(struct interface *ifp, struct prefix *p, struct stream *s)
180 : {
181 0 : struct zebra_if *zi=ifp->info;
182 0 : struct irdp_interface *irdp=&zi->irdp;
183 : u_int32_t dst;
184 0 : u_int32_t ttl=1;
185 :
186 0 : if (! (ifp->flags & IFF_UP)) return;
187 :
188 0 : if (irdp->flags & IF_BROADCAST)
189 0 : dst =INADDR_BROADCAST ;
190 : else
191 0 : dst = htonl(INADDR_ALLHOSTS_GROUP);
192 :
193 0 : if(irdp->flags & IF_DEBUG_MESSAGES)
194 0 : zlog_debug("IRDP: TX Advert on %s %s/%d Holdtime=%d Preference=%d",
195 0 : ifp->name,
196 : inet_ntoa(p->u.prefix4),
197 0 : p->prefixlen,
198 0 : irdp->flags & IF_SHUTDOWN? 0 : irdp->Lifetime,
199 : get_pref(irdp, p));
200 :
201 0 : send_packet (ifp, s, dst, p, ttl);
202 : }
203 :
204 0 : static void irdp_advertisement (struct interface *ifp, struct prefix *p)
205 : {
206 : struct stream *s;
207 0 : s = stream_new (128);
208 0 : make_advertisement_packet (ifp, p, s);
209 0 : irdp_send(ifp, p, s);
210 0 : stream_free (s);
211 0 : }
212 :
213 0 : int irdp_send_thread(struct thread *t_advert)
214 : {
215 : u_int32_t timer, tmp;
216 0 : struct interface *ifp = THREAD_ARG (t_advert);
217 0 : struct zebra_if *zi=ifp->info;
218 0 : struct irdp_interface *irdp=&zi->irdp;
219 : struct prefix *p;
220 : struct listnode *node, *nnode;
221 : struct connected *ifc;
222 :
223 0 : irdp->flags &= ~IF_SOLICIT;
224 :
225 0 : if(ifp->connected)
226 0 : for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, ifc))
227 : {
228 0 : p = ifc->address;
229 :
230 0 : if (p->family != AF_INET)
231 0 : continue;
232 :
233 0 : irdp_advertisement(ifp, p);
234 0 : irdp->irdp_sent++;
235 : }
236 :
237 0 : tmp = irdp->MaxAdvertInterval-irdp->MinAdvertInterval;
238 0 : timer = (random () % tmp ) + 1;
239 0 : timer = irdp->MinAdvertInterval + timer;
240 :
241 0 : if(irdp->irdp_sent < MAX_INITIAL_ADVERTISEMENTS &&
242 : timer > MAX_INITIAL_ADVERT_INTERVAL )
243 0 : timer= MAX_INITIAL_ADVERT_INTERVAL;
244 :
245 0 : if(irdp->flags & IF_DEBUG_MISC)
246 0 : zlog_debug("IRDP: New timer for %s set to %u\n", ifp->name, timer);
247 :
248 0 : irdp->t_advertise = thread_add_timer(zebrad.master, irdp_send_thread, ifp, timer);
249 0 : return 0;
250 : }
251 :
252 0 : void irdp_advert_off(struct interface *ifp)
253 : {
254 0 : struct zebra_if *zi=ifp->info;
255 0 : struct irdp_interface *irdp=&zi->irdp;
256 : struct listnode *node, *nnode;
257 : int i;
258 : struct connected *ifc;
259 : struct prefix *p;
260 :
261 0 : if(irdp->t_advertise) thread_cancel(irdp->t_advertise);
262 0 : irdp->t_advertise = NULL;
263 :
264 0 : if(ifp->connected)
265 0 : for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, ifc))
266 : {
267 0 : p = ifc->address;
268 :
269 : /* Output some packets with Lifetime 0
270 : we should add a wait...
271 : */
272 :
273 0 : for(i=0; i< IRDP_LAST_ADVERT_MESSAGES; i++)
274 : {
275 0 : irdp->irdp_sent++;
276 0 : irdp_advertisement(ifp, p);
277 : }
278 : }
279 0 : }
280 :
281 :
282 0 : void process_solicit (struct interface *ifp)
283 : {
284 0 : struct zebra_if *zi=ifp->info;
285 0 : 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 0 : if( irdp->flags & IF_SOLICIT) return;
293 :
294 0 : irdp->flags |= IF_SOLICIT;
295 0 : if(irdp->t_advertise) thread_cancel(irdp->t_advertise);
296 0 : irdp->t_advertise = NULL;
297 :
298 0 : timer = (random () % MAX_RESPONSE_DELAY) + 1;
299 :
300 0 : irdp->t_advertise = thread_add_timer(zebrad.master,
301 : irdp_send_thread,
302 : ifp,
303 : timer);
304 : }
305 :
306 45 : 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 45 : zlog_info("IRDP: Received shutdown notification.");
315 :
316 179 : for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
317 : {
318 134 : zi = ifp->info;
319 :
320 134 : if (!zi)
321 0 : continue;
322 134 : irdp = &zi->irdp;
323 134 : if (!irdp)
324 0 : continue;
325 :
326 134 : if (irdp->flags & IF_ACTIVE )
327 : {
328 0 : irdp->flags |= IF_SHUTDOWN;
329 0 : irdp_advert_off(ifp);
330 : }
331 : }
332 45 : }
333 :
334 : #endif /* HAVE_IRDP */
|