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