Transport.cpp 18 KB

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