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