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