blob: 8f908dbfd912571b5f3077e71cd43147450be871 [file] [log] [blame]
wubf975eac2019-08-19 19:41:01 -07001// 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
QUICHE team5be974e2020-12-29 18:35:24 -05005#include "quic/qbone/qbone_packet_processor.h"
wubf975eac2019-08-19 19:41:01 -07006
7#include <cstring>
8
vasilvv1436e342020-10-09 12:31:16 -07009#include "absl/strings/string_view.h"
QUICHE team5be974e2020-12-29 18:35:24 -050010#include "quic/platform/api/quic_bug_tracker.h"
11#include "quic/platform/api/quic_logging.h"
12#include "quic/qbone/platform/icmp_packet.h"
13#include "quic/qbone/platform/internet_checksum.h"
14#include "quic/qbone/platform/tcp_packet.h"
15#include "common/quiche_endian.h"
wubf975eac2019-08-19 19:41:01 -070016
17namespace {
18
19constexpr size_t kIPv6AddressSize = 16;
20constexpr size_t kIPv6MinPacketSize = 1280;
21constexpr size_t kIcmpTtl = 64;
22constexpr size_t kICMPv6DestinationUnreachableDueToSourcePolicy = 5;
23
24} // namespace
25
26namespace quic {
27
28const QuicIpAddress QbonePacketProcessor::kInvalidIpAddress =
29 QuicIpAddress::Any6();
30
31QbonePacketProcessor::QbonePacketProcessor(QuicIpAddress self_ip,
32 QuicIpAddress client_ip,
33 size_t client_ip_subnet_length,
34 OutputInterface* output,
35 StatsInterface* stats)
36 : client_ip_(client_ip),
37 output_(output),
38 stats_(stats),
39 filter_(new Filter) {
40 memcpy(self_ip_.s6_addr, self_ip.ToPackedString().data(), kIPv6AddressSize);
41 DCHECK_LE(client_ip_subnet_length, kIPv6AddressSize * 8);
42 client_ip_subnet_length_ = client_ip_subnet_length;
43
44 DCHECK(IpAddressFamily::IP_V6 == self_ip.address_family());
45 DCHECK(IpAddressFamily::IP_V6 == client_ip.address_family());
46 DCHECK(self_ip != kInvalidIpAddress);
47}
48
49QbonePacketProcessor::OutputInterface::~OutputInterface() {}
50QbonePacketProcessor::StatsInterface::~StatsInterface() {}
51QbonePacketProcessor::Filter::~Filter() {}
52
53QbonePacketProcessor::ProcessingResult
vasilvv1436e342020-10-09 12:31:16 -070054QbonePacketProcessor::Filter::FilterPacket(Direction direction,
55 absl::string_view full_packet,
56 absl::string_view payload,
57 icmp6_hdr* icmp_header,
58 OutputInterface* output) {
wubf975eac2019-08-19 19:41:01 -070059 return ProcessingResult::OK;
60}
61
QUICHE teamb80d7c32020-02-23 23:44:20 -080062void QbonePacketProcessor::ProcessPacket(std::string* packet,
63 Direction direction) {
wubf975eac2019-08-19 19:41:01 -070064 if (QUIC_PREDICT_FALSE(!IsValid())) {
65 QUIC_BUG << "QuicPacketProcessor is invoked in an invalid state.";
66 stats_->OnPacketDroppedSilently(direction);
67 return;
68 }
69
70 uint8_t transport_protocol;
71 char* transport_data;
72 icmp6_hdr icmp_header;
73 memset(&icmp_header, 0, sizeof(icmp_header));
74 ProcessingResult result = ProcessIPv6HeaderAndFilter(
75 packet, direction, &transport_protocol, &transport_data, &icmp_header);
76
77 switch (result) {
78 case ProcessingResult::OK:
79 switch (direction) {
QUICHE team234c8772019-12-06 14:14:12 -080080 case Direction::FROM_OFF_NETWORK:
wubf975eac2019-08-19 19:41:01 -070081 output_->SendPacketToNetwork(*packet);
82 break;
83 case Direction::FROM_NETWORK:
84 output_->SendPacketToClient(*packet);
85 break;
86 }
87 stats_->OnPacketForwarded(direction);
88 break;
89 case ProcessingResult::SILENT_DROP:
90 stats_->OnPacketDroppedSilently(direction);
91 break;
92 case ProcessingResult::DEFER:
93 stats_->OnPacketDeferred(direction);
94 break;
95 case ProcessingResult::ICMP:
96 SendIcmpResponse(&icmp_header, *packet, direction);
97 stats_->OnPacketDroppedWithIcmp(direction);
98 break;
99 case ProcessingResult::ICMP_AND_TCP_RESET:
100 SendIcmpResponse(&icmp_header, *packet, direction);
101 stats_->OnPacketDroppedWithIcmp(direction);
102 SendTcpReset(*packet, direction);
103 stats_->OnPacketDroppedWithTcpReset(direction);
104 break;
105 }
106}
107
108QbonePacketProcessor::ProcessingResult
QUICHE teamb80d7c32020-02-23 23:44:20 -0800109QbonePacketProcessor::ProcessIPv6HeaderAndFilter(std::string* packet,
wubf975eac2019-08-19 19:41:01 -0700110 Direction direction,
111 uint8_t* transport_protocol,
112 char** transport_data,
113 icmp6_hdr* icmp_header) {
114 ProcessingResult result = ProcessIPv6Header(
115 packet, direction, transport_protocol, transport_data, icmp_header);
116
117 if (result == ProcessingResult::OK) {
118 char* packet_data = &*packet->begin();
119 size_t header_size = *transport_data - packet_data;
120 // Sanity-check the bounds.
121 if (packet_data >= *transport_data || header_size > packet->size() ||
122 header_size < kIPv6HeaderSize) {
123 QUIC_BUG << "Invalid pointers encountered in "
124 "QbonePacketProcessor::ProcessPacket. Dropping the packet";
125 return ProcessingResult::SILENT_DROP;
126 }
127
128 result = filter_->FilterPacket(
129 direction, *packet,
vasilvv1436e342020-10-09 12:31:16 -0700130 absl::string_view(*transport_data, packet->size() - header_size),
wubf975eac2019-08-19 19:41:01 -0700131 icmp_header, output_);
132 }
133
134 // Do not send ICMP error messages in response to ICMP errors.
135 if (result == ProcessingResult::ICMP) {
136 const uint8_t* header = reinterpret_cast<const uint8_t*>(packet->data());
137
138 constexpr size_t kIPv6NextHeaderOffset = 6;
139 constexpr size_t kIcmpMessageTypeOffset = kIPv6HeaderSize + 0;
140 constexpr size_t kIcmpMessageTypeMaxError = 127;
141 if (
142 // Check size.
143 packet->size() >= (kIPv6HeaderSize + kICMPv6HeaderSize) &&
144 // Check that the packet is in fact ICMP.
145 header[kIPv6NextHeaderOffset] == IPPROTO_ICMPV6 &&
146 // Check that ICMP message type is an error.
147 header[kIcmpMessageTypeOffset] < kIcmpMessageTypeMaxError) {
148 result = ProcessingResult::SILENT_DROP;
149 }
150 }
151
152 return result;
153}
154
155QbonePacketProcessor::ProcessingResult QbonePacketProcessor::ProcessIPv6Header(
QUICHE teamb80d7c32020-02-23 23:44:20 -0800156 std::string* packet,
wubf975eac2019-08-19 19:41:01 -0700157 Direction direction,
158 uint8_t* transport_protocol,
159 char** transport_data,
160 icmp6_hdr* icmp_header) {
161 // Check if the packet is big enough to have IPv6 header.
162 if (packet->size() < kIPv6HeaderSize) {
163 QUIC_DVLOG(1) << "Dropped malformed packet: IPv6 header too short";
164 return ProcessingResult::SILENT_DROP;
165 }
166
167 // Check version field.
168 ip6_hdr* header = reinterpret_cast<ip6_hdr*>(&*packet->begin());
169 if (header->ip6_vfc >> 4 != 6) {
170 QUIC_DVLOG(1) << "Dropped malformed packet: IP version is not IPv6";
171 return ProcessingResult::SILENT_DROP;
172 }
173
174 // Check payload size.
175 const size_t declared_payload_size =
QUICHE team173c48f2019-11-19 16:34:44 -0800176 quiche::QuicheEndian::NetToHost16(header->ip6_plen);
wubf975eac2019-08-19 19:41:01 -0700177 const size_t actual_payload_size = packet->size() - kIPv6HeaderSize;
178 if (declared_payload_size != actual_payload_size) {
179 QUIC_DVLOG(1)
180 << "Dropped malformed packet: incorrect packet length specified";
181 return ProcessingResult::SILENT_DROP;
182 }
183
184 // Check that the address of the client is in the packet.
185 QuicIpAddress address_to_check;
186 uint8_t address_reject_code;
187 bool ip_parse_result;
188 switch (direction) {
QUICHE team234c8772019-12-06 14:14:12 -0800189 case Direction::FROM_OFF_NETWORK:
wubf975eac2019-08-19 19:41:01 -0700190 // Expect the source IP to match the client.
191 ip_parse_result = address_to_check.FromPackedString(
192 reinterpret_cast<const char*>(&header->ip6_src),
193 sizeof(header->ip6_src));
194 address_reject_code = kICMPv6DestinationUnreachableDueToSourcePolicy;
195 break;
196 case Direction::FROM_NETWORK:
197 // Expect the destination IP to match the client.
198 ip_parse_result = address_to_check.FromPackedString(
199 reinterpret_cast<const char*>(&header->ip6_dst),
200 sizeof(header->ip6_src));
201 address_reject_code = ICMP6_DST_UNREACH_NOROUTE;
202 break;
203 }
204 DCHECK(ip_parse_result);
205 if (!client_ip_.InSameSubnet(address_to_check, client_ip_subnet_length_)) {
206 QUIC_DVLOG(1)
207 << "Dropped packet: source/destination address is not client's";
208 icmp_header->icmp6_type = ICMP6_DST_UNREACH;
209 icmp_header->icmp6_code = address_reject_code;
210 return ProcessingResult::ICMP;
211 }
212
213 // Check and decrement TTL.
214 if (header->ip6_hops <= 1) {
215 icmp_header->icmp6_type = ICMP6_TIME_EXCEEDED;
216 icmp_header->icmp6_code = ICMP6_TIME_EXCEED_TRANSIT;
217 return ProcessingResult::ICMP;
218 }
219 header->ip6_hops--;
220
221 // Check and extract IP headers.
222 switch (header->ip6_nxt) {
223 case IPPROTO_TCP:
224 case IPPROTO_UDP:
225 case IPPROTO_ICMPV6:
226 *transport_protocol = header->ip6_nxt;
227 *transport_data = (&*packet->begin()) + kIPv6HeaderSize;
228 break;
229 default:
230 icmp_header->icmp6_type = ICMP6_PARAM_PROB;
231 icmp_header->icmp6_code = ICMP6_PARAMPROB_NEXTHEADER;
232 return ProcessingResult::ICMP;
233 }
234
235 return ProcessingResult::OK;
236}
237
vasilvv1436e342020-10-09 12:31:16 -0700238void QbonePacketProcessor::SendIcmpResponse(icmp6_hdr* icmp_header,
239 absl::string_view original_packet,
240 Direction original_direction) {
wubf975eac2019-08-19 19:41:01 -0700241 in6_addr dst;
242 // TODO(b/70339814): ensure this is actually a unicast address.
243 memcpy(dst.s6_addr, &original_packet[8], kIPv6AddressSize);
244
vasilvv1436e342020-10-09 12:31:16 -0700245 CreateIcmpPacket(self_ip_, dst, *icmp_header, original_packet,
246 [this, original_direction](absl::string_view packet) {
247 SendResponse(original_direction, packet);
248 });
wubf975eac2019-08-19 19:41:01 -0700249}
250
vasilvv1436e342020-10-09 12:31:16 -0700251void QbonePacketProcessor::SendTcpReset(absl::string_view original_packet,
252 Direction original_direction) {
253 CreateTcpResetPacket(original_packet,
254 [this, original_direction](absl::string_view packet) {
255 SendResponse(original_direction, packet);
256 });
wubf975eac2019-08-19 19:41:01 -0700257}
258
259void QbonePacketProcessor::SendResponse(Direction original_direction,
vasilvv1436e342020-10-09 12:31:16 -0700260 absl::string_view packet) {
wubf975eac2019-08-19 19:41:01 -0700261 switch (original_direction) {
QUICHE team234c8772019-12-06 14:14:12 -0800262 case Direction::FROM_OFF_NETWORK:
wubf975eac2019-08-19 19:41:01 -0700263 output_->SendPacketToClient(packet);
264 break;
265 case Direction::FROM_NETWORK:
266 output_->SendPacketToNetwork(packet);
267 break;
268 }
269}
270
271} // namespace quic