1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-06-01 09:48:11 +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; return true;
} }
void IPv4Socket::allocate_source_port_if_needed() int IPv4Socket::allocate_source_port_if_needed()
{ {
if (m_source_port) if (m_source_port)
return; return m_source_port;
protocol_allocate_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) 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); 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); kprintf("sendto: destination=%s:%u\n", m_destination_address.to_string().characters(), m_destination_port);

View file

@ -45,12 +45,12 @@ public:
protected: protected:
IPv4Socket(int type, int protocol); 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_receive(const ByteBuffer&, void*, size_t, int, sockaddr*, socklen_t*) { return -ENOTIMPL; }
virtual int protocol_send(const void*, int) { return -ENOTIMPL; } virtual int protocol_send(const void*, int) { return -ENOTIMPL; }
virtual KResult protocol_connect() { return KSuccess; } 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; } virtual bool protocol_is_disconnected() const { return false; }
private: private:

View file

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

View file

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

View file

@ -2,6 +2,7 @@
#include <Kernel/TCP.h> #include <Kernel/TCP.h>
#include <Kernel/NetworkAdapter.h> #include <Kernel/NetworkAdapter.h>
#include <Kernel/Process.h> #include <Kernel/Process.h>
#include <Kernel/RandomDevice.h>
Lockable<HashMap<word, TCPSocket*>>& TCPSocket::sockets_by_port() Lockable<HashMap<word, TCPSocket*>>& TCPSocket::sockets_by_port()
{ {
@ -173,19 +174,28 @@ KResult TCPSocket::protocol_connect()
return KSuccess; return KSuccess;
} }
void TCPSocket::protocol_allocate_source_port() int TCPSocket::protocol_allocate_source_port()
{ {
// This is not a very efficient allocation algorithm. static const word first_ephemeral_port = 32768;
// FIXME: Replace it with a bitmap or some other fast-paced looker-upper. 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()); 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); auto it = sockets_by_port().resource().find(port);
if (it == sockets_by_port().resource().end()) { if (it == sockets_by_port().resource().end()) {
set_source_port(port); set_source_port(port);
sockets_by_port().resource().set(port, this); 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 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_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 int protocol_send(const void*, int) override;
virtual KResult protocol_connect() 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; virtual bool protocol_is_disconnected() const override;
dword m_sequence_number { 0 }; dword m_sequence_number { 0 };

View file

@ -2,6 +2,7 @@
#include <Kernel/UDP.h> #include <Kernel/UDP.h>
#include <Kernel/NetworkAdapter.h> #include <Kernel/NetworkAdapter.h>
#include <Kernel/Process.h> #include <Kernel/Process.h>
#include <Kernel/RandomDevice.h>
Lockable<HashMap<word, UDPSocket*>>& UDPSocket::sockets_by_port() Lockable<HashMap<word, UDPSocket*>>& UDPSocket::sockets_by_port()
{ {
@ -83,17 +84,26 @@ KResult UDPSocket::protocol_connect()
return KSuccess; return KSuccess;
} }
void UDPSocket::protocol_allocate_source_port() int UDPSocket::protocol_allocate_source_port()
{ {
// This is not a very efficient allocation algorithm. static const word first_ephemeral_port = 32768;
// FIXME: Replace it with a bitmap or some other fast-paced looker-upper. 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()); 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); auto it = sockets_by_port().resource().find(port);
if (it == sockets_by_port().resource().end()) { if (it == sockets_by_port().resource().end()) {
set_source_port(port); set_source_port(port);
sockets_by_port().resource().set(port, this); 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_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 int protocol_send(const void*, int) override;
virtual KResult protocol_connect() override; virtual KResult protocol_connect() override;
virtual void protocol_allocate_source_port() override; virtual int protocol_allocate_source_port() override;
}; };
class UDPSocketHandle : public SocketHandle { class UDPSocketHandle : public SocketHandle {