Home | History | Annotate | Download | only in net
      1 // Copyright 2013 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 #include "chrome/browser/net/probe_message.h"
      6 
      7 #include <string>
      8 
      9 #include "base/logging.h"
     10 
     11 namespace chrome_browser_net {
     12 
     13 const uint32 ProbeMessage::kVersion = 2;
     14 const uint32 ProbeMessage::kMaxNumberProbePackets = 21;
     15 const uint32 ProbeMessage::kMaxProbePacketBytes = 1500;
     16 // Maximum pacing interval is 300 seconds (for testing NAT binding).
     17 const uint32 ProbeMessage::kMaxPacingIntervalMicros = 300000000;
     18 const char ProbeMessage::kEncodingString[] =
     19     "T\xd3?\xa5h2\x9c\x8en\xf1Q6\xbc{\xc6-4\xfa$f\xb9[\xa6\xcd@6,\xdf\xb3i-\xe6"
     20     "v\x9eV\x8dXd\xd9kE\xf6=\xbeO";
     21 
     22 ProbeMessage::ProbeMessage() {}
     23 
     24 bool ProbeMessage::ParseInput(const std::string& input,
     25                               ProbePacket* probe_packet) const {
     26   // Encode is used for decoding here.
     27   std::string input_decoded = Encode(input);
     28 
     29   bool parse_result = probe_packet->ParseFromString(input_decoded);
     30   if (!parse_result) {
     31     DVLOG(1) << "ProtoBuffer string parsing error. Input size:" << input.size();
     32     return false;
     33   }
     34   const ProbePacket_Header& header = probe_packet->header();
     35   DVLOG(2) << "version " << header.version() << " checksum "
     36            << header.checksum() << " type " << header.type();
     37   if (header.version() != kVersion) {
     38     DVLOG(1) << "Bad version number: " << header.version()
     39              << " expected: " << kVersion;
     40     return false;
     41   }
     42 
     43   // Checksum is computed on padding only.
     44   if (probe_packet->has_padding()) {
     45     DVLOG(3) << "received padding: " << probe_packet->padding();
     46     uint32 computed_checksum = Checksum(probe_packet->padding());
     47     if (computed_checksum != header.checksum()) {
     48       DVLOG(1) << "Checksum mismatch.  Got: " << header.checksum()
     49                << " expected: " << computed_checksum;
     50       return false;
     51     }
     52   }
     53 
     54   if (header.type() != ProbePacket_Type_HELLO_REPLY &&
     55       header.type() != ProbePacket_Type_PROBE_REPLY) {
     56     DVLOG(1) << "Received unknown packet type:" << header.type();
     57     return false;
     58   }
     59   return true;
     60 }
     61 
     62 uint32 ProbeMessage::Checksum(const std::string& str) const {
     63   uint32 ret = 0;
     64   for (std::string::const_iterator i = str.begin(); i != str.end(); ++i) {
     65     ret += static_cast<uint8>(*i);
     66   }
     67   return ret;
     68 }
     69 
     70 void ProbeMessage::GenerateProbeRequest(const ProbePacket_Token& token,
     71                                         uint32 group_id,
     72                                         uint32 probe_size,
     73                                         uint32 pacing_interval_micros,
     74                                         uint32 number_probe_packets,
     75                                         ProbePacket* probe_packet) {
     76   DCHECK_LE(number_probe_packets, kMaxNumberProbePackets);
     77   DCHECK_LE(probe_size, kMaxProbePacketBytes);
     78   DCHECK_LE(pacing_interval_micros, kMaxPacingIntervalMicros);
     79 
     80   SetPacketHeader(ProbePacket_Type_PROBE_REQUEST, probe_packet);
     81   *(probe_packet->mutable_token()) = token;
     82   probe_packet->set_group_id(group_id);
     83   probe_packet->set_probe_size_bytes(probe_size);
     84   probe_packet->set_pacing_interval_micros(pacing_interval_micros);
     85   probe_packet->set_number_probe_packets(number_probe_packets);
     86 
     87   // Add padding to mitigate amplification attack.
     88   std::string* padding = probe_packet->mutable_padding();
     89   int padding_size = probe_size - probe_packet->ByteSize();
     90   padding->append(std::string(std::max(0, padding_size), 0));
     91   probe_packet->mutable_header()->set_checksum(Checksum(*padding));
     92   DVLOG(3) << "Request size " << probe_packet->ByteSize() << " probe size "
     93            << probe_size;
     94   DCHECK_LE(probe_size, static_cast<uint32>(probe_packet->ByteSize()));
     95 }
     96 
     97 void ProbeMessage::SetPacketHeader(ProbePacket_Type packet_type,
     98                                    ProbePacket* probe_packet) const {
     99   ProbePacket_Header* header = probe_packet->mutable_header();
    100   header->set_version(kVersion);
    101   header->set_type(packet_type);
    102 }
    103 
    104 std::string ProbeMessage::Encode(const std::string& input) const {
    105 
    106   std::string output(input.size(), 0);
    107   int key_pos = 0;
    108   // kEncodingString contains a ending '\0' character, excluded for encoding.
    109   int key_size = sizeof(kEncodingString) - 1;
    110   for (size_t i = 0; i < input.size(); ++i) {
    111     output[i] = input[i] ^ kEncodingString[key_pos];
    112     ++key_pos;
    113     if (key_pos >= key_size)
    114       key_pos = 0;
    115   }
    116   return output;
    117 }
    118 
    119 std::string ProbeMessage::MakeEncodedPacket(
    120     const ProbePacket& probe_packet) const {
    121   std::string output;
    122   probe_packet.SerializeToString(&output);
    123   return Encode(output);
    124 }
    125 
    126 }  // namespace chrome_browser_net
    127