Преглед изворни кода

Kernel: Send RST/ACK if no socket is available

Previously there was no way for Serenity to send a packet without an
established socket connection, and there was no way to appropriately
respond to a SYN packet on a non-listening port. This patch will respond
to any non-established socket attempts with the appropraite RST/ACK,
letting the client know to close the connection.
brapru пре 4 година
родитељ
комит
9c3e6f3f63
2 измењених фајлова са 38 додато и 16 уклоњено
  1. 36 14
      Kernel/Net/NetworkTask.cpp
  2. 2 2
      Kernel/Net/TCPSocket.h

+ 36 - 14
Kernel/Net/NetworkTask.cpp

@@ -30,6 +30,7 @@ static void handle_icmp(EthernetFrameHeader const&, IPv4Packet const&, Time cons
 static void handle_udp(IPv4Packet const&, Time const& packet_timestamp);
 static void handle_udp(IPv4Packet const&, Time const& packet_timestamp);
 static void handle_tcp(IPv4Packet const&, Time const& packet_timestamp);
 static void handle_tcp(IPv4Packet const&, Time const& packet_timestamp);
 static void send_delayed_tcp_ack(RefPtr<TCPSocket> socket);
 static void send_delayed_tcp_ack(RefPtr<TCPSocket> socket);
+static void send_tcp_rst(IPv4Packet const& ipv4_packet, TCPPacket const& tcp_packet, RefPtr<NetworkAdapter> adapter);
 static void flush_delayed_tcp_acks();
 static void flush_delayed_tcp_acks();
 static void retransmit_tcp_packets();
 static void retransmit_tcp_packets();
 
 
@@ -328,6 +329,39 @@ void flush_delayed_tcp_acks()
     }
     }
 }
 }
 
 
+void send_tcp_rst(IPv4Packet const& ipv4_packet, TCPPacket const& tcp_packet, RefPtr<NetworkAdapter> adapter)
+{
+    auto routing_decision = route_to(ipv4_packet.source(), ipv4_packet.destination(), adapter);
+    if (routing_decision.is_zero())
+        return;
+
+    auto ipv4_payload_offset = routing_decision.adapter->ipv4_payload_offset();
+
+    const size_t options_size = 0;
+    const size_t tcp_header_size = sizeof(TCPPacket) + options_size;
+    const size_t buffer_size = ipv4_payload_offset + tcp_header_size;
+
+    auto packet = routing_decision.adapter->acquire_packet_buffer(buffer_size);
+    if (!packet)
+        return;
+    routing_decision.adapter->fill_in_ipv4_header(*packet, ipv4_packet.destination(),
+        routing_decision.next_hop, ipv4_packet.source(), IPv4Protocol::TCP,
+        buffer_size - ipv4_payload_offset, 64);
+    memset(packet->buffer.data() + ipv4_payload_offset, 0, sizeof(TCPPacket));
+    auto& rst_packet = *(TCPPacket*)(packet->buffer.data() + ipv4_payload_offset);
+    rst_packet.set_source_port(tcp_packet.destination_port());
+    rst_packet.set_destination_port(tcp_packet.source_port());
+    rst_packet.set_window_size(0);
+    rst_packet.set_sequence_number(0);
+    rst_packet.set_ack_number(tcp_packet.sequence_number() + 1);
+    rst_packet.set_data_offset(tcp_header_size / sizeof(u32));
+    rst_packet.set_flags(TCPFlags::RST | TCPFlags::ACK);
+    rst_packet.set_checksum(TCPSocket::compute_tcp_checksum(ipv4_packet.source(), ipv4_packet.destination(), rst_packet, 0));
+
+    routing_decision.adapter->send_packet({ packet->buffer.data(), packet->buffer.size() });
+    routing_decision.adapter->release_packet_buffer(*packet);
+}
+
 void handle_tcp(IPv4Packet const& ipv4_packet, Time const& packet_timestamp)
 void handle_tcp(IPv4Packet const& ipv4_packet, Time const& packet_timestamp)
 {
 {
     if (ipv4_packet.payload_size() < sizeof(TCPPacket)) {
     if (ipv4_packet.payload_size() < sizeof(TCPPacket)) {
@@ -377,20 +411,8 @@ void handle_tcp(IPv4Packet const& ipv4_packet, Time const& packet_timestamp)
 
 
     auto socket = TCPSocket::from_tuple(tuple);
     auto socket = TCPSocket::from_tuple(tuple);
     if (!socket) {
     if (!socket) {
-        dbgln("handle_tcp: No TCP socket for tuple {}", tuple.to_string());
-        dbgln("handle_tcp: source={}:{}, destination={}:{}, seq_no={}, ack_no={}, flags={:#04x} ({}{}{}{}), window_size={}, payload_size={}",
-            ipv4_packet.source().to_string(), tcp_packet.source_port(),
-            ipv4_packet.destination().to_string(),
-            tcp_packet.destination_port(),
-            tcp_packet.sequence_number(),
-            tcp_packet.ack_number(),
-            tcp_packet.flags(),
-            tcp_packet.has_syn() ? "SYN " : "",
-            tcp_packet.has_ack() ? "ACK " : "",
-            tcp_packet.has_fin() ? "FIN " : "",
-            tcp_packet.has_rst() ? "RST " : "",
-            tcp_packet.window_size(),
-            payload_size);
+        dbgln("handle_tcp: No TCP socket for tuple {}. Sending RST.", tuple.to_string());
+        send_tcp_rst(ipv4_packet, tcp_packet, adapter);
         return;
         return;
     }
     }
 
 

+ 2 - 2
Kernel/Net/TCPSocket.h

@@ -159,6 +159,8 @@ public:
 
 
     virtual bool can_write(const FileDescription&, size_t) const override;
     virtual bool can_write(const FileDescription&, size_t) const override;
 
 
+    static NetworkOrdered<u16> compute_tcp_checksum(IPv4Address const& source, IPv4Address const& destination, TCPPacket const&, u16 payload_size);
+
 protected:
 protected:
     void set_direction(Direction direction) { m_direction = direction; }
     void set_direction(Direction direction) { m_direction = direction; }
 
 
@@ -166,8 +168,6 @@ private:
     explicit TCPSocket(int protocol);
     explicit TCPSocket(int protocol);
     virtual StringView class_name() const override { return "TCPSocket"; }
     virtual StringView class_name() const override { return "TCPSocket"; }
 
 
-    static NetworkOrdered<u16> compute_tcp_checksum(const IPv4Address& source, const IPv4Address& destination, const TCPPacket&, u16 payload_size);
-
     virtual void shut_down_for_writing() override;
     virtual void shut_down_for_writing() override;
 
 
     virtual KResultOr<size_t> protocol_receive(ReadonlyBytes raw_ipv4_packet, UserOrKernelBuffer& buffer, size_t buffer_size, int flags) override;
     virtual KResultOr<size_t> protocol_receive(ReadonlyBytes raw_ipv4_packet, UserOrKernelBuffer& buffer, size_t buffer_size, int flags) override;