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:
parent
77a782a67e
commit
c24d4b07db
8 changed files with 54 additions and 20 deletions
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 };
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue