Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cookie data #229

Open
wants to merge 35 commits into
base: stable
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
3e2e59e
Cookie added
ismaileke Jul 28, 2024
963c533
Cookie added 2
ismaileke Jul 28, 2024
c22a7d1
Update OpenConnectionRequest2.php
ismaileke Jul 28, 2024
7425ec5
extra byte
ismaileke Jul 28, 2024
80e89f0
some fixes
ismaileke Jul 29, 2024
c58e264
updated unconnected message handler
ismaileke Jul 29, 2024
967555e
oops
ismaileke Jul 29, 2024
78f5cf5
Update OpenConnectionRequest2.php
ismaileke Jul 29, 2024
3cdf46e
Cookie Class
ismaileke Jul 30, 2024
1c94a8c
againagainagain
ismaileke Jul 30, 2024
440196c
Update Cookie.php
ismaileke Jul 30, 2024
1287f4c
Update Cookie.php
ismaileke Jul 30, 2024
3764e4b
for now
ismaileke Aug 3, 2024
312e11e
fix
ismaileke Aug 3, 2024
9078818
some fixes
ismaileke Aug 3, 2024
9c11bb4
okay
ismaileke Aug 3, 2024
ba4c754
is it right to add that lol
ismaileke Aug 3, 2024
9555243
client supports security
ismaileke Aug 7, 2024
ec8532b
added static function
ismaileke Aug 8, 2024
884bbff
non-static funcs
ismaileke Aug 9, 2024
b6c85e7
fix nullable
ismaileke Aug 9, 2024
15d1b13
use method
ismaileke Aug 9, 2024
75e8526
i forgot
ismaileke Aug 9, 2024
ff2a37e
fix but not finished
ismaileke Aug 9, 2024
8e6c677
uhhh
ismaileke Aug 9, 2024
f8250af
short usage
ismaileke Aug 10, 2024
df75ce4
Update src/protocol/OpenConnectionReply1.php
ismaileke Aug 10, 2024
64cb140
some fixes are not yet complete
ismaileke Aug 13, 2024
b9bb269
random_int
ismaileke Aug 13, 2024
65e2da8
Limits
ismaileke Aug 13, 2024
0e8b732
new name CookieCache
ismaileke Aug 13, 2024
bd80d49
delete the cookie when player log out
ismaileke Sep 20, 2024
cb35ab3
CookieCache::check() fix?
ismaileke Sep 20, 2024
41ac282
snake case :|
ismaileke Sep 20, 2024
7d1586f
pls gimme blue tick
ismaileke Sep 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions src/protocol/OpenConnectionReply1.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,32 +16,41 @@

namespace raklib\protocol;

use function is_int;

