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