1 /*
2 * Copyright (c) 2022, The OpenThread Authors.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the copyright holder nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /**
30 * @file
31 * This file implements IP4 headers processing.
32 */
33
34 #include "ip4_types.hpp"
35
36 #include "common/numeric_limits.hpp"
37 #include "net/ip6_address.hpp"
38
39 namespace ot {
40 namespace Ip4 {
41
FromString(const char * aString,char aTerminatorChar)42 Error Address::FromString(const char *aString, char aTerminatorChar)
43 {
44 constexpr char kSeparatorChar = '.';
45
46 Error error = kErrorParse;
47 const char *cur = aString;
48
49 for (uint8_t index = 0;; index++)
50 {
51 SuccessOrExit(StringParseUint8(cur, mFields.m8[index]));
52
53 if (index == sizeof(Address) - 1)
54 {
55 break;
56 }
57
58 VerifyOrExit(*cur == kSeparatorChar);
59 cur++;
60 }
61
62 VerifyOrExit(*cur == aTerminatorChar);
63 error = kErrorNone;
64
65 exit:
66 return error;
67 }
68
ExtractFromIp4MappedIp6Address(const Ip6::Address & aIp6Address)69 Error Address::ExtractFromIp4MappedIp6Address(const Ip6::Address &aIp6Address)
70 {
71 Error error = kErrorNone;
72
73 VerifyOrExit(aIp6Address.IsIp4Mapped(), error = kErrorParse);
74 SetBytes(&aIp6Address.GetBytes()[12]);
75
76 exit:
77 return error;
78 }
79
ExtractFromIp6Address(uint8_t aPrefixLength,const Ip6::Address & aIp6Address)80 void Address::ExtractFromIp6Address(uint8_t aPrefixLength, const Ip6::Address &aIp6Address)
81 {
82 // The prefix length must be 32, 40, 48, 56, 64, 96. IPv4 bytes are added
83 // after the prefix, skipping over the bits 64 to 71 (byte at `kSkipIndex`)
84 // which must be set to zero. The suffix is set to zero (per RFC 6052).
85 //
86 // +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
87 // |PL| 0-------------32--40--48--56--64--72--80--88--96--104---------|
88 // +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
89 // |32| prefix |v4(32) | u | suffix |
90 // +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
91 // |40| prefix |v4(24) | u |(8)| suffix |
92 // +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
93 // |48| prefix |v4(16) | u | (16) | suffix |
94 // +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
95 // |56| prefix |(8)| u | v4(24) | suffix |
96 // +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
97 // |64| prefix | u | v4(32) | suffix |
98 // +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
99 // |96| prefix | v4(32) |
100 // +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
101
102 constexpr uint8_t kSkipIndex = 8;
103
104 uint8_t ip6Index;
105
106 OT_ASSERT(Ip6::Prefix::IsValidNat64PrefixLength(aPrefixLength));
107
108 ip6Index = aPrefixLength / kBitsPerByte;
109
110 for (uint8_t &i : mFields.m8)
111 {
112 if (ip6Index == kSkipIndex)
113 {
114 ip6Index++;
115 }
116
117 i = aIp6Address.GetBytes()[ip6Index++];
118 }
119 }
120
SynthesizeFromCidrAndHost(const Cidr & aCidr,const uint32_t aHost)121 void Address::SynthesizeFromCidrAndHost(const Cidr &aCidr, const uint32_t aHost)
122 {
123 mFields.m32 = (aCidr.mAddress.mFields.m32 & aCidr.SubnetMask()) | (BigEndian::HostSwap32(aHost) & aCidr.HostMask());
124 }
125
ToString(StringWriter & aWriter) const126 void Address::ToString(StringWriter &aWriter) const
127 {
128 aWriter.Append("%d.%d.%d.%d", mFields.m8[0], mFields.m8[1], mFields.m8[2], mFields.m8[3]);
129 }
130
ToString(char * aBuffer,uint16_t aSize) const131 void Address::ToString(char *aBuffer, uint16_t aSize) const
132 {
133 StringWriter writer(aBuffer, aSize);
134
135 ToString(writer);
136 }
137
ToString(void) const138 Address::InfoString Address::ToString(void) const
139 {
140 InfoString string;
141
142 ToString(string);
143
144 return string;
145 }
146
FromString(const char * aString)147 Error Cidr::FromString(const char *aString)
148 {
149 constexpr char kSlashChar = '/';
150 constexpr uint16_t kMaxCidrLength = 32;
151
152 Error error = kErrorParse;
153 const char *cur;
154
155 SuccessOrExit(AsCoreType(&mAddress).FromString(aString, kSlashChar));
156
157 cur = StringFind(aString, kSlashChar);
158 VerifyOrExit(cur != nullptr);
159 cur++;
160
161 SuccessOrExit(StringParseUint8(cur, mLength, kMaxCidrLength));
162 VerifyOrExit(*cur == kNullChar);
163
164 error = kErrorNone;
165
166 exit:
167 return error;
168 }
169
ToString(StringWriter & aWriter) const170 void Cidr::ToString(StringWriter &aWriter) const
171 {
172 aWriter.Append("%s/%d", AsCoreType(&mAddress).ToString().AsCString(), mLength);
173 }
174
ToString(char * aBuffer,uint16_t aSize) const175 void Cidr::ToString(char *aBuffer, uint16_t aSize) const
176 {
177 StringWriter writer(aBuffer, aSize);
178
179 ToString(writer);
180 }
181
ToString(void) const182 Cidr::InfoString Cidr::ToString(void) const
183 {
184 InfoString string;
185
186 ToString(string);
187
188 return string;
189 }
190
operator ==(const Cidr & aOther) const191 bool Cidr::operator==(const Cidr &aOther) const
192 {
193 return (mLength == aOther.mLength) &&
194 (Ip6::Prefix::MatchLength(GetBytes(), aOther.GetBytes(), Ip4::Address::kSize) >= mLength);
195 }
196
Set(const uint8_t * aAddress,uint8_t aLength)197 void Cidr::Set(const uint8_t *aAddress, uint8_t aLength)
198 {
199 memcpy(mAddress.mFields.m8, aAddress, Ip4::Address::kSize);
200 mLength = aLength;
201 }
202
ParseFrom(const Message & aMessage)203 Error Header::ParseFrom(const Message &aMessage)
204 {
205 Error error = kErrorParse;
206
207 SuccessOrExit(aMessage.Read(0, *this));
208 VerifyOrExit(IsValid());
209 VerifyOrExit(GetTotalLength() == aMessage.GetLength());
210
211 error = kErrorNone;
212
213 exit:
214 return error;
215 }
216
217 //---------------------------------------------------------------------------------------------------------------------
218 // Headers
219
ParseFrom(const Message & aMessage)220 Error Headers::ParseFrom(const Message &aMessage)
221 {
222 Error error = kErrorParse;
223
224 Clear();
225
226 SuccessOrExit(mIp4Header.ParseFrom(aMessage));
227
228 switch (mIp4Header.GetProtocol())
229 {
230 case kProtoUdp:
231 SuccessOrExit(aMessage.Read(sizeof(Header), mHeader.mUdp));
232 break;
233 case kProtoTcp:
234 SuccessOrExit(aMessage.Read(sizeof(Header), mHeader.mTcp));
235 break;
236 case kProtoIcmp:
237 SuccessOrExit(aMessage.Read(sizeof(Header), mHeader.mIcmp));
238 break;
239 default:
240 break;
241 }
242
243 error = kErrorNone;
244
245 exit:
246 return error;
247 }
248
GetSourcePort(void) const249 uint16_t Headers::GetSourcePort(void) const
250 {
251 uint16_t port = 0;
252
253 switch (GetIpProto())
254 {
255 case kProtoUdp:
256 port = mHeader.mUdp.GetSourcePort();
257 break;
258
259 case kProtoTcp:
260 port = mHeader.mTcp.GetSourcePort();
261 break;
262
263 default:
264 break;
265 }
266
267 return port;
268 }
269
GetDestinationPort(void) const270 uint16_t Headers::GetDestinationPort(void) const
271 {
272 uint16_t port = 0;
273
274 switch (GetIpProto())
275 {
276 case kProtoUdp:
277 port = mHeader.mUdp.GetDestinationPort();
278 break;
279
280 case kProtoTcp:
281 port = mHeader.mTcp.GetDestinationPort();
282 break;
283
284 default:
285 break;
286 }
287
288 return port;
289 }
290
SetDestinationPort(uint16_t aDstPort)291 void Headers::SetDestinationPort(uint16_t aDstPort)
292 {
293 switch (GetIpProto())
294 {
295 case kProtoUdp:
296 mHeader.mUdp.SetDestinationPort(aDstPort);
297 break;
298
299 case kProtoTcp:
300 mHeader.mTcp.SetDestinationPort(aDstPort);
301 break;
302
303 default:
304 break;
305 }
306 }
307
GetChecksum(void) const308 uint16_t Headers::GetChecksum(void) const
309 {
310 uint16_t checksum = 0;
311
312 switch (GetIpProto())
313 {
314 case kProtoUdp:
315 checksum = mHeader.mUdp.GetChecksum();
316 break;
317
318 case kProtoTcp:
319 checksum = mHeader.mTcp.GetChecksum();
320 break;
321
322 case kProtoIcmp:
323 checksum = mHeader.mIcmp.GetChecksum();
324 break;
325
326 default:
327 break;
328 }
329
330 return checksum;
331 }
332
333 } // namespace Ip4
334 } // namespace ot
335