[ip-utils] extend and improve ip4/ip6 headers (#11151)

This commit adds a new class, Ip4::Headers that offers support for
managing an IPv4 header along with UDP/TCP/ICMP4 headers from a received
message/frame. This functionality is equivalent to the one already
present for IPv6.

Added GetId() and SetId() methods to ICMP4 class.

Improved the Ip6::Headers functionality:
- added SetSourcePort() method to allow easier translation of ports in NAT64.
- added GetIpLength() and GetIpHopLimit() methods.

Added SetSourcePort() and SetDestinationPort() methods for TCP.

Signed-off-by: Marius Preda <[email protected]>
This commit is contained in:
Marius Preda
2025-01-13 10:20:06 -08:00
committed by GitHub
parent 4b782d5b77
commit f8a27c250c
5 changed files with 339 additions and 6 deletions
+116
View File
@@ -214,5 +214,121 @@ exit:
return error;
}
//---------------------------------------------------------------------------------------------------------------------
// Headers
Error Headers::ParseFrom(const Message &aMessage)
{
Error error = kErrorParse;
Clear();
SuccessOrExit(mIp4Header.ParseFrom(aMessage));
switch (mIp4Header.GetProtocol())
{
case kProtoUdp:
SuccessOrExit(aMessage.Read(sizeof(Header), mHeader.mUdp));
break;
case kProtoTcp:
SuccessOrExit(aMessage.Read(sizeof(Header), mHeader.mTcp));
break;
case kProtoIcmp:
SuccessOrExit(aMessage.Read(sizeof(Header), mHeader.mIcmp));
break;
default:
break;
}
error = kErrorNone;
exit:
return error;
}
uint16_t Headers::GetSourcePort(void) const
{
uint16_t port = 0;
switch (GetIpProto())
{
case kProtoUdp:
port = mHeader.mUdp.GetSourcePort();
break;
case kProtoTcp:
port = mHeader.mTcp.GetSourcePort();
break;
default:
break;
}
return port;
}
uint16_t Headers::GetDestinationPort(void) const
{
uint16_t port = 0;
switch (GetIpProto())
{
case kProtoUdp:
port = mHeader.mUdp.GetDestinationPort();
break;
case kProtoTcp:
port = mHeader.mTcp.GetDestinationPort();
break;
default:
break;
}
return port;
}
void Headers::SetDestinationPort(uint16_t aDstPort)
{
switch (GetIpProto())
{
case kProtoUdp:
mHeader.mUdp.SetDestinationPort(aDstPort);
break;
case kProtoTcp:
mHeader.mTcp.SetDestinationPort(aDstPort);
break;
default:
break;
}
}
uint16_t Headers::GetChecksum(void) const
{
uint16_t checksum = 0;
switch (GetIpProto())
{
case kProtoUdp:
checksum = mHeader.mUdp.GetChecksum();
break;
case kProtoTcp:
checksum = mHeader.mTcp.GetChecksum();
break;
case kProtoIcmp:
checksum = mHeader.mIcmp.GetChecksum();
break;
default:
break;
}
return checksum;
}
} // namespace Ip4
} // namespace ot
+171 -6
View File
@@ -619,28 +619,44 @@ public:
*/
void SetChecksum(uint16_t aChecksum) { mChecksum = BigEndian::HostSwap16(aChecksum); }
/**
* Returns the ICMPv4 message ID for Echo Requests and Replies.
*
* @returns The ICMPv4 message ID.
*/
uint16_t GetId(void) const { return BigEndian::HostSwap16(mData.m16[0]); }
/**
* Sets the ICMPv4 message ID for Echo Requests and Replies.
*
* @param[in] aId The ICMPv4 message ID.
*/
void SetId(uint16_t aId) { mData.m16[0] = BigEndian::HostSwap16(aId); }
/**
* Returns the rest of header field in the ICMP message.
*
* @returns The rest of header field in the ICMP message. The returned buffer has 4 octets.
*/
const uint8_t *GetRestOfHeader(void) const { return mRestOfHeader; }
const uint8_t *GetRestOfHeader(void) const { return mData.m8; }
/**
* Sets the rest of header field in the ICMP message.
*
* @param[in] aRestOfHeader The rest of header field in the ICMP message. The buffer should have 4 octets.
*/
void SetRestOfHeader(const uint8_t *aRestOfHeader)
{
memcpy(mRestOfHeader, aRestOfHeader, sizeof(mRestOfHeader));
}
void SetRestOfHeader(const uint8_t *aRestOfHeader) { memcpy(mData.m8, aRestOfHeader, sizeof(mData)); }
private:
uint8_t mType;
uint8_t mCode;
uint16_t mChecksum;
uint8_t mRestOfHeader[4];
union OT_TOOL_PACKED_FIELD
{
uint8_t m8[4];
uint16_t m16[2];
uint32_t m32[1];
} mData;
} OT_TOOL_PACKED_END;
};
@@ -652,6 +668,155 @@ static constexpr uint8_t kProtoIcmp = 1; ///< ICMP for IPv4
using Tcp = Ip6::Tcp; // TCP in IPv4 is the same as TCP in IPv6
using Udp = Ip6::Udp; // UDP in IPv4 is the same as UDP in IPv6
/**
* Represents parsed IPv4 header along with UDP/TCP/ICMP4 headers from a received message/frame.
*/
class Headers : private Clearable<Headers>
{
friend class Clearable<Headers>;
public:
/**
* Parses the IPv4 and UDP/TCP/ICMP4 headers from a given message.
*
* @param[in] aMessage The message to parse the headers from.
*
* @retval kErrorNone The headers are parsed successfully.
* @retval kErrorParse Failed to parse the headers.
*/
Error ParseFrom(const Message &aMessage);
/**
* Returns the IPv4 header.
*
* @returns The IPv4 header.
*/
const Header &GetIp4Header(void) const { return mIp4Header; }
/**
* Returns the IP protocol number from IPv4 Protocol field.
*
* @returns The IP protocol number.
*/
uint8_t GetIpProto(void) const { return mIp4Header.GetProtocol(); }
/**
* Returns the IPv4 header Total length value.
*
* @returns The IPv4 header Total length value.
*/
uint8_t GetIpLength(void) const { return mIp4Header.GetTotalLength(); }
/**
* Returns the IPv4 TTL value.
*
* @returns The IPv4 TTL value.
*/
uint8_t GetIpTtl(void) const { return mIp4Header.GetTtl(); }
/**
* Indicates if the protocol number from IPv4 header is UDP.
*
* @retval TRUE If the protocol number in IPv4 header is UDP.
* @retval FALSE If the protocol number in IPv4 header is not UDP.
*/
bool IsUdp(void) const { return GetIpProto() == kProtoUdp; }
/**
* Indicates if the protocol number from IPv4 header is TCP.
*
* @retval TRUE If the protocol number in IPv4 header is TCP.
* @retval FALSE If the protocol number in IPv4 header is not TCP.
*/
bool IsTcp(void) const { return GetIpProto() == kProtoTcp; }
/**
* Indicates if the protocol number from IPv4 header is ICMPv4.
*
* @retval TRUE If the protocol number in IPv4 header is ICMPv4.
* @retval FALSE If the protocol number in IPv4 header is not ICMPv4.
*/
bool IsIcmp4(void) const { return GetIpProto() == kProtoIcmp; }
/**
* Returns the source IPv4 address from IPv4 header.
*
* @returns The source IPv4 address.
*/
const Address &GetSourceAddress(void) const { return mIp4Header.GetSource(); }
/**
* Returns the destination IPv4 address from IPv4 header.
*
* @returns The destination IPv4 address.
*/
const Address &GetDestinationAddress(void) const { return mIp4Header.GetDestination(); }
/**
* Returns the UDP header.
*
* MUST be used when `IsUdp() == true`. Otherwise its behavior is undefined
*
* @returns The UDP header.
*/
const Udp::Header &GetUdpHeader(void) const { return mHeader.mUdp; }
/**
* Returns the TCP header.
*
* MUST be used when `IsTcp() == true`. Otherwise its behavior is undefined
*
* @returns The TCP header.
*/
const Tcp::Header &GetTcpHeader(void) const { return mHeader.mTcp; }
/**
* Returns the ICMPv4 header.
*
* MUST be used when `IsIcmp4() == true`. Otherwise its behavior is undefined
*
* @returns The ICMPv4 header.
*/
const Icmp::Header &GetIcmpHeader(void) const { return mHeader.mIcmp; }
/**
* Returns the source port number if the header is UDP or TCP, or zero otherwise
*
* @returns The source port number under UDP / TCP or zero.
*/
uint16_t GetSourcePort(void) const;
/**
* Returns the destination port number if the header is UDP or TCP, or zero otherwise.
*
* @returns The destination port number under UDP / TCP or zero.
*/
uint16_t GetDestinationPort(void) const;
/**
* Sets the destination port number if the header is UDP or TCP, does nothing otherwise
*
* @param[in] aDstPort The UDP / TCP destination Port.
*/
void SetDestinationPort(uint16_t aDstPort);
/**
* Returns the checksum values from corresponding UDP, TCP, or ICMPv4 header.
*
* @returns The checksum value.
*/
uint16_t GetChecksum(void) const;
private:
Header mIp4Header;
union
{
Udp::Header mUdp;
Tcp::Header mTcp;
Icmp::Header mIcmp;
} mHeader;
};
/**
* @}
*/
+17
View File
@@ -1619,6 +1619,23 @@ uint16_t Headers::GetSourcePort(void) const
return port;
}
void Headers::SetSourcePort(uint16_t aSrcPort)
{
switch (GetIpProto())
{
case kProtoUdp:
mHeader.mUdp.SetSourcePort(aSrcPort);
break;
case kProtoTcp:
mHeader.mTcp.SetSourcePort(aSrcPort);
break;
default:
break;
}
}
uint16_t Headers::GetDestinationPort(void) const
{
uint16_t port = 0;
+21
View File
@@ -466,6 +466,20 @@ public:
*/
uint8_t GetIpProto(void) const { return mIp6Header.GetNextHeader(); }
/**
* Returns the IPv6 Payload Length value.
*
* @returns The IPv6 Payload Length value.
*/
uint8_t GetIpLength(void) const { return mIp6Header.GetPayloadLength(); }
/**
* Returns the IPv6 Hop Limit value.
*
* @returns The IPv6 Hop Limit value.
*/
uint8_t GetIpHopLimit(void) const { return mIp6Header.GetHopLimit(); }
/**
* Returns the 2-bit Explicit Congestion Notification (ECN) from Traffic Class field from IPv6 header.
*
@@ -545,6 +559,13 @@ public:
*/
uint16_t GetSourcePort(void) const;
/**
* Sets the source port number if the header is UDP or TCP, does nothing otherwise
*
* @param[in] aSrcPort The UDP / TCP source Port.
*/
void SetSourcePort(uint16_t aSrcPort);
/**
* Returns the destination port number if header is UDP or TCP, or zero otherwise.
*
+14
View File
@@ -533,6 +533,20 @@ public:
*/
uint16_t GetDestinationPort(void) const { return BigEndian::HostSwap16(mDestination); }
/**
* Sets the TCP Source Port.
*
* @param[in] aPort The TCP Source Port.
*/
void SetSourcePort(uint16_t aPort) { mSource = BigEndian::HostSwap16(aPort); }
/**
* Sets the TCP Destination Port.
*
* @param[in] aPort The TCP Destination Port.
*/
void SetDestinationPort(uint16_t aPort) { mDestination = BigEndian::HostSwap16(aPort); }
/**
* Returns the TCP Sequence Number.
*