Line data Source code
1 : //* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : #ifndef ProtocolParser_h__
7 : #define ProtocolParser_h__
8 :
9 : #include "HashStore.h"
10 : #include "nsICryptoHMAC.h"
11 : #include "safebrowsing.pb.h"
12 :
13 : namespace mozilla {
14 : namespace safebrowsing {
15 :
16 : /**
17 : * Abstract base class for parsing update data in multiple formats.
18 : */
19 : class ProtocolParser {
20 : public:
21 0 : struct ForwardedUpdate {
22 : nsCString table;
23 : nsCString url;
24 : };
25 :
26 : ProtocolParser();
27 : virtual ~ProtocolParser();
28 :
29 2 : nsresult Status() const { return mUpdateStatus; }
30 :
31 : nsresult Init(nsICryptoHash* aHasher);
32 :
33 : #ifdef MOZ_SAFEBROWSING_DUMP_FAILED_UPDATES
34 0 : virtual nsCString GetRawTableUpdates() const { return mPending; }
35 : #endif
36 :
37 : virtual void SetCurrentTable(const nsACString& aTable) = 0;
38 :
39 1 : void SetRequestedTables(const nsTArray<nsCString>& aRequestTables)
40 : {
41 1 : mRequestedTables = aRequestTables;
42 1 : }
43 :
44 : nsresult Begin();
45 : virtual nsresult AppendStream(const nsACString& aData) = 0;
46 :
47 2 : uint32_t UpdateWaitSec() { return mUpdateWaitSec; }
48 :
49 : // Notify that the inbound data is ready for parsing if progressive
50 : // parsing is not supported, for example in V4.
51 : virtual void End() = 0;
52 :
53 : // Forget the table updates that were created by this pass. It
54 : // becomes the caller's responsibility to free them. This is shitty.
55 : TableUpdate *GetTableUpdate(const nsACString& aTable);
56 1 : void ForgetTableUpdates() { mTableUpdates.Clear(); }
57 1 : nsTArray<TableUpdate*> &GetTableUpdates() { return mTableUpdates; }
58 :
59 : // These are only meaningful to V2. Since they were originally public,
60 : // moving them to ProtocolParserV2 requires a dymamic cast in the call
61 : // sites. As a result, we will leave them until we remove support
62 : // for V2 entirely..
63 0 : virtual const nsTArray<ForwardedUpdate> &Forwards() const { return mForwards; }
64 0 : virtual bool ResetRequested() { return false; }
65 :
66 : protected:
67 : virtual TableUpdate* CreateTableUpdate(const nsACString& aTableName) const = 0;
68 :
69 : nsCString mPending;
70 : nsresult mUpdateStatus;
71 :
72 : // Keep track of updates to apply before passing them to the DBServiceWorkers.
73 : nsTArray<TableUpdate*> mTableUpdates;
74 :
75 : nsTArray<ForwardedUpdate> mForwards;
76 : nsCOMPtr<nsICryptoHash> mCryptoHash;
77 :
78 : // The table names that were requested from the client.
79 : nsTArray<nsCString> mRequestedTables;
80 :
81 : // How long we should wait until the next update.
82 : uint32_t mUpdateWaitSec;
83 :
84 : private:
85 : void CleanupUpdates();
86 : };
87 :
88 : /**
89 : * Helpers to parse the "shavar", "digest256" and "simple" list formats.
90 : */
91 : class ProtocolParserV2 final : public ProtocolParser {
92 : public:
93 : ProtocolParserV2();
94 : virtual ~ProtocolParserV2();
95 :
96 : virtual void SetCurrentTable(const nsACString& aTable) override;
97 : virtual nsresult AppendStream(const nsACString& aData) override;
98 : virtual void End() override;
99 :
100 : // Update information.
101 1 : virtual const nsTArray<ForwardedUpdate> &Forwards() const override { return mForwards; }
102 1 : virtual bool ResetRequested() override { return mResetRequested; }
103 :
104 : #ifdef MOZ_SAFEBROWSING_DUMP_FAILED_UPDATES
105 : // Unfortunately we have to override to return mRawUpdate which
106 : // will not be modified during the parsing, unlike mPending.
107 1 : virtual nsCString GetRawTableUpdates() const override { return mRawUpdate; }
108 : #endif
109 :
110 : private:
111 : virtual TableUpdate* CreateTableUpdate(const nsACString& aTableName) const override;
112 :
113 : nsresult ProcessControl(bool* aDone);
114 : nsresult ProcessExpirations(const nsCString& aLine);
115 : nsresult ProcessChunkControl(const nsCString& aLine);
116 : nsresult ProcessForward(const nsCString& aLine);
117 : nsresult AddForward(const nsACString& aUrl);
118 : nsresult ProcessChunk(bool* done);
119 : // Remove this, it's only used for testing
120 : nsresult ProcessPlaintextChunk(const nsACString& aChunk);
121 : nsresult ProcessShaChunk(const nsACString& aChunk);
122 : nsresult ProcessHostAdd(const Prefix& aDomain, uint8_t aNumEntries,
123 : const nsACString& aChunk, uint32_t* aStart);
124 : nsresult ProcessHostSub(const Prefix& aDomain, uint8_t aNumEntries,
125 : const nsACString& aChunk, uint32_t* aStart);
126 : nsresult ProcessHostAddComplete(uint8_t aNumEntries, const nsACString& aChunk,
127 : uint32_t *aStart);
128 : nsresult ProcessHostSubComplete(uint8_t numEntries, const nsACString& aChunk,
129 : uint32_t* start);
130 : // Digest chunks are very similar to shavar chunks, except digest chunks
131 : // always contain the full hash, so there is no need for chunk data to
132 : // contain prefix sizes.
133 : nsresult ProcessDigestChunk(const nsACString& aChunk);
134 : nsresult ProcessDigestAdd(const nsACString& aChunk);
135 : nsresult ProcessDigestSub(const nsACString& aChunk);
136 : bool NextLine(nsACString& aLine);
137 :
138 : enum ParserState {
139 : PROTOCOL_STATE_CONTROL,
140 : PROTOCOL_STATE_CHUNK
141 : };
142 : ParserState mState;
143 :
144 : enum ChunkType {
145 : // Types for shavar tables.
146 : CHUNK_ADD,
147 : CHUNK_SUB,
148 : // Types for digest256 tables. digest256 tables differ in format from
149 : // shavar tables since they only contain complete hashes.
150 : CHUNK_ADD_DIGEST,
151 : CHUNK_SUB_DIGEST
152 : };
153 :
154 : struct ChunkState {
155 : ChunkType type;
156 : uint32_t num;
157 : uint32_t hashSize;
158 : uint32_t length;
159 7 : void Clear() { num = 0; hashSize = 0; length = 0; }
160 : };
161 : ChunkState mChunkState;
162 :
163 : bool mResetRequested;
164 :
165 : // Updates to apply to the current table being parsed.
166 : TableUpdateV2 *mTableUpdate;
167 :
168 : #ifdef MOZ_SAFEBROWSING_DUMP_FAILED_UPDATES
169 : nsCString mRawUpdate; // Keep a copy of mPending before it's processed.
170 : #endif
171 : };
172 :
173 : // Helpers to parse the "proto" list format.
174 : class ProtocolParserProtobuf final : public ProtocolParser {
175 : public:
176 : typedef FetchThreatListUpdatesResponse_ListUpdateResponse ListUpdateResponse;
177 : typedef google::protobuf::RepeatedPtrField<ThreatEntrySet> ThreatEntrySetList;
178 :
179 : public:
180 : ProtocolParserProtobuf();
181 :
182 : virtual void SetCurrentTable(const nsACString& aTable) override;
183 : virtual nsresult AppendStream(const nsACString& aData) override;
184 : virtual void End() override;
185 :
186 : private:
187 : virtual ~ProtocolParserProtobuf();
188 :
189 : virtual TableUpdate* CreateTableUpdate(const nsACString& aTableName) const override;
190 :
191 : // For parsing update info.
192 : nsresult ProcessOneResponse(const ListUpdateResponse& aResponse);
193 :
194 : nsresult ProcessAdditionOrRemoval(TableUpdateV4& aTableUpdate,
195 : const ThreatEntrySetList& aUpdate,
196 : bool aIsAddition);
197 :
198 : nsresult ProcessRawAddition(TableUpdateV4& aTableUpdate,
199 : const ThreatEntrySet& aAddition);
200 :
201 : nsresult ProcessRawRemoval(TableUpdateV4& aTableUpdate,
202 : const ThreatEntrySet& aRemoval);
203 :
204 : nsresult ProcessEncodedAddition(TableUpdateV4& aTableUpdate,
205 : const ThreatEntrySet& aAddition);
206 :
207 : nsresult ProcessEncodedRemoval(TableUpdateV4& aTableUpdate,
208 : const ThreatEntrySet& aRemoval);
209 : };
210 :
211 : } // namespace safebrowsing
212 : } // namespace mozilla
213 :
214 : #endif
|