]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/icmp6-packet.c
Merge pull request #31899 from yuwata/sd-journal-add-match
[thirdparty/systemd.git] / src / libsystemd-network / icmp6-packet.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <netinet/icmp6.h>
4
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"
11
12 DEFINE_TRIVIAL_REF_UNREF_FUNC(ICMP6Packet, icmp6_packet, mfree);
13
14 static ICMP6Packet* icmp6_packet_new(size_t size) {
15 ICMP6Packet *p;
16
17 if (size > SIZE_MAX - offsetof(ICMP6Packet, raw_packet))
18 return NULL;
19
20 p = malloc0(offsetof(ICMP6Packet, raw_packet) + size);
21 if (!p)
22 return NULL;
23
24 p->raw_size = size;
25 p->n_ref = 1;
26
27 return p;
28 }
29
30 int icmp6_packet_get_sender_address(ICMP6Packet *p, struct in6_addr *ret) {
31 assert(p);
32
33 if (in6_addr_is_null(&p->sender_address))
34 return -ENODATA;
35
36 if (ret)
37 *ret = p->sender_address;
38 return 0;
39 }
40
41 int icmp6_packet_get_timestamp(ICMP6Packet *p, clockid_t clock, usec_t *ret) {
42 assert(p);
43 assert(ret);
44
45 if (!TRIPLE_TIMESTAMP_HAS_CLOCK(clock) || !clock_supported(clock))
46 return -EOPNOTSUPP;
47
48 if (!triple_timestamp_is_set(&p->timestamp))
49 return -ENODATA;
50
51 *ret = triple_timestamp_by_clock(&p->timestamp, clock);
52 return 0;
53 }
54
55 const struct icmp6_hdr* icmp6_packet_get_header(ICMP6Packet *p) {
56 assert(p);
57
58 if (p->raw_size < sizeof(struct icmp6_hdr))
59 return NULL;
60
61 return (const struct icmp6_hdr*) p->raw_packet;
62 }
63
64 int icmp6_packet_get_type(ICMP6Packet *p) {
65 const struct icmp6_hdr *hdr = icmp6_packet_get_header(p);
66 if (!hdr)
67 return -EBADMSG;
68
69 return hdr->icmp6_type;
70 }
71
72 static int icmp6_packet_verify(ICMP6Packet *p) {
73 const struct icmp6_hdr *hdr = icmp6_packet_get_header(p);
74 if (!hdr)
75 return -EBADMSG;
76
77 if (hdr->icmp6_code != 0)
78 return -EBADMSG;
79
80 return 0;
81 }
82
83 int icmp6_packet_receive(int fd, ICMP6Packet **ret) {
84 _cleanup_(icmp6_packet_unrefp) ICMP6Packet *p = NULL;
85 ssize_t len;
86 int r;
87
88 assert(fd >= 0);
89 assert(ret);
90
91 len = next_datagram_size_fd(fd);
92 if (len < 0)
93 return (int) len;
94
95 p = icmp6_packet_new(len);
96 if (!p)
97 return -ENOMEM;
98
99 r = icmp6_receive(fd, p->raw_packet, p->raw_size, &p->sender_address, &p->timestamp);
100 if (r < 0)
101 switch (r) {
102 case -EADDRNOTAVAIL:
103 return log_debug_errno(r, "ICMPv6: Received a packet from neither link-local nor null address.");
104
105 case -EMULTIHOP:
106 return log_debug_errno(r, "ICMPv6: Received a packet with an invalid hop limit.");
107
108 case -EPFNOSUPPORT:
109 return log_debug_errno(r, "ICMPv6: Received a packet with an invalid source address.");
110
111 default:
112 return log_debug_errno(r, "ICMPv6: Unexpected error while receiving a packet: %m");
113 }
114
115 r = icmp6_packet_verify(p);
116 if (r < 0)
117 return r;
118
119 *ret = TAKE_PTR(p);
120 return 0;
121 }