void UdpRelay::onServerUdpSocketReadyRead() { if (listenSocket.pendingDatagramSize() > RecvSize) { emit info("[UDP] Datagram is too large. discarded."); return; } QByteArray data; data.resize(listenSocket.pendingDatagramSize()); QHostAddress r_addr; quint16 r_port; qint64 readSize = listenSocket.readDatagram(data.data(), RecvSize, &r_addr, &r_port); emit bytesRead(readSize); if (isLocal) { if (static_cast<int>(data[2]) != 0) { emit info("[UDP] Drop a message since frag is not 0"); return; } data.remove(0, 3); } else { if (autoBan && Common::isAddressBanned(r_addr)) { emit debug(QString("[UDP] A banned IP %1 " "attempted to access this server") .arg(r_addr.toString())); return; } data = encryptor->decryptAll(data); } Address destAddr, remoteAddr(r_addr, r_port);//remote == client int header_length = 0; bool at_auth = false; Common::parseHeader(data, destAddr, header_length, at_auth); if (header_length == 0) { emit info("[UDP] Can't parse header. " "Wrong encryption method or password?"); if (!isLocal && autoBan) { Common::banAddress(r_addr); } return; } QUdpSocket *client = cache.value(remoteAddr, nullptr); QString dbg; if (!client) { client = new QUdpSocket(this); client->setReadBufferSize(RecvSize); client->setSocketOption(QAbstractSocket::LowDelayOption, 1); cache.insert(remoteAddr, client); connect(client, &QUdpSocket::readyRead, this, &UdpRelay::onClientUdpSocketReadyRead); connect(client, &QUdpSocket::disconnected, this, &UdpRelay::onClientDisconnected); QDebug(&dbg) << "[UDP] cache miss:" << destAddr << "<->" << remoteAddr; } else { QDebug(&dbg) << "[UDP] cache hit:" << destAddr << "<->" << remoteAddr; } emit debug(dbg); if (isLocal) { if (auth || at_auth) { /* * shadowsocks UDP Request (OTA-enabled, unencrypted) * +------+----------+----------+----------+-------------+ * | ATYP | DST.ADDR | DST.PORT | DATA | HMAC-SHA1 | * +------+----------+----------+----------+-------------+ * | 1 | Variable | 2 | Variable | 10 | * +------+----------+----------+----------+-------------+ */ encryptor->addHeaderAuth(data); } data = encryptor->encryptAll(data); destAddr = serverAddress; } else { if (auth || at_auth) { if (!encryptor->verifyHeaderAuth(data, data.length() - Cipher::AUTH_LEN)) { emit info("[UDP] One-time message authentication " "for header failed."); if (autoBan) { Common::banAddress(r_addr); } return; } } data = data.mid(header_length, data.length() - header_length - Cipher::AUTH_LEN); } if (!destAddr.isIPValid()) {//TODO async dns destAddr.blockingLookUp(); } client->writeDatagram(data, destAddr.getFirstIP(), destAddr.getPort()); }