Transport.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576
  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::reconnect() {
  95. boost::system::error_code errorCode;
  96. udpSocket.close(errorCode);
  97. if (errorCode) {
  98. logger.warn("SSL socket close return an error: %s.", errorCode.message().c_str());
  99. }
  100. }
  101. void mumlib::Transport::sendVersion() {
  102. MumbleProto::Version version;
  103. version.set_version(CLIENT_VERSION);
  104. version.set_os(CLIENT_OS);
  105. version.set_release(CLIENT_RELEASE);
  106. version.set_os_version(CLIENT_OS_VERSION);
  107. logger.info("Sending version information.");
  108. sendControlMessagePrivate(MessageType::VERSION, version);
  109. }
  110. void mumlib::Transport::sendAuthentication() {
  111. string user, password;
  112. tie(user, password) = credentials;
  113. MumbleProto::Authenticate authenticate;
  114. authenticate.set_username(user);
  115. authenticate.set_password(password);
  116. authenticate.clear_celt_versions();
  117. authenticate.clear_tokens();
  118. authenticate.set_opus(true);
  119. logger.info("Sending authententication.");
  120. sendControlMessagePrivate(MessageType::AUTHENTICATE, authenticate);
  121. }
  122. void mumlib::Transport::sendSslPing() {
  123. MumbleProto::Ping ping;
  124. ping.set_timestamp(std::time(nullptr));
  125. logger.debug("Sending SSL ping.");
  126. sendControlMessagePrivate(MessageType::PING, ping);
  127. }
  128. bool mumlib::Transport::isUdpActive() {
  129. return udpActive;
  130. }
  131. void mumlib::Transport::doReceiveUdp() {
  132. if (state == ConnectionState::NOT_CONNECTED) {
  133. return;
  134. }
  135. udpSocket.async_receive_from(
  136. buffer(udpIncomingBuffer, MAX_UDP_LENGTH),
  137. udpReceiverEndpoint,
  138. [this](const boost::system::error_code &ec, size_t bytesTransferred) {
  139. if (!ec and bytesTransferred > 0) {
  140. logger.debug("Received UDP packet of %d B.", bytesTransferred);
  141. if (not cryptState.isValid()) {
  142. throwTransportException("received UDP packet before CRYPT SETUP message");
  143. } else {
  144. lastReceivedUdpPacketTimestamp = std::chrono::system_clock::now();
  145. if (udpActive == false) {
  146. udpActive = true;
  147. logger.notice("UDP is up.");
  148. }
  149. uint8_t plainBuffer[1024];
  150. const int plainBufferLength = static_cast<const int>(bytesTransferred - 4);
  151. bool success = cryptState.decrypt(
  152. udpIncomingBuffer, plainBuffer, static_cast<unsigned int>(bytesTransferred));
  153. if (not success) {
  154. throwTransportException("UDP packet decryption failed");
  155. }
  156. processAudioPacket(plainBuffer, plainBufferLength);
  157. }
  158. doReceiveUdp();
  159. } else if (ec == boost::asio::error::operation_aborted) {
  160. logger.debug("UDP receive function cancelled.");
  161. } else {
  162. throwTransportException("UDP receive failed: " + ec.message());
  163. }
  164. });
  165. }
  166. void mumlib::Transport::sslConnectHandler(const boost::system::error_code &error) {
  167. if (!error) {
  168. sslSocket.async_handshake(ssl::stream_base::client,
  169. boost::bind(&Transport::sslHandshakeHandler, this,
  170. boost::asio::placeholders::error));
  171. }
  172. else {
  173. throwTransportException((boost::format("Connect failed: %s.") % error.message()).str());
  174. }
  175. }
  176. void mumlib::Transport::sslHandshakeHandler(const boost::system::error_code &error) {
  177. if (!error) {
  178. doReceiveSsl();
  179. sendVersion();
  180. sendAuthentication();
  181. }
  182. else {
  183. throwTransportException((boost::format("Handshake failed: %s.") % error.message()).str());
  184. }
  185. }
  186. void mumlib::Transport::pingTimerTick(const boost::system::error_code &e) {
  187. if (state == ConnectionState::CONNECTED) {
  188. sendSslPing();
  189. if (not noUdp) {
  190. using namespace std::chrono;
  191. sendUdpPing();
  192. if (udpActive) {
  193. const int lastUdpReceivedMilliseconds = duration_cast<milliseconds>(
  194. system_clock::now() - lastReceivedUdpPacketTimestamp).count();
  195. if (lastUdpReceivedMilliseconds > PING_INTERVAL.total_milliseconds() + 1000) {
  196. udpActive = false;
  197. logger.warn("Didn't receive UDP ping in %d ms, falling back to TCP.", lastUdpReceivedMilliseconds);
  198. }
  199. }
  200. }
  201. }
  202. pingTimer.expires_at(pingTimer.expires_at() + PING_INTERVAL);
  203. pingTimer.async_wait(boost::bind(&Transport::pingTimerTick, this, _1));
  204. }
  205. void mumlib::Transport::sendUdpAsync(uint8_t *buff, int length) {
  206. if (length > MAX_UDP_LENGTH - 4) {
  207. throwTransportException("maximum allowed data length is %d" + to_string(MAX_UDP_LENGTH - 4));
  208. }
  209. auto *encryptedMsgBuff = asyncBufferPool.malloc();
  210. const int encryptedMsgLength = length + 4;
  211. cryptState.encrypt(buff, reinterpret_cast<uint8_t *>(encryptedMsgBuff), static_cast<unsigned int>(length));
  212. logger.debug("Sending %d B of data UDP asynchronously.", encryptedMsgLength);
  213. udpSocket.async_send_to(
  214. boost::asio::buffer(encryptedMsgBuff, static_cast<size_t>(length + 4)),
  215. udpReceiverEndpoint,
  216. [this, encryptedMsgBuff](const boost::system::error_code &ec, size_t bytesTransferred) {
  217. asyncBufferPool.free(encryptedMsgBuff);
  218. if (!ec and bytesTransferred > 0) {
  219. logger.debug("Sent %d B via UDP.", bytesTransferred);
  220. } else {
  221. throwTransportException("UDP send failed: " + ec.message());
  222. }
  223. });
  224. }
  225. void mumlib::Transport::doReceiveSsl() {
  226. if (state == ConnectionState::NOT_CONNECTED) {
  227. return;
  228. }
  229. async_read(
  230. sslSocket,
  231. boost::asio::buffer(sslIncomingBuffer, MAX_TCP_LENGTH),
  232. [this](const boost::system::error_code &error, size_t bytesTransferred) -> size_t {
  233. if (bytesTransferred < 6) {
  234. // we need the message header to determine the payload length
  235. return 6 - bytesTransferred;
  236. }
  237. const int payloadSize = ntohl(*reinterpret_cast<uint32_t *>(sslIncomingBuffer + 2));
  238. const int wholeMessageLength = payloadSize + 6;
  239. size_t remaining = wholeMessageLength - bytesTransferred;
  240. remaining = max(remaining, (size_t) 0);
  241. if (wholeMessageLength > MAX_TCP_LENGTH) {
  242. throwTransportException(
  243. (boost::format("message bigger (%d B) than max allowed size (%d B)")
  244. % wholeMessageLength % MAX_TCP_LENGTH).str());
  245. }
  246. return remaining;
  247. },
  248. [this](const boost::system::error_code &ec, size_t bytesTransferred) {
  249. if (!ec and bytesTransferred > 0) {
  250. int messageType = ntohs(*reinterpret_cast<uint16_t *>(sslIncomingBuffer));
  251. logger.debug("Received %d B of data (%d B payload, type %d).", bytesTransferred,
  252. bytesTransferred - 6, messageType);
  253. processMessageInternal(
  254. static_cast<MessageType>(messageType),
  255. &sslIncomingBuffer[6],
  256. static_cast<int>(bytesTransferred - 6));
  257. doReceiveSsl();
  258. } else {
  259. logger.error("SSL receiver error: %s. Bytes transferred: %d.",
  260. ec.message().c_str(), bytesTransferred);
  261. //todo temporarily disable exception throwing until issue #6 is solved
  262. //throwTransportException("receive failed: " + ec.message());
  263. }
  264. });
  265. }
  266. void mumlib::Transport::processMessageInternal(MessageType messageType, uint8_t *buffer, int length) {
  267. switch (messageType) {
  268. case MessageType::UDPTUNNEL: {
  269. logger.debug("Received %d B of encoded audio data via TCP.", length);
  270. processAudioPacket(buffer, length);
  271. }
  272. break;
  273. case MessageType::AUTHENTICATE: {
  274. logger.warn("Authenticate message received after authenticated.");
  275. }
  276. break;
  277. case MessageType::PING: {
  278. MumbleProto::Ping ping;
  279. ping.ParseFromArray(buffer, length);
  280. stringstream log;
  281. log << "Received ping.";
  282. if (ping.has_good()) {
  283. log << " good: " << ping.good();
  284. }
  285. if (ping.has_late()) {
  286. log << " late: " << ping.late();
  287. }
  288. if (ping.has_lost()) {
  289. log << " lost: " << ping.lost();
  290. }
  291. if (ping.has_tcp_ping_avg()) {
  292. log << " TCP avg: " << ping.tcp_ping_avg() << " ms";
  293. }
  294. if (ping.has_udp_ping_avg()) {
  295. log << " UDP avg: " << ping.udp_ping_avg() << " ms";
  296. }
  297. logger.debug(log.str());
  298. }
  299. break;
  300. case MessageType::REJECT: {
  301. MumbleProto::Reject reject;
  302. reject.ParseFromArray(buffer, length);
  303. stringstream errorMesg;
  304. errorMesg << "failed to authenticate";
  305. if (reject.has_type()) {
  306. errorMesg << ": " << rejectMessages.at(reject.type());
  307. }
  308. if (reject.has_reason()) {
  309. errorMesg << ", reason: " << reject.reason();
  310. }
  311. throwTransportException(errorMesg.str());
  312. }
  313. break;
  314. case MessageType::SERVERSYNC: {
  315. state = ConnectionState::CONNECTED;
  316. logger.debug("SERVERSYNC. Calling external ProcessControlMessageFunction.");
  317. processMessageFunction(messageType, buffer, length);
  318. }
  319. break;
  320. case MessageType::CRYPTSETUP: {
  321. if (not noUdp) {
  322. MumbleProto::CryptSetup cryptsetup;
  323. cryptsetup.ParseFromArray(buffer, length);
  324. if (cryptsetup.client_nonce().length() != AES_BLOCK_SIZE
  325. or cryptsetup.server_nonce().length() != AES_BLOCK_SIZE
  326. or cryptsetup.key().length() != AES_BLOCK_SIZE) {
  327. throwTransportException("one of cryptographic parameters has invalid length");
  328. }
  329. cryptState.setKey(
  330. reinterpret_cast<const unsigned char *>(cryptsetup.key().c_str()),
  331. reinterpret_cast<const unsigned char *>(cryptsetup.client_nonce().c_str()),
  332. reinterpret_cast<const unsigned char *>(cryptsetup.server_nonce().c_str()));
  333. if (not cryptState.isValid()) {
  334. throwTransportException("crypt setup data not valid");
  335. }
  336. logger.info("Set up cryptography for UDP transport. Sending UDP ping.");
  337. sendUdpPing();
  338. } else {
  339. logger.info("Ignoring crypt setup message, because UDP is disabled.");
  340. }
  341. }
  342. break;
  343. default: {
  344. logger.debug("Calling external ProcessControlMessageFunction.");
  345. processMessageFunction(messageType, buffer, length);
  346. }
  347. break;
  348. }
  349. }
  350. void mumlib::Transport::sendUdpPing() {
  351. if (state == ConnectionState::NOT_CONNECTED) {
  352. logger.debug("State changed to NOT_CONNECTED, skipping UDP ping.");
  353. return;
  354. }
  355. logger.debug("Sending UDP ping.");
  356. vector<uint8_t> message;
  357. message.push_back(0x20);
  358. auto timestampVarint = VarInt(static_cast<int64_t>(time(nullptr))).getEncoded();
  359. message.insert(message.end(), timestampVarint.begin(), timestampVarint.end());
  360. sendUdpAsync(&message[0], static_cast<int>(message.size()));
  361. }
  362. void mumlib::Transport::sendSsl(uint8_t *buff, int length) {
  363. if (length > MAX_TCP_LENGTH) {
  364. logger.warn("Sending %d B of data via SSL. Maximal allowed data length to receive is %d B.", length,
  365. MAX_TCP_LENGTH);
  366. }
  367. logger.debug("Sending %d bytes of data.", length);
  368. try {
  369. write(sslSocket, boost::asio::buffer(buff, static_cast<size_t>(length)));
  370. } catch (boost::system::system_error &err) {
  371. throwTransportException(std::string("SSL send failed: ") + err.what());
  372. }
  373. }
  374. void mumlib::Transport::sendSslAsync(uint8_t *buff, int length) {
  375. if (length > MAX_TCP_LENGTH) {
  376. logger.warn("Sending %d B of data via SSL. Maximal allowed data length to receive is %d B.", length,
  377. MAX_TCP_LENGTH);
  378. }
  379. auto *asyncBuff = asyncBufferPool.malloc();
  380. memcpy(asyncBuff, buff, static_cast<size_t>(length));
  381. logger.debug("Sending %d B of data asynchronously.", length);
  382. async_write(
  383. sslSocket,
  384. boost::asio::buffer(asyncBuff, static_cast<size_t>(length)),
  385. [this, asyncBuff](const boost::system::error_code &ec, size_t bytesTransferred) {
  386. asyncBufferPool.free(asyncBuff);
  387. logger.debug("Sent %d B.", bytesTransferred);
  388. if (!ec and bytesTransferred > 0) {
  389. } else {
  390. throwTransportException("async SSL send failed: " + ec.message());
  391. }
  392. });
  393. }
  394. void mumlib::Transport::sendControlMessage(MessageType type, google::protobuf::Message &message) {
  395. if (state != ConnectionState::CONNECTED) {
  396. logger.warn("Connection not established.");
  397. return;
  398. }
  399. sendControlMessagePrivate(type, message);
  400. }
  401. void mumlib::Transport::sendControlMessagePrivate(MessageType type, google::protobuf::Message &message) {
  402. const uint16_t type_network = htons(static_cast<uint16_t>(type));
  403. const int size = message.ByteSize();
  404. const uint32_t size_network = htonl((uint32_t) size);
  405. const int length = sizeof(type_network) + sizeof(size_network) + size;
  406. uint8_t buff[MAX_TCP_LENGTH];
  407. memcpy(buff, &type_network, sizeof(type_network));
  408. memcpy(buff + sizeof(type_network), &size_network, sizeof(size_network));
  409. message.SerializeToArray(buff + sizeof(type_network) + sizeof(size_network), size);
  410. sendSsl(buff, length);
  411. }
  412. void mumlib::Transport::throwTransportException(string message) {
  413. state = ConnectionState::FAILED;
  414. throw TransportException(std::move(message));
  415. }
  416. void mumlib::Transport::sendEncodedAudioPacket(uint8_t *buffer, int length) {
  417. if (state != ConnectionState::CONNECTED) {
  418. logger.warn("Connection not established.");
  419. return;
  420. }
  421. if (udpActive) {
  422. logger.info("Sending %d B of audio data via UDP.", length);
  423. sendUdpAsync(buffer, length);
  424. } else {
  425. logger.info("Sending %d B of audio data via TCP.", length);
  426. const uint16_t netUdptunnelType = htons(static_cast<uint16_t>(MessageType::UDPTUNNEL));
  427. const uint32_t netLength = htonl(static_cast<uint32_t>(length));
  428. const int packet = sizeof(netUdptunnelType) + sizeof(netLength) + length;
  429. uint8_t packetBuff[MAX_TCP_LENGTH];
  430. memcpy(packetBuff, &netUdptunnelType, sizeof(netUdptunnelType));
  431. memcpy(packetBuff + sizeof(netUdptunnelType), &netLength, sizeof(netLength));
  432. memcpy(packetBuff + sizeof(netUdptunnelType) + sizeof(netLength), buffer, static_cast<size_t>(length));
  433. sendSslAsync(packetBuff, length + sizeof(netUdptunnelType) + sizeof(netLength));
  434. }
  435. }
  436. void mumlib::Transport::processAudioPacket(uint8_t *buff, int length) {
  437. auto type = static_cast<AudioPacketType >((buff[0] & 0xE0) >> 5);
  438. switch (type) {
  439. case AudioPacketType::CELT_Alpha:
  440. case AudioPacketType::Speex:
  441. case AudioPacketType::CELT_Beta:
  442. case AudioPacketType::OPUS:
  443. processEncodedAudioPacketFunction(type, buff, length);
  444. break;
  445. case AudioPacketType::Ping:
  446. break;
  447. default:
  448. logger.error("Not recognized audio type: %xd.", buff[0]);
  449. }
  450. }