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