Transport.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566
  1. #include "mumlib/Transport.hpp"
  2. #include "Mumble.pb.h"
  3. #include <boost/format.hpp>
  4. #include <utility>
  5. using namespace std;
  6. static boost::posix_time::seconds PING_INTERVAL(5);
  7. const long CLIENT_VERSION = 0x01020A;
  8. const string CLIENT_RELEASE("Mumlib");
  9. const string CLIENT_OS("OS Unknown");
  10. const string CLIENT_OS_VERSION("1");
  11. static map<MumbleProto::Reject_RejectType, string> rejectMessages = {
  12. {MumbleProto::Reject_RejectType_None, "no reason provided"},
  13. {MumbleProto::Reject_RejectType_WrongVersion, "wrong version"},
  14. {MumbleProto::Reject_RejectType_InvalidUsername, "invalid username"},
  15. {MumbleProto::Reject_RejectType_WrongUserPW, "wrong user password"},
  16. {MumbleProto::Reject_RejectType_WrongServerPW, "wrong server password"},
  17. {MumbleProto::Reject_RejectType_UsernameInUse, "username in use"},
  18. {MumbleProto::Reject_RejectType_ServerFull, "server full"},
  19. {MumbleProto::Reject_RejectType_NoCertificate, "no certificate provided"},
  20. {MumbleProto::Reject_RejectType_AuthenticatorFail, "authenticator fail"}
  21. };
  22. mumlib::Transport::Transport(
  23. io_service &ioService,
  24. mumlib::ProcessControlMessageFunction processMessageFunc,
  25. ProcessEncodedAudioPacketFunction processEncodedAudioPacketFunction,
  26. bool noUdp) :
  27. logger(log4cpp::Category::getInstance("mumlib.Transport")),
  28. ioService(ioService),
  29. processMessageFunction(std::move(processMessageFunc)),
  30. processEncodedAudioPacketFunction(std::move(processEncodedAudioPacketFunction)),
  31. noUdp(noUdp),
  32. state(ConnectionState::NOT_CONNECTED),
  33. udpSocket(ioService),
  34. sslContext(ssl::context::sslv23),
  35. sslSocket(ioService, sslContext),
  36. pingTimer(ioService, PING_INTERVAL),
  37. asyncBufferPool(static_cast<const unsigned long>(max(MAX_UDP_LENGTH, MAX_TCP_LENGTH))) {
  38. sslIncomingBuffer = new uint8_t[MAX_TCP_LENGTH];
  39. pingTimer.async_wait(boost::bind(&Transport::pingTimerTick, this, _1));
  40. }
  41. mumlib::Transport::~Transport() {
  42. disconnect();
  43. delete[] sslIncomingBuffer;
  44. }
  45. void mumlib::Transport::connect(
  46. std::string host,
  47. int port,
  48. std::string user,
  49. std::string password) {
  50. state = ConnectionState::IN_PROGRESS;
  51. connectionParams = make_pair(host, port);
  52. credentials = make_pair(user, password);
  53. udpActive = false;
  54. sslSocket.set_verify_mode(boost::asio::ssl::verify_peer);
  55. //todo for now it accepts every certificate, move it to callback
  56. sslSocket.set_verify_callback([](bool preverified, boost::asio::ssl::verify_context &ctx) {
  57. return true;
  58. });
  59. try {
  60. if (not noUdp) {
  61. ip::udp::resolver resolverUdp(ioService);
  62. ip::udp::resolver::query queryUdp(ip::udp::v4(), host, to_string(port));
  63. udpReceiverEndpoint = *resolverUdp.resolve(queryUdp);
  64. udpSocket.open(ip::udp::v4());
  65. doReceiveUdp();
  66. }
  67. ip::tcp::resolver resolverTcp(ioService);
  68. ip::tcp::resolver::query queryTcp(host, to_string(port));
  69. async_connect(sslSocket.lowest_layer(), resolverTcp.resolve(queryTcp),
  70. bind(&Transport::sslConnectHandler, this, boost::asio::placeholders::error));
  71. } catch (runtime_error &exp) {
  72. throwTransportException(string("failed to establish connection: ") + exp.what());
  73. }
  74. }
  75. void mumlib::Transport::disconnect() {
  76. if (state != ConnectionState::NOT_CONNECTED) {
  77. boost::system::error_code errorCode;
  78. // todo perform different operations for each ConnectionState
  79. sslSocket.shutdown(errorCode);
  80. if (errorCode) {
  81. logger.warn("SSL socket shutdown returned an error: %s.", errorCode.message().c_str());
  82. }
  83. sslSocket.lowest_layer().shutdown(tcp::socket::shutdown_both, errorCode);
  84. if (errorCode) {
  85. logger.warn("SSL socket lowest layer shutdown returned an error: %s.", errorCode.message().c_str());
  86. }
  87. udpSocket.close(errorCode);
  88. if (errorCode) {
  89. logger.warn("UDP socket close returned error: %s.", errorCode.message().c_str());
  90. }
  91. state = ConnectionState::NOT_CONNECTED;
  92. }
  93. }
  94. void mumlib::Transport::sendVersion() {
  95. MumbleProto::Version version;
  96. version.set_version(CLIENT_VERSION);
  97. version.set_os(CLIENT_OS);
  98. version.set_release(CLIENT_RELEASE);
  99. version.set_os_version(CLIENT_OS_VERSION);
  100. logger.info("Sending version information.");
  101. sendControlMessagePrivate(MessageType::VERSION, version);
  102. }
  103. void mumlib::Transport::sendAuthentication() {
  104. string user, password;
  105. tie(user, password) = credentials;
  106. MumbleProto::Authenticate authenticate;
  107. authenticate.set_username(user);
  108. authenticate.set_password(password);
  109. authenticate.clear_celt_versions();
  110. authenticate.clear_tokens();
  111. authenticate.set_opus(true);
  112. logger.info("Sending authententication.");
  113. sendControlMessagePrivate(MessageType::AUTHENTICATE, authenticate);
  114. }
  115. void mumlib::Transport::sendSslPing() {
  116. MumbleProto::Ping ping;
  117. ping.set_timestamp(std::time(nullptr));
  118. logger.debug("Sending SSL ping.");
  119. sendControlMessagePrivate(MessageType::PING, ping);
  120. }
  121. bool mumlib::Transport::isUdpActive() {
  122. return udpActive;
  123. }
  124. void mumlib::Transport::doReceiveUdp() {
  125. if (state == ConnectionState::NOT_CONNECTED) {
  126. return;
  127. }
  128. udpSocket.async_receive_from(
  129. buffer(udpIncomingBuffer, MAX_UDP_LENGTH),
  130. udpReceiverEndpoint,
  131. [this](const boost::system::error_code &ec, size_t bytesTransferred) {
  132. if (!ec and bytesTransferred > 0) {
  133. logger.debug("Received UDP packet of %d B.", bytesTransferred);
  134. if (not cryptState.isValid()) {
  135. throwTransportException("received UDP packet before CRYPT SETUP message");
  136. } else {
  137. lastReceivedUdpPacketTimestamp = std::chrono::system_clock::now();
  138. if (udpActive == false) {
  139. udpActive = true;
  140. logger.notice("UDP is up.");
  141. }
  142. uint8_t plainBuffer[1024];
  143. const int plainBufferLength = static_cast<const int>(bytesTransferred - 4);
  144. bool success = cryptState.decrypt(
  145. udpIncomingBuffer, plainBuffer, static_cast<unsigned int>(bytesTransferred));
  146. if (not success) {
  147. throwTransportException("UDP packet decryption failed");
  148. }
  149. processAudioPacket(plainBuffer, plainBufferLength);
  150. }
  151. doReceiveUdp();
  152. } else if (ec == boost::asio::error::operation_aborted) {
  153. logger.debug("UDP receive function cancelled.");
  154. } else {
  155. throwTransportException("UDP receive failed: " + ec.message());
  156. }
  157. });
  158. }
  159. void mumlib::Transport::sslConnectHandler(const boost::system::error_code &error) {
  160. if (!error) {
  161. sslSocket.async_handshake(ssl::stream_base::client,
  162. boost::bind(&Transport::sslHandshakeHandler, this,
  163. boost::asio::placeholders::error));
  164. }
  165. else {
  166. throwTransportException((boost::format("Connect failed: %s.") % error.message()).str());
  167. }
  168. }
  169. void mumlib::Transport::sslHandshakeHandler(const boost::system::error_code &error) {
  170. if (!error) {
  171. doReceiveSsl();
  172. sendVersion();
  173. sendAuthentication();
  174. }
  175. else {
  176. throwTransportException((boost::format("Handshake failed: %s.") % error.message()).str());
  177. }
  178. }
  179. void mumlib::Transport::pingTimerTick(const boost::system::error_code &e) {
  180. if (state == ConnectionState::CONNECTED) {
  181. sendSslPing();
  182. if (not noUdp) {
  183. using namespace std::chrono;
  184. sendUdpPing();
  185. if (udpActive) {
  186. const int lastUdpReceivedMilliseconds = duration_cast<milliseconds>(
  187. system_clock::now() - lastReceivedUdpPacketTimestamp).count();
  188. if (lastUdpReceivedMilliseconds > PING_INTERVAL.total_milliseconds() + 1000) {
  189. udpActive = false;
  190. logger.warn("Didn't receive UDP ping in %d ms, falling back to TCP.", lastUdpReceivedMilliseconds);
  191. }
  192. }
  193. }
  194. }
  195. pingTimer.expires_at(pingTimer.expires_at() + PING_INTERVAL);
  196. pingTimer.async_wait(boost::bind(&Transport::pingTimerTick, this, _1));
  197. }
  198. void mumlib::Transport::sendUdpAsync(uint8_t *buff, int length) {
  199. if (length > MAX_UDP_LENGTH - 4) {
  200. throwTransportException("maximum allowed data length is %d" + to_string(MAX_UDP_LENGTH - 4));
  201. }
  202. auto *encryptedMsgBuff = asyncBufferPool.malloc();
  203. const int encryptedMsgLength = length + 4;
  204. cryptState.encrypt(buff, reinterpret_cast<uint8_t *>(encryptedMsgBuff), static_cast<unsigned int>(length));
  205. logger.debug("Sending %d B of data UDP asynchronously.", encryptedMsgLength);
  206. udpSocket.async_send_to(
  207. boost::asio::buffer(encryptedMsgBuff, static_cast<size_t>(length + 4)),
  208. udpReceiverEndpoint,
  209. [this, encryptedMsgBuff](const boost::system::error_code &ec, size_t bytesTransferred) {
  210. asyncBufferPool.free(encryptedMsgBuff);
  211. if (!ec and bytesTransferred > 0) {
  212. logger.debug("Sent %d B via UDP.", bytesTransferred);
  213. } else {
  214. throwTransportException("UDP send failed: " + ec.message());
  215. }
  216. });
  217. }
  218. void mumlib::Transport::doReceiveSsl() {
  219. if (state == ConnectionState::NOT_CONNECTED) {
  220. return;
  221. }
  222. async_read(
  223. sslSocket,
  224. boost::asio::buffer(sslIncomingBuffer, MAX_TCP_LENGTH),
  225. [this](const boost::system::error_code &error, size_t bytesTransferred) -> size_t {
  226. if (bytesTransferred < 6) {
  227. // we need the message header to determine the payload length
  228. return 6 - bytesTransferred;
  229. }
  230. const int payloadSize = ntohl(*reinterpret_cast<uint32_t *>(sslIncomingBuffer + 2));
  231. const int wholeMessageLength = payloadSize + 6;
  232. size_t remaining = wholeMessageLength - bytesTransferred;
  233. remaining = max(remaining, (size_t) 0);
  234. if (wholeMessageLength > MAX_TCP_LENGTH) {
  235. throwTransportException(
  236. (boost::format("message bigger (%d B) than max allowed size (%d B)")
  237. % wholeMessageLength % MAX_TCP_LENGTH).str());
  238. }
  239. return remaining;
  240. },
  241. [this](const boost::system::error_code &ec, size_t bytesTransferred) {
  242. if (!ec and bytesTransferred > 0) {
  243. int messageType = ntohs(*reinterpret_cast<uint16_t *>(sslIncomingBuffer));
  244. logger.debug("Received %d B of data (%d B payload, type %d).", bytesTransferred,
  245. bytesTransferred - 6, messageType);
  246. processMessageInternal(
  247. static_cast<MessageType>(messageType),
  248. &sslIncomingBuffer[6],
  249. static_cast<int>(bytesTransferred - 6));
  250. doReceiveSsl();
  251. } else {
  252. logger.error("SSL receiver error: %s. Bytes transferred: %d.",
  253. ec.message().c_str(), bytesTransferred);
  254. //todo temporarily disable exception throwing until issue #6 is solved
  255. //throwTransportException("receive failed: " + ec.message());
  256. }
  257. });
  258. }
  259. void mumlib::Transport::processMessageInternal(MessageType messageType, uint8_t *buffer, int length) {
  260. switch (messageType) {
  261. case MessageType::UDPTUNNEL: {
  262. logger.debug("Received %d B of encoded audio data via TCP.", length);
  263. processAudioPacket(buffer, length);
  264. }
  265. break;
  266. case MessageType::AUTHENTICATE: {
  267. logger.warn("Authenticate message received after authenticated.");
  268. }
  269. break;
  270. case MessageType::PING: {
  271. MumbleProto::Ping ping;
  272. ping.ParseFromArray(buffer, length);
  273. stringstream log;
  274. log << "Received ping.";
  275. if (ping.has_good()) {
  276. log << " good: " << ping.good();
  277. }
  278. if (ping.has_late()) {
  279. log << " late: " << ping.late();
  280. }
  281. if (ping.has_lost()) {
  282. log << " lost: " << ping.lost();
  283. }
  284. if (ping.has_tcp_ping_avg()) {
  285. log << " TCP avg: " << ping.tcp_ping_avg() << " ms";
  286. }
  287. if (ping.has_udp_ping_avg()) {
  288. log << " UDP avg: " << ping.udp_ping_avg() << " ms";
  289. }
  290. logger.debug(log.str());
  291. }
  292. break;
  293. case MessageType::REJECT: {
  294. MumbleProto::Reject reject;
  295. reject.ParseFromArray(buffer, length);
  296. stringstream errorMesg;
  297. errorMesg << "failed to authenticate";
  298. if (reject.has_type()) {
  299. errorMesg << ": " << rejectMessages.at(reject.type());
  300. }
  301. if (reject.has_reason()) {
  302. errorMesg << ", reason: " << reject.reason();
  303. }
  304. throwTransportException(errorMesg.str());
  305. }
  306. break;
  307. case MessageType::SERVERSYNC: {
  308. state = ConnectionState::CONNECTED;
  309. logger.debug("SERVERSYNC. Calling external ProcessControlMessageFunction.");
  310. processMessageFunction(messageType, buffer, length);
  311. }
  312. break;
  313. case MessageType::CRYPTSETUP: {
  314. if (not noUdp) {
  315. MumbleProto::CryptSetup cryptsetup;
  316. cryptsetup.ParseFromArray(buffer, length);
  317. if (cryptsetup.client_nonce().length() != AES_BLOCK_SIZE
  318. or cryptsetup.server_nonce().length() != AES_BLOCK_SIZE
  319. or cryptsetup.key().length() != AES_BLOCK_SIZE) {
  320. throwTransportException("one of cryptographic parameters has invalid length");
  321. }
  322. cryptState.setKey(
  323. reinterpret_cast<const unsigned char *>(cryptsetup.key().c_str()),
  324. reinterpret_cast<const unsigned char *>(cryptsetup.client_nonce().c_str()),
  325. reinterpret_cast<const unsigned char *>(cryptsetup.server_nonce().c_str()));
  326. if (not cryptState.isValid()) {
  327. throwTransportException("crypt setup data not valid");
  328. }
  329. logger.info("Set up cryptography for UDP transport. Sending UDP ping.");
  330. sendUdpPing();
  331. } else {
  332. logger.info("Ignoring crypt setup message, because UDP is disabled.");
  333. }
  334. }
  335. break;
  336. default: {
  337. logger.debug("Calling external ProcessControlMessageFunction.");
  338. processMessageFunction(messageType, buffer, length);
  339. }
  340. break;
  341. }
  342. }
  343. void mumlib::Transport::sendUdpPing() {
  344. if (state == ConnectionState::NOT_CONNECTED) {
  345. logger.debug("State changed to NOT_CONNECTED, skipping UDP ping.");
  346. return;
  347. }
  348. logger.debug("Sending UDP ping.");
  349. vector<uint8_t> message;
  350. message.push_back(0x20);
  351. auto timestampVarint = VarInt(static_cast<int64_t>(time(nullptr))).getEncoded();
  352. message.insert(message.end(), timestampVarint.begin(), timestampVarint.end());
  353. sendUdpAsync(&message[0], static_cast<int>(message.size()));
  354. }
  355. void mumlib::Transport::sendSsl(uint8_t *buff, int length) {
  356. if (length > MAX_TCP_LENGTH) {
  357. logger.warn("Sending %d B of data via SSL. Maximal allowed data length to receive is %d B.", length,
  358. MAX_TCP_LENGTH);
  359. }
  360. logger.debug("Sending %d bytes of data.", length);
  361. try {
  362. write(sslSocket, boost::asio::buffer(buff, static_cast<size_t>(length)));
  363. } catch (boost::system::system_error &err) {
  364. throwTransportException(std::string("SSL send failed: ") + err.what());
  365. }
  366. }
  367. void mumlib::Transport::sendSslAsync(uint8_t *buff, int length) {
  368. if (length > MAX_TCP_LENGTH) {
  369. logger.warn("Sending %d B of data via SSL. Maximal allowed data length to receive is %d B.", length,
  370. MAX_TCP_LENGTH);
  371. }
  372. auto *asyncBuff = asyncBufferPool.malloc();
  373. memcpy(asyncBuff, buff, static_cast<size_t>(length));
  374. logger.debug("Sending %d B of data asynchronously.", length);
  375. async_write(
  376. sslSocket,
  377. boost::asio::buffer(asyncBuff, static_cast<size_t>(length)),
  378. [this, asyncBuff](const boost::system::error_code &ec, size_t bytesTransferred) {
  379. asyncBufferPool.free(asyncBuff);
  380. logger.debug("Sent %d B.", bytesTransferred);
  381. if (!ec and bytesTransferred > 0) {
  382. } else {
  383. throwTransportException("async SSL send failed: " + ec.message());
  384. }
  385. });
  386. }
  387. void mumlib::Transport::sendControlMessage(MessageType type, google::protobuf::Message &message) {
  388. if (state != ConnectionState::CONNECTED) {
  389. logger.warn("Connection not established.");
  390. return;
  391. }
  392. sendControlMessagePrivate(type, message);
  393. }
  394. void mumlib::Transport::sendControlMessagePrivate(MessageType type, google::protobuf::Message &message) {
  395. const uint16_t type_network = htons(static_cast<uint16_t>(type));
  396. const int size = message.ByteSize();
  397. const uint32_t size_network = htonl((uint32_t) size);
  398. const int length = sizeof(type_network) + sizeof(size_network) + size;
  399. uint8_t buff[MAX_TCP_LENGTH];
  400. memcpy(buff, &type_network, sizeof(type_network));
  401. memcpy(buff + sizeof(type_network), &size_network, sizeof(size_network));
  402. message.SerializeToArray(buff + sizeof(type_network) + sizeof(size_network), size);
  403. sendSsl(buff, length);
  404. }
  405. void mumlib::Transport::throwTransportException(string message) {
  406. state = ConnectionState::FAILED;
  407. throw TransportException(std::move(message));
  408. }
  409. void mumlib::Transport::sendEncodedAudioPacket(uint8_t *buffer, int length) {
  410. if (state != ConnectionState::CONNECTED) {
  411. logger.warn("Connection not established.");
  412. return;
  413. }
  414. if (udpActive) {
  415. logger.info("Sending %d B of audio data via UDP.", length);
  416. sendUdpAsync(buffer, length);
  417. } else {
  418. logger.info("Sending %d B of audio data via TCP.", length);
  419. const uint16_t netUdptunnelType = htons(static_cast<uint16_t>(MessageType::UDPTUNNEL));
  420. const uint32_t netLength = htonl(static_cast<uint32_t>(length));
  421. const int packet = sizeof(netUdptunnelType) + sizeof(netLength) + length;
  422. uint8_t packetBuff[MAX_TCP_LENGTH];
  423. memcpy(packetBuff, &netUdptunnelType, sizeof(netUdptunnelType));
  424. memcpy(packetBuff + sizeof(netUdptunnelType), &netLength, sizeof(netLength));
  425. memcpy(packetBuff + sizeof(netUdptunnelType) + sizeof(netLength), buffer, static_cast<size_t>(length));
  426. sendSslAsync(packetBuff, length + sizeof(netUdptunnelType) + sizeof(netLength));
  427. }
  428. }
  429. void mumlib::Transport::processAudioPacket(uint8_t *buff, int length) {
  430. auto type = static_cast<AudioPacketType >((buff[0] & 0xE0) >> 5);
  431. switch (type) {
  432. case AudioPacketType::CELT_Alpha:
  433. case AudioPacketType::Speex:
  434. case AudioPacketType::CELT_Beta:
  435. case AudioPacketType::OPUS:
  436. processEncodedAudioPacketFunction(type, buff, length);
  437. break;
  438. case AudioPacketType::Ping:
  439. break;
  440. default:
  441. logger.error("Not recognized audio type: %xd.", buff[0]);
  442. }
  443. }