]> git.proxmox.com Git - mirror_frr.git/blame - zebra/irdp_packet.c
Merge pull request #8035 from qlyoung/remove-more-sprintf
[mirror_frr.git] / zebra / irdp_packet.c
CommitLineData
ca776988 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 *
896014f4
DL
18 * You should have received a copy of the GNU General Public License along
19 * with this program; see the file COPYING; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
ca776988 21 */
22
d62a17ae 23/*
ca776988 24 * This work includes work with the following copywrite:
25 *
26 * Copyright (C) 1997, 2000 Kunihiro Ishiguro
27 *
28 */
29
d62a17ae 30/*
43e52561 31 * Thanks to Jens Laas at Swedish University of Agricultural Sciences
ca776988 32 * for reviewing and tests.
33 */
34
35
36#include <zebra.h>
43e52561 37#include <netinet/ip_icmp.h>
ca776988 38
43e52561 39#include "checksum.h"
ca776988 40#include "command.h"
ca776988 41#include "connected.h"
43e52561
QY
42#include "if.h"
43#include "ioctl.h"
ca776988 44#include "log.h"
43e52561
QY
45#include "log.h"
46#include "memory.h"
47#include "prefix.h"
48#include "sockopt.h"
49#include "sockunion.h"
50#include "sockunion.h"
51#include "stream.h"
ca776988 52#include "thread.h"
43e52561
QY
53#include "vty.h"
54#include "zclient.h"
9df414fe 55#include "lib_errors.h"
43e52561
QY
56
57#include "zebra_memory.h"
ca776988 58#include "zebra/interface.h"
59#include "zebra/rtadv.h"
60#include "zebra/rib.h"
3801e764 61#include "zebra/zebra_router.h"
ca776988 62#include "zebra/redistribute.h"
63#include "zebra/irdp.h"
43e52561 64#include "zebra/zebra_errors.h"
ca776988 65
66
67/* GLOBAL VARS */
68
2da40f49 69int irdp_sock = -1;
ca776988 70
ca776988 71extern struct thread *t_irdp_raw;
ca776988 72
d62a17ae 73static void parse_irdp_packet(char *p, int len, struct interface *ifp)
ca776988 74{
d62a17ae 75 struct ip *ip = (struct ip *)p;
76 struct icmphdr *icmp;
77 struct in_addr src;
78 int ip_hlen, iplen, datalen;
79 struct zebra_if *zi;
80 struct irdp_interface *irdp;
30b544ed 81 uint16_t saved_chksum;
9bcef951 82 char buf[PREFIX_STRLEN];
d62a17ae 83
84 zi = ifp->info;
85 if (!zi)
86 return;
87
ead4ee99 88 irdp = zi->irdp;
d62a17ae 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) {
e914ccbe 101 flog_err(EC_ZEBRA_IRDP_LEN_MISMATCH,
0437e105 102 "IRDP: RX length doesn't match IP length");
d62a17ae 103 return;
104 }
105
106 if (iplen < ICMP_MINLEN) {
e914ccbe 107 flog_err(EC_ZEBRA_IRDP_LEN_MISMATCH,
1d5453d6 108 "IRDP: RX ICMP packet too short from %pI4",
9bcef951 109 &src);
d62a17ae 110 return;
111 }
112
0437e105 113 /* XXX: RAW doesn't receive link-layer, surely? ??? */
d62a17ae 114 /* Check so we don't checksum packets longer than oure RX_BUF - (ethlen
115 +
116 len of IP-header) 14+20 */
117 if (iplen > IRDP_RX_BUF - 34) {
e914ccbe 118 flog_err(EC_ZEBRA_IRDP_LEN_MISMATCH,
1d5453d6 119 "IRDP: RX ICMP packet too long from %pI4",
9bcef951 120 &src);
d62a17ae 121 return;
122 }
123
124 icmp = (struct icmphdr *)(p + ip_hlen);
125
30b544ed
DS
126 saved_chksum = icmp->checksum;
127 icmp->checksum = 0;
d62a17ae 128 /* check icmp checksum */
30b544ed 129 if (in_cksum(icmp, datalen) != saved_chksum) {
9df414fe 130 flog_warn(
e914ccbe 131 EC_ZEBRA_IRDP_BAD_CHECKSUM,
9bcef951
MS
132 "IRDP: RX ICMP packet from %pI4 Bad checksum, silently ignored",
133 &src);
d62a17ae 134 return;
135 }
136
137 /* Handle just only IRDP */
138 if (!(icmp->type == ICMP_ROUTERADVERT
139 || icmp->type == ICMP_ROUTERSOLICIT))
140 return;
141
142 if (icmp->code != 0) {
f203510a
QY
143 flog_warn(
144 EC_ZEBRA_IRDP_BAD_TYPE_CODE,
9bcef951
MS
145 "IRDP: RX packet type %d from %pI4 Bad ICMP type code, silently ignored",
146 icmp->type, &src);
d62a17ae 147 return;
148 }
149
150 if (!((ntohl(ip->ip_dst.s_addr) == INADDR_BROADCAST)
151 && (irdp->flags & IF_BROADCAST))
152 || (ntohl(ip->ip_dst.s_addr) == INADDR_ALLRTRS_GROUP
153 && !(irdp->flags & IF_BROADCAST))) {
9df414fe 154 flog_warn(
e914ccbe 155 EC_ZEBRA_IRDP_BAD_RX_FLAGS,
1d5453d6 156 "IRDP: RX illegal from %pI4 to %s while %s operates in %s; Please correct settings",
9bcef951 157 &src,
d62a17ae 158 ntohl(ip->ip_dst.s_addr) == INADDR_ALLRTRS_GROUP
159 ? "multicast"
9bcef951
MS
160 : inet_ntop(AF_INET, &ip->ip_dst,
161 buf, sizeof(buf)),
d62a17ae 162 ifp->name,
163 irdp->flags & IF_BROADCAST ? "broadcast" : "multicast");
d62a17ae 164 return;
165 }
166
167 switch (icmp->type) {
168 case ICMP_ROUTERADVERT:
169 break;
170
171 case ICMP_ROUTERSOLICIT:
172
173 if (irdp->flags & IF_DEBUG_MESSAGES)
9bcef951
MS
174 zlog_debug("IRDP: RX Solicit on %s from %pI4",
175 ifp->name, &src);
d62a17ae 176
177 process_solicit(ifp);
178 break;
179
180 default:
9df414fe 181 flog_warn(
f203510a 182 EC_ZEBRA_IRDP_BAD_TYPE_CODE,
9bcef951
MS
183 "IRDP: RX packet type %d from %pI4 Bad ICMP type code, silently ignored",
184 icmp->type, &src);
d62a17ae 185 }
ca776988 186}
6b0655a2 187
d7c0a89a 188static int irdp_recvmsg(int sock, uint8_t *buf, int size, int *ifindex)
ca776988 189{
d62a17ae 190 struct msghdr msg;
191 struct iovec iov;
192 char adata[CMSG_SPACE(SOPT_SIZE_CMSG_PKTINFO_IPV4())];
193 int ret;
194
0af35d90 195 memset(&msg, 0, sizeof(msg));
d62a17ae 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;
0d6f7fd6 201 msg.msg_controllen = sizeof(adata);
d62a17ae 202
203 iov.iov_base = buf;
204 iov.iov_len = size;
205
206 ret = recvmsg(sock, &msg, 0);
207 if (ret < 0) {
450971aa 208 flog_warn(EC_LIB_SOCKET, "IRDP: recvmsg: read error %s",
9df414fe 209 safe_strerror(errno));
d62a17ae 210 return ret;
211 }
212
213 if (msg.msg_flags & MSG_TRUNC) {
450971aa 214 flog_warn(EC_LIB_SOCKET, "IRDP: recvmsg: truncated message");
d62a17ae 215 return ret;
216 }
217 if (msg.msg_flags & MSG_CTRUNC) {
450971aa 218 flog_warn(EC_LIB_SOCKET,
9df414fe 219 "IRDP: recvmsg: truncated control message");
d62a17ae 220 return ret;
221 }
222
223 *ifindex = getsockopt_ifindex(AF_INET, &msg);
224
225 return ret;
ca776988 226}
6b0655a2 227
ca776988 228int irdp_read_raw(struct thread *r)
229{
d62a17ae 230 struct interface *ifp;
231 struct zebra_if *zi;
232 struct irdp_interface *irdp;
233 char buf[IRDP_RX_BUF];
234 int ret, ifindex = 0;
235
236 int irdp_sock = THREAD_FD(r);
237 t_irdp_raw = NULL;
3801e764 238 thread_add_read(zrouter.master, irdp_read_raw, NULL, irdp_sock,
d62a17ae 239 &t_irdp_raw);
240
d7c0a89a 241 ret = irdp_recvmsg(irdp_sock, (uint8_t *)buf, IRDP_RX_BUF, &ifindex);
d62a17ae 242
243 if (ret < 0)
450971aa 244 flog_warn(EC_LIB_SOCKET, "IRDP: RX Error length = %d", ret);
d62a17ae 245
246 ifp = if_lookup_by_index(ifindex, VRF_DEFAULT);
247 if (!ifp)
248 return ret;
249
250 zi = ifp->info;
251 if (!zi)
252 return ret;
253
ead4ee99 254 irdp = zi->irdp;
d62a17ae 255 if (!irdp)
256 return ret;
257
258 if (!(irdp->flags & IF_ACTIVE)) {
259
260 if (irdp->flags & IF_DEBUG_MISC)
9165c5f5 261 zlog_debug("IRDP: RX ICMP for disabled interface %s",
d62a17ae 262 ifp->name);
263 return 0;
264 }
265
266 if (irdp->flags & IF_DEBUG_PACKET) {
267 int i;
268 zlog_debug("IRDP: RX (idx %d) ", ifindex);
269 for (i = 0; i < ret; i++)
270 zlog_debug("IRDP: RX %x ", buf[i] & 0xFF);
271 }
272
273 parse_irdp_packet(buf, ret, ifp);
274
275 return ret;
ca776988 276}
6b0655a2 277
d7c0a89a
QY
278void send_packet(struct interface *ifp, struct stream *s, uint32_t dst,
279 struct prefix *p, uint32_t ttl)
ca776988 280{
d62a17ae 281 static struct sockaddr_in sockdst = {AF_INET};
282 struct ip *ip;
283 struct icmphdr *icmp;
284 struct msghdr *msg;
285 struct cmsghdr *cmsg;
286 struct iovec iovector;
287 char msgbuf[256];
288 char buf[256];
289 struct in_pktinfo *pktinfo;
d7c0a89a
QY
290 unsigned long src;
291 uint8_t on;
d62a17ae 292
293 if (!(ifp->flags & IFF_UP))
294 return;
295
296 if (p)
297 src = ntohl(p->u.prefix4.s_addr);
298 else
299 src = 0; /* Is filled in */
300
301 ip = (struct ip *)buf;
302 ip->ip_hl = sizeof(struct ip) >> 2;
303 ip->ip_v = IPVERSION;
304 ip->ip_tos = 0xC0;
305 ip->ip_off = 0L;
306 ip->ip_p = 1; /* IP_ICMP */
307 ip->ip_ttl = ttl;
308 ip->ip_src.s_addr = src;
309 ip->ip_dst.s_addr = dst;
310 icmp = (struct icmphdr *)(buf + sizeof(struct ip));
311
312 /* Merge IP header with icmp packet */
313 assert(stream_get_endp(s) < (sizeof(buf) - sizeof(struct ip)));
314 stream_get(icmp, s, stream_get_endp(s));
315
316 /* icmp->checksum is already calculated */
317 ip->ip_len = sizeof(struct ip) + stream_get_endp(s);
318
319 on = 1;
320 if (setsockopt(irdp_sock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
321 sizeof(on))
322 < 0)
3d0deb9c
DS
323 flog_err(EC_LIB_SOCKET,
324 "IRDP: Cannot set IP_HDRINCLU %s(%d) on %s",
325 safe_strerror(errno), errno, ifp->name);
d62a17ae 326
327
328 if (dst == INADDR_BROADCAST) {
08fa52a8
DS
329 uint32_t bon = 1;
330
331 if (setsockopt(irdp_sock, SOL_SOCKET, SO_BROADCAST, &bon,
332 sizeof(bon))
d62a17ae 333 < 0)
3d0deb9c
DS
334 flog_err(EC_LIB_SOCKET,
335 "IRDP: Cannot set SO_BROADCAST %s(%d) on %s",
336 safe_strerror(errno), errno, ifp->name);
d62a17ae 337 }
338
339 if (dst != INADDR_BROADCAST)
340 setsockopt_ipv4_multicast_loop(irdp_sock, 0);
341
342 memset(&sockdst, 0, sizeof(sockdst));
343 sockdst.sin_family = AF_INET;
344 sockdst.sin_addr.s_addr = dst;
345
346 cmsg = (struct cmsghdr *)(msgbuf + sizeof(struct msghdr));
347 cmsg->cmsg_len = sizeof(struct cmsghdr) + sizeof(struct in_pktinfo);
348 cmsg->cmsg_level = SOL_IP;
349 cmsg->cmsg_type = IP_PKTINFO;
350 pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
351 pktinfo->ipi_ifindex = ifp->ifindex;
352 pktinfo->ipi_spec_dst.s_addr = src;
353 pktinfo->ipi_addr.s_addr = src;
354
355 iovector.iov_base = (void *)buf;
356 iovector.iov_len = ip->ip_len;
357 msg = (struct msghdr *)msgbuf;
358 msg->msg_name = &sockdst;
359 msg->msg_namelen = sizeof(sockdst);
360 msg->msg_iov = &iovector;
361 msg->msg_iovlen = 1;
362 msg->msg_control = cmsg;
363 msg->msg_controllen = cmsg->cmsg_len;
364
365 sockopt_iphdrincl_swab_htosys(ip);
366
3d0deb9c
DS
367 if (sendmsg(irdp_sock, msg, 0) < 0)
368 flog_err(EC_LIB_SOCKET,
369 "IRDP: sendmsg send failure %s(%d) on %s",
370 safe_strerror(errno), errno, ifp->name);
ca776988 371}