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 PhantomSubnetsList phantom_subnets_list = 4;
87    optional PubKey conjure_pubkey = 5;
88}
89
90message DecoyList {
91    repeated TLSDecoySpec tls_decoys = 1;
92}
93
94message PhantomSubnetsList{
95    repeated PhantomSubnets weighted_subnets = 1;
96}
97
98message PhantomSubnets{
99    optional uint32 weight = 1;
100    repeated string subnets = 2;
101}
102
103// State transitions of the client
104enum C2S_Transition {
105    C2S_NO_CHANGE = 0;
106    C2S_SESSION_INIT = 1; // connect me to squid
107    C2S_SESSION_COVERT_INIT = 11; // connect me to provided covert
108    C2S_EXPECT_RECONNECT = 2;
109    C2S_SESSION_CLOSE = 3;
110    C2S_YIELD_UPLOAD = 4;
111    C2S_ACQUIRE_UPLOAD = 5;
112    C2S_EXPECT_UPLOADONLY_RECONN = 6;
113    C2S_ERROR = 255;
114}
115
116// State transitions of the server
117enum S2C_Transition {
118    S2C_NO_CHANGE = 0;
119    S2C_SESSION_INIT = 1; // connected to squid
120    S2C_SESSION_COVERT_INIT = 11; // connected to covert host
121    S2C_CONFIRM_RECONNECT = 2;
122    S2C_SESSION_CLOSE = 3;
123    // TODO should probably also allow EXPECT_RECONNECT here, for DittoTap
124    S2C_ERROR = 255;
125}
126
127// Should accompany all S2C_ERROR messages.
128enum ErrorReasonS2C {
129    NO_ERROR = 0;
130    COVERT_STREAM = 1; // Squid TCP connection broke
131    CLIENT_REPORTED = 2; // You told me something was wrong, client
132    CLIENT_PROTOCOL = 3; // You messed up, client (e.g. sent a bad protobuf)
133    STATION_INTERNAL = 4; // I broke
134    DECOY_OVERLOAD = 5; // Everything's fine, but don't use this decoy right now
135
136    CLIENT_STREAM = 100; // My stream to you broke. (This is impossible to send)
137    CLIENT_TIMEOUT = 101; // You never came back. (This is impossible to send)
138}
139
140enum TransportType {
141    Null = 0;
142    Min = 1;   // Send a 32-byte HMAC id to let the station distinguish registrations to same host
143    Obfs4 = 2; // Not implemented yet?
144}
145
146message StationToClient {
147    // Should accompany (at least) SESSION_INIT and CONFIRM_RECONNECT.
148    optional uint32 protocol_version = 1;
149
150    // There might be a state transition. May be absent; absence should be
151    // treated identically to NO_CHANGE.
152    optional S2C_Transition state_transition = 2;
153
154    // The station can send client config info piggybacked
155    // on any message, as it sees fit
156    optional ClientConf config_info = 3;
157
158    // If state_transition == S2C_ERROR, this field is the explanation.
159    optional ErrorReasonS2C err_reason = 4;
160
161    // Signals client to stop connecting for following amount of seconds
162    optional uint32 tmp_backoff = 5;
163
164    // Sent in SESSION_INIT, identifies the station that picked up
165    optional string station_id = 6;
166
167    // Random-sized junk to defeat packet size fingerprinting.
168    optional bytes padding = 100;
169}
170
171message RegistrationFlags {
172	optional bool upload_only = 1;
173	optional bool dark_decoy = 2;
174	optional bool proxy_header = 3;
175    optional bool use_TIL = 4;
176    optional bool prescanned = 5;
177}
178
179message ClientToStation {
180    optional uint32 protocol_version = 1;
181
182    // The client reports its decoy list's version number here, which the
183    // station can use to decide whether to send an updated one. The station
184    // should always send a list if this field is set to 0.
185    optional uint32 decoy_list_generation = 2;
186
187    optional C2S_Transition state_transition = 3;
188
189    // The position in the overall session's upload sequence where the current
190    // YIELD=>ACQUIRE switchover is happening.
191    optional uint64 upload_sync = 4;
192
193
194    // List of decoys that client have unsuccessfully tried in current session.
195    // Could be sent in chunks
196    repeated string failed_decoys = 10;
197
198    optional SessionStats stats = 11;
199
200    // NullTransport, MinTransport, Obfs4Transport, etc. Transport type we want from phantom proxy
201    optional TransportType transport = 12;
202
203    // Station is only required to check this variable during session initialization.
204    // If set, station must facilitate connection to said target by itself, i.e. write into squid
205    // socket an HTTP/SOCKS/any other connection request.
206    // covert_address must have exactly one ':' colon, that separates host (literal IP address or
207    // resolvable hostname) and port
208    // TODO: make it required for initialization, and stop connecting any client straight to squid?
209    optional string covert_address = 20;
210
211    // Used in dark decoys to signal which dark decoy it will connect to.
212    optional string masked_decoy_server_name = 21;
213
214    // Used to indicate to server if client is registering v4, v6 or both
215    optional bool v6_support = 22;
216    optional bool v4_support = 23;
217
218	// A collection of optional flags for the registration.
219	optional RegistrationFlags flags = 24;
220
221    // Random-sized junk to defeat packet size fingerprinting.
222    optional bytes padding = 100;
223}
224
225
226enum RegistrationSource {
227    Unspecified = 0;
228	Detector = 1;
229	API = 2;
230    DetectorPrescan = 3;
231}
232
233message C2SWrapper {
234	optional bytes shared_secret = 1;
235	optional ClientToStation registration_payload = 3;
236    optional RegistrationSource registration_source = 4;
237
238    // client source address when receiving a registration
239    optional bytes registration_address = 6;
240
241    // Decoy address used when registering over Decoy registrar
242    optional bytes decoy_address = 7;
243}
244
245message SessionStats {
246    optional uint32 failed_decoys_amount = 20; // how many decoys were tried before success
247
248    // Timings below are in milliseconds
249
250    // Applicable to whole session:
251    optional uint32 total_time_to_connect = 31; // includes failed attempts
252
253    // Last (i.e. successful) decoy:
254    optional uint32 rtt_to_station = 33; // measured during initial handshake
255    optional uint32 tls_to_decoy = 38; // includes tcp to decoy
256    optional uint32 tcp_to_decoy = 39; // measured when establishing tcp connection to decot
257}
258
259message StationToDetector {
260    optional string phantom_ip = 1;
261    optional string client_ip = 2;
262
263    optional uint64 timeout_ns = 3;
264}