UlsoPacket.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. /*
  2. * Copyright (c) 2021 The Linux Foundation. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions are
  6. * met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above
  10. * copyright notice, this list of conditions and the following
  11. * disclaimer in the documentation and/or other materials provided
  12. * with the distribution.
  13. * * Neither the name of The Linux Foundation nor the names of its
  14. * contributors may be used to endorse or promote products derived
  15. * from this software without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
  18. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  19. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
  20. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
  21. * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  22. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  23. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
  24. * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  25. * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
  26. * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
  27. * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. */
  29. #ifndef NETWORK_TRAFFIC_ULSOPACKET_H
  30. #define NETWORK_TRAFFIC_ULSOPACKET_H
  31. #include <algorithm>
  32. #include <utility>
  33. #include <stdexcept>
  34. #include "QmapHeader.h"
  35. #include "UdpHeader.h"
  36. #include "TcpHeader.h"
  37. #include "IPv4Header.h"
  38. #include "IPv6Header.h"
  39. #include "packets.h"
  40. #include "Ethernet2Header.h"
  41. template <typename Transport=UdpHeader, typename Internet=IPv4Header>
  42. class UlsoPacket {
  43. static_assert(std::is_base_of<TransportHeader, Transport>::value,
  44. "Transport is not derived from TransportHeader");
  45. static_assert(std::is_base_of<InternetHeader, Internet>::value,
  46. "Internet is not derived from InternetHeader");
  47. private:
  48. static constexpr uint8_t qmapIPv4UdpPacketNoSeg[] = {
  49. //C=0,Next Header=1,PAD=b'63,MUXID=0,Packet length=30
  50. 0X7f, 0x00, 0x00, 0x1e,//QMAP header
  51. //type=3,Next Header=0,IPIDCfg=1,Zero Checksum=1,Additional header size=0,segment size=2
  52. 0X06, 0xc0, 0x00, 0x02,//QMAP header extension
  53. //IPv4 header
  54. 0x45, 0x00, 0x00, 0x1e,//version=4,IHL=5,DSCP=0,ECN=0,length=30
  55. 0x00, 0x00, 0x00, 0x00,//id=0,flags=0,fragment offset=0
  56. 0xff, 0x11, 0x36, 0x03,//TTL=255,Protocol=17 (TCP),checksum=
  57. 0xc0, 0xa8, 0x02, 0x13,//IPv4 SRC Addr 192.168.2.19
  58. 0xc0, 0xa8, 0x02, 0x68,//IPv4 DST Addr 192.168.2.104
  59. //UDP header
  60. 0x04, 0x57, 0x08, 0xae,//source port=1111, destination port=2222
  61. 0x00, 0x0a, 0x00, 0x00,//length=10,checksum=
  62. //payload
  63. 0x00, 0x01
  64. };
  65. /**
  66. * Resembles ULSO related endpoint configurations.
  67. */
  68. unsigned int mMinId {0};
  69. unsigned int mMaxId {65535};
  70. bool mIsSegmented {false};
  71. public:
  72. static constexpr int maxSize {65536};//64 KB
  73. QmapHeader mQmapHeader;
  74. Ethernet2Header mEthernetHeader;
  75. Internet mInternetHeader;
  76. bool mEthernetHeaderValid {false};
  77. Transport mTransportHeader;
  78. vector<uint8_t> mPayload {};
  79. UlsoPacket(unsigned int segmentSize, unsigned int payloadSize, bool ethernetHeaderValid=true):
  80. mEthernetHeaderValid(ethernetHeaderValid){
  81. bool first = true;
  82. uint32_t seqNum = 0;
  83. mQmapHeader.setmSegmentSize(segmentSize);
  84. if(mEthernetHeaderValid){
  85. mEthernetHeader.setmEtherType(mInternetHeader.getEtherType());
  86. }
  87. mPayload = vector<uint8_t>(payloadSize);
  88. for(unsigned int i = 0; i < payloadSize; i++){
  89. mPayload[i] = i % UINT8_MAX;
  90. }
  91. mInternetHeader.adjust(mTransportHeader.size() + mPayload.size(), mTransportHeader.protocolNum());
  92. mQmapHeader.setmPacketLength(mInternetHeader.size() + mTransportHeader.size() + mPayload.size());
  93. adjustHeader(mTransportHeader, seqNum, first);
  94. }
  95. UlsoPacket(unsigned int segmentSize, uint8_t* payload, unsigned int payloadSize){
  96. bool first = true;
  97. uint32_t seqNum = 0;
  98. mQmapHeader.setmSegmentSize(segmentSize);
  99. mPayload = vector<uint8_t>{payload, payload + payloadSize};
  100. mInternetHeader.adjust(mTransportHeader.size() + mPayload.size(), mTransportHeader.protocolNum());
  101. mQmapHeader.setmPacketLength(mInternetHeader.size() + mTransportHeader.size() + mPayload.size());
  102. adjustHeader(mTransportHeader, seqNum, first);
  103. }
  104. size_t size() const {
  105. return (!isSegmented() * mQmapHeader.size()) + (mEthernetHeaderValid * mEthernetHeader.size())
  106. + mInternetHeader.size() + mTransportHeader.size() + mPayload.size();
  107. }
  108. UlsoPacket(const QmapHeader& qmapHeader, const Internet& iPv4Header, const Transport& udpHeader,
  109. const vector<uint8_t>& payload) :
  110. mQmapHeader(qmapHeader),
  111. mInternetHeader(iPv4Header),
  112. mTransportHeader(udpHeader),
  113. mPayload(payload) {}
  114. explicit UlsoPacket(size_t bufLen, uint8_t *buf=const_cast<uint8_t *>(qmapIPv4UdpPacketNoSeg)) {
  115. size_t curIndex = 0;
  116. mQmapHeader = QmapHeader(buf + curIndex);
  117. curIndex += mQmapHeader.size();
  118. mInternetHeader = Internet(buf + curIndex);
  119. curIndex += mInternetHeader.size();
  120. mTransportHeader = Transport(buf + curIndex);
  121. curIndex += mTransportHeader.size();
  122. mPayload = vector<uint8_t>();
  123. while(curIndex < bufLen){
  124. mPayload.emplace_back(buf[curIndex]);
  125. curIndex++;
  126. }
  127. }
  128. UlsoPacket(){
  129. mQmapHeader.setmPacketLength(mInternetHeader.size() + mTransportHeader.size() + mPayload.size());
  130. mInternetHeader.adjust(mTransportHeader.size() + mPayload.size(), mTransportHeader.protocolNum());
  131. adjustHeader(mTransportHeader, 0, true);
  132. }
  133. vector<bool> asVector() const {
  134. vector<bool> outVec;
  135. auto concatenateFunc = [](vector<bool>& v1, const vector<bool>& v2){
  136. v1.insert(v1.end(), v2.begin(), v2.end());
  137. };
  138. if(!mIsSegmented){
  139. concatenateFunc(outVec, mQmapHeader.asVector());
  140. }
  141. if(mEthernetHeaderValid){
  142. concatenateFunc(outVec, mEthernetHeader.asVector());
  143. }
  144. concatenateFunc(outVec, mInternetHeader.asVector());
  145. concatenateFunc(outVec, mTransportHeader.asVector());
  146. std::for_each(mPayload.cbegin(), mPayload.cend(), [&outVec](char c){
  147. for (int i = SIZE_OF_BITS(c) - 1; i >= 0; i--)
  148. outVec.emplace_back((c & ( 1 << i )) >> i); // NOLINT(hicpp-signed-bitwise)
  149. });
  150. return outVec;
  151. }
  152. uint8_t* asArray() const {
  153. vector<bool> vec = asVector();
  154. size_t resSize = vec.size() / CHAR_BIT + ((vec.size() % CHAR_BIT) > 0);
  155. auto *outArr = new uint8_t[resSize];
  156. asArray(outArr);
  157. return outArr;
  158. }
  159. size_t asArray(uint8_t* buf) const {
  160. vector<bool> vec = asVector();
  161. size_t bufSize = vec.size() / CHAR_BIT + ((vec.size() % CHAR_BIT) > 0);
  162. memset(buf, 0, bufSize);
  163. if(!isSegmented()){
  164. buf += mQmapHeader.asArray(buf);
  165. }
  166. if(mEthernetHeaderValid){
  167. buf += mEthernetHeader.asArray(buf);
  168. }
  169. buf += mInternetHeader.asArray(buf);
  170. buf += mTransportHeader.asArray(buf);
  171. for(auto val: mPayload){
  172. *buf++ = val;
  173. }
  174. return bufSize;
  175. }
  176. vector<UlsoPacket> segment() const {
  177. bool first = true;
  178. uint32_t seqNum = 0;
  179. if(isSegmented()){
  180. return vector<UlsoPacket>();
  181. }
  182. unsigned int segmentSize = mQmapHeader.mSegmentSize.to_ulong();
  183. vector<vector<uint8_t>> payloads = segmentPayload(segmentSize, mPayload);
  184. UlsoPacket ulsoCopy(*this);
  185. fixFlags(ulsoCopy.mTransportHeader);
  186. vector<UlsoPacket> outVec = vector<UlsoPacket>(payloads.size(), ulsoCopy);
  187. for(size_t i = 0; i < outVec.size(); i++){
  188. UlsoPacket& p = outVec[i];
  189. p.mPayload = payloads[i];
  190. }
  191. if(!outVec.empty()){
  192. fixLastSegmentFlags(outVec[outVec.size() - 1].mTransportHeader);
  193. }
  194. if(mQmapHeader.mIpIdCfg == 0){
  195. fixIpId(outVec, mMinId, mMaxId);
  196. }
  197. for(UlsoPacket& p: outVec){
  198. p.mInternetHeader.adjust(p.mTransportHeader.size() + p.mPayload.size(), p.mTransportHeader.protocolNum());
  199. p.adjustHeader(p.mTransportHeader, seqNum, first);
  200. p.mIsSegmented = true;
  201. }
  202. return outVec;
  203. }
  204. bool isSegmented() const {
  205. return mIsSegmented;
  206. }
  207. void setIpId(const uint16_t id){
  208. changeIpId(mInternetHeader, mTransportHeader);
  209. }
  210. void changeIpId(IPv4Header& iPv4Header, UdpHeader& udpHeader){
  211. bool first = true;
  212. uint32_t seqNum = 0;
  213. mInternetHeader.adjust(mTransportHeader.size() + mPayload.size(), mTransportHeader.protocolNum());
  214. adjustHeader(mTransportHeader, seqNum, first);
  215. }
  216. void changeIpId(IPv4Header& iPv4Header, TcpHeader& tcpHeader){
  217. bool first = true;
  218. uint32_t seqNum = 0;
  219. mInternetHeader.adjust(mTransportHeader.size() + mPayload.size(), mTransportHeader.protocolNum());
  220. adjustHeader(mTransportHeader, seqNum, first);
  221. }
  222. private:
  223. static void fixFlags(TcpHeader& tcpHeader){
  224. tcpHeader.setmFIN(0);
  225. tcpHeader.setmPSH(0);
  226. tcpHeader.setmRST(0);
  227. tcpHeader.setmCWR(0);
  228. }
  229. static void fixFlags(UdpHeader& udpHeader){}
  230. void fixLastSegmentFlags(TcpHeader& tcpHeader) const {
  231. TcpHeader::flags flags = mTransportHeader.getFlags();
  232. tcpHeader.setmFIN(flags.fin);
  233. tcpHeader.setmPSH(flags.psh);
  234. tcpHeader.setmRST(flags.rst);
  235. tcpHeader.setmCWR(flags.cwr);
  236. }
  237. void fixLastSegmentFlags(UdpHeader& udpHeader) const {}
  238. static vector<vector<uint8_t>> segmentPayload(unsigned long segmentSize, const vector<uint8_t>& payload) {
  239. vector<vector<uint8_t>> outVec;
  240. for(size_t i = 0; i < payload.size(); i += segmentSize) {
  241. auto last = std::min<size_t>(static_cast<size_t>(payload.size()), i + segmentSize);
  242. auto index = i / segmentSize;
  243. outVec.emplace_back(vector<uint8_t>());
  244. auto& vec = outVec[index];
  245. vec.reserve(last - i);
  246. move(payload.begin() + i, payload.begin() + last, back_inserter(vec));
  247. }
  248. return outVec;
  249. }
  250. void adjustHeader(TcpHeader& tcpHeader, uint32_t& seqNum, bool& first){
  251. tcpHeader.zeroChecksum();
  252. if(first){
  253. seqNum = tcpHeader.getSeqNum();
  254. first = false;
  255. }
  256. tcpHeader.setmSequenceNumber(seqNum);
  257. seqNum += mPayload.size();
  258. size_t checksumBufSize = mInternetHeader.l3ChecksumPseudoHeaderSize() + mTransportHeader.size() + mPayload.size();
  259. uint8_t checksumBuf[checksumBufSize];
  260. memset(checksumBuf, 0, checksumBufSize);
  261. uint8_t *checksumBufPtr = checksumBuf;
  262. size_t ulsoBufSize = size();
  263. uint8_t ulsoBuf[ulsoBufSize];
  264. memset(ulsoBuf, 0, ulsoBufSize);
  265. asArray(ulsoBuf);
  266. size_t ipOffset = mQmapHeader.size() + mEthernetHeaderValid * mEthernetHeader.size();
  267. mInternetHeader.tcpChecksumPseudoHeader(checksumBuf, ulsoBuf + ipOffset);
  268. checksumBufPtr += mInternetHeader.l3ChecksumPseudoHeaderSize();
  269. checksumBufPtr += tcpHeader.asArray(checksumBufPtr);
  270. for(auto val: mPayload){
  271. *checksumBufPtr++ = val;
  272. }
  273. mTransportHeader.adjust(checksumBuf, checksumBufSize);
  274. }
  275. void adjustHeader(UdpHeader& udpHeader, uint32_t seqNum, bool first){
  276. udpHeader.zeroChecksum();
  277. if(mQmapHeader.mZeroChecksum.test(0)){
  278. mTransportHeader.adjust(mPayload.size());
  279. } else{
  280. udpHeader.setmLength(udpHeader.size() + mPayload.size());
  281. size_t checksumBufSize = mInternetHeader.l3ChecksumPseudoHeaderSize() + mTransportHeader.size() + mPayload.size();
  282. uint8_t checksumBuf[checksumBufSize];
  283. memset(checksumBuf, 0, checksumBufSize);
  284. uint8_t *checksumBufPtr = checksumBuf;
  285. size_t ulsoBufSize = size();
  286. uint8_t ulsoBuf[ulsoBufSize];
  287. memset(ulsoBuf, 0, ulsoBufSize);
  288. asArray(ulsoBuf);
  289. size_t ipOffset = mQmapHeader.size() + mEthernetHeaderValid * mEthernetHeader.size();
  290. mInternetHeader.udpChecksumPseudoHeader(checksumBuf, ulsoBuf + ipOffset);
  291. checksumBufPtr += mInternetHeader.l3ChecksumPseudoHeaderSize();
  292. checksumBufPtr += udpHeader.asArray(checksumBufPtr);
  293. for(auto val: mPayload){
  294. *checksumBufPtr++ = val;
  295. }
  296. mTransportHeader.adjust(checksumBuf, checksumBufSize, mPayload.size());
  297. }
  298. }
  299. template <typename T, typename I>
  300. friend std::ostream& operator<< (std::ostream &out, UlsoPacket<Transport, Internet> const& packet);
  301. };
  302. template <typename Transport, typename Internet>
  303. constexpr uint8_t UlsoPacket<Transport, Internet>::qmapIPv4UdpPacketNoSeg[];
  304. template <typename Transport, typename Internet>
  305. inline std::ostream& operator << (std::ostream &out, UlsoPacket<Transport, Internet> const& packet) {
  306. out << "ULSO Packet\n" << "#Bytes=" << packet.size() << std::endl;
  307. if(!packet.isSegmented()){
  308. out << packet.mQmapHeader << std::endl;
  309. } else {
  310. out << "QMAP header removed in segmentation\n";
  311. }
  312. if(packet.mEthernetHeaderValid){
  313. out << packet.mEthernetHeader << std::endl;
  314. }
  315. out << packet.mInternetHeader << std::endl;
  316. out << packet.mTransportHeader << std::endl;
  317. out << "Payload\n" << packet.mPayload;
  318. return out;
  319. }
  320. template<typename Transport, typename Internet>
  321. void fixIpId(vector<UlsoPacket<Transport, Internet>>& v, unsigned int minId, unsigned int maxId) {
  322. return;
  323. }
  324. template<>
  325. void fixIpId<UdpHeader, IPv4Header>(vector<UlsoPacket<UdpHeader, IPv4Header>>& v, unsigned int minId, unsigned int maxId) {
  326. unsigned int curId = 0;
  327. if(!v.empty()){
  328. curId = std::max(static_cast<unsigned int>(v[0].mInternetHeader.mId.to_ulong()), minId) % (maxId + 1);
  329. }
  330. for (auto &p: v) {
  331. p.mInternetHeader.setmId(curId);
  332. curId++;
  333. if (curId == (maxId + 1)) curId = minId;
  334. }
  335. }
  336. template<>
  337. void fixIpId<TcpHeader, IPv4Header>(vector<UlsoPacket<TcpHeader, IPv4Header>>& v, unsigned int minId, unsigned int maxId) {
  338. unsigned int curId = 0;
  339. if(!v.empty()){
  340. curId = std::max(static_cast<unsigned int>(v[0].mInternetHeader.mId.to_ulong()), minId) % (maxId + 1);
  341. }
  342. for (auto &p: v) {
  343. p.mInternetHeader.setmId(curId);
  344. curId++;
  345. if (curId == (maxId + 1)) curId = minId;
  346. }
  347. }
  348. template<typename Internet, typename Transport>
  349. bool changeIpId(Internet& ipHeader, uint16_t id){
  350. return false;
  351. }
  352. template<>
  353. bool changeIpId<IPv4Header, UdpHeader>(IPv4Header& iPv4Header, uint16_t id){
  354. iPv4Header.setmId(id);
  355. return true;
  356. }
  357. #endif //NETWORK_TRAFFIC_ULSOPACKET_H