OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 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 #ifndef NET_QUIC_CRYPTO_STRIKE_REGISTER_H_ | |
6 #define NET_QUIC_CRYPTO_STRIKE_REGISTER_H_ | |
7 | |
8 #include <set> | |
9 #include <utility> | |
10 #include <vector> | |
11 | |
12 #include "base/basictypes.h" | |
13 #include "base/memory/scoped_ptr.h" | |
14 #include "net/base/net_export.h" | |
15 | |
16 namespace net { | |
17 | |
18 // A StrikeRegister is critbit tree which stores a set of observed nonces. | |
19 // We use a critbit tree because: | |
20 // 1) It's immune to algorithmic complexity attacks. If we had used a hash | |
21 // tree, an attacker could send us a series of values which stretch out one | |
22 // of the hash chains, causing us to do much more work than normal. | |
23 // 2) We can write it to use a fixed block of memory: avoiding fragmentation | |
24 // issues and so forth. (We might be able to do that with the STL | |
25 // algorithms and a custom allocator, but I don't want to go there.) | |
26 // 3) It's simple (compared to balanced binary trees) and doesn't involve | |
27 // bouncing nearly as many cache lines around. | |
28 // 4) It allows us to query for the oldest element in log(n) time. | |
29 // | |
30 // This code is based on djb's public domain critbit tree from qhasm. | |
31 // | |
32 // A critbit tree has external and internal nodes. External nodes are just the | |
33 // nonce values (which are stored without the orbit values included). Internal | |
34 // nodes contain the bit number at which the tree is branching and exactly two | |
35 // children. The critical bit is stored as a byte number and a byte | |
36 // (|otherbits|) which has all the bits set /except/ the one in question. | |
37 // | |
38 // Internal nodes have exactly two children: an internal node with only a | |
39 // single child would be useless. | |
40 // | |
41 // The branching bit number (considering the MSB to be the 1st bit) is | |
42 // monotonically increasing as you go down the tree. | |
43 class NET_EXPORT_PRIVATE StrikeRegister { | |
44 public: | |
45 enum { | |
46 // An external node takes 24 bytes as we don't record the orbit. | |
47 kExternalNodeSize = 24, | |
48 // We address the nodes by their index in the array. This means that 0 is a | |
49 // valid index. Therefore this is our invalid index. It also has a one bit | |
50 // in the LSB position because we tend to store indexes shifted up 8 bits | |
51 // and this distinguishes kNil from (kExternalFlag | 0) << 8. | |
52 kNil = (1 << 31) | 1, | |
jar (doing other things)
2013/04/06 02:26:37
nit: to avoid casting to int in cc files, better w
ramant (doing other things)
2013/04/06 04:20:10
Done.
| |
53 // Our pointers from internal nodes can either point to an internal or | |
54 // external node. We flag the 24th bit to mark a pointer as external. | |
55 kExternalFlag = 1 << 23, | |
56 }; | |
57 | |
58 // Construct a new set which can hold, at most, |max_entries| (which must be | |
59 // less than 2**23). Once constructed, all nonces created before | |
60 // |current_time| (in seconds) will be rejected. In the future, all nonces | |
61 // that are outside +/- |window_secs| from the current time will be rejected. | |
62 // Additionally, all nonces that have an orbit value other than |orbit| will | |
63 // be rejected. | |
64 // | |
65 // (Note that this code is independent of the actual units of time used, but | |
66 // you should use seconds.) | |
67 StrikeRegister(unsigned max_entries, | |
68 uint32 current_time, | |
69 uint32 window_secs, | |
70 const uint8 orbit[8]); | |
71 | |
72 ~StrikeRegister(); | |
73 | |
74 void Reset(); | |
75 | |
76 // |Insert| queries to see if |nonce| is | |
77 // a) for the wrong orbit | |
78 // b) before the current horizon | |
79 // c) outside of the valid time window | |
80 // d) already in the set of observed nonces | |
81 // and returns false if any of these are true. It is also free to return | |
82 // false for other reasons as it's always safe to reject an nonce. | |
83 // | |
84 // nonces are: | |
85 // 4 bytes of timestamp (UNIX epoch seconds) | |
86 // 8 bytes of orbit value (a cluster id) | |
87 // 20 bytes of random data | |
88 // | |
89 // Otherwise, it inserts |nonce| into the observed set and returns true. | |
90 bool Insert(const uint8 nonce[32], const uint32 current_time); | |
91 | |
92 // This is a debugging aid which checks the tree for sanity. | |
93 void Validate(); | |
94 | |
95 private: | |
96 class InternalNode; | |
97 | |
98 // TimeFromBytes returns a big-endian uint32 from |d|. | |
99 static uint32 TimeFromBytes(const uint8 d[4]); | |
100 | |
101 // BestMatch returns either kNil, or an external node index which could | |
102 // possibly match |v|. | |
103 uint32 BestMatch(const uint8 v[24]) const; | |
104 | |
105 // external_node_next_ptr returns the 'next' pointer embedded in external | |
106 // node |i|. This is used to thread a free list through the external nodes. | |
107 uint32& external_node_next_ptr(unsigned i); | |
108 | |
109 uint8* external_node(unsigned i); | |
110 | |
111 uint32 GetFreeExternalNode(); | |
112 | |
113 uint32 GetFreeInternalNode(); | |
114 | |
115 // DropNode removes the oldest node in the tree and updates |horizon_| | |
116 // accordingly. | |
117 void DropNode(); | |
118 | |
119 void FreeExternalNode(uint32 index); | |
120 | |
121 void FreeInternalNode(uint32 index); | |
122 | |
123 void ValidateTree(uint32 internal_node, | |
124 int last_bit, | |
125 const std::vector<std::pair<unsigned, bool> >& bits, | |
126 const std::set<uint32>& free_internal_nodes, | |
127 const std::set<uint32>& free_external_nodes, | |
128 std::set<uint32>* used_internal_nodes, | |
129 std::set<uint32>* used_external_nodes); | |
130 | |
131 const unsigned max_entries_; | |
jar (doing other things)
2013/04/06 02:26:37
nit: more consistent would be uint32 here.
ramant (doing other things)
2013/04/06 04:20:10
Done.
| |
132 const unsigned window_secs_; | |
133 uint8 orbit_[8]; | |
134 uint32 horizon_; | |
135 | |
136 uint32 internal_node_free_head_; | |
137 uint32 external_node_free_head_; | |
138 uint32 internal_node_head_; | |
139 // internal_nodes_ can't be a scoped_ptr because the type isn't defined in | |
140 // this header. | |
141 InternalNode* internal_nodes_; | |
142 scoped_ptr<uint8[]> external_nodes_; | |
143 }; | |
144 | |
145 } // namespace net | |
146 | |
147 #endif // NET_QUIC_CRYPTO_STRIKE_REGISTER_H_ | |
OLD | NEW |