@@ -257,6 +257,8 @@ handshake_fiber (gpointer user_data)
257257 if (is_incoming )
258258 {
259259 g_autoptr (JsonNode ) peer_identity = NULL ;
260+ const char * target_device_id = NULL ;
261+ int64_t target_protocol_version = 0 ;
260262
261263 peer_identity = dex_await_boxed (valent_packet_from_stream_future (g_io_stream_get_input_stream (data -> connection ),
262264 IDENTITY_BUFFER_MAX ,
@@ -265,21 +267,72 @@ handshake_fiber (gpointer user_data)
265267 if (peer_identity == NULL )
266268 goto fail ;
267269
270+ /* When accepting a TCP connection, the identity packet may indicate its
271+ * intended target, allowing the local device to mitigate amplification
272+ * attacks from a spoofed UDP address.
273+ */
274+ if (valent_packet_get_string (peer_identity , "targetDeviceId" , & target_device_id ))
275+ {
276+ g_autofree char * local_id = valent_channel_service_dup_id (service );
277+
278+ if (g_strcmp0 (target_device_id , local_id ) != 0 )
279+ {
280+ g_set_error (& error ,
281+ G_IO_ERROR ,
282+ G_IO_ERROR_FAILED ,
283+ "expected \"targetDeviceId\" field holding \"%s\"" ,
284+ local_id );
285+ goto fail ;
286+ }
287+ }
288+
289+ if (valent_packet_get_int (peer_identity , "targetProtocolVersion" , & target_protocol_version ) &&
290+ target_protocol_version != VALENT_NETWORK_PROTOCOL_MAX )
291+ {
292+ g_set_error (& error ,
293+ G_IO_ERROR ,
294+ G_IO_ERROR_FAILED ,
295+ "expected \"targetProtocolVersion\" field holding \"%u\"" ,
296+ VALENT_NETWORK_PROTOCOL_MAX );
297+ goto fail ;
298+ }
299+
268300 data -> peer_identity = g_steal_pointer (& peer_identity );
269301 }
270302 else
271303 {
304+ JsonObject * body ;
305+ gboolean success ;
306+ const char * target_device_id = NULL ;
307+ int64_t target_protocol_version = 0 ;
308+
272309 data -> connection = dex_await_object (_dex_socket_client_connect_to_host (data -> host ,
273310 data -> port ,
274311 cancellable ),
275312 & error );
276313 if (data -> connection == NULL )
277314 goto fail ;
278315
279- if (!dex_await (valent_packet_to_stream_future (g_io_stream_get_output_stream (data -> connection ),
280- identity ,
281- cancellable ),
282- & error ))
316+ /* When responding to a UDP broadcast, mark the identity packet for its
317+ * intended target, allowing the remote device to abort if the broadcast
318+ * address was spoofed.
319+ */
320+ valent_packet_get_string (data -> peer_identity , "deviceId" , & target_device_id );
321+ valent_packet_get_int (data -> peer_identity , "protocolVersion" , & target_protocol_version );
322+
323+ body = valent_packet_get_body (identity );
324+ json_object_set_string_member (body , "targetDeviceId" , target_device_id );
325+ json_object_set_int_member (body , "targetProtocolVersion" , target_protocol_version );
326+
327+ success = dex_await (valent_packet_to_stream_future (g_io_stream_get_output_stream (data -> connection ),
328+ identity ,
329+ cancellable ),
330+ & error );
331+ // TODO: operate on a deep-copy instead?
332+ json_object_remove_member (body , "targetDeviceId" );
333+ json_object_remove_member (body , "targetProtocolVersion" );
334+
335+ if (!success )
283336 goto fail ;
284337 }
285338
0 commit comments