| // Copyright (c) 2016 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "net/tools/quic/chlo_extractor.h" |
| |
| #include "net/quic/crypto/crypto_framer.h" |
| #include "net/quic/crypto/crypto_handshake_message.h" |
| #include "net/quic/crypto/crypto_protocol.h" |
| #include "net/quic/crypto/quic_decrypter.h" |
| #include "net/quic/crypto/quic_encrypter.h" |
| #include "net/quic/quic_framer.h" |
| |
| using base::StringPiece; |
| |
| namespace net { |
| |
| namespace { |
| |
| class ChloFramerVisitor : public QuicFramerVisitorInterface, |
| public CryptoFramerVisitorInterface { |
| public: |
| ChloFramerVisitor(QuicFramer* framer, ChloExtractor::Delegate* delegate); |
| |
| ~ChloFramerVisitor() override {} |
| |
| // QuicFramerVisitorInterface implementation |
| void OnError(QuicFramer* framer) override {} |
| bool OnProtocolVersionMismatch(QuicVersion version) override; |
| void OnPacket() override {} |
| void OnPublicResetPacket(const QuicPublicResetPacket& packet) override {} |
| void OnVersionNegotiationPacket( |
| const QuicVersionNegotiationPacket& packet) override {} |
| bool OnUnauthenticatedPublicHeader( |
| const QuicPacketPublicHeader& header) override; |
| bool OnUnauthenticatedHeader(const QuicPacketHeader& header) override; |
| void OnDecryptedPacket(EncryptionLevel level) override {} |
| bool OnPacketHeader(const QuicPacketHeader& header) override; |
| bool OnStreamFrame(const QuicStreamFrame& frame) override; |
| bool OnAckFrame(const QuicAckFrame& frame) override; |
| bool OnStopWaitingFrame(const QuicStopWaitingFrame& frame) override; |
| bool OnPingFrame(const QuicPingFrame& frame) override; |
| bool OnRstStreamFrame(const QuicRstStreamFrame& frame) override; |
| bool OnConnectionCloseFrame(const QuicConnectionCloseFrame& frame) override; |
| bool OnGoAwayFrame(const QuicGoAwayFrame& frame) override; |
| bool OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) override; |
| bool OnBlockedFrame(const QuicBlockedFrame& frame) override; |
| bool OnPathCloseFrame(const QuicPathCloseFrame& frame) override; |
| bool OnPaddingFrame(const QuicPaddingFrame& frame) override; |
| void OnPacketComplete() override {} |
| |
| // CryptoFramerVisitorInterface implementation. |
| void OnError(CryptoFramer* framer) override; |
| void OnHandshakeMessage(const CryptoHandshakeMessage& message) override; |
| |
| bool found_chlo() { return found_chlo_; } |
| |
| private: |
| QuicFramer* framer_; |
| ChloExtractor::Delegate* delegate_; |
| bool found_chlo_; |
| QuicConnectionId connection_id_; |
| }; |
| |
| ChloFramerVisitor::ChloFramerVisitor(QuicFramer* framer, |
| ChloExtractor::Delegate* delegate) |
| : framer_(framer), |
| delegate_(delegate), |
| found_chlo_(false), |
| connection_id_(0) {} |
| |
| bool ChloFramerVisitor::OnProtocolVersionMismatch(QuicVersion version) { |
| if (!framer_->IsSupportedVersion(version)) { |
| return false; |
| } |
| framer_->set_version(version); |
| return true; |
| } |
| |
| bool ChloFramerVisitor::OnUnauthenticatedPublicHeader( |
| const QuicPacketPublicHeader& header) { |
| connection_id_ = header.connection_id; |
| return true; |
| } |
| bool ChloFramerVisitor::OnUnauthenticatedHeader( |
| const QuicPacketHeader& header) { |
| return true; |
| } |
| bool ChloFramerVisitor::OnPacketHeader(const QuicPacketHeader& header) { |
| return true; |
| } |
| bool ChloFramerVisitor::OnStreamFrame(const QuicStreamFrame& frame) { |
| StringPiece data(frame.data_buffer, frame.data_length); |
| if (frame.stream_id == kCryptoStreamId && frame.offset == 0 && |
| data.starts_with("CHLO")) { |
| CryptoFramer crypto_framer; |
| crypto_framer.set_visitor(this); |
| if (!crypto_framer.ProcessInput(data)) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| bool ChloFramerVisitor::OnAckFrame(const QuicAckFrame& frame) { |
| return true; |
| } |
| |
| bool ChloFramerVisitor::OnStopWaitingFrame(const QuicStopWaitingFrame& frame) { |
| return true; |
| } |
| |
| bool ChloFramerVisitor::OnPingFrame(const QuicPingFrame& frame) { |
| return true; |
| } |
| |
| bool ChloFramerVisitor::OnRstStreamFrame(const QuicRstStreamFrame& frame) { |
| return true; |
| } |
| |
| bool ChloFramerVisitor::OnConnectionCloseFrame( |
| const QuicConnectionCloseFrame& frame) { |
| return true; |
| } |
| |
| bool ChloFramerVisitor::OnGoAwayFrame(const QuicGoAwayFrame& frame) { |
| return true; |
| } |
| |
| bool ChloFramerVisitor::OnWindowUpdateFrame( |
| const QuicWindowUpdateFrame& frame) { |
| return true; |
| } |
| |
| bool ChloFramerVisitor::OnBlockedFrame(const QuicBlockedFrame& frame) { |
| return true; |
| } |
| |
| bool ChloFramerVisitor::OnPathCloseFrame(const QuicPathCloseFrame& frame) { |
| return true; |
| } |
| |
| bool ChloFramerVisitor::OnPaddingFrame(const QuicPaddingFrame& frame) { |
| return true; |
| } |
| |
| void ChloFramerVisitor::OnError(CryptoFramer* framer) {} |
| |
| void ChloFramerVisitor::OnHandshakeMessage( |
| const CryptoHandshakeMessage& message) { |
| delegate_->OnChlo(framer_->version(), connection_id_, message); |
| found_chlo_ = true; |
| } |
| |
| } // namespace |
| |
| // static |
| bool ChloExtractor::Extract(const QuicEncryptedPacket& packet, |
| const QuicVersionVector& versions, |
| Delegate* delegate) { |
| QuicFramer framer(versions, QuicTime::Zero(), Perspective::IS_SERVER); |
| ChloFramerVisitor visitor(&framer, delegate); |
| framer.set_visitor(&visitor); |
| if (!framer.ProcessPacket(packet)) { |
| return false; |
| } |
| return visitor.found_chlo(); |
| } |
| |
| } // namespace net |