xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/qbone/qbone_packet_processor.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright (c) 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef QUICHE_QUIC_QBONE_QBONE_PACKET_PROCESSOR_H_
6 #define QUICHE_QUIC_QBONE_QBONE_PACKET_PROCESSOR_H_
7 
8 #include <netinet/icmp6.h>
9 #include <netinet/in.h>
10 #include <netinet/ip6.h>
11 
12 #include <cstddef>
13 #include <cstdint>
14 
15 #include "absl/strings/string_view.h"
16 #include "quiche/quic/core/quic_types.h"
17 #include "quiche/quic/platform/api/quic_ip_address.h"
18 
19 namespace quic {
20 
21 enum : size_t {
22   kIPv6HeaderSize = 40,
23   kICMPv6HeaderSize = sizeof(icmp6_hdr),
24   kTotalICMPv6HeaderSize = kIPv6HeaderSize + kICMPv6HeaderSize,
25 };
26 
27 // QBONE packet processor accepts packets destined in either direction
28 // (client-to-network or network-to-client).  It inspects them and makes
29 // decisions on whether they should be forwarded or dropped, replying with ICMP
30 // messages as appropriate.
31 class QbonePacketProcessor {
32  public:
33   enum class Direction {
34     // Packet is going from the QBONE client into the network behind the QBONE.
35     FROM_OFF_NETWORK = 0,
36     // Packet is going from the network begin QBONE to the client.
37     FROM_NETWORK = 1
38   };
39 
40   enum class ProcessingResult {
41     OK = 0,
42     SILENT_DROP = 1,
43     ICMP = 2,
44     // Equivalent to |SILENT_DROP| at the moment, but indicates that the
45     // downstream filter has buffered the packet and deferred its processing.
46     // The packet may be emitted at a later time.
47     DEFER = 3,
48     // In addition to sending an ICMP message, also send a TCP RST. This option
49     // requires the incoming packet to have been a valid TCP packet, as a TCP
50     // RST requires information from the current connection state to be
51     // well-formed.
52     ICMP_AND_TCP_RESET = 4,
53     // Send a TCP RST.
54     TCP_RESET = 5,
55   };
56 
57   class OutputInterface {
58    public:
59     virtual ~OutputInterface();
60 
61     virtual void SendPacketToClient(absl::string_view packet) = 0;
62     virtual void SendPacketToNetwork(absl::string_view packet) = 0;
63   };
64 
65   // A visitor interface that allows the packet processor to collect stats
66   // without relying on a specific backend or exposing the entire packet.
67   // |traffic_class| should be extracted directly from the IPv6 header.
68   class StatsInterface {
69    public:
70     virtual ~StatsInterface();
71 
72     virtual void OnPacketForwarded(Direction direction,
73                                    uint8_t traffic_class) = 0;
74     virtual void OnPacketDroppedSilently(Direction direction,
75                                          uint8_t traffic_class) = 0;
76     virtual void OnPacketDroppedWithIcmp(Direction direction,
77                                          uint8_t traffic_class) = 0;
78     virtual void OnPacketDroppedWithTcpReset(Direction direction,
79                                              uint8_t traffic_class) = 0;
80     virtual void OnPacketDeferred(Direction direction,
81                                   uint8_t traffic_class) = 0;
82     virtual void RecordThroughput(size_t bytes, Direction direction,
83                                   uint8_t traffic_class) = 0;
84   };
85 
86   // Allows to implement a custom packet filter on top of the filtering done by
87   // the packet processor itself.
88   class Filter {
89    public:
90     virtual ~Filter();
91     // The main interface function.  The following arguments are supplied:
92     // - |direction|, to indicate direction of the packet.
93     // - |full_packet|, which includes the IPv6 header and possibly the IPv6
94     //   options that were understood by the processor.
95     // - |payload|, the contents of the IPv6 packet, i.e. a TCP, a UDP or an
96     //   ICMP packet.
97     // - |icmp_header|, an output argument which allows the filter to specify
98     //   the ICMP message with which the packet is to be rejected.
99     // The method is called only on packets which were already verified as valid
100     // IPv6 packets.
101     //
102     // The implementer of this method has four options to return:
103     // - OK will cause the filter to pass the packet through
104     // - SILENT_DROP will cause the filter to drop the packet silently
105     // - ICMP will cause the filter to drop the packet and send an ICMP
106     //   response.
107     // - DEFER will cause the packet to be not forwarded; the filter is
108     //   responsible for sending (or not sending) it later using |output|.
109     //
110     // Note that |output| should not be used except in the DEFER case, as the
111     // processor will perform the necessary writes itself.
112     virtual ProcessingResult FilterPacket(Direction direction,
113                                           absl::string_view full_packet,
114                                           absl::string_view payload,
115                                           icmp6_hdr* icmp_header,
116                                           OutputInterface* output);
117 
118    protected:
119     // Helper methods that allow to easily extract information that is required
120     // for filtering from the |ipv6_header| argument.  All of those assume that
121     // the header is of valid size, which is true for everything passed into
122     // FilterPacket().
TransportProtocolFromHeader(absl::string_view ipv6_header)123     uint8_t TransportProtocolFromHeader(absl::string_view ipv6_header) {
124       return ipv6_header[6];
125     }
126 
SourceIpFromHeader(absl::string_view ipv6_header)127     QuicIpAddress SourceIpFromHeader(absl::string_view ipv6_header) {
128       QuicIpAddress address;
129       address.FromPackedString(&ipv6_header[8],
130                                QuicIpAddress::kIPv6AddressSize);
131       return address;
132     }
DestinationIpFromHeader(absl::string_view ipv6_header)133     QuicIpAddress DestinationIpFromHeader(absl::string_view ipv6_header) {
134       QuicIpAddress address;
135       address.FromPackedString(&ipv6_header[24],
136                                QuicIpAddress::kIPv6AddressSize);
137       return address;
138     }
139   };
140 
141   // |self_ip| is the IP address from which the processor will originate ICMP
142   // messages.  |client_ip| is the expected IP address of the client, used for
143   // packet validation.
144   //
145   // |output| and |stats| are the visitor interfaces used by the processor.
146   // |output| gets notified whenever the processor decides to send a packet, and
147   // |stats| gets notified about any decisions that processor makes, without a
148   // reference to which packet that decision was made about.
149   QbonePacketProcessor(QuicIpAddress self_ip, QuicIpAddress client_ip,
150                        size_t client_ip_subnet_length, OutputInterface* output,
151                        StatsInterface* stats);
152   QbonePacketProcessor(const QbonePacketProcessor&) = delete;
153   QbonePacketProcessor& operator=(const QbonePacketProcessor&) = delete;
154 
155   // Accepts an IPv6 packet and handles it accordingly by either forwarding it,
156   // replying with an ICMP packet or silently dropping it.  |packet| will be
157   // modified in the process, by having the TTL field decreased.
158   void ProcessPacket(std::string* packet, Direction direction);
159 
set_filter(std::unique_ptr<Filter> filter)160   void set_filter(std::unique_ptr<Filter> filter) {
161     filter_ = std::move(filter);
162   }
163 
set_client_ip(QuicIpAddress client_ip)164   void set_client_ip(QuicIpAddress client_ip) { client_ip_ = client_ip; }
set_client_ip_subnet_length(size_t client_ip_subnet_length)165   void set_client_ip_subnet_length(size_t client_ip_subnet_length) {
166     client_ip_subnet_length_ = client_ip_subnet_length;
167   }
168 
169   static const QuicIpAddress kInvalidIpAddress;
170 
171   // This function assumes that the packet is valid.
172   static uint8_t TrafficClassFromHeader(absl::string_view ipv6_header);
173 
174  protected:
175   // Processes the header and returns what should be done with the packet.
176   // After that, calls an external packet filter if registered.  TTL of the
177   // packet may be decreased in the process.
178   ProcessingResult ProcessIPv6HeaderAndFilter(std::string* packet,
179                                               Direction direction,
180                                               uint8_t* transport_protocol,
181                                               char** transport_data,
182                                               icmp6_hdr* icmp_header);
183 
184   void SendIcmpResponse(in6_addr dst, icmp6_hdr* icmp_header,
185                         absl::string_view payload,
186                         Direction original_direction);
187 
188   void SendTcpReset(absl::string_view original_packet,
189                     Direction original_direction);
190 
IsValid()191   bool IsValid() const { return client_ip_ != kInvalidIpAddress; }
192 
193   // IP address of the server.  Used to send ICMP messages.
194   in6_addr self_ip_;
195   // IP address range of the VPN client.
196   QuicIpAddress client_ip_;
197   size_t client_ip_subnet_length_;
198 
199   OutputInterface* output_;
200   StatsInterface* stats_;
201   std::unique_ptr<Filter> filter_;
202 
203  private:
204   // Performs basic sanity and permission checks on the packet, and decreases
205   // the TTL.
206   ProcessingResult ProcessIPv6Header(std::string* packet, Direction direction,
207                                      uint8_t* transport_protocol,
208                                      char** transport_data,
209                                      icmp6_hdr* icmp_header);
210 
211   void SendResponse(Direction original_direction, absl::string_view packet);
212 
213   in6_addr GetDestinationFromPacket(absl::string_view packet);
214 };
215 
216 }  // namespace quic
217 #endif  // QUICHE_QUIC_QBONE_QBONE_PACKET_PROCESSOR_H_
218