Branch data Line data Source code
1 : : /* 2 : : ** Copyright (C) 2023 Sylvain Fargier 3 : : ** 4 : : ** This software is provided 'as-is', without any express or implied 5 : : ** warranty. In no event will the authors be held liable for any damages 6 : : ** arising from the use of this software. 7 : : ** 8 : : ** Permission is granted to anyone to use this software for any purpose, 9 : : ** including commercial applications, and to alter it and redistribute it 10 : : ** freely, subject to the following restrictions: 11 : : ** 12 : : ** 1. The origin of this software must not be misrepresented; you must not 13 : : ** claim that you wrote the original software. If you use this software 14 : : ** in a product, an acknowledgment in the product documentation would be 15 : : ** appreciated but is not required. 16 : : ** 2. Altered source versions must be plainly marked as such, and must not be 17 : : ** misrepresented as being the original software. 18 : : ** 3. This notice may not be removed or altered from any source distribution. 19 : : ** 20 : : ** Created on: 2023-12-21T22:20:54 21 : : ** Author: Sylvain Fargier <fargier.sylvain@gmail.com> 22 : : */ 23 : : 24 : : #include "RawIPSocket.hpp" 25 : : 26 : : #include <netinet/in.h> 27 : : #include <sys/socket.h> 28 : : 29 : : #include "../../Exception.hpp" 30 : : #include "RawIPMessage.hpp" 31 : : 32 : : namespace ccut { 33 : : namespace net { 34 : : 35 : : static const std::string s_logCat{"ccut:net:raw"}; 36 : : 37 : 1 : RawIPv4Socket::RawIPv4Socket(Protocol proto, const std::string &name) : 38 : : Socket(name), 39 : 1 : m_proto(proto) 40 : 1 : {} 41 : : 42 : 1 : int RawIPv4Socket::makeSocket(bool ipv6) 43 : : { 44 : 1 : if (ipv6) 45 : 0 : throw Exception(ErrorCode::Runtime, 46 : 0 : "can't bind a v4 socket using bind6"); 47 : : 48 : 1 : int ret = socket(AF_INET, SOCK_RAW, enum_cast(m_proto)); 49 : 1 : if (ret >= 0) 50 : : { 51 : 0 : int value = 1; 52 : 0 : setsockopt(ret, IPPROTO_IP, IP_HDRINCL, &value, sizeof(value)); 53 : : } 54 : 1 : else if (errno == EPERM) 55 : : { 56 : 1 : logger::error(s_logCat) << "failed to open RAW socket"; 57 : 2 : logger::info(s_logCat) << "try `setcap cap_net_raw=ep <exe>` on " 58 : 1 : "run this process as root"; 59 : : } 60 : : 61 : 1 : return ret; 62 : : } 63 : : 64 : 0 : RawIPv4Socket::Message RawIPv4Socket::processMessage( 65 : : const address_t &from, 66 : : const address_t &to, 67 : : const cow_ptr<buffer_t> &buffer) 68 : : { 69 : 0 : logger::debug(s_logCat) << "(raw) message received " << from << " -> " << to 70 : 0 : << " size:" << (buffer ? buffer->size() : -1); 71 : 0 : return Message(from, to, buffer); 72 : : } 73 : : 74 : 1 : RawIPv6Socket::RawIPv6Socket(Protocol proto, const std::string &name) : 75 : : Socket(name), 76 : 1 : m_proto(proto) 77 : 1 : {} 78 : : 79 : 1 : int RawIPv6Socket::makeSocket(bool ipv6) 80 : : { 81 : 1 : if (!ipv6) 82 : 0 : throw Exception(ErrorCode::Runtime, 83 : 0 : "can't bind a v6 socket using bind4"); 84 : : 85 : : #ifndef IPV6_HDRINCL 86 : : /* see 87 : : * https://github.com/torvalds/linux/commit/715f504b118998c41a2079a17e16bf5a8a114885 88 : : * for details 89 : : */ 90 : : #ifndef STATIC_ANALYSIS 91 : : #warning RawIPv6Socket not supported, kernel too old 92 : : #endif 93 : : 94 : : throw Exception(ErrorCode::NotSupported, 95 : : "Raw IPv6 not supported, kernel headers must be >=4.5"); 96 : : 97 : : #else 98 : 1 : int ret = socket(AF_INET6, SOCK_RAW, enum_cast(m_proto)); 99 : 1 : if (ret >= 0) 100 : : { 101 : 0 : int value = 1; 102 : 0 : setsockopt(ret, IPPROTO_IPV6, IPV6_HDRINCL, &value, sizeof(value)); 103 : : } 104 : 1 : else if (errno == EPERM) 105 : : { 106 : 1 : logger::error(s_logCat) << "failed to open RAW socket"; 107 : 2 : logger::info(s_logCat) << "try `setcap cap_net_raw=ep <exe>` on " 108 : 1 : "run this process as root"; 109 : : } 110 : : 111 : 1 : return ret; 112 : : #endif 113 : : } 114 : : 115 : 0 : RawIPv6Socket::Message RawIPv6Socket::processMessage( 116 : : const address_t &from, 117 : : const address_t &to, 118 : : const cow_ptr<buffer_t> &buffer) 119 : : { 120 : 0 : logger::debug(s_logCat) << "(raw) message received " << from << " -> " << to 121 : 0 : << " size:" << (buffer ? buffer->size() : -1); 122 : : /* even with IPV6_HDRINCL it seems that header is not present when receiving 123 : : * packets, let's reconstruct (until a better solution is found) 124 : : * FIXME: one should use recvmsg to better reconstruct this (adding hoplimit 125 : : * and other fields) */ 126 : 0 : Message ret(from, to); 127 : 0 : ret.data = make_cow<buffer_t>(RawIPv6Message::MinDataSize + buffer->size()); 128 : 0 : ret.setNextHeader(m_proto); 129 : 0 : std::copy(buffer->cbegin(), buffer->cend(), 130 : 0 : ret.data.data() + RawIPv6Message::MinDataSize); 131 : 0 : ret.prepare(); 132 : 0 : return ret; 133 : 0 : } 134 : : 135 : : } // namespace net 136 : : } // namespace ccut