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