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 } // namespace Ip4
218 } // namespace ot
219