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