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 #include "ip6_address.hpp"
36 
37 namespace ot {
38 namespace Ip4 {
39 
FromString(const char * aString,char aTerminatorChar)40 Error Address::FromString(const char *aString, char aTerminatorChar)
41 {
42     constexpr char kSeparatorChar = '.';
43 
44     Error       error = kErrorParse;
45     const char *cur   = aString;
46 
47     for (uint8_t index = 0;; index++)
48     {
49         SuccessOrExit(StringParseUint8(cur, mFields.m8[index]));
50 
51         if (index == sizeof(Address) - 1)
52         {
53             break;
54         }
55 
56         VerifyOrExit(*cur == kSeparatorChar);
57         cur++;
58     }
59 
60     VerifyOrExit(*cur == aTerminatorChar);
61     error = kErrorNone;
62 
63 exit:
64     return error;
65 }
66 
ExtractFromIp6Address(uint8_t aPrefixLength,const Ip6::Address & aIp6Address)67 void Address::ExtractFromIp6Address(uint8_t aPrefixLength, const Ip6::Address &aIp6Address)
68 {
69     // The prefix length must be 32, 40, 48, 56, 64, 96. IPv4 bytes are added
70     // after the prefix, skipping over the bits 64 to 71 (byte at `kSkipIndex`)
71     // which must be set to zero. The suffix is set to zero (per RFC 6052).
72     //
73     //    +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
74     //    |PL| 0-------------32--40--48--56--64--72--80--88--96--104---------|
75     //    +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
76     //    |32|     prefix    |v4(32)         | u | suffix                    |
77     //    +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
78     //    |40|     prefix        |v4(24)     | u |(8)| suffix                |
79     //    +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
80     //    |48|     prefix            |v4(16) | u | (16)  | suffix            |
81     //    +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
82     //    |56|     prefix                |(8)| u |  v4(24)   | suffix        |
83     //    +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
84     //    |64|     prefix                    | u |   v4(32)      | suffix    |
85     //    +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
86     //    |96|     prefix                                    |    v4(32)     |
87     //    +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
88 
89     constexpr uint8_t kSkipIndex = 8;
90 
91     uint8_t ip6Index;
92 
93     OT_ASSERT(Ip6::Prefix::IsValidNat64PrefixLength(aPrefixLength));
94 
95     ip6Index = aPrefixLength / CHAR_BIT;
96 
97     for (uint8_t &i : mFields.m8)
98     {
99         if (ip6Index == kSkipIndex)
100         {
101             ip6Index++;
102         }
103 
104         i = aIp6Address.GetBytes()[ip6Index++];
105     }
106 }
107 
SynthesizeFromCidrAndHost(const Cidr & aCidr,const uint32_t aHost)108 void Address::SynthesizeFromCidrAndHost(const Cidr &aCidr, const uint32_t aHost)
109 {
110     mFields.m32 = (aCidr.mAddress.mFields.m32 & aCidr.SubnetMask()) | (HostSwap32(aHost) & aCidr.HostMask());
111 }
112 
ToString(StringWriter & aWriter) const113 void Address::ToString(StringWriter &aWriter) const
114 {
115     aWriter.Append("%d.%d.%d.%d", mFields.m8[0], mFields.m8[1], mFields.m8[2], mFields.m8[3]);
116 }
117 
ToString(char * aBuffer,uint16_t aSize) const118 void Address::ToString(char *aBuffer, uint16_t aSize) const
119 {
120     StringWriter writer(aBuffer, aSize);
121 
122     ToString(writer);
123 }
124 
ToString(void) const125 Address::InfoString Address::ToString(void) const
126 {
127     InfoString string;
128 
129     ToString(string);
130 
131     return string;
132 }
133 
FromString(const char * aString)134 Error Cidr::FromString(const char *aString)
135 {
136     constexpr char     kSlashChar     = '/';
137     constexpr uint16_t kMaxCidrLength = 32;
138 
139     Error       error = kErrorParse;
140     const char *cur;
141 
142     SuccessOrExit(AsCoreType(&mAddress).FromString(aString, kSlashChar));
143 
144     cur = StringFind(aString, kSlashChar);
145     VerifyOrExit(cur != nullptr);
146     cur++;
147 
148     SuccessOrExit(StringParseUint8(cur, mLength, kMaxCidrLength));
149     VerifyOrExit(*cur == kNullChar);
150 
151     error = kErrorNone;
152 
153 exit:
154     return error;
155 }
156 
ToString(StringWriter & aWriter) const157 void Cidr::ToString(StringWriter &aWriter) const
158 {
159     aWriter.Append("%s/%d", AsCoreType(&mAddress).ToString().AsCString(), mLength);
160 }
161 
ToString(char * aBuffer,uint16_t aSize) const162 void Cidr::ToString(char *aBuffer, uint16_t aSize) const
163 {
164     StringWriter writer(aBuffer, aSize);
165 
166     ToString(writer);
167 }
168 
ToString(void) const169 Cidr::InfoString Cidr::ToString(void) const
170 {
171     InfoString string;
172 
173     ToString(string);
174 
175     return string;
176 }
177 
operator ==(const Cidr & aOther) const178 bool Cidr::operator==(const Cidr &aOther) const
179 {
180     return (mLength == aOther.mLength) &&
181            (Ip6::Prefix::MatchLength(GetBytes(), aOther.GetBytes(), Ip4::Address::kSize) >= mLength);
182 }
183 
Set(const uint8_t * aAddress,uint8_t aLength)184 void Cidr::Set(const uint8_t *aAddress, uint8_t aLength)
185 {
186     memcpy(mAddress.mFields.m8, aAddress, Ip4::Address::kSize);
187     mLength = aLength;
188 }
189 
ParseFrom(const Message & aMessage)190 Error Header::ParseFrom(const Message &aMessage)
191 {
192     Error error = kErrorParse;
193 
194     SuccessOrExit(aMessage.Read(0, *this));
195     VerifyOrExit(IsValid());
196     VerifyOrExit(GetTotalLength() == aMessage.GetLength());
197 
198     error = kErrorNone;
199 
200 exit:
201     return error;
202 }
203 
204 } // namespace Ip4
205 } // namespace ot
206