master
hxx 106 lines 3.07 KB
Raw
1 // Copyright (C) Microsoft Corporation. All rights reserved.
2 #pragma once
3
4 #include <format>
5 #include <string>
6 #include <linux/if_link.h>
7
8 #include "NetlinkMessage.h"
9 #include "NetlinkParseException.h"
10
11 template <typename TMessage>
12 NetlinkMessage<TMessage>::NetlinkMessage(const NetlinkResponse& response, Titerator responseBegin, Titerator begin, Titerator end) :
13 m_response(response), m_responseBegin(responseBegin), m_begin(begin), m_end(end)
14 {
15 }
16
17 template <typename TMessage>
18 const TMessage* NetlinkMessage<TMessage>::Payload() const
19 {
20 const auto* data = reinterpret_cast<const char*>(NLMSG_DATA(&*m_begin));
21 if (data + sizeof(TMessage) > &*m_end)
22 {
23 throw NetlinkParseException(
24 m_response,
25 std::format(
26 "Message at offset {}: attempted to access beyond message offset ({} > {})",
27 (m_begin - m_responseBegin),
28 sizeof(TMessage),
29 (m_end - m_begin)));
30 }
31
32 return reinterpret_cast<const TMessage*>(NLMSG_DATA(&*m_begin));
33 }
34
35 template <>
36 inline const rtattr* NetlinkMessage<rtmsg>::FirstAttribute() const
37 {
38 return RTM_RTA(NLMSG_DATA(&*m_begin));
39 }
40
41 template <>
42 inline const rtattr* NetlinkMessage<ifaddrmsg>::FirstAttribute() const
43 {
44 return IFA_RTA(NLMSG_DATA(&*m_begin));
45 }
46
47 template <typename TAttribute>
48 const rtattr* NetlinkMessage<TAttribute>::FirstAttribute() const
49 {
50 throw RuntimeErrorWithSourceLocation("Tried listing attributes for a message without attributes");
51 }
52
53 template <typename TMessage>
54 template <typename TAttribute>
55 std::vector<const TAttribute*> NetlinkMessage<TMessage>::Attributes(int type) const
56 {
57 std::vector<const TAttribute*> attributes;
58
59 auto len = NLMSG_PAYLOAD(Header(), sizeof(TMessage));
60 for (const rtattr* e = FirstAttribute(); RTA_OK(e, len); e = RTA_NEXT(e, len))
61 {
62 if (e->rta_type == type)
63 {
64 const auto* ptr = reinterpret_cast<const TAttribute*>(RTA_DATA(e));
65
66 if (sizeof(TAttribute) > e->rta_len)
67 {
68 throw NetlinkParseException(
69 m_response,
70 std::format(
71 "Attribute at offset {}: attempted to access beyond attribute offset ({} > {})",
72 (reinterpret_cast<const char*>(e) - &*m_responseBegin),
73 sizeof(TAttribute),
74 e->rta_len));
75 }
76
77 attributes.push_back(ptr);
78 }
79 }
80
81 return attributes;
82 }
83
84 template <typename TMessage>
85 template <typename TAttribute>
86 std::optional<const TAttribute*> NetlinkMessage<TMessage>::UniqueAttribute(int type) const
87 {
88 auto attributes = Attributes<TAttribute>(type);
89
90 if (attributes.empty())
91 {
92 return {};
93 }
94 else if (attributes.size() == 1)
95 {
96 return attributes[0];
97 }
98
99 throw RuntimeErrorWithSourceLocation(std::format("Unexpected attribute count: {} for attribute type: {}", attributes.size(), type));
100 }
101
102 template <typename TMessage>
103 const nlmsghdr* NetlinkMessage<TMessage>::Header() const
104 {
105 return reinterpret_cast<const nlmsghdr*>(&*m_begin);
106 }