Transport.cpp 20 KB

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