/src/serenity/AK/IPv4Address.h
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> |
3 | | * |
4 | | * SPDX-License-Identifier: BSD-2-Clause |
5 | | */ |
6 | | |
7 | | #pragma once |
8 | | |
9 | | #include <AK/Endian.h> |
10 | | #include <AK/Format.h> |
11 | | #include <AK/Optional.h> |
12 | | #include <AK/SipHash.h> |
13 | | #include <AK/StringView.h> |
14 | | #include <AK/Vector.h> |
15 | | |
16 | | #ifdef KERNEL |
17 | | # include <AK/Error.h> |
18 | | # include <Kernel/Library/KString.h> |
19 | | #else |
20 | | # include <AK/ByteString.h> |
21 | | # include <AK/String.h> |
22 | | #endif |
23 | | |
24 | | namespace AK { |
25 | | |
26 | | class [[gnu::packed]] IPv4Address { |
27 | | enum class SubnetClass : int { |
28 | | A = 0, |
29 | | B, |
30 | | C, |
31 | | D |
32 | | }; |
33 | | |
34 | | public: |
35 | | using in_addr_t = u32; |
36 | | |
37 | 0 | constexpr IPv4Address() = default; |
38 | | |
39 | | constexpr IPv4Address(u32 a, u32 b, u32 c, u32 d) |
40 | 0 | { |
41 | 0 | m_data = (d << 24) | (c << 16) | (b << 8) | a; |
42 | 0 | } |
43 | | |
44 | | constexpr IPv4Address(u8 const data[4]) |
45 | 675 | { |
46 | 675 | m_data = (u32(data[3]) << 24) | (u32(data[2]) << 16) | (u32(data[1]) << 8) | u32(data[0]); |
47 | 675 | } |
48 | | |
49 | | constexpr IPv4Address(NetworkOrdered<u32> address) |
50 | 0 | : m_data(address) |
51 | 0 | { |
52 | 0 | } |
53 | | |
54 | | constexpr u8 operator[](int i) const |
55 | 0 | { |
56 | 0 | VERIFY(i >= 0 && i < 4); |
57 | 0 | return octet(SubnetClass(i)); |
58 | 0 | } |
59 | | |
60 | | #ifdef KERNEL |
61 | | ErrorOr<NonnullOwnPtr<Kernel::KString>> to_string() const |
62 | | { |
63 | | return Kernel::KString::formatted("{}.{}.{}.{}", |
64 | | octet(SubnetClass::A), |
65 | | octet(SubnetClass::B), |
66 | | octet(SubnetClass::C), |
67 | | octet(SubnetClass::D)); |
68 | | } |
69 | | #else |
70 | | ByteString to_byte_string() const |
71 | 0 | { |
72 | 0 | return ByteString::formatted("{}.{}.{}.{}", |
73 | 0 | octet(SubnetClass::A), |
74 | 0 | octet(SubnetClass::B), |
75 | 0 | octet(SubnetClass::C), |
76 | 0 | octet(SubnetClass::D)); |
77 | 0 | } |
78 | | |
79 | | ByteString to_byte_string_reversed() const |
80 | 0 | { |
81 | 0 | return ByteString::formatted("{}.{}.{}.{}", |
82 | 0 | octet(SubnetClass::D), |
83 | 0 | octet(SubnetClass::C), |
84 | 0 | octet(SubnetClass::B), |
85 | 0 | octet(SubnetClass::A)); |
86 | 0 | } |
87 | | |
88 | | ErrorOr<String> to_string() const |
89 | 675 | { |
90 | 675 | return String::formatted("{}.{}.{}.{}", |
91 | 675 | octet(SubnetClass::A), |
92 | 675 | octet(SubnetClass::B), |
93 | 675 | octet(SubnetClass::C), |
94 | 675 | octet(SubnetClass::D)); |
95 | 675 | } |
96 | | #endif |
97 | | |
98 | | static Optional<IPv4Address> from_string(StringView string) |
99 | 0 | { |
100 | 0 | if (string.is_null()) |
101 | 0 | return {}; |
102 | 0 |
|
103 | 0 | auto const parts = string.split_view('.'); |
104 | 0 |
|
105 | 0 | u32 a {}; |
106 | 0 | u32 b {}; |
107 | 0 | u32 c {}; |
108 | 0 | u32 d {}; |
109 | 0 |
|
110 | 0 | if (parts.size() == 1) { |
111 | 0 | d = parts[0].to_number<u32>().value_or(256); |
112 | 0 | } else if (parts.size() == 2) { |
113 | 0 | a = parts[0].to_number<u32>().value_or(256); |
114 | 0 | d = parts[1].to_number<u32>().value_or(256); |
115 | 0 | } else if (parts.size() == 3) { |
116 | 0 | a = parts[0].to_number<u32>().value_or(256); |
117 | 0 | b = parts[1].to_number<u32>().value_or(256); |
118 | 0 | d = parts[2].to_number<u32>().value_or(256); |
119 | 0 | } else if (parts.size() == 4) { |
120 | 0 | a = parts[0].to_number<u32>().value_or(256); |
121 | 0 | b = parts[1].to_number<u32>().value_or(256); |
122 | 0 | c = parts[2].to_number<u32>().value_or(256); |
123 | 0 | d = parts[3].to_number<u32>().value_or(256); |
124 | 0 | } else { |
125 | 0 | return {}; |
126 | 0 | } |
127 | 0 |
|
128 | 0 | if (a > 255 || b > 255 || c > 255 || d > 255) |
129 | 0 | return {}; |
130 | 0 | return IPv4Address(a, b, c, d); |
131 | 0 | } |
132 | | |
133 | | static constexpr IPv4Address netmask_from_cidr(int cidr) |
134 | 0 | { |
135 | 0 | VERIFY(cidr >= 0 && cidr <= 32); |
136 | 0 | u32 value = 0xffffffffull << (32 - cidr); |
137 | 0 | return IPv4Address((value & 0xff000000) >> 24, (value & 0xff0000) >> 16, (value & 0xff00) >> 8, (value & 0xff)); |
138 | 0 | } |
139 | | |
140 | 0 | constexpr in_addr_t to_in_addr_t() const { return m_data; } |
141 | 0 | constexpr u32 to_u32() const { return m_data; } |
142 | | |
143 | | constexpr bool operator==(IPv4Address const& other) const = default; |
144 | | constexpr bool operator!=(IPv4Address const& other) const = default; |
145 | | |
146 | | constexpr bool is_zero() const |
147 | 0 | { |
148 | 0 | return m_data == 0u; |
149 | 0 | } |
150 | | |
151 | | private: |
152 | | constexpr u32 octet(SubnetClass const subnet) const |
153 | 2.70k | { |
154 | 2.70k | constexpr auto bits_per_byte = 8; |
155 | 2.70k | auto const bits_to_shift = bits_per_byte * int(subnet); |
156 | 2.70k | return (m_data >> bits_to_shift) & 0x0000'00FF; |
157 | 2.70k | } |
158 | | |
159 | | u32 m_data {}; |
160 | | }; |
161 | | |
162 | | static_assert(sizeof(IPv4Address) == 4); |
163 | | |
164 | | template<> |
165 | | struct Traits<IPv4Address> : public DefaultTraits<IPv4Address> { |
166 | 0 | static unsigned hash(IPv4Address const& address) { return secure_sip_hash(static_cast<u64>(address.to_u32())); } |
167 | | }; |
168 | | |
169 | | #ifdef KERNEL |
170 | | template<> |
171 | | struct Formatter<IPv4Address> : Formatter<StringView> { |
172 | | ErrorOr<void> format(FormatBuilder& builder, IPv4Address value) |
173 | | { |
174 | | return Formatter<StringView>::format(builder, TRY(value.to_string())->view()); |
175 | | } |
176 | | }; |
177 | | #else |
178 | | template<> |
179 | | struct Formatter<IPv4Address> : Formatter<StringView> { |
180 | | ErrorOr<void> format(FormatBuilder& builder, IPv4Address value) |
181 | 0 | { |
182 | 0 | return Formatter<StringView>::format(builder, value.to_byte_string()); |
183 | 0 | } |
184 | | }; |
185 | | #endif |
186 | | |
187 | | } |
188 | | |
189 | | #if USING_AK_GLOBALLY |
190 | | using AK::IPv4Address; |
191 | | #endif |