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: parse_irdp_packet(char *p,
77: int len,
78: struct interface *ifp)
79: {
80: 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: zi = ifp->info;
88: if (!zi)
89: return;
90:
91: irdp = &zi->irdp;
92: if (!irdp)
93: return;
94:
95: ip_hlen = ip->ip_hl << 2;
96:
97: sockopt_iphdrincl_swab_systoh (ip);
98:
99: iplen = ip->ip_len;
100: datalen = len - ip_hlen;
101: src = ip->ip_src;
102:
103: if (len != iplen)
104: {
105: zlog_err ("IRDP: RX length doesnt match IP length");
106: return;
107: }
108:
109: if (iplen < ICMP_MINLEN)
110: {
111: zlog_err ("IRDP: RX ICMP packet too short from %s\n",
112: inet_ntoa (src));
113: 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: if (iplen > IRDP_RX_BUF-34)
120: {
121: zlog_err ("IRDP: RX ICMP packet too long from %s\n",
122: inet_ntoa (src));
123: return;
124: }
125:
126: icmp = (struct icmphdr *) (p+ip_hlen);
127:
128: /* check icmp checksum */
129: if (in_cksum (icmp, datalen) != icmp->checksum)
130: {
131: zlog_warn ("IRDP: RX ICMP packet from %s. Bad checksum, silently ignored",
132: inet_ntoa (src));
133: return;
134: }
135:
136: /* Handle just only IRDP */
137: if (!(icmp->type == ICMP_ROUTERADVERT
138: || icmp->type == ICMP_ROUTERSOLICIT))
139: return;
140:
141: if (icmp->code != 0)
142: {
143: zlog_warn ("IRDP: RX packet type %d from %s. Bad ICMP type code,"
144: " silently ignored",
145: icmp->type, inet_ntoa (src));
146: return;
147: }
148:
149: if (! ((ntohl (ip->ip_dst.s_addr) == INADDR_BROADCAST)
150: && (irdp->flags & IF_BROADCAST))
151: ||
152: (ntohl (ip->ip_dst.s_addr) == INADDR_ALLRTRS_GROUP
153: && !(irdp->flags & IF_BROADCAST)))
154: {
155: zlog_warn ("IRDP: RX illegal from %s to %s while %s operates in %s\n",
156: inet_ntoa (src),
157: ntohl (ip->ip_dst.s_addr) == INADDR_ALLRTRS_GROUP ?
158: "multicast" : inet_ntoa (ip->ip_dst),
159: ifp->name,
160: irdp->flags & IF_BROADCAST ? "broadcast" : "multicast");
161:
162: zlog_warn ("IRDP: Please correct settings\n");
163: return;
164: }
165:
166: switch (icmp->type)
167: {
168: case ICMP_ROUTERADVERT:
169: break;
170:
171: case ICMP_ROUTERSOLICIT:
172:
173: if(irdp->flags & IF_DEBUG_MESSAGES)
174: zlog_debug ("IRDP: RX Solicit on %s from %s\n",
175: ifp->name,
176: inet_ntoa (src));
177:
178: process_solicit(ifp);
179: break;
180:
181: default:
182: zlog_warn ("IRDP: RX type %d from %s. Bad ICMP type, silently ignored",
183: icmp->type,
184: inet_ntoa (src));
185: }
186: }
187:
188: static int
189: 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: msg.msg_name = (void *)0;
197: msg.msg_namelen = 0;
198: msg.msg_iov = &iov;
199: msg.msg_iovlen = 1;
200: msg.msg_control = (void *) adata;
201: msg.msg_controllen = sizeof adata;
202:
203: iov.iov_base = buf;
204: iov.iov_len = size;
205:
206: ret = recvmsg (sock, &msg, 0);
207: if (ret < 0) {
208: zlog_warn("IRDP: recvmsg: read error %s", safe_strerror(errno));
209: return ret;
210: }
211:
212: if (msg.msg_flags & MSG_TRUNC) {
213: zlog_warn("IRDP: recvmsg: truncated message");
214: return ret;
215: }
216: if (msg.msg_flags & MSG_CTRUNC) {
217: zlog_warn("IRDP: recvmsg: truncated control message");
218: return ret;
219: }
220:
221: *ifindex = getsockopt_ifindex (AF_INET, &msg);
222:
223: return ret;
224: }
225:
226: 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: int ret, ifindex = 0;
233:
234: int irdp_sock = THREAD_FD (r);
235: t_irdp_raw = thread_add_read (zebrad.master, irdp_read_raw, NULL, irdp_sock);
236:
237: ret = irdp_recvmsg (irdp_sock, (u_char *) buf, IRDP_RX_BUF, &ifindex);
238:
239: if (ret < 0) zlog_warn ("IRDP: RX Error length = %d", ret);
240:
241: ifp = if_lookup_by_index(ifindex);
242: if(! ifp ) return ret;
243:
244: zi= ifp->info;
245: if(! zi ) return ret;
246:
247: irdp = &zi->irdp;
248: if(! irdp ) return ret;
249:
250: if(! (irdp->flags & IF_ACTIVE)) {
251:
252: if(irdp->flags & IF_DEBUG_MISC)
253: zlog_debug("IRDP: RX ICMP for disabled interface %s\n", ifp->name);
254: return 0;
255: }
256:
257: if(irdp->flags & IF_DEBUG_PACKET) {
258: int i;
259: zlog_debug("IRDP: RX (idx %d) ", ifindex);
260: for(i=0; i < ret; i++) zlog_debug( "IRDP: RX %x ", buf[i]&0xFF);
261: }
262:
263: parse_irdp_packet(buf, ret, ifp);
264:
265: return ret;
266: }
267:
268: void
269: 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: if (!(ifp->flags & IFF_UP))
288: return;
289:
290: if (!p)
291: src = ntohl(p->u.prefix4.s_addr);
292: else
293: src = 0; /* Is filled in */
294:
295: ip = (struct ip *) buf;
296: ip->ip_hl = sizeof(struct ip) >> 2;
297: ip->ip_v = IPVERSION;
298: ip->ip_tos = 0xC0;
299: ip->ip_off = 0L;
300: ip->ip_p = 1; /* IP_ICMP */
301: ip->ip_ttl = ttl;
302: ip->ip_src.s_addr = src;
303: ip->ip_dst.s_addr = dst;
304: icmp = (struct icmphdr *) (buf + sizeof (struct ip));
305:
306: /* Merge IP header with icmp packet */
307: assert (stream_get_endp(s) < (sizeof (buf) - sizeof (struct ip)));
308: stream_get(icmp, s, stream_get_endp(s));
309:
310: /* icmp->checksum is already calculated */
311: ip->ip_len = sizeof(struct ip) + stream_get_endp(s);
312:
313: on = 1;
314: if (setsockopt(irdp_sock, IPPROTO_IP, IP_HDRINCL,
315: (char *) &on, sizeof(on)) < 0)
316: zlog_warn("sendto %s", safe_strerror (errno));
317:
318:
319: if(dst == INADDR_BROADCAST ) {
320: on = 1;
321: if (setsockopt(irdp_sock, SOL_SOCKET, SO_BROADCAST,
322: (char *) &on, sizeof(on)) < 0)
323: zlog_warn("sendto %s", safe_strerror (errno));
324: }
325:
326: if(dst != INADDR_BROADCAST) {
327: on = 0;
328: if( setsockopt(irdp_sock,IPPROTO_IP, IP_MULTICAST_LOOP,
329: (char *)&on,sizeof(on)) < 0)
330: zlog_warn("sendto %s", safe_strerror (errno));
331: }
332:
333: memset(&sockdst,0,sizeof(sockdst));
334: sockdst.sin_family=AF_INET;
335: sockdst.sin_addr.s_addr = dst;
336:
337: cmsg = (struct cmsghdr *) (msgbuf + sizeof(struct msghdr));
338: cmsg->cmsg_len = sizeof(struct cmsghdr) + sizeof(struct in_pktinfo);
339: cmsg->cmsg_level = SOL_IP;
340: cmsg->cmsg_type = IP_PKTINFO;
341: pktinfo = (struct in_pktinfo *) CMSG_DATA(cmsg);
342: pktinfo->ipi_ifindex = ifp->ifindex;
343: pktinfo->ipi_spec_dst.s_addr = src;
344: pktinfo->ipi_addr.s_addr = src;
345:
346: iovector.iov_base = (void *) buf;
347: iovector.iov_len = ip->ip_len;
348: msg = (struct msghdr *) msgbuf;
349: msg->msg_name = &sockdst;
350: msg->msg_namelen = sizeof(sockdst);
351: msg->msg_iov = &iovector;
352: msg->msg_iovlen = 1;
353: msg->msg_control = cmsg;
354: msg->msg_controllen = cmsg->cmsg_len;
355:
356: sockopt_iphdrincl_swab_htosys (ip);
357:
358: if (sendmsg(irdp_sock, msg, 0) < 0) {
359: 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:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>