1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include <netinet/icmp6.h>
5 #include "icmp6-packet.h"
6 #include "icmp6-util.h"
7 #include "in-addr-util.h"
8 #include "iovec-util.h"
9 #include "network-common.h"
10 #include "socket-util.h"
12 DEFINE_TRIVIAL_REF_UNREF_FUNC(ICMP6Packet
, icmp6_packet
, mfree
);
14 static ICMP6Packet
* icmp6_packet_new(size_t size
) {
17 if (size
> SIZE_MAX
- offsetof(ICMP6Packet
, raw_packet
))
20 p
= malloc0(offsetof(ICMP6Packet
, raw_packet
) + size
);
30 int icmp6_packet_set_sender_address(ICMP6Packet
*p
, const struct in6_addr
*addr
) {
34 p
->sender_address
= *addr
;
36 p
->sender_address
= (const struct in6_addr
) {};
41 int icmp6_packet_get_sender_address(ICMP6Packet
*p
, struct in6_addr
*ret
) {
44 if (in6_addr_is_null(&p
->sender_address
))
48 *ret
= p
->sender_address
;
52 int icmp6_packet_get_timestamp(ICMP6Packet
*p
, clockid_t clock
, usec_t
*ret
) {
56 if (!TRIPLE_TIMESTAMP_HAS_CLOCK(clock
) || !clock_supported(clock
))
59 if (!triple_timestamp_is_set(&p
->timestamp
))
62 *ret
= triple_timestamp_by_clock(&p
->timestamp
, clock
);
66 const struct icmp6_hdr
* icmp6_packet_get_header(ICMP6Packet
*p
) {
69 if (p
->raw_size
< sizeof(struct icmp6_hdr
))
72 return (const struct icmp6_hdr
*) p
->raw_packet
;
75 int icmp6_packet_get_type(ICMP6Packet
*p
) {
76 const struct icmp6_hdr
*hdr
= icmp6_packet_get_header(p
);
80 return hdr
->icmp6_type
;
83 static int icmp6_packet_verify(ICMP6Packet
*p
) {
84 const struct icmp6_hdr
*hdr
= icmp6_packet_get_header(p
);
88 if (hdr
->icmp6_code
!= 0)
91 /* Drop any overly large packets early. We are not interested in jumbograms,
92 * which could cause excessive processing. */
93 if (p
->raw_size
> ICMP6_MAX_NORMAL_PAYLOAD_SIZE
)
99 int icmp6_packet_receive(int fd
, ICMP6Packet
**ret
) {
100 _cleanup_(icmp6_packet_unrefp
) ICMP6Packet
*p
= NULL
;
107 len
= next_datagram_size_fd(fd
);
111 p
= icmp6_packet_new(len
);
115 r
= icmp6_receive(fd
, p
->raw_packet
, p
->raw_size
, &p
->sender_address
, &p
->timestamp
);
116 if (r
== -EADDRNOTAVAIL
)
117 return log_debug_errno(r
, "ICMPv6: Received a packet from neither link-local nor null address.");
119 return log_debug_errno(r
, "ICMPv6: Received a packet with an invalid hop limit.");
120 if (r
== -EPFNOSUPPORT
)
121 return log_debug_errno(r
, "ICMPv6: Received a packet with an invalid source address.");
123 return log_debug_errno(r
, "ICMPv6: Unexpected error while receiving a packet: %m");
125 r
= icmp6_packet_verify(p
);