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}