class OpenConnectionReply1 extends OfflineMessage{
public static $ID = MessageIdentifiers::ID_OPEN_CONNECTION_REPLY_1;

public int $serverID;
public bool $serverSecurity = false;
public bool $serverSecurity;
ismaileke marked this conversation as resolved.
Show resolved Hide resolved
public ?int $cookie = null;
public int $mtuSize;

public static function create(int $serverId, bool $serverSecurity, int $mtuSize) : self{
public static function create(int $serverId, ?int $cookie, int $mtuSize) : self{
$result = new self;
$result->serverID = $serverId;
$result->serverSecurity = $serverSecurity;
$result->cookie = $cookie;
$result->mtuSize = $mtuSize;
return $result;
}

protected function encodePayload(PacketSerializer $out) : void{
$this->writeMagic($out);
$out->putLong($this->serverID);
$out->putByte($this->serverSecurity ? 1 : 0);
$out->putByte($this->cookie !== null ? 1 : 0);
if ($this->cookie !== null) {
$out->putInt($this->cookie);
}
$out->putShort($this->mtuSize);
}

protected function decodePayload(PacketSerializer $in) : void{
$this->readMagic($in);
$this->serverID = $in->getLong();
$this->serverSecurity = $in->getByte() !== 0;
if ($this->serverSecurity) {
$this->cookie = $in->getInt();
}
ismaileke marked this conversation as resolved.
Show resolved Hide resolved
$this->mtuSize = $in->getShort();
}
}
11 changes: 11 additions & 0 deletions src/protocol/OpenConnectionRequest2.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,29 @@ class OpenConnectionRequest2 extends OfflineMessage{
public static $ID = MessageIdentifiers::ID_OPEN_CONNECTION_REQUEST_2;

public int $clientID;
public ?int $cookie;
public bool $clientSupportsSecurity = false; // Always false for the vanilla client.
public InternetAddress $serverAddress;
public int $mtuSize;

protected function encodePayload(PacketSerializer $out) : void{
$this->writeMagic($out);
if ($this->cookie !== null) {
$out->putInt($this->cookie);
$out->putBool($this->clientSupportsSecurity);
}
$out->putAddress($this->serverAddress);
$out->putShort($this->mtuSize);
$out->putLong($this->clientID);
}

protected function decodePayload(PacketSerializer $in) : void{
//$length = strlen($in->getRemaining()); // magic(16) + cookie(4) + clientSupportsSecurity(1) + serverAddress(??) + mtuSize(2) + clientID(8)
$this->readMagic($in);
if ($this->cookie !== null) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cookie is always going to be null when you haven't decoded it yet

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cookie is always going to be null when you haven't decoded it yet

what should i do?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This depends on the protocol. How do we know if the client is going to send a cookie in this request?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This depends on the protocol. How do we know if the client is going to send a cookie in this request?

We can understand something from the length of the incoming buffer, but I don't know if it's the right thing to do.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we just need a context-aware parser that can read whether cookie is expected. If we always send cookies for all clients, we should always read it. If we never send cookies, we should never read it. It doesn't seem that we require any guessing.

$this->cookie = $in->getInt();
$this->clientSupportsSecurity = $in->getBool();
}
$this->serverAddress = $in->getAddress();
$this->mtuSize = $in->getShort();
$this->clientID = $in->getLong();
Expand Down
13 changes: 13 additions & 0 deletions src/server/Server.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
use raklib\protocol\NACK;
use raklib\protocol\Packet;
use raklib\protocol\PacketSerializer;
use raklib\utils\CookieCache;
use raklib\utils\ExceptionTraceCleaner;
use raklib\utils\InternetAddress;
use function asort;
Expand Down Expand Up @@ -77,6 +78,8 @@ class Server implements ServerInterface{

protected int $nextSessionId = 0;

public ?CookieCache $cookieCache = null;

/**
* @phpstan-param positive-int $recvMaxSplitParts
* @phpstan-param positive-int $recvMaxConcurrentSplits
Expand All @@ -99,6 +102,9 @@ public function __construct(
$this->socket->setBlocking(false);

$this->unconnectedMessageHandler = new UnconnectedMessageHandler($this, $protocolAcceptor);

// If you don't want to use security on the server, just delete this line.
$this->cookieCache = new CookieCache();
}

public function getPort() : int{
Expand All @@ -113,6 +119,10 @@ public function getLogger() : \Logger{
return $this->logger;
}

public function getCookieCache() : ?CookieCache {
return $this->cookieCache;
}

public function tickProcessor() : void{
$start = microtime(true);

Expand Down Expand Up @@ -169,6 +179,9 @@ private function tick() : void{
foreach($this->sessions as $session){
$session->update($time);
if($session->isFullyDisconnected()){
if ($this->getCookieCache() instanceof CookieCache) {
$this->getCookieCache()->remove($session->getAddress());
}
$this->removeSessionInternal($session);
}
}
Expand Down
16 changes: 15 additions & 1 deletion src/server/UnconnectedMessageHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
use raklib\protocol\UnconnectedPingOpenConnections;
use raklib\protocol\UnconnectedPong;
use raklib\utils\InternetAddress;
use raklib\utils\CookieCache;
use function get_class;
use function min;
use function ord;
Expand Down Expand Up @@ -81,10 +82,15 @@ private function handle(OfflineMessage $packet, InternetAddress $address) : bool
$this->server->sendPacket(IncompatibleProtocolVersion::create($this->protocolAcceptor->getPrimaryVersion(), $this->server->getID()), $address);
$this->server->getLogger()->notice("Refused connection from $address due to incompatible RakNet protocol version (version $packet->protocol)");
}else{
$cookie = null;
if ($this->server->getCookieCache() instanceof CookieCache) {
$cookie = $this->server->getCookieCache()->add($address);
}
//IP header size (20 bytes) + UDP header size (8 bytes)
$this->server->sendPacket(OpenConnectionReply1::create($this->server->getID(), false, $packet->mtuSize + 28), $address);
$this->server->sendPacket(OpenConnectionReply1::create($this->server->getID(), $cookie, $packet->mtuSize + 28), $address);
}
}elseif($packet instanceof OpenConnectionRequest2){
// The client may not send such data even though serverSecurity is enabled, and if we try to decode this, we may encounter an error
if($packet->serverAddress->getPort() === $this->server->getPort() or !$this->server->portChecking){
if($packet->mtuSize < Session::MIN_MTU_SIZE){
$this->server->getLogger()->debug("Not creating session for $address due to bad MTU size $packet->mtuSize");
Expand All @@ -97,6 +103,14 @@ private function handle(OfflineMessage $packet, InternetAddress $address) : bool
$this->server->getLogger()->debug("Not creating session for $address due to session already opened");
return true;
}
if ($this->server->getCookieCache() instanceof CookieCache) { // womp womp
if ($packet->cookie === null || !$this->server->getCookieCache()->check($address, $packet->cookie)) {
// Disconnect if OpenConnectionReply1 and the cookie in the OpenConnectionRequest2 packet do not match
$this->server->getLogger()->debug("Not creating session for $address due to session mismatched cookies");
return true;
}

}
$mtuSize = min($packet->mtuSize, $this->server->getMaxMtuSize()); //Max size, do not allow creating large buffers to fill server memory
$this->server->sendPacket(OpenConnectionReply2::create($this->server->getID(), $address, $mtuSize, false), $address);
$this->server->createSession($address, $packet->clientID, $mtuSize);
Expand Down
59 changes: 59 additions & 0 deletions src/utils/CookieCache.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

/*
* This file is part of RakLib.
* Copyright (C) 2014-2022 PocketMine Team <https://github.com/pmmp/RakLib>
*
* RakLib is not affiliated with Jenkins Software LLC nor RakNet.
*
* RakLib is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*/

declare(strict_types=1);

namespace raklib\utils;

use raklib\utils\InternetAddress;
use pocketmine\utils\Limits;
use function random_int;

final class CookieCache{

/**
* @var array<string, int> $cookies
*/
private array $cookies = [];

public function check(InternetAddress $address, int $cookie) : bool{
$addressStr = $address->toString();

if (isset($this->cookies[$addressStr])) {
// If it checks the Cookie, it means that it is in the OpenConnectionRequest2 phase, and we can delete it from memory.
if ($this->cookies[$addressStr] === $cookie) {
unset($this->cookies[$addressStr]);
return true;
}
} // Is there any chance that this is something else?
return false;
}

public function add(InternetAddress $address) : int{
$cookie = $this->generate($address);
$this->cookies[$address->toString()] = $cookie;
return $cookie;
}

public function remove(InternetAddress $address) : void{
$addressStr = $address->toString();
if (isset($this->cookies[$addressStr])) {
unset($this->cookies[$addressStr]);
}
}

private function generate(InternetAddress $address) : int{
return random_int(0, Limits::UINT32_MAX);
}
}
Loading