| // Copyright 2018 The ChromiumOS Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef NET_BASE_RTNL_MESSAGE_H_ |
| #define NET_BASE_RTNL_MESSAGE_H_ |
| |
| #include <memory> |
| #include <optional> |
| #include <string> |
| #include <unordered_map> |
| #include <vector> |
| |
| #include <base/containers/contains.h> |
| #include <base/containers/span.h> |
| #include <brillo/brillo_export.h> |
| |
| #include "net-base/http_url.h" |
| #include "net-base/ip_address.h" |
| #include "net-base/ipv6_address.h" |
| |
| struct rtattr; |
| |
| namespace net_base { |
| |
| struct RTNLHeader; |
| |
| using RTNLAttrMap = std::unordered_map<uint16_t, std::vector<uint8_t>>; |
| |
| // Helper class for processing rtnetlink messages. See uapi/linux/rtnetlink.h |
| // and rtnetlink manual page for details about the message binary encoding and |
| // meaning of struct fields populated by the kernel. |
| class BRILLO_EXPORT RTNLMessage { |
| public: |
| enum Type { |
| kTypeUnknown, |
| kTypeLink, |
| kTypeAddress, |
| kTypeRoute, |
| kTypeRule, |
| kTypeRdnss, |
| kTypeDnssl, |
| kTypeCaptivePortal, |
| kTypeNeighbor, |
| kTypeNdUserOption, // Unknown ND user options that does not have own types. |
| }; |
| |
| enum Mode { kModeUnknown, kModeGet, kModeAdd, kModeDelete, kModeQuery }; |
| |
| // Helper struct corresponding to struct ifinfomsg. |
| struct LinkStatus { |
| LinkStatus() : type(0), flags(0), change(0) {} |
| LinkStatus(unsigned int in_type, |
| unsigned int in_flags, |
| unsigned int in_change, |
| std::optional<std::string> kind = std::nullopt) |
| : type(in_type), flags(in_flags), change(in_change), kind(kind) {} |
| // Device type. Corresponds to ifi_type. |
| unsigned int type; |
| // Device flags. Corresponds to ifi_flags. |
| unsigned int flags; |
| // Change mask. Corresponds to ifi_mask. |
| unsigned int change; |
| // Device kind, as defined by the device driver. Corresponds to rtattr |
| // IFLA_INFO_KIND nested inside rtattr IFLA_LINKINFO. |
| std::optional<std::string> kind; |
| }; |
| |
| // Helper struct corresponding to struct ifaddrmsg. |
| struct AddressStatus { |
| AddressStatus() : prefix_len(0), flags(0), scope(0) {} |
| AddressStatus(unsigned char prefix_len_in, |
| unsigned char flags_in, |
| unsigned char scope_in) |
| : prefix_len(prefix_len_in), flags(flags_in), scope(scope_in) {} |
| // Prefix length of the address. Corresponds to ifa_prefixlen. |
| unsigned char prefix_len; |
| // Address flags. Corresponds to ifa_flags. |
| unsigned char flags; |
| // Address scope. Corresponds to ifa_scope. |
| unsigned char scope; |
| }; |
| |
| // Helper struct corresponding to struct rtmsg. |
| struct RouteStatus { |
| RouteStatus() |
| : dst_prefix(0), |
| src_prefix(0), |
| table(0), |
| protocol(0), |
| scope(0), |
| type(0), |
| flags(0) {} |
| RouteStatus(unsigned char dst_prefix_in, |
| unsigned char src_prefix_in, |
| unsigned char table_in, |
| unsigned char protocol_in, |
| unsigned char scope_in, |
| unsigned char type_in, |
| unsigned flags_in) |
| : dst_prefix(dst_prefix_in), |
| src_prefix(src_prefix_in), |
| table(table_in), |
| protocol(protocol_in), |
| scope(scope_in), |
| type(type_in), |
| flags(flags_in) {} |
| // Prefix length of the destination. Corresponds to rtm_dst_len. |
| unsigned char dst_prefix; |
| // Prefix length of the source. Corresponds to rtm_src_len. |
| unsigned char src_prefix; |
| // Legacy routing table id. Corresponds to rtm_table. |
| // TODO(b/154500323) This cannot expose correctly the per-device routing |
| // tables which starts with a +1000 offset. Instead this class should |
| // expose the RTA_TABLE rtattr for kTypeRoute messages and the FRA_TABLE |
| // rtattr for kTypeRule messages. |
| unsigned char table; |
| // Routing protocol. Corresponds to rtm_protocol. |
| unsigned char protocol; |
| // Distance to the destination. Corresponds to rtm_scope. |
| unsigned char scope; |
| // The type of route. Corresponds to rtm_type. |
| unsigned char type; |
| // Route flags. Corresponds to rtm_flags. |
| unsigned flags; |
| }; |
| |
| // Helper struct corresponding to struct ndmsg. |
| struct NeighborStatus { |
| NeighborStatus() : state(0), flags(0), type(0) {} |
| NeighborStatus(uint16_t state_in, uint8_t flags_in, uint8_t type_in) |
| : state(state_in), flags(flags_in), type(type_in) {} |
| std::string ToString() const; |
| // Neighbor state. Corresponds to ndm_state. |
| uint16_t state; |
| // Neighbor flags. Corresponds to ndm_flags. |
| uint8_t flags; |
| // Neighbor type. Corresponds to ndm_type. |
| uint8_t type; |
| }; |
| |
| struct RdnssOption { |
| RdnssOption() : lifetime(0) {} |
| RdnssOption(uint32_t lifetime_in, std::vector<IPv6Address> addresses_in) |
| : lifetime(lifetime_in), addresses(addresses_in) {} |
| std::string ToString() const; |
| uint32_t lifetime; |
| std::vector<IPv6Address> addresses; |
| }; |
| |
| struct DnsslOption { |
| DnsslOption() = default; |
| std::string ToString() const; |
| uint32_t lifetime; |
| std::vector<std::string> domains; |
| }; |
| |
| struct NdUserOption { |
| NdUserOption() = default; |
| std::string ToString() const; |
| uint8_t type; |
| std::vector<uint8_t> option_bytes; // Including header |
| }; |
| |
| // Packs the attribute map into bytes, with the proper alignment. |
| static std::vector<uint8_t> PackAttrs(const RTNLAttrMap& attrs); |
| |
| // Parse an RTNL message. Returns nullptr on failure. |
| static std::unique_ptr<RTNLMessage> Decode(base::span<const uint8_t> data); |
| |
| // Build an RTNL message from arguments |
| RTNLMessage(Type type, |
| Mode mode, |
| uint16_t flags, |
| uint32_t seq, |
| uint32_t pid, |
| int32_t interface_index, |
| sa_family_t family); |
| RTNLMessage(const RTNLMessage&) = delete; |
| RTNLMessage& operator=(const RTNLMessage&) = delete; |
| |
| // Encode an RTNL message. Returns empty vector on failure. |
| std::vector<uint8_t> Encode() const; |
| |
| // Getters and setters |
| Type type() const { return type_; } |
| Mode mode() const { return mode_; } |
| uint16_t flags() const { return flags_; } |
| uint32_t seq() const { return seq_; } |
| void set_seq(uint32_t seq) { seq_ = seq; } |
| uint32_t pid() const { return pid_; } |
| int32_t interface_index() const { return interface_index_; } |
| sa_family_t family() const { return family_; } |
| |
| static std::string ModeToString(Mode mode); |
| static std::string TypeToString(Type type); |
| std::string ToString() const; |
| |
| const LinkStatus& link_status() const { return link_status_; } |
| void set_link_status(const LinkStatus& link_status) { |
| link_status_ = link_status; |
| } |
| const AddressStatus& address_status() const { return address_status_; } |
| void set_address_status(const AddressStatus& address_status) { |
| address_status_ = address_status; |
| } |
| const RouteStatus& route_status() const { return route_status_; } |
| void set_route_status(const RouteStatus& route_status) { |
| route_status_ = route_status; |
| } |
| const RdnssOption& rdnss_option() const { return rdnss_option_; } |
| void set_rdnss_option(const RdnssOption& rdnss_option) { |
| rdnss_option_ = rdnss_option; |
| } |
| const DnsslOption& dnssl_option() const { return dnssl_option_; } |
| void set_dnssl_option(const DnsslOption& dnssl_option) { |
| dnssl_option_ = dnssl_option; |
| } |
| const HttpUrl& captive_portal_uri() const { return captive_portal_uri_; } |
| void set_captive_portal_uri(const HttpUrl& captive_portal_uri) { |
| captive_portal_uri_ = captive_portal_uri; |
| } |
| const NdUserOption& nd_user_option() const { return nd_user_option_; } |
| const NeighborStatus& neighbor_status() const { return neighbor_status_; } |
| void set_neighbor_status(const NeighborStatus& neighbor_status) { |
| neighbor_status_ = neighbor_status; |
| } |
| // GLint hates "unsigned short", and I don't blame it, but that's the |
| // type that's used in the system headers. Use uint16_t instead and hope |
| // that the conversion never ends up truncating on some strange platform. |
| bool HasAttribute(uint16_t attr) const { |
| return base::Contains(attributes_, attr); |
| } |
| std::vector<uint8_t> GetAttribute(uint16_t attr) const { |
| return HasAttribute(attr) ? attributes_.find(attr)->second |
| : std::vector<uint8_t>(); |
| } |
| void SetAttribute(uint16_t attr, base::span<const uint8_t> val) { |
| attributes_[attr] = {val.data(), val.data() + val.size()}; |
| } |
| // Return the value of an rtattr attribute of type uint32_t. |
| uint32_t GetUint32Attribute(uint16_t attr) const; |
| // Returns the value of an rtattr attribute of type string. String attributes |
| // serialized by the kernel with nla_put_string() are null terminated and the |
| // null terminator is included in the underlying std::vector<uint8_t>. In case |
| // the std::vector<uint8_t> does not contain any terminator, all the bytes of |
| // contained in the std::vector<uint8_t> are copied into the standard string. |
| std::string GetStringAttribute(uint16_t attr) const; |
| // returns the IFLA_IFNAME attribute as standard string. This should only be |
| // used for RTNLMessages of type kTypeLink. |
| std::string GetIflaIfname() const; |
| // Returns the local address. IFA_LOCAL will be looked up at first, and if it |
| // does not exist, value of IFA_ADDRESS will be used. This should only be used |
| // for RTNLMessages of type kTypeAddress. |
| std::optional<IPCIDR> GetAddress() const; |
| // Returns the routing table id of RTNLMessages with type kTypeRoute. |
| uint32_t GetRtaTable() const; |
| // Returns the RTA_DST attribute for RTNLMessages of type kTypeRoute. |
| std::optional<IPCIDR> GetRtaDst() const; |
| // Returns the RTA_SRC attribute for RTNLMessages of type kTypeRoute. |
| std::optional<IPCIDR> GetRtaSrc() const; |
| // Returns the RTA_GATEWAY attribute for RTNLMessages of type kTypeRoute. |
| std::optional<IPAddress> GetRtaGateway() const; |
| // Returns the RTA_PREFSRC attribute for RTNLMessages of type kTypeRoute. |
| std::optional<IPAddress> GetRtaPrefSrc() const; |
| // Returns the RTA_OIF output interface attribute as an interface index |
| // name for RTNLMessages of type kTypeRoute. |
| uint32_t GetRtaOif() const; |
| // Returns the RTA_OIF output interface attribute translated as an interface |
| // name for RTNLMessages of type kTypeRoute. |
| std::string GetRtaOifname() const; |
| // Returns the RTA_PRIORITY attribute for RTNLMessages of type kTypeRoute. |
| uint32_t GetRtaPriority() const; |
| // Returns the lookup routing table id of RTNLMessages with type kTypeRule. |
| uint32_t GetFraTable() const; |
| // Returns the input interface name of RTNLMessages with type kTypeRule. |
| std::string GetFraOifname() const; |
| // Returns the output interface name of RTNLMessages with type kTypeRule. |
| std::string GetFraIifname() const; |
| // Returns the fwmark value of RTNLMessages with type kTypeRule. |
| uint32_t GetFraFwmark() const; |
| // Returns the fwmask value of RTNLMessages with type kTypeRule. |
| uint32_t GetFraFwmask() const; |
| // Returns the FRA_PRIORITY attribute for RTNLMessages of type kTypeRule. |
| uint32_t GetFraPriority() const; |
| // Returns the FRA_SRC attribute for RTNLMessages of type kTypeRule. |
| std::optional<IPCIDR> GetFraSrc() const; |
| // Returns the FRA_DST attribute for RTNLMessages of type kTypeRule. |
| std::optional<IPCIDR> GetFraDst() const; |
| |
| // Sets the IFLA_INFO_KIND attribute which is nested in IFLA_LINKINFO (and |
| // thus it is hard to be set via SetAttribute() directly). This attribute will |
| // be used as the type string of a link when creating a new link. This |
| // function should be used only for RTNLMessages of type kTypeLink. The second |
| // optional parameter |info_data| will be used as the value of IFLA_INFO_DATA, |
| // which is kind-specific. Leave it empty if there is no addtiional data |
| // needed for |link_kind|. |
| void SetIflaInfoKind(const std::string& link_kind, |
| base::span<const uint8_t> info_data); |
| |
| private: |
| // Decodes different kind of NL messages. |payload| points to the remaining |
| // data after the `struct nlmsghdr`. |
| static std::unique_ptr<RTNLMessage> DecodeLink( |
| Mode mode, base::span<const uint8_t> payload); |
| static std::unique_ptr<RTNLMessage> DecodeAddress( |
| Mode mode, base::span<const uint8_t> payload); |
| static std::unique_ptr<RTNLMessage> DecodeRoute( |
| Mode mode, base::span<const uint8_t> payload); |
| static std::unique_ptr<RTNLMessage> DecodeRule( |
| Mode mode, base::span<const uint8_t> payload); |
| static std::unique_ptr<RTNLMessage> DecodeNdUserOption( |
| Mode mode, base::span<const uint8_t> payload); |
| static std::unique_ptr<RTNLMessage> DecodeNeighbor( |
| Mode mode, base::span<const uint8_t> payload); |
| |
| void SetNdUserOptionBytes(base::span<const uint8_t> data); |
| bool ParseDnsslOption(base::span<const uint8_t> data); |
| bool ParseRdnssOption(base::span<const uint8_t> data); |
| bool ParseCaptivePortalOption(base::span<const uint8_t> data); |
| bool EncodeLink(RTNLHeader* hdr) const; |
| bool EncodeAddress(RTNLHeader* hdr) const; |
| bool EncodeRoute(RTNLHeader* hdr) const; |
| bool EncodeNeighbor(RTNLHeader* hdr) const; |
| |
| // Type and mode of the message, corresponding to a subset of the RTM_* enum |
| // defined in uapi/linux/rtnetlink.h |
| Type type_; |
| Mode mode_; |
| // Netlink request flags. Corresponds to nlmsg_flags in struct nlmsghdr. |
| uint16_t flags_; |
| // Arbitrary msg id used for response correlation. Corresponds to nlmsg_seq in |
| // struct nlmsghdr. |
| uint32_t seq_; |
| // The sender id. Corresponds to nlmsg_pid in struct nlmsghdr. |
| uint32_t pid_; |
| // Corresponds to ifi_index (kTypeLink), ifa_index (kTypeAddress), ndm_ifindex |
| // (kTypeNeighbor). |
| int32_t interface_index_; |
| // Corresponds to ifi_family (kTypeLink), ifa_family (kTypeAddress), |
| // rtm_family (kTypeRoute and kTypeRule), ndm_family (kTypeNeighbor). Always |
| // IPv6 for neighbor discovery options (kTypeRdnss, kTypeDnssl, |
| // kTypeNdUserOption). |
| sa_family_t family_; |
| // Details specific to a message type. |
| LinkStatus link_status_; |
| AddressStatus address_status_; |
| RouteStatus route_status_; |
| NeighborStatus neighbor_status_; |
| RdnssOption rdnss_option_; |
| DnsslOption dnssl_option_; |
| HttpUrl captive_portal_uri_; |
| NdUserOption nd_user_option_; |
| // Additional rtattr contained in the message. |
| RTNLAttrMap attributes_; |
| // NOTE: Update Reset() accordingly when adding a new member field. |
| }; |
| |
| } // namespace net_base |
| #endif // NET_BASE_RTNL_MESSAGE_H_ |