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