TCP module now refuses connections to closed ports.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@18616 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Andrew Galante 2006-08-24 20:31:10 +00:00
parent cad14954c8
commit b611759230
2 changed files with 214 additions and 29 deletions

View File

@ -49,14 +49,14 @@ private:
class TCPSegment {
public:
TCPSegment(net_buffer *_buffer, uint32 _sequenceNumber, bigtime_t timeout);
TCPSegment(uint32 sequenceNumber, uint32 size, bigtime_t timeout);
~TCPSegment();
net_buffer *fBuffer;
bigtime_t fTime;
uint32 fSequenceNumber;
uint32 fAcknowledgementNumber;
net_timer fTimeout;
net_timer fTimer;
bool fTimedOut;
};
status_t Send(uint8 flags);
@ -79,32 +79,37 @@ private:
TCPConnection *fHashLink;
tcp_state fState;
benaphore fLock;
net_route *fRoute;
};
TCPConnection::TCPSegment::TCPSegment(net_buffer *_buffer, uint32 _sequenceNumber, bigtime_t timeout)
TCPConnection::TCPSegment::TCPSegment(uint32 sequenceNumber, uint32 size, bigtime_t timeout)
:
fBuffer(_buffer),
fSequenceNumber(_sequenceNumber)
fTime(system_time()),
fSequenceNumber(sequenceNumber),
fAcknowledgementNumber(sequenceNumber+size),
fTimedOut(false)
{
sStackModule->init_timer(&fTimeout, &TCPConnection::ResendSegment, this);
sStackModule->init_timer(&fTimer, &TCPConnection::ResendSegment, this);
sStackModule->set_timer(&fTimer, timeout);
}
TCPConnection::TCPSegment::~TCPSegment()
{
sStackModule->set_timer(&fTimeout, -1);
sBufferModule->free(fBuffer);
sStackModule->set_timer(&fTimer, -1);
}
TCPConnection::TCPConnection(net_socket *socket)
:
fLastByteSent(0),//system_time()),
fLastByteAckd(0),//fLastByteSent),
fLastByteWritten(0),//fLastByteSent),
fLastByteSent(0), //system_time()),
fLastByteAckd(1), //fLastByteSent + 1),
fLastByteWritten(1), //fLastByteSent + 1),
fAvgRTT(TCP_INITIAL_RTT),
fState(CLOSED)
fState(CLOSED),
fRoute(NULL)
{
benaphore_init(&fLock, "TCPConnection");
}
@ -292,7 +297,10 @@ status_t
TCPConnection::Listen(int count)
{
TRACE(("%p.Listen()\n", this));
return B_ERROR;
if (fState != CLOSED)
return B_ERROR;
fState = LISTEN;
return B_OK;
}
@ -304,6 +312,9 @@ TCPConnection::Shutdown(int direction)
}
/*!
Puts data contained in \a buffer into send buffer
*/
status_t
TCPConnection::SendData(net_buffer *buffer)
{
@ -316,7 +327,8 @@ status_t
TCPConnection::SendRoutedData(net_route *route, net_buffer *buffer)
{
TRACE(("%p.SendRoutedData()\n", this));
return B_ERROR;
fRoute = route;
return SendData(buffer);
}
@ -348,6 +360,37 @@ status_t
TCPConnection::ReceiveData(net_buffer *buffer)
{
TRACE(("%p.ReceiveData()\n", this));
switch (fState) {
case CLOSED:
// shouldn't happen. send RST
TRACE(("TCP: Connection in CLOSED state received packet %p!\n", buffer));
break;
case LISTEN:
// if packet is SYN, spawn new TCPConnection in SYN_RCVD state
// and add it to the Connection Queue. The new TCPConnection
// must continue the handshake by replying with SYN+ACK. Any
// data in the packet must go into the new TCPConnection's receive
// buffer.
// Otherwise, RST+ACK is sent.
// The current TCPConnection always remains in LISTEN state.
break;
case SYN_SENT:
// if packet is SYN+ACK, send ACK & enter ESTABLISHED state.
// if packet is SYN, send ACK & enter SYN_RCVD state.
break;
case SYN_RCVD:
// if packet is ACK, enter ESTABLISHED
break;
case ESTABLISHED:
// if packet has ACK, update send buffer
// if packet is FIN, send ACK & enter CLOSE_WAIT
// update receive buffer if necessary
break;
// more cases needed covering connection tear-down
default:
return B_ERROR;
}
return B_ERROR;
}
@ -360,6 +403,8 @@ void
TCPConnection::ResendSegment(struct net_timer *timer, void *data)
{
TRACE(("ResendSegment(%p)\n", data));
if (data == NULL)
return;
}
@ -374,6 +419,37 @@ TCPConnection::Send(uint8 flags)
{
TRACE(("%p.Send()\n", this));
return B_OK;
uint32 sequenceNum = 0;
uint32 ackNum = 0;
net_buffer *buffer;
if (1/*no data in send buffer*/) {
buffer = sBufferModule->create(512);
if (buffer == NULL)
return ENOBUFS;
} else {
//TODO: create net_buffer from data in send buffer
}
// get a net_route if there isn't one
if (fRoute == NULL) {
fRoute = sDatalinkModule->get_route(sDomain, (sockaddr *)&socket->peer);
if (fRoute == NULL) {
sBufferModule->free(buffer);
return ENETUNREACH;
}
}
uint16 advWin = TCP_MAX_RECV_BUF - (fNextByteExpected - fLastByteRead);
tcp_segment(buffer, flags, sequenceNum, ackNum, advWin);
#if 0
TCPSegment *segment = new(std::nothrow)
TCPSegment(sequenceNum, 0, 2*fAvgRTT);
#endif
return next->module->send_routed_data(next, fRoute, buffer);
}

View File

@ -48,13 +48,15 @@ static net_stack_module_info *sStackModule;
static hash_table *sTCPHash;
static benaphore sTCPLock;
status_t
tcp_segment(net_buffer *buffer, uint16 flags, uint32 seq, uint32 ack, uint16 adv_win);
#include "tcp.h"
#include "TCPConnection.h"
#ifdef TRACE_TCP
# define DUMP_HASH tcp_dump_hash()
# define DUMP_TCP_HASH tcp_dump_hash()
// Dumps the TCP Connection hash. sTCPLock must NOT be held when calling
void
tcp_dump_hash(){
@ -76,14 +78,14 @@ tcp_dump_hash(){
hash_close(sTCPHash, &iterator, false);
}
#else
# define DUMP_HASH
# define DUMP_TCP_HASH
#endif
net_protocol *
tcp_init_protocol(net_socket *socket)
{
DUMP_HASH;
DUMP_TCP_HASH;
socket->protocol = IPPROTO_TCP;
TCPConnection *protocol = new (std::nothrow) TCPConnection(socket);
TRACE(("Creating new TCPConnection: %p\n", protocol));
@ -94,7 +96,7 @@ tcp_init_protocol(net_socket *socket)
status_t
tcp_uninit_protocol(net_protocol *protocol)
{
DUMP_HASH;
DUMP_TCP_HASH;
TRACE(("Deleting TCPConnection: %p\n", protocol));
delete (TCPConnection *)protocol;
return B_OK;
@ -108,7 +110,7 @@ tcp_open(net_protocol *protocol)
sDomain = sStackModule->get_domain(AF_INET);
if (!sAddressModule)
sAddressModule = sDomain->address_module;
DUMP_HASH;
DUMP_TCP_HASH;
return ((TCPConnection *)protocol)->Open();
}
@ -117,7 +119,7 @@ tcp_open(net_protocol *protocol)
status_t
tcp_close(net_protocol *protocol)
{
DUMP_HASH;
DUMP_TCP_HASH;
return ((TCPConnection *)protocol)->Close();
}
@ -125,7 +127,7 @@ tcp_close(net_protocol *protocol)
status_t
tcp_free(net_protocol *protocol)
{
DUMP_HASH;
DUMP_TCP_HASH;
return ((TCPConnection *)protocol)->Free();
}
@ -133,7 +135,7 @@ tcp_free(net_protocol *protocol)
status_t
tcp_connect(net_protocol *protocol, const struct sockaddr *address)
{
DUMP_HASH;
DUMP_TCP_HASH;
return ((TCPConnection *)protocol)->Connect(address);
}
@ -157,7 +159,7 @@ tcp_control(net_protocol *protocol, int level, int option, void *value,
status_t
tcp_bind(net_protocol *protocol, struct sockaddr *address)
{
DUMP_HASH;
DUMP_TCP_HASH;
return ((TCPConnection *)protocol)->Bind(address);
}
@ -165,7 +167,7 @@ tcp_bind(net_protocol *protocol, struct sockaddr *address)
status_t
tcp_unbind(net_protocol *protocol, struct sockaddr *address)
{
DUMP_HASH;
DUMP_TCP_HASH;
return ((TCPConnection *)protocol)->Unbind(address);
}
@ -237,19 +239,126 @@ tcp_get_mtu(net_protocol *protocol, const struct sockaddr *address)
/*!
Constructs a TCP header on \a buffer with the specified values
for \a flags, \a seq and \a ack. The packet is then sent on \a route
for \a flags, \a seq \a ack and \a adv_win.
*/
status_t
tcp_send_segment(net_buffer *buffer, net_route *route, uint16 flags, uint32 seq, uint32 ack)
tcp_segment(net_buffer *buffer, uint16 flags, uint32 seq, uint32 ack, uint16 adv_win)
{
return B_ERROR;
buffer->protocol = IPPROTO_TCP;
NetBufferPrepend<tcp_header> bufferHeader(buffer);
if (bufferHeader.Status() != B_OK)
return bufferHeader.Status();
tcp_header &header = bufferHeader.Data();
header.source_port = sAddressModule->get_port((sockaddr *)&buffer->source);
header.destination_port = sAddressModule->get_port((sockaddr *)&buffer->destination);
header.sequence_num = htonl(seq);
header.acknowledge_num = htonl(ack);
header.reserved = 0;
header.header_length = 5;// currently no options supported
header.flags = (uint8)flags;
header.advertised_window = adv_win;
header.checksum = 0;
header.urgent_ptr = 0;// urgent pointer not supported
// compute and store checksum
Checksum checksum;
sAddressModule->checksum_address(&checksum, (sockaddr *)&buffer->source);
sAddressModule->checksum_address(&checksum, (sockaddr *)&buffer->destination);
checksum
<< (uint16)htons(IPPROTO_TCP)
<< (uint16)htons(buffer->size)
<< Checksum::BufferHelper(buffer, sBufferModule);
header.checksum = checksum;
TRACE(("TCP: Checksum for segment %p is %d\n", buffer, header.checksum));
return B_OK;
}
status_t
tcp_receive_data(net_buffer *buffer)
{
return B_ERROR;
TRACE(("TCP: Received buffer %p\n", buffer));
if (!sDomain) {
// domain and address module are not known yet, we copy them from
// the buffer's interface (if any):
if (buffer->interface == NULL || buffer->interface->domain == NULL)
sDomain = sStackModule->get_domain(AF_INET);
else
sDomain = buffer->interface->domain;
if (sDomain == NULL) {
// this shouldn't occur, of course, but who knows...
return B_BAD_VALUE;
}
sAddressModule = sDomain->address_module;
}
NetBufferHeader<tcp_header> bufferHeader(buffer);
if (bufferHeader.Status() < B_OK)
return bufferHeader.Status();
tcp_header &header = bufferHeader.Data();
tcp_connection_key key;
key.peer = (struct sockaddr *)&buffer->source;
key.local = (struct sockaddr *)&buffer->destination;
//TODO: check TCP Checksum
sAddressModule->set_port((struct sockaddr *)&buffer->source, header.source_port);
sAddressModule->set_port((struct sockaddr *)&buffer->destination, header.destination_port);
DUMP_TCP_HASH;
BenaphoreLocker hashLock(&sTCPLock);
TCPConnection *connection = (TCPConnection *)hash_lookup(sTCPHash, &key);
TRACE(("TCP: Received packet corresponds to connection %p\n", connection));
if (connection != NULL){
return connection->ReceiveData(buffer);
} else {
/* TODO:
No explicit connection exists. Check for wildcard connections:
First check if any connections exist where local = IPADDR_ANY
then check when local = peer = IPADDR_ANY.
port numbers always remain the same */
// If no connection exists (and RST is not set) send RST
if (!(header.flags & TCP_FLG_RST)) {
TRACE(("TCP: Connection does not exist!\n"));
net_buffer *reply_buf = sBufferModule->create(512);
reply_buf->source = buffer->destination;
reply_buf->destination = buffer->source;
uint32 sequenceNum, acknowledgeNum;
uint16 flags;
if (header.flags & TCP_FLG_ACK) {
sequenceNum = ntohl(header.acknowledge_num);
acknowledgeNum = 0;
flags = TCP_FLG_RST;
} else {
sequenceNum = 0;
acknowledgeNum = ntohl(header.sequence_num) + 1 + buffer->size - ((uint32)header.header_length<<2);
flags = TCP_FLG_RST | TCP_FLG_ACK;
}
status_t status = tcp_segment(reply_buf, flags, sequenceNum, acknowledgeNum, 0);
if (status != B_OK) {
sBufferModule->free(reply_buf);
return status;
}
TRACE(("TCP: Sending RST...\n"));
status = sDomain->module->send_data(NULL, reply_buf);
if (status !=B_OK) {
sBufferModule->free(reply_buf);
return status;
}
TRACE(("TCP: Sent.\n"));
}
}
sBufferModule->free(buffer);
return B_OK;
}