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 :
40 : #ifdef HAVE_IRDP
41 :
42 : #include "if.h"
43 : #include "vty.h"
44 : #include "sockunion.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 "zebra/interface.h"
55 : #include "zebra/rtadv.h"
56 : #include "zebra/rib.h"
57 : #include "zebra/zserv.h"
58 : #include "zebra/redistribute.h"
59 : #include "zebra/irdp.h"
60 : #include <netinet/ip_icmp.h>
61 : #include "if.h"
62 : #include "checksum.h"
63 : #include "sockunion.h"
64 : #include "log.h"
65 : #include "sockopt.h"
66 :
67 :
68 : /* GLOBAL VARS */
69 :
70 : int irdp_sock = -1;
71 :
72 : extern struct zebra_t zebrad;
73 : extern struct thread *t_irdp_raw;
74 :
75 : static void
76 0 : parse_irdp_packet(char *p,
77 : int len,
78 : struct interface *ifp)
79 : {
80 0 : struct ip *ip = (struct ip *)p ;
81 : struct icmphdr *icmp;
82 : struct in_addr src;
83 : int ip_hlen, iplen, datalen;
84 : struct zebra_if *zi;
85 : struct irdp_interface *irdp;
86 :
87 0 : zi = ifp->info;
88 0 : if (!zi)
89 0 : return;
90 :
91 0 : irdp = &zi->irdp;
92 0 : if (!irdp)
93 0 : return;
94 :
95 0 : ip_hlen = ip->ip_hl << 2;
96 :
97 0 : sockopt_iphdrincl_swab_systoh (ip);
98 :
99 0 : iplen = ip->ip_len;
100 0 : datalen = len - ip_hlen;
101 0 : src = ip->ip_src;
102 :
103 0 : if (len != iplen)
104 : {
105 0 : zlog_err ("IRDP: RX length doesnt match IP length");
106 0 : return;
107 : }
108 :
109 0 : if (iplen < ICMP_MINLEN)
110 : {
111 0 : zlog_err ("IRDP: RX ICMP packet too short from %s\n",
112 : inet_ntoa (src));
113 0 : return;
114 : }
115 :
116 : /* XXX: RAW doesnt receive link-layer, surely? ??? */
117 : /* Check so we don't checksum packets longer than oure RX_BUF - (ethlen +
118 : len of IP-header) 14+20 */
119 0 : if (iplen > IRDP_RX_BUF-34)
120 : {
121 0 : zlog_err ("IRDP: RX ICMP packet too long from %s\n",
122 : inet_ntoa (src));
123 0 : return;
124 : }
125 :
126 0 : icmp = (struct icmphdr *) (p+ip_hlen);
127 :
128 : /* check icmp checksum */
129 0 : if (in_cksum (icmp, datalen) != icmp->checksum)
130 : {
131 0 : zlog_warn ("IRDP: RX ICMP packet from %s. Bad checksum, silently ignored",
132 : inet_ntoa (src));
133 0 : return;
134 : }
135 :
136 : /* Handle just only IRDP */
137 0 : if (!(icmp->type == ICMP_ROUTERADVERT
138 0 : || icmp->type == ICMP_ROUTERSOLICIT))
139 0 : return;
140 :
141 0 : if (icmp->code != 0)
142 : {
143 0 : zlog_warn ("IRDP: RX packet type %d from %s. Bad ICMP type code,"
144 : " silently ignored",
145 0 : icmp->type, inet_ntoa (src));
146 0 : return;
147 : }
148 :
149 0 : if (! ((ntohl (ip->ip_dst.s_addr) == INADDR_BROADCAST)
150 0 : && (irdp->flags & IF_BROADCAST))
151 0 : ||
152 0 : (ntohl (ip->ip_dst.s_addr) == INADDR_ALLRTRS_GROUP
153 0 : && !(irdp->flags & IF_BROADCAST)))
154 : {
155 0 : zlog_warn ("IRDP: RX illegal from %s to %s while %s operates in %s\n",
156 : inet_ntoa (src),
157 0 : ntohl (ip->ip_dst.s_addr) == INADDR_ALLRTRS_GROUP ?
158 : "multicast" : inet_ntoa (ip->ip_dst),
159 0 : ifp->name,
160 0 : irdp->flags & IF_BROADCAST ? "broadcast" : "multicast");
161 :
162 0 : zlog_warn ("IRDP: Please correct settings\n");
163 0 : return;
164 : }
165 :
166 0 : switch (icmp->type)
167 : {
168 : case ICMP_ROUTERADVERT:
169 0 : break;
170 :
171 : case ICMP_ROUTERSOLICIT:
172 :
173 0 : if(irdp->flags & IF_DEBUG_MESSAGES)
174 0 : zlog_debug ("IRDP: RX Solicit on %s from %s\n",
175 0 : ifp->name,
176 : inet_ntoa (src));
177 :
178 0 : process_solicit(ifp);
179 0 : break;
180 :
181 : default:
182 0 : zlog_warn ("IRDP: RX type %d from %s. Bad ICMP type, silently ignored",
183 0 : icmp->type,
184 : inet_ntoa (src));
185 : }
186 : }
187 :
188 : static int
189 0 : irdp_recvmsg (int sock, u_char *buf, int size, int *ifindex)
190 : {
191 : struct msghdr msg;
192 : struct iovec iov;
193 : char adata[CMSG_SPACE( SOPT_SIZE_CMSG_PKTINFO_IPV4() )];
194 : int ret;
195 :
196 0 : msg.msg_name = (void *)0;
197 0 : msg.msg_namelen = 0;
198 0 : msg.msg_iov = &iov;
199 0 : msg.msg_iovlen = 1;
200 0 : msg.msg_control = (void *) adata;
201 0 : msg.msg_controllen = sizeof adata;
202 :
203 0 : iov.iov_base = buf;
204 0 : iov.iov_len = size;
205 :
206 0 : ret = recvmsg (sock, &msg, 0);
207 0 : if (ret < 0) {
208 0 : zlog_warn("IRDP: recvmsg: read error %s", safe_strerror(errno));
209 0 : return ret;
210 : }
211 :
212 0 : if (msg.msg_flags & MSG_TRUNC) {
213 0 : zlog_warn("IRDP: recvmsg: truncated message");
214 0 : return ret;
215 : }
216 0 : if (msg.msg_flags & MSG_CTRUNC) {
217 0 : zlog_warn("IRDP: recvmsg: truncated control message");
218 0 : return ret;
219 : }
220 :
221 0 : *ifindex = getsockopt_ifindex (AF_INET, &msg);
222 :
223 0 : return ret;
224 : }
225 :
226 0 : int irdp_read_raw(struct thread *r)
227 : {
228 : struct interface *ifp;
229 : struct zebra_if *zi;
230 : struct irdp_interface *irdp;
231 : char buf[IRDP_RX_BUF];
232 0 : int ret, ifindex = 0;
233 :
234 0 : int irdp_sock = THREAD_FD (r);
235 0 : t_irdp_raw = thread_add_read (zebrad.master, irdp_read_raw, NULL, irdp_sock);
236 :
237 0 : ret = irdp_recvmsg (irdp_sock, (u_char *) buf, IRDP_RX_BUF, &ifindex);
238 :
239 0 : if (ret < 0) zlog_warn ("IRDP: RX Error length = %d", ret);
240 :
241 0 : ifp = if_lookup_by_index(ifindex);
242 0 : if(! ifp ) return ret;
243 :
244 0 : zi= ifp->info;
245 0 : if(! zi ) return ret;
246 :
247 0 : irdp = &zi->irdp;
248 0 : if(! irdp ) return ret;
249 :
250 0 : if(! (irdp->flags & IF_ACTIVE)) {
251 :
252 0 : if(irdp->flags & IF_DEBUG_MISC)
253 0 : zlog_debug("IRDP: RX ICMP for disabled interface %s\n", ifp->name);
254 0 : return 0;
255 : }
256 :
257 0 : if(irdp->flags & IF_DEBUG_PACKET) {
258 : int i;
259 0 : zlog_debug("IRDP: RX (idx %d) ", ifindex);
260 0 : for(i=0; i < ret; i++) zlog_debug( "IRDP: RX %x ", buf[i]&0xFF);
261 : }
262 :
263 0 : parse_irdp_packet(buf, ret, ifp);
264 :
265 0 : return ret;
266 : }
267 :
268 : void
269 0 : send_packet(struct interface *ifp,
270 : struct stream *s,
271 : u_int32_t dst,
272 : struct prefix *p,
273 : u_int32_t ttl)
274 : {
275 : static struct sockaddr_in sockdst = {AF_INET};
276 : struct ip *ip;
277 : struct icmphdr *icmp;
278 : struct msghdr *msg;
279 : struct cmsghdr *cmsg;
280 : struct iovec iovector;
281 : char msgbuf[256];
282 : char buf[256];
283 : struct in_pktinfo *pktinfo;
284 : u_long src;
285 : int on;
286 :
287 0 : if (!(ifp->flags & IFF_UP))
288 0 : return;
289 :
290 0 : if (p)
291 0 : src = ntohl(p->u.prefix4.s_addr);
292 : else
293 0 : src = 0; /* Is filled in */
294 :
295 0 : ip = (struct ip *) buf;
296 0 : ip->ip_hl = sizeof(struct ip) >> 2;
297 0 : ip->ip_v = IPVERSION;
298 0 : ip->ip_tos = 0xC0;
299 0 : ip->ip_off = 0L;
300 0 : ip->ip_p = 1; /* IP_ICMP */
301 0 : ip->ip_ttl = ttl;
302 0 : ip->ip_src.s_addr = src;
303 0 : ip->ip_dst.s_addr = dst;
304 0 : icmp = (struct icmphdr *) (buf + sizeof (struct ip));
305 :
306 : /* Merge IP header with icmp packet */
307 0 : assert (stream_get_endp(s) < (sizeof (buf) - sizeof (struct ip)));
308 0 : stream_get(icmp, s, stream_get_endp(s));
309 :
310 : /* icmp->checksum is already calculated */
311 0 : ip->ip_len = sizeof(struct ip) + stream_get_endp(s);
312 :
313 0 : on = 1;
314 0 : if (setsockopt(irdp_sock, IPPROTO_IP, IP_HDRINCL,
315 : (char *) &on, sizeof(on)) < 0)
316 0 : zlog_warn("sendto %s", safe_strerror (errno));
317 :
318 :
319 0 : if(dst == INADDR_BROADCAST ) {
320 0 : on = 1;
321 0 : if (setsockopt(irdp_sock, SOL_SOCKET, SO_BROADCAST,
322 : (char *) &on, sizeof(on)) < 0)
323 0 : zlog_warn("sendto %s", safe_strerror (errno));
324 : }
325 :
326 0 : if(dst != INADDR_BROADCAST) {
327 0 : on = 0;
328 0 : if( setsockopt(irdp_sock,IPPROTO_IP, IP_MULTICAST_LOOP,
329 : (char *)&on,sizeof(on)) < 0)
330 0 : zlog_warn("sendto %s", safe_strerror (errno));
331 : }
332 :
333 0 : memset(&sockdst,0,sizeof(sockdst));
334 0 : sockdst.sin_family=AF_INET;
335 0 : sockdst.sin_addr.s_addr = dst;
336 :
337 0 : cmsg = (struct cmsghdr *) (msgbuf + sizeof(struct msghdr));
338 0 : cmsg->cmsg_len = sizeof(struct cmsghdr) + sizeof(struct in_pktinfo);
339 0 : cmsg->cmsg_level = SOL_IP;
340 0 : cmsg->cmsg_type = IP_PKTINFO;
341 0 : pktinfo = (struct in_pktinfo *) CMSG_DATA(cmsg);
342 0 : pktinfo->ipi_ifindex = ifp->ifindex;
343 0 : pktinfo->ipi_spec_dst.s_addr = src;
344 0 : pktinfo->ipi_addr.s_addr = src;
345 :
346 0 : iovector.iov_base = (void *) buf;
347 0 : iovector.iov_len = ip->ip_len;
348 0 : msg = (struct msghdr *) msgbuf;
349 0 : msg->msg_name = &sockdst;
350 0 : msg->msg_namelen = sizeof(sockdst);
351 0 : msg->msg_iov = &iovector;
352 0 : msg->msg_iovlen = 1;
353 0 : msg->msg_control = cmsg;
354 0 : msg->msg_controllen = cmsg->cmsg_len;
355 :
356 0 : sockopt_iphdrincl_swab_htosys (ip);
357 :
358 0 : if (sendmsg(irdp_sock, msg, 0) < 0) {
359 0 : zlog_warn("sendto %s", safe_strerror (errno));
360 : }
361 : /* printf("TX on %s idx %d\n", ifp->name, ifp->ifindex); */
362 : }
363 :
364 :
365 : #endif /* HAVE_IRDP */
366 :
367 :
368 :
|