1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 19:57:35 +00:00

IPv4: Add simple pseudorandom ephemeral port allocators for TCP and UDP.

This commit is contained in:
Andreas Kling 2019-03-18 04:03:44 +01:00
parent 77a782a67e
commit c24d4b07db
8 changed files with 54 additions and 20 deletions

View file

@ -112,11 +112,15 @@ bool IPv4Socket::can_write(SocketRole) const
return true;
}
void IPv4Socket::allocate_source_port_if_needed()
int IPv4Socket::allocate_source_port_if_needed()
{
if (m_source_port)
return;
protocol_allocate_source_port();
return m_source_port;
int port = protocol_allocate_source_port();
if (port < 0)
return port;
m_source_port = (word)port;
return port;
}
ssize_t IPv4Socket::sendto(const void* data, size_t data_length, int flags, const sockaddr* addr, socklen_t addr_length)
@ -142,7 +146,9 @@ ssize_t IPv4Socket::sendto(const void* data, size_t data_length, int flags, cons
m_destination_port = ntohs(ia.sin_port);
}
allocate_source_port_if_needed();
int rc = allocate_source_port_if_needed();
if (rc < 0)
return rc;
kprintf("sendto: destination=%s:%u\n", m_destination_address.to_string().characters(), m_destination_port);

View file

@ -45,12 +45,12 @@ public:
protected:
IPv4Socket(int type, int protocol);
void allocate_source_port_if_needed();
int allocate_source_port_if_needed();
virtual int protocol_receive(const ByteBuffer&, void*, size_t, int, sockaddr*, socklen_t*) { return -ENOTIMPL; }
virtual int protocol_send(const void*, int) { return -ENOTIMPL; }
virtual KResult protocol_connect() { return KSuccess; }
virtual void protocol_allocate_source_port() { }
virtual int protocol_allocate_source_port() { return 0; }
virtual bool protocol_is_disconnected() const { return false; }
private:

View file

@ -16,12 +16,17 @@ RandomDevice::~RandomDevice()
static unsigned long next = 1;
#define MY_RAND_MAX 32767
static int myrand()
int RandomDevice::random_value()
{
next = next * 1103515245 + 12345;
return((unsigned)(next/((MY_RAND_MAX + 1) * 2)) % (MY_RAND_MAX + 1));
}
float RandomDevice::random_percentage()
{
return (float)random_value() / (float)MY_RAND_MAX;
}
#if 0
static void mysrand(unsigned seed)
{
@ -39,7 +44,7 @@ ssize_t RandomDevice::read(Process&, byte* buffer, ssize_t size)
const int range = 'z' - 'a';
ssize_t nread = min(size, GoodBufferSize);
for (ssize_t i = 0; i < nread; ++i) {
dword r = myrand() % range;
dword r = random_value() % range;
buffer[i] = (byte)('a' + r);
}
return nread;

View file

@ -8,6 +8,9 @@ public:
RandomDevice();
virtual ~RandomDevice() override;
static int random_value();
static float random_percentage();
private:
// ^CharacterDevice
virtual ssize_t read(Process&, byte*, ssize_t) override;

View file

@ -2,6 +2,7 @@
#include <Kernel/TCP.h>
#include <Kernel/NetworkAdapter.h>
#include <Kernel/Process.h>
#include <Kernel/RandomDevice.h>
Lockable<HashMap<word, TCPSocket*>>& TCPSocket::sockets_by_port()
{
@ -173,19 +174,28 @@ KResult TCPSocket::protocol_connect()
return KSuccess;
}
void TCPSocket::protocol_allocate_source_port()
int TCPSocket::protocol_allocate_source_port()
{
// This is not a very efficient allocation algorithm.
// FIXME: Replace it with a bitmap or some other fast-paced looker-upper.
static const word first_ephemeral_port = 32768;
static const word last_ephemeral_port = 60999;
static const word ephemeral_port_range_size = last_ephemeral_port - first_ephemeral_port;
word first_scan_port = first_ephemeral_port + (word)(RandomDevice::random_percentage() * ephemeral_port_range_size);
LOCKER(sockets_by_port().lock());
for (word port = 2000; port < 60000; ++port) {
for (word port = first_scan_port;;) {
auto it = sockets_by_port().resource().find(port);
if (it == sockets_by_port().resource().end()) {
set_source_port(port);
sockets_by_port().resource().set(port, this);
return;
return port;
}
++port;
if (port > last_ephemeral_port)
port = first_ephemeral_port;
if (port == first_scan_port)
break;
}
return -EADDRINUSE;
}
bool TCPSocket::protocol_is_disconnected() const

View file

@ -35,7 +35,7 @@ private:
virtual int protocol_receive(const ByteBuffer&, void* buffer, size_t buffer_size, int flags, sockaddr* addr, socklen_t* addr_length) override;
virtual int protocol_send(const void*, int) override;
virtual KResult protocol_connect() override;
virtual void protocol_allocate_source_port() override;
virtual int protocol_allocate_source_port() override;
virtual bool protocol_is_disconnected() const override;
dword m_sequence_number { 0 };

View file

@ -2,6 +2,7 @@
#include <Kernel/UDP.h>
#include <Kernel/NetworkAdapter.h>
#include <Kernel/Process.h>
#include <Kernel/RandomDevice.h>
Lockable<HashMap<word, UDPSocket*>>& UDPSocket::sockets_by_port()
{
@ -83,17 +84,26 @@ KResult UDPSocket::protocol_connect()
return KSuccess;
}
void UDPSocket::protocol_allocate_source_port()
int UDPSocket::protocol_allocate_source_port()
{
// This is not a very efficient allocation algorithm.
// FIXME: Replace it with a bitmap or some other fast-paced looker-upper.
static const word first_ephemeral_port = 32768;
static const word last_ephemeral_port = 60999;
static const word ephemeral_port_range_size = last_ephemeral_port - first_ephemeral_port;
word first_scan_port = first_ephemeral_port + (word)(RandomDevice::random_percentage() * ephemeral_port_range_size);
LOCKER(sockets_by_port().lock());
for (word port = 2000; port < 60000; ++port) {
for (word port = first_scan_port;;) {
auto it = sockets_by_port().resource().find(port);
if (it == sockets_by_port().resource().end()) {
set_source_port(port);
sockets_by_port().resource().set(port, this);
return;
return port;
}
++port;
if (port > last_ephemeral_port)
port = first_ephemeral_port;
if (port == first_scan_port)
break;
}
return -EADDRINUSE;
}

View file

@ -18,7 +18,7 @@ private:
virtual int protocol_receive(const ByteBuffer&, void* buffer, size_t buffer_size, int flags, sockaddr* addr, socklen_t* addr_length) override;
virtual int protocol_send(const void*, int) override;
virtual KResult protocol_connect() override;
virtual void protocol_allocate_source_port() override;
virtual int protocol_allocate_source_port() override;
};
class UDPSocketHandle : public SocketHandle {