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/zebra_router.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 
parse_irdp_packet(char * p,int len,struct interface * ifp)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 	uint16_t saved_chksum;
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 %s\n",
108 			 inet_ntoa(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 %s\n",
119 			 inet_ntoa(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 %s. Bad checksum, silently ignored",
132 			inet_ntoa(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 %s. Bad ICMP type code, silently ignored",
145 			icmp->type, inet_ntoa(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 %s to %s while %s operates in %s; Please correct settings\n",
156 			inet_ntoa(src),
157 			ntohl(ip->ip_dst.s_addr) == INADDR_ALLRTRS_GROUP
158 				? "multicast"
159 				: inet_ntoa(ip->ip_dst),
160 			ifp->name,
161 			irdp->flags & IF_BROADCAST ? "broadcast" : "multicast");
162 		return;
163 	}
164 
165 	switch (icmp->type) {
166 	case ICMP_ROUTERADVERT:
167 		break;
168 
169 	case ICMP_ROUTERSOLICIT:
170 
171 		if (irdp->flags & IF_DEBUG_MESSAGES)
172 			zlog_debug("IRDP: RX Solicit on %s from %s",
173 				   ifp->name, inet_ntoa(src));
174 
175 		process_solicit(ifp);
176 		break;
177 
178 	default:
179 		flog_warn(
180 			EC_ZEBRA_IRDP_BAD_TYPE_CODE,
181 			"IRDP: RX packet type %d from %s. Bad ICMP type code, silently ignored",
182 			icmp->type, inet_ntoa(src));
183 	}
184 }
185 
irdp_recvmsg(int sock,uint8_t * buf,int size,int * ifindex)186 static int irdp_recvmsg(int sock, uint8_t *buf, int size, int *ifindex)
187 {
188 	struct msghdr msg;
189 	struct iovec iov;
190 	char adata[CMSG_SPACE(SOPT_SIZE_CMSG_PKTINFO_IPV4())];
191 	int ret;
192 
193 	memset(&msg, 0, sizeof(msg));
194 	msg.msg_name = (void *)0;
195 	msg.msg_namelen = 0;
196 	msg.msg_iov = &iov;
197 	msg.msg_iovlen = 1;
198 	msg.msg_control = (void *)adata;
199 	msg.msg_controllen = sizeof(adata);
200 
201 	iov.iov_base = buf;
202 	iov.iov_len = size;
203 
204 	ret = recvmsg(sock, &msg, 0);
205 	if (ret < 0) {
206 		flog_warn(EC_LIB_SOCKET, "IRDP: recvmsg: read error %s",
207 			  safe_strerror(errno));
208 		return ret;
209 	}
210 
211 	if (msg.msg_flags & MSG_TRUNC) {
212 		flog_warn(EC_LIB_SOCKET, "IRDP: recvmsg: truncated message");
213 		return ret;
214 	}
215 	if (msg.msg_flags & MSG_CTRUNC) {
216 		flog_warn(EC_LIB_SOCKET,
217 			  "IRDP: recvmsg: truncated control message");
218 		return ret;
219 	}
220 
221 	*ifindex = getsockopt_ifindex(AF_INET, &msg);
222 
223 	return ret;
224 }
225 
irdp_read_raw(struct thread * r)226 int irdp_read_raw(struct thread *r)
227 {
228 	struct interface *ifp;
229 	struct zebra_if *zi;
230 	struct irdp_interface *irdp;
231 	char buf[IRDP_RX_BUF];
232 	int ret, ifindex = 0;
233 
234 	int irdp_sock = THREAD_FD(r);
235 	t_irdp_raw = NULL;
236 	thread_add_read(zrouter.master, irdp_read_raw, NULL, irdp_sock,
237 			&t_irdp_raw);
238 
239 	ret = irdp_recvmsg(irdp_sock, (uint8_t *)buf, IRDP_RX_BUF, &ifindex);
240 
241 	if (ret < 0)
242 		flog_warn(EC_LIB_SOCKET, "IRDP: RX Error length = %d", ret);
243 
244 	ifp = if_lookup_by_index(ifindex, VRF_DEFAULT);
245 	if (!ifp)
246 		return ret;
247 
248 	zi = ifp->info;
249 	if (!zi)
250 		return ret;
251 
252 	irdp = zi->irdp;
253 	if (!irdp)
254 		return ret;
255 
256 	if (!(irdp->flags & IF_ACTIVE)) {
257 
258 		if (irdp->flags & IF_DEBUG_MISC)
259 			zlog_debug("IRDP: RX ICMP for disabled interface %s",
260 				   ifp->name);
261 		return 0;
262 	}
263 
264 	if (irdp->flags & IF_DEBUG_PACKET) {
265 		int i;
266 		zlog_debug("IRDP: RX (idx %d) ", ifindex);
267 		for (i = 0; i < ret; i++)
268 			zlog_debug("IRDP: RX %x ", buf[i] & 0xFF);
269 	}
270 
271 	parse_irdp_packet(buf, ret, ifp);
272 
273 	return ret;
274 }
275 
send_packet(struct interface * ifp,struct stream * s,uint32_t dst,struct prefix * p,uint32_t ttl)276 void send_packet(struct interface *ifp, struct stream *s, uint32_t dst,
277 		 struct prefix *p, uint32_t ttl)
278 {
279 	static struct sockaddr_in sockdst = {AF_INET};
280 	struct ip *ip;
281 	struct icmphdr *icmp;
282 	struct msghdr *msg;
283 	struct cmsghdr *cmsg;
284 	struct iovec iovector;
285 	char msgbuf[256];
286 	char buf[256];
287 	struct in_pktinfo *pktinfo;
288 	unsigned long src;
289 	uint8_t on;
290 
291 	if (!(ifp->flags & IFF_UP))
292 		return;
293 
294 	if (p)
295 		src = ntohl(p->u.prefix4.s_addr);
296 	else
297 		src = 0; /* Is filled in */
298 
299 	ip = (struct ip *)buf;
300 	ip->ip_hl = sizeof(struct ip) >> 2;
301 	ip->ip_v = IPVERSION;
302 	ip->ip_tos = 0xC0;
303 	ip->ip_off = 0L;
304 	ip->ip_p = 1; /* IP_ICMP */
305 	ip->ip_ttl = ttl;
306 	ip->ip_src.s_addr = src;
307 	ip->ip_dst.s_addr = dst;
308 	icmp = (struct icmphdr *)(buf + sizeof(struct ip));
309 
310 	/* Merge IP header with icmp packet */
311 	assert(stream_get_endp(s) < (sizeof(buf) - sizeof(struct ip)));
312 	stream_get(icmp, s, stream_get_endp(s));
313 
314 	/* icmp->checksum is already calculated */
315 	ip->ip_len = sizeof(struct ip) + stream_get_endp(s);
316 
317 	on = 1;
318 	if (setsockopt(irdp_sock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
319 		       sizeof(on))
320 	    < 0)
321 		flog_err(EC_LIB_SOCKET,
322 			 "IRDP: Cannot set IP_HDRINCLU %s(%d) on %s",
323 			 safe_strerror(errno), errno, ifp->name);
324 
325 
326 	if (dst == INADDR_BROADCAST) {
327 		uint32_t bon = 1;
328 
329 		if (setsockopt(irdp_sock, SOL_SOCKET, SO_BROADCAST, &bon,
330 			       sizeof(bon))
331 		    < 0)
332 			flog_err(EC_LIB_SOCKET,
333 				 "IRDP: Cannot set SO_BROADCAST %s(%d) on %s",
334 				 safe_strerror(errno), errno, ifp->name);
335 	}
336 
337 	if (dst != INADDR_BROADCAST)
338 		setsockopt_ipv4_multicast_loop(irdp_sock, 0);
339 
340 	memset(&sockdst, 0, sizeof(sockdst));
341 	sockdst.sin_family = AF_INET;
342 	sockdst.sin_addr.s_addr = dst;
343 
344 	cmsg = (struct cmsghdr *)(msgbuf + sizeof(struct msghdr));
345 	cmsg->cmsg_len = sizeof(struct cmsghdr) + sizeof(struct in_pktinfo);
346 	cmsg->cmsg_level = SOL_IP;
347 	cmsg->cmsg_type = IP_PKTINFO;
348 	pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
349 	pktinfo->ipi_ifindex = ifp->ifindex;
350 	pktinfo->ipi_spec_dst.s_addr = src;
351 	pktinfo->ipi_addr.s_addr = src;
352 
353 	iovector.iov_base = (void *)buf;
354 	iovector.iov_len = ip->ip_len;
355 	msg = (struct msghdr *)msgbuf;
356 	msg->msg_name = &sockdst;
357 	msg->msg_namelen = sizeof(sockdst);
358 	msg->msg_iov = &iovector;
359 	msg->msg_iovlen = 1;
360 	msg->msg_control = cmsg;
361 	msg->msg_controllen = cmsg->cmsg_len;
362 
363 	sockopt_iphdrincl_swab_htosys(ip);
364 
365 	if (sendmsg(irdp_sock, msg, 0) < 0)
366 		flog_err(EC_LIB_SOCKET,
367 			 "IRDP: sendmsg send failure %s(%d) on %s",
368 			 safe_strerror(errno), errno, ifp->name);
369 }
370