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