1syntax = "proto2";
2
3// TODO: We're using proto2 because it's the default on Ubuntu 16.04.
4// At some point we will want to migrate to proto3, but we are not
5// using any proto3 features yet.
6
7package tapdance;
8
9enum KeyType {
10    AES_GCM_128 = 90;
11    AES_GCM_256 = 91; // not supported atm
12}
13
14message PubKey {
15    // A public key, as used by the station.
16    optional bytes key = 1;
17
18    optional KeyType type = 2;
19}
20
21message TLSDecoySpec {
22    // The hostname/SNI to use for this host
23    //
24    // The hostname is the only required field, although other
25    // fields are expected to be present in most cases.
26    optional string hostname = 1;
27
28    // The 32-bit ipv4 address, in network byte order
29    //
30    // If the IPv4 address is absent, then it may be resolved via
31    // DNS by the client, or the client may discard this decoy spec
32    // if local DNS is untrusted, or the service may be multihomed.
33    optional fixed32 ipv4addr = 2;
34
35    // The 128-bit ipv6 address, in network byte order
36    optional bytes ipv6addr = 6;
37
38    // The Tapdance station public key to use when contacting this
39    // decoy
40    //
41    // If omitted, the default station public key (if any) is used.
42    optional PubKey pubkey = 3;
43
44    // The maximum duration, in milliseconds, to maintain an open
45    // connection to this decoy (because the decoy may close the
46    // connection itself after this length of time)
47    //
48    // If omitted, a default of 30,000 milliseconds is assumed.
49    optional uint32 timeout = 4;
50
51    // The maximum TCP window size to attempt to use for this decoy.
52    //
53    // If omitted, a default of 15360 is assumed.
54    //
55    // TODO: the default is based on the current heuristic of only
56    // using decoys that permit windows of 15KB or larger.  If this
57    // heuristic changes, then this default doesn't make sense.
58    optional uint32 tcpwin = 5;
59}
60
61// In version 1, the request is very simple: when
62// the client sends a MSG_PROTO to the station, if the
63// generation number is present, then this request includes
64// (in addition to whatever other operations are part of the
65// request) a request for the station to send a copy of
66// the current decoy set that has a generation number greater
67// than the generation number in its request.
68//
69// If the response contains a DecoyListUpdate with a generation number equal
70// to that which the client sent, then the client is "caught up" with
71// the station and the response contains no new information
72// (and all other fields may be omitted or empty).  Otherwise,
73// the station will send the latest configuration information,
74// along with its generation number.
75//
76// The station can also send ClientConf messages
77// (as part of Station2Client messages) whenever it wants.
78// The client is expected to react as if it had requested
79// such messages -- possibly by ignoring them, if the client
80// is already up-to-date according to the generation number.
81
82message ClientConf {
83    optional DecoyList decoy_list = 1;
84    optional uint32 generation = 2;
85    optional PubKey default_pubkey = 3;
86    optional DarkDecoyBlocks dark_decoy_blocks = 4;
87    optional PubKey conjure_pubkey = 5;
88}
89
90message DecoyList {
91    repeated TLSDecoySpec tls_decoys = 1;
92}
93
94message DarkDecoyBlocks{
95    repeated string blocks = 1;
96}
97
98// State transitions of the client
99enum C2S_Transition {
100    C2S_NO_CHANGE = 0;
101    C2S_SESSION_INIT = 1; // connect me to squid
102    C2S_SESSION_COVERT_INIT = 11; // connect me to provided covert
103    C2S_EXPECT_RECONNECT = 2;
104    C2S_SESSION_CLOSE = 3;
105    C2S_YIELD_UPLOAD = 4;
106    C2S_ACQUIRE_UPLOAD = 5;
107    C2S_EXPECT_UPLOADONLY_RECONN = 6;
108    C2S_ERROR = 255;
109}
110
111// State transitions of the server
112enum S2C_Transition {
113    S2C_NO_CHANGE = 0;
114    S2C_SESSION_INIT = 1; // connected to squid
115    S2C_SESSION_COVERT_INIT = 11; // connected to covert host
116    S2C_CONFIRM_RECONNECT = 2;
117    S2C_SESSION_CLOSE = 3;
118    // TODO should probably also allow EXPECT_RECONNECT here, for DittoTap
119    S2C_ERROR = 255;
120}
121
122// Should accompany all S2C_ERROR messages.
123enum ErrorReasonS2C {
124    NO_ERROR = 0;
125    COVERT_STREAM = 1; // Squid TCP connection broke
126    CLIENT_REPORTED = 2; // You told me something was wrong, client
127    CLIENT_PROTOCOL = 3; // You messed up, client (e.g. sent a bad protobuf)
128    STATION_INTERNAL = 4; // I broke
129    DECOY_OVERLOAD = 5; // Everything's fine, but don't use this decoy right now
130
131    CLIENT_STREAM = 100; // My stream to you broke. (This is impossible to send)
132    CLIENT_TIMEOUT = 101; // You never came back. (This is impossible to send)
133}
134
135enum TransportType {
136    Null = 0;
137    Min = 1;   // Send a 32-byte HMAC id to let the station distinguish registrations to same host
138    Obfs4 = 2; // Not implemented yet?
139}
140
141message StationToClient {
142    // Should accompany (at least) SESSION_INIT and CONFIRM_RECONNECT.
143    optional uint32 protocol_version = 1;
144
145    // There might be a state transition. May be absent; absence should be
146    // treated identically to NO_CHANGE.
147    optional S2C_Transition state_transition = 2;
148
149    // The station can send client config info piggybacked
150    // on any message, as it sees fit
151    optional ClientConf config_info = 3;
152
153    // If state_transition == S2C_ERROR, this field is the explanation.
154    optional ErrorReasonS2C err_reason = 4;
155
156    // Signals client to stop connecting for following amount of seconds
157    optional uint32 tmp_backoff = 5;
158
159    // Sent in SESSION_INIT, identifies the station that picked up
160    optional string station_id = 6;
161
162    // Random-sized junk to defeat packet size fingerprinting.
163    optional bytes padding = 100;
164}
165
166message RegistrationFlags {
167	optional bool upload_only = 1;
168	optional bool dark_decoy = 2;
169	optional bool proxy_header = 3;
170    optional bool use_TIL = 4;
171    optional bool prescanned = 5;
172}
173
174message ClientToStation {
175    optional uint32 protocol_version = 1;
176
177    // The client reports its decoy list's version number here, which the
178    // station can use to decide whether to send an updated one. The station
179    // should always send a list if this field is set to 0.
180    optional uint32 decoy_list_generation = 2;
181
182    optional C2S_Transition state_transition = 3;
183
184    // The position in the overall session's upload sequence where the current
185    // YIELD=>ACQUIRE switchover is happening.
186    optional uint64 upload_sync = 4;
187
188
189    // List of decoys that client have unsuccessfully tried in current session.
190    // Could be sent in chunks
191    repeated string failed_decoys = 10;
192
193    optional SessionStats stats = 11;
194
195    // NullTransport, MinTransport, Obfs4Transport, etc. Transport type we want from phantom proxy
196    optional TransportType transport = 12;
197
198    // Station is only required to check this variable during session initialization.
199    // If set, station must facilitate connection to said target by itself, i.e. write into squid
200    // socket an HTTP/SOCKS/any other connection request.
201    // covert_address must have exactly one ':' colon, that separates host (literal IP address or
202    // resolvable hostname) and port
203    // TODO: make it required for initialization, and stop connecting any client straight to squid?
204    optional string covert_address = 20;
205
206    // Used in dark decoys to signal which dark decoy it will connect to.
207    optional string masked_decoy_server_name = 21;
208
209    // Used to indicate to server if client is registering v4, v6 or both
210    optional bool v6_support = 22;
211    optional bool v4_support = 23;
212
213	// A collection of optional flags for the registration.
214	optional RegistrationFlags flags = 24;
215
216    // Random-sized junk to defeat packet size fingerprinting.
217    optional bytes padding = 100;
218}
219
220
221enum RegistrationSource {
222    Unspecified = 0;
223	Detector = 1;
224	API = 2;
225    DetectorPrescan = 3;
226}
227
228message C2SWrapper {
229	optional bytes shared_secret = 1;
230	optional ClientToStation registration_payload = 3;
231    optional RegistrationSource registration_source = 4;
232
233    // client source address when receiving a registration
234    optional bytes registration_address = 6;
235
236    // Decoy address used when registering over Decoy registrar
237    optional bytes decoy_address = 7;
238}
239
240message SessionStats {
241    optional uint32 failed_decoys_amount = 20; // how many decoys were tried before success
242
243    // Timings below are in milliseconds
244
245    // Applicable to whole session:
246    optional uint32 total_time_to_connect = 31; // includes failed attempts
247
248    // Last (i.e. successful) decoy:
249    optional uint32 rtt_to_station = 33; // measured during initial handshake
250    optional uint32 tls_to_decoy = 38; // includes tcp to decoy
251    optional uint32 tcp_to_decoy = 39; // measured when establishing tcp connection to decot
252}
253
254