1 // SPDX-License-Identifier: GPL-2.0-or-later
4 * Copyright (C) 2000 Robert Olsson.
5 * Swedish University of Agricultural Sciences
9 * This work includes work with the following copywrite:
11 * Copyright (C) 1997, 2000 Kunihiro Ishiguro
16 * Thanks to Jens Laas at Swedish University of Agricultural Sciences
17 * for reviewing and tests.
22 #include <netinet/ip_icmp.h>
26 #include "connected.h"
34 #include "sockunion.h"
35 #include "sockunion.h"
40 #include "lib_errors.h"
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"
55 extern struct thread
*t_irdp_raw
;
57 static void parse_irdp_packet(char *p
, int len
, struct interface
*ifp
)
59 struct ip
*ip
= (struct ip
*)p
;
62 int ip_hlen
, iplen
, datalen
;
64 struct irdp_interface
*irdp
;
65 uint16_t saved_chksum
;
66 char buf
[PREFIX_STRLEN
];
76 ip_hlen
= ip
->ip_hl
<< 2;
78 sockopt_iphdrincl_swab_systoh(ip
);
81 datalen
= len
- ip_hlen
;
85 flog_err(EC_ZEBRA_IRDP_LEN_MISMATCH
,
86 "IRDP: RX length doesn't match IP length");
90 if (iplen
< ICMP_MINLEN
) {
91 flog_err(EC_ZEBRA_IRDP_LEN_MISMATCH
,
92 "IRDP: RX ICMP packet too short from %pI4",
97 /* XXX: RAW doesn't receive link-layer, surely? ??? */
98 /* Check so we don't checksum packets longer than oure RX_BUF - (ethlen
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",
108 icmp
= (struct icmphdr
*)(p
+ ip_hlen
);
110 saved_chksum
= icmp
->checksum
;
112 /* check icmp checksum */
113 if (in_cksum(icmp
, datalen
) != saved_chksum
) {
115 EC_ZEBRA_IRDP_BAD_CHECKSUM
,
116 "IRDP: RX ICMP packet from %pI4 Bad checksum, silently ignored",
121 /* Handle just only IRDP */
122 if (!(icmp
->type
== ICMP_ROUTERADVERT
123 || icmp
->type
== ICMP_ROUTERSOLICIT
))
126 if (icmp
->code
!= 0) {
128 EC_ZEBRA_IRDP_BAD_TYPE_CODE
,
129 "IRDP: RX packet type %d from %pI4 Bad ICMP type code, silently ignored",
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
))) {
139 EC_ZEBRA_IRDP_BAD_RX_FLAGS
,
140 "IRDP: RX illegal from %pI4 to %s while %s operates in %s; Please correct settings",
142 ntohl(ip
->ip_dst
.s_addr
) == INADDR_ALLRTRS_GROUP
144 : inet_ntop(AF_INET
, &ip
->ip_dst
,
147 irdp
->flags
& IF_BROADCAST
? "broadcast" : "multicast");
151 switch (icmp
->type
) {
152 case ICMP_ROUTERADVERT
:
155 case ICMP_ROUTERSOLICIT
:
157 if (irdp
->flags
& IF_DEBUG_MESSAGES
)
158 zlog_debug("IRDP: RX Solicit on %s from %pI4",
161 process_solicit(ifp
);
166 EC_ZEBRA_IRDP_BAD_TYPE_CODE
,
167 "IRDP: RX packet type %d from %pI4 Bad ICMP type code, silently ignored",
172 static int irdp_recvmsg(int sock
, uint8_t *buf
, int size
, int *ifindex
)
176 char adata
[CMSG_SPACE(SOPT_SIZE_CMSG_PKTINFO_IPV4())];
179 memset(&msg
, 0, sizeof(msg
));
180 msg
.msg_name
= (void *)0;
184 msg
.msg_control
= (void *)adata
;
185 msg
.msg_controllen
= sizeof(adata
);
190 ret
= recvmsg(sock
, &msg
, 0);
192 flog_warn(EC_LIB_SOCKET
, "IRDP: recvmsg: read error %s",
193 safe_strerror(errno
));
197 if (msg
.msg_flags
& MSG_TRUNC
) {
198 flog_warn(EC_LIB_SOCKET
, "IRDP: recvmsg: truncated message");
201 if (msg
.msg_flags
& MSG_CTRUNC
) {
202 flog_warn(EC_LIB_SOCKET
,
203 "IRDP: recvmsg: truncated control message");
207 *ifindex
= getsockopt_ifindex(AF_INET
, &msg
);
212 void irdp_read_raw(struct thread
*r
)
214 struct interface
*ifp
;
216 struct irdp_interface
*irdp
;
217 char buf
[IRDP_RX_BUF
];
218 int ret
, ifindex
= 0;
220 int irdp_sock
= THREAD_FD(r
);
221 thread_add_read(zrouter
.master
, irdp_read_raw
, NULL
, irdp_sock
,
224 ret
= irdp_recvmsg(irdp_sock
, (uint8_t *)buf
, IRDP_RX_BUF
, &ifindex
);
227 flog_warn(EC_LIB_SOCKET
, "IRDP: RX Error length = %d", ret
);
229 ifp
= if_lookup_by_index(ifindex
, VRF_DEFAULT
);
241 if (!(irdp
->flags
& IF_ACTIVE
)) {
243 if (irdp
->flags
& IF_DEBUG_MISC
)
244 zlog_debug("IRDP: RX ICMP for disabled interface %s",
249 if (irdp
->flags
& IF_DEBUG_PACKET
) {
251 zlog_debug("IRDP: RX (idx %d) ", ifindex
);
252 for (i
= 0; i
< ret
; i
++)
253 zlog_debug("IRDP: RX %x ", buf
[i
] & 0xFF);
256 parse_irdp_packet(buf
, ret
, ifp
);
259 void send_packet(struct interface
*ifp
, struct stream
*s
, uint32_t dst
,
260 struct prefix
*p
, uint32_t ttl
)
262 static struct sockaddr_in sockdst
= {AF_INET
};
264 struct icmphdr
*icmp
;
266 struct cmsghdr
*cmsg
;
267 struct iovec iovector
;
270 struct in_pktinfo
*pktinfo
;
274 if (!(ifp
->flags
& IFF_UP
))
278 src
= ntohl(p
->u
.prefix4
.s_addr
);
280 src
= 0; /* Is filled in */
282 ip
= (struct ip
*)buf
;
283 ip
->ip_hl
= sizeof(struct ip
) >> 2;
284 ip
->ip_v
= IPVERSION
;
287 ip
->ip_p
= 1; /* IP_ICMP */
289 ip
->ip_src
.s_addr
= src
;
290 ip
->ip_dst
.s_addr
= dst
;
291 icmp
= (struct icmphdr
*)(buf
+ sizeof(struct ip
));
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
));
297 /* icmp->checksum is already calculated */
298 ip
->ip_len
= sizeof(struct ip
) + stream_get_endp(s
);
301 if (setsockopt(irdp_sock
, IPPROTO_IP
, IP_HDRINCL
, (char *)&on
,
304 flog_err(EC_LIB_SOCKET
,
305 "IRDP: Cannot set IP_HDRINCLU %s(%d) on %s",
306 safe_strerror(errno
), errno
, ifp
->name
);
309 if (dst
== INADDR_BROADCAST
) {
312 if (setsockopt(irdp_sock
, SOL_SOCKET
, SO_BROADCAST
, &bon
,
315 flog_err(EC_LIB_SOCKET
,
316 "IRDP: Cannot set SO_BROADCAST %s(%d) on %s",
317 safe_strerror(errno
), errno
, ifp
->name
);
320 if (dst
!= INADDR_BROADCAST
)
321 setsockopt_ipv4_multicast_loop(irdp_sock
, 0);
323 memset(&sockdst
, 0, sizeof(sockdst
));
324 sockdst
.sin_family
= AF_INET
;
325 sockdst
.sin_addr
.s_addr
= dst
;
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
;
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
;
343 msg
->msg_control
= cmsg
;
344 msg
->msg_controllen
= cmsg
->cmsg_len
;
346 sockopt_iphdrincl_swab_htosys(ip
);
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
);