1558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// Copyright 2013 The Chromium Authors. All rights reserved.
2558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// Use of this source code is governed by a BSD-style license that can be
3558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// found in the LICENSE file.
4558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
5558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch#include "chrome/browser/net/probe_message.h"
6558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
7558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch#include <string>
8558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
9558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch#include "base/logging.h"
10558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
11558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochnamespace chrome_browser_net {
12558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
13558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochconst uint32 ProbeMessage::kVersion = 2;
14558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochconst uint32 ProbeMessage::kMaxNumberProbePackets = 21;
15558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochconst uint32 ProbeMessage::kMaxProbePacketBytes = 1500;
16f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Maximum pacing interval is 300 seconds (for testing NAT binding).
17558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochconst uint32 ProbeMessage::kMaxPacingIntervalMicros = 300000000;
18558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochconst char ProbeMessage::kEncodingString[] =
19558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    "T\xd3?\xa5h2\x9c\x8en\xf1Q6\xbc{\xc6-4\xfa$f\xb9[\xa6\xcd@6,\xdf\xb3i-\xe6"
20558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    "v\x9eV\x8dXd\xd9kE\xf6=\xbeO";
21558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
22558790d6acca3451cf3a6b497803a5f07d0bec58Ben MurdochProbeMessage::ProbeMessage() {}
23558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
24558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochbool ProbeMessage::ParseInput(const std::string& input,
25558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                              ProbePacket* probe_packet) const {
26558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  // Encode is used for decoding here.
27558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  std::string input_decoded = Encode(input);
28558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
29558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  bool parse_result = probe_packet->ParseFromString(input_decoded);
30558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  if (!parse_result) {
31558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    DVLOG(1) << "ProtoBuffer string parsing error. Input size:" << input.size();
32558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    return false;
33558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  }
34558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  const ProbePacket_Header& header = probe_packet->header();
35558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  DVLOG(2) << "version " << header.version() << " checksum "
36558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch           << header.checksum() << " type " << header.type();
37558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  if (header.version() != kVersion) {
38558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    DVLOG(1) << "Bad version number: " << header.version()
39558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch             << " expected: " << kVersion;
40558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    return false;
41558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  }
42558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
43558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  // Checksum is computed on padding only.
44558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  if (probe_packet->has_padding()) {
45558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    DVLOG(3) << "received padding: " << probe_packet->padding();
46558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    uint32 computed_checksum = Checksum(probe_packet->padding());
47558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    if (computed_checksum != header.checksum()) {
48558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      DVLOG(1) << "Checksum mismatch.  Got: " << header.checksum()
49558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch               << " expected: " << computed_checksum;
50558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      return false;
51558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    }
52558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  }
53558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
54558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  if (header.type() != ProbePacket_Type_HELLO_REPLY &&
55558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      header.type() != ProbePacket_Type_PROBE_REPLY) {
56558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    DVLOG(1) << "Received unknown packet type:" << header.type();
57558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    return false;
58558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  }
59558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  return true;
60558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}
61558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
62558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochuint32 ProbeMessage::Checksum(const std::string& str) const {
63558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  uint32 ret = 0;
64558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  for (std::string::const_iterator i = str.begin(); i != str.end(); ++i) {
65558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    ret += static_cast<uint8>(*i);
66558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  }
67558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  return ret;
68558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}
69558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
70558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochvoid ProbeMessage::GenerateProbeRequest(const ProbePacket_Token& token,
71558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                                        uint32 group_id,
72558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                                        uint32 probe_size,
73558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                                        uint32 pacing_interval_micros,
74558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                                        uint32 number_probe_packets,
75558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                                        ProbePacket* probe_packet) {
76558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  DCHECK_LE(number_probe_packets, kMaxNumberProbePackets);
77558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  DCHECK_LE(probe_size, kMaxProbePacketBytes);
78558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  DCHECK_LE(pacing_interval_micros, kMaxPacingIntervalMicros);
79558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
80558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  SetPacketHeader(ProbePacket_Type_PROBE_REQUEST, probe_packet);
81558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  *(probe_packet->mutable_token()) = token;
82558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  probe_packet->set_group_id(group_id);
83558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  probe_packet->set_probe_size_bytes(probe_size);
84558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  probe_packet->set_pacing_interval_micros(pacing_interval_micros);
85558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  probe_packet->set_number_probe_packets(number_probe_packets);
86558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
87558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  // Add padding to mitigate amplification attack.
88558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  std::string* padding = probe_packet->mutable_padding();
89558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  int padding_size = probe_size - probe_packet->ByteSize();
90558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  padding->append(std::string(std::max(0, padding_size), 0));
91558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  probe_packet->mutable_header()->set_checksum(Checksum(*padding));
92558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  DVLOG(3) << "Request size " << probe_packet->ByteSize() << " probe size "
93558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch           << probe_size;
94558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  DCHECK_LE(probe_size, static_cast<uint32>(probe_packet->ByteSize()));
95558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}
96558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
97558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochvoid ProbeMessage::SetPacketHeader(ProbePacket_Type packet_type,
98558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                                   ProbePacket* probe_packet) const {
99558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  ProbePacket_Header* header = probe_packet->mutable_header();
100558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  header->set_version(kVersion);
101558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  header->set_type(packet_type);
102558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}
103558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
104558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochstd::string ProbeMessage::Encode(const std::string& input) const {
105558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
106558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  std::string output(input.size(), 0);
107558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  int key_pos = 0;
108558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  // kEncodingString contains a ending '\0' character, excluded for encoding.
109558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  int key_size = sizeof(kEncodingString) - 1;
110558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  for (size_t i = 0; i < input.size(); ++i) {
111558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    output[i] = input[i] ^ kEncodingString[key_pos];
112558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    ++key_pos;
113558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    if (key_pos >= key_size)
114558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      key_pos = 0;
115558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  }
116558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  return output;
117558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}
118558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
119558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochstd::string ProbeMessage::MakeEncodedPacket(
120558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    const ProbePacket& probe_packet) const {
121558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  std::string output;
122558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  probe_packet.SerializeToString(&output);
123558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  return Encode(output);
124558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}
125558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
126558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}  // namespace chrome_browser_net
127