18
18
19
19
#include "construct_unix.h"
20
20
21
+ #include "utils.h"
22
+
21
23
#include <errno.h>
22
24
#include <stdio.h>
23
25
#include <string.h>
32
34
#define SOL_IP IPPROTO_IP
33
35
#endif
34
36
37
+ #ifdef HAVE_LIBCAP
38
+ #include <sys/capability.h>
39
+ #endif
40
+
35
41
/* A source of data for computing a checksum */
36
42
struct checksum_source_t {
37
43
const void * data ;
@@ -278,6 +284,102 @@ int construct_udp6_packet(
278
284
return 0 ;
279
285
}
280
286
287
+ /*
288
+ This defines a common interface which elevates privileges on
289
+ platforms with LIBCAP and acts as a NOOP on platforms without
290
+ it.
291
+ */
292
+ #ifdef HAVE_LIBCAP
293
+
294
+ typedef cap_value_t mayadd_cap_value_t ;
295
+ #define MAYADD_CAP_NET_RAW CAP_NET_RAW
296
+ #define MAYADD_CAP_NET_ADMIN CAP_NET_ADMIN
297
+
298
+ #else /* ifdef HAVE_LIBCAP */
299
+
300
+ typedef int mayadd_cap_value_t ;
301
+ #define MAYADD_CAP_NET_RAW ((mayadd_cap_value_t) 0)
302
+ #define MAYADD_CAP_NET_ADMIN ((mayadd_cap_value_t) 0)
303
+
304
+ #endif /* ifdef HAVE_LIBCAP */
305
+
306
+ UNUSED static
307
+ int set_privileged_socket_opt (int socket , int option_name ,
308
+ void const * option_value , socklen_t option_len ,
309
+ UNUSED mayadd_cap_value_t required_cap ) {
310
+
311
+ int result = -1 ;
312
+
313
+ // Add CAP_NET_ADMIN to the effective set if libcap is present
314
+ #ifdef HAVE_LIBCAP
315
+ static cap_value_t cap_add [1 ];
316
+ cap_add [0 ] = required_cap ;
317
+
318
+ // Get the capabilities of the current process
319
+ cap_t cap = cap_get_proc ();
320
+ if (cap == NULL ) {
321
+ goto cleanup_and_exit ;
322
+ }
323
+
324
+ // Set the required capability flag
325
+ if (cap_set_flag (cap , CAP_EFFECTIVE , N_ENTRIES (cap_add ), cap_add ,
326
+ CAP_SET )) {
327
+ goto cleanup_and_exit ;
328
+ }
329
+
330
+ // Apply the modified capabilities to the current process
331
+ if (cap_set_proc (cap )) {
332
+ goto cleanup_and_exit ;
333
+ }
334
+ #endif /* ifdef HAVE_LIBCAP */
335
+
336
+ // Set the socket mark
337
+ int set_sock_err = setsockopt (socket , SOL_SOCKET , option_name , option_value , option_len );
338
+
339
+ // Drop CAP_NET_ADMIN from the effective set if libcap is present
340
+ #ifdef HAVE_LIBCAP
341
+
342
+ // Clear the CAP_NET_ADMIN capability flag
343
+ if (cap_set_flag (cap , CAP_EFFECTIVE , N_ENTRIES (cap_add ), cap_add ,
344
+ CAP_CLEAR )) {
345
+ goto cleanup_and_exit ;
346
+ }
347
+
348
+ // Apply the modified capabilities to the current process
349
+ if (cap_set_proc (cap )) {
350
+ goto cleanup_and_exit ;
351
+ }
352
+ #endif /* ifdef HAVE_LIBCAP */
353
+
354
+ if (!set_sock_err ) {
355
+ result = 0 ; // Success
356
+ }
357
+
358
+ #ifdef HAVE_LIBCAP
359
+ cleanup_and_exit :
360
+ cap_free (cap );
361
+ #endif /* ifdef HAVE_LIBCAP */
362
+
363
+ return result ;
364
+ }
365
+
366
+ /* Set the socket mark */
367
+ #ifdef SO_MARK
368
+ static
369
+ int set_socket_mark (int socket , unsigned int mark ) {
370
+ return set_privileged_socket_opt (socket , SO_MARK , & mark , sizeof (mark ),
371
+ MAYADD_CAP_NET_ADMIN );
372
+ }
373
+ #endif /* ifdef SO_MARK */
374
+
375
+ #ifdef SO_BINDTODEVICE
376
+ static
377
+ int set_bind_to_device (int socket , char const * device ) {
378
+ return set_privileged_socket_opt (socket , SO_BINDTODEVICE , device ,
379
+ strlen (device ), MAYADD_CAP_NET_RAW );
380
+ }
381
+ #endif /* ifdef SO_BINDTODEVICE */
382
+
281
383
/*
282
384
Set the socket options for an outgoing stream protocol socket based on
283
385
the packet parameters.
@@ -341,17 +443,15 @@ int set_stream_socket_options(
341
443
}
342
444
#ifdef SO_MARK
343
445
if (param -> routing_mark ) {
344
- if (setsockopt (stream_socket , SOL_SOCKET ,
345
- SO_MARK , & param -> routing_mark , sizeof (int ))) {
446
+ if (set_socket_mark (stream_socket , param -> routing_mark )) {
346
447
return -1 ;
347
448
}
348
449
}
349
450
#endif
350
451
351
452
#ifdef SO_BINDTODEVICE
352
453
if (param -> local_device ) {
353
- if (setsockopt (stream_socket , SOL_SOCKET ,
354
- SO_BINDTODEVICE , param -> local_device , strlen (param -> local_device ))) {
454
+ if (set_bind_to_device (stream_socket , param -> local_device )) {
355
455
return -1 ;
356
456
}
357
457
}
@@ -360,6 +460,7 @@ int set_stream_socket_options(
360
460
return 0 ;
361
461
}
362
462
463
+
363
464
/*
364
465
Open a TCP or SCTP socket, respecting the probe paramters as much as
365
466
we can, and use it as an outgoing probe.
@@ -577,17 +678,15 @@ int construct_ip4_packet(
577
678
*/
578
679
#ifdef SO_MARK
579
680
if (param -> routing_mark ) {
580
- if (setsockopt (send_socket , SOL_SOCKET ,
581
- SO_MARK , & param -> routing_mark , sizeof (int ))) {
681
+ if (set_socket_mark (send_socket , param -> routing_mark )) {
582
682
return -1 ;
583
683
}
584
684
}
585
685
#endif
586
686
587
687
#ifdef SO_BINDTODEVICE
588
688
if (param -> local_device ) {
589
- if (setsockopt (send_socket , SOL_SOCKET ,
590
- SO_BINDTODEVICE , param -> local_device , strlen (param -> local_device ))) {
689
+ if (set_bind_to_device (send_socket , param -> local_device )) {
591
690
return -1 ;
592
691
}
593
692
}
@@ -750,9 +849,7 @@ int construct_ip6_packet(
750
849
}
751
850
#ifdef SO_MARK
752
851
if (param -> routing_mark ) {
753
- if (setsockopt (send_socket ,
754
- SOL_SOCKET , SO_MARK , & param -> routing_mark ,
755
- sizeof (int ))) {
852
+ if (set_socket_mark (send_socket , param -> routing_mark )) {
756
853
return -1 ;
757
854
}
758
855
}
0 commit comments