12
12
#include <sys/socket.h>
13
13
#include <sys/types.h>
14
14
#include <sys/wait.h>
15
+ #include <sys/timex.h>
15
16
#include <linux/if_tun.h>
16
17
#include <arpa/inet.h>
17
18
#include <net/if.h>
23
24
#include "slirp4netns.h"
24
25
#include <ifaddrs.h>
25
26
#include <seccomp.h>
27
+ #include <openssl/sha.h>
26
28
27
29
#define DEFAULT_MTU (1500)
28
30
#define DEFAULT_CIDR ("10.0.2.0/24")
31
+ #define DEFAULT_CIDR6 ("fd00::/64")
29
32
#define DEFAULT_VHOST_OFFSET (2) // 10.0.2.2
33
+ #define DEFAULT_VHOST_OFFSET6 ("2")
30
34
#define DEFAULT_VDHCPSTART_OFFSET (15) // 10.0.2.15
35
+ #define DEFAULT_VDHCPSTART_OFFSET6 ("15")
31
36
#define DEFAULT_VNAMESERVER_OFFSET (3) // 10.0.2.3
37
+ #define DEFAULT_VNAMESERVER_OFFSET6 ("3")
32
38
#define DEFAULT_RECOMMENDED_VGUEST_OFFSET (100) // 10.0.2.100
39
+ #define DEFAULT_RECOMMENDED_VGUEST_OFFSET6 ("100")
33
40
#define DEFAULT_NETNS_TYPE ("pid")
34
41
#define NETWORK_PREFIX_MIN (1)
35
42
// >=26 is not supported because the recommended guest IP is set to network addr
36
43
// + 100 .
37
44
#define NETWORK_PREFIX_MAX (25)
45
+ #define NETWORK_PREFIX_MIN6 (8)
46
+ #define NETWORK_PREFIX_MAX6 (64)
38
47
39
48
static int nsenter (pid_t target_pid , char * netns , char * userns ,
40
49
bool only_userns )
@@ -211,6 +220,103 @@ struct in6_ifreq {
211
220
unsigned int ifr6_ifindex ;
212
221
};
213
222
223
+ static const char * pseudo_random_global_id (const char * device )
224
+ {
225
+ static char id [40 ];
226
+ char tmp [40 ];
227
+ unsigned char eui64 [16 ];
228
+ unsigned char hash [SHA_DIGEST_LENGTH ];
229
+ struct ntptimeval ntv ;
230
+ struct ifreq ifr ;
231
+ const unsigned char * mac ;
232
+ int sockfd ;
233
+
234
+ sockfd = socket (AF_INET , SOCK_DGRAM , 0 );
235
+ if (sockfd < 0 ) {
236
+ perror ("cannot create socket" );
237
+ return NULL ;
238
+ }
239
+
240
+ memset (& ifr , 0 , sizeof (ifr ));
241
+ ifr .ifr_flags = IFF_UP | IFF_RUNNING ;
242
+
243
+ if (device == NULL ) {
244
+ /* TODO: which device should we get the mac address from? */
245
+ device = "lo" ;
246
+ }
247
+ strncpy (ifr .ifr_name , device , sizeof (ifr .ifr_name ) - 1 );
248
+
249
+ if (ioctl (sockfd , SIOCGIFHWADDR , & ifr ) < 0 ) {
250
+ perror ("cannot get dev hwaddr" );
251
+ return NULL ;
252
+ }
253
+
254
+ mac = (unsigned char * )ifr .ifr_ifru .ifru_addr .sa_data ;
255
+
256
+ /* https://tools.ietf.org/html/rfc4193
257
+ *
258
+ * 3.2.2. Sample Code for Pseudo-Random Global ID Algorithm
259
+ */
260
+
261
+ /*
262
+ * 1) Obtain the current time of day in 64-bit NTP format [NTP].
263
+ */
264
+ if (ntp_gettime (& ntv ) == -1 ) {
265
+ perror ("cannot get ntp time" );
266
+ return NULL ;
267
+ }
268
+
269
+ /*
270
+ * 2) Obtain an EUI-64 identifier from the system running this
271
+ * algorithm. If an EUI-64 does not exist, one can be created from
272
+ * a 48-bit MAC address as specified in [ADDARCH]. If an EUI-64
273
+ * cannot be obtained or created, a suitably unique identifier,
274
+ * local to the node, should be used (e.g., system serial number).
275
+ */
276
+ eui64 [8 ] = mac [0 ];
277
+ eui64 [9 ] = mac [1 ];
278
+ eui64 [10 ] = mac [2 ];
279
+ eui64 [11 ] = 0xff ;
280
+ eui64 [12 ] = 0xfe ;
281
+ eui64 [13 ] = mac [3 ];
282
+ eui64 [14 ] = mac [4 ];
283
+ eui64 [15 ] = mac [5 ];
284
+
285
+ /*
286
+ * 3) Concatenate the time of day with the system-specific identifier
287
+ * in order to create a key.
288
+ */
289
+ memcpy (& eui64 [0 ], (void * )& ntv .time .tv_sec , 4 );
290
+ memcpy (& eui64 [4 ], (void * )& ntv .time .tv_usec , 4 );
291
+
292
+ /*
293
+ * 4) Compute an SHA-1 digest on the key as specified in [FIPS, SHA1];
294
+ * the resulting value is 160 bits.
295
+ */
296
+ SHA1 (eui64 , sizeof (eui64 ), hash );
297
+
298
+ /*
299
+ * 5) Use the least significant 40 bits as the Global ID.
300
+ */
301
+ int i = 0 , j = 0 ;
302
+ for (; j < 5 ; i += 2 , j ++ ) {
303
+ sprintf (& tmp [i ], "%02x" , hash [j ]);
304
+ if (j > 0 && (j % 2 )) {
305
+ tmp [i + 2 ] = ':' ;
306
+ i ++ ;
307
+ }
308
+ }
309
+
310
+ /*
311
+ * 6) Concatenate FC00::/7, the L bit set to 1, and the 40-bit Global
312
+ * ID to create a Local IPv6 address prefix.
313
+ */
314
+
315
+ sprintf (id , "fd00:%s::" , tmp );
316
+
317
+ return id ;
318
+ }
319
+
214
320
static int configure_network6 (const char * tapname ,
215
321
struct slirp4netns_config * cfg )
216
322
{
@@ -219,6 +325,7 @@ static int configure_network6(const char *tapname,
219
325
struct in6_ifreq ifr6 ;
220
326
struct sockaddr_in6 sai ;
221
327
int sockfd ;
328
+ const char * id ;
222
329
223
330
sockfd = socket (AF_INET6 , SOCK_DGRAM , 0 );
224
331
if (sockfd < 0 ) {
@@ -230,20 +337,21 @@ static int configure_network6(const char *tapname,
230
337
ifr .ifr_flags = IFF_UP | IFF_RUNNING ;
231
338
strncpy (ifr .ifr_name , tapname , sizeof (ifr .ifr_name ) - 1 );
232
339
340
+ if (ioctl (sockfd , SIOCGIFHWADDR , & ifr ) < 0 ) {
341
+ perror ("cannot get dev hwaddr" );
342
+ return -1 ;
343
+ }
344
+
233
345
if (ioctl (sockfd , SIOGIFINDEX , & ifr ) < 0 ) {
234
346
perror ("cannot get dev index" );
235
347
return -1 ;
236
348
}
237
349
238
350
memset (& sai , 0 , sizeof (struct sockaddr ));
239
351
sai .sin6_family = AF_INET6 ;
352
+ sai .sin6_addr = cfg -> recommended_vguest6 ;
240
353
sai .sin6_port = 0 ;
241
354
242
- if (inet_pton (AF_INET6 , "fd00::100" , & sai .sin6_addr ) != 1 ) {
243
- perror ("cannot create device address" );
244
- return -1 ;
245
- }
246
-
247
355
memcpy ((char * )& ifr6 .ifr6_addr , & sai .sin6_addr , sizeof (struct in6_addr ));
248
356
249
357
ifr6 .ifr6_ifindex = ifr .ifr_ifindex ;
@@ -321,6 +429,7 @@ static int parent(int sock, int ready_fd, int exit_fd, const char *api_socket,
321
429
struct slirp4netns_config * cfg , pid_t target_pid )
322
430
{
323
431
int rc , tapfd ;
432
+ char ipv6 [INET6_ADDRSTRLEN ];
324
433
if ((tapfd = recvfd (sock )) < 0 ) {
325
434
return tapfd ;
326
435
}
@@ -333,6 +442,18 @@ static int parent(int sock, int ready_fd, int exit_fd, const char *api_socket,
333
442
printf ("* Gateway: %s\n" , inet_ntoa (cfg -> vhost ));
334
443
printf ("* DNS: %s\n" , inet_ntoa (cfg -> vnameserver ));
335
444
printf ("* Recommended IP: %s\n" , inet_ntoa (cfg -> recommended_vguest ));
445
+ if (cfg -> enable_ipv6 ) {
446
+ inet_ntop (AF_INET6 , & cfg -> vnetwork6 , ipv6 , INET6_ADDRSTRLEN );
447
+ printf ("* IPv6 Network: %s\n" , ipv6 );
448
+ inet_ntop (AF_INET6 , & cfg -> vnetmask6 , ipv6 , INET6_ADDRSTRLEN );
449
+ printf ("* IPv6 Netmask: %s\n" , ipv6 );
450
+ inet_ntop (AF_INET6 , & cfg -> vhost6 , ipv6 , INET6_ADDRSTRLEN );
451
+ printf ("* IPv6 Gateway: %s\n" , ipv6 );
452
+ inet_ntop (AF_INET6 , & cfg -> vnameserver6 , ipv6 , INET6_ADDRSTRLEN );
453
+ printf ("* IPv6 DNS: %s\n" , ipv6 );
454
+ inet_ntop (AF_INET6 , & cfg -> recommended_vguest6 , ipv6 , INET6_ADDRSTRLEN );
455
+ printf ("* IPv6 Recommended IP: %s\n" , ipv6 );
456
+ }
336
457
if (api_socket != NULL ) {
337
458
printf ("* API Socket: %s\n" , api_socket );
338
459
}
@@ -453,6 +574,7 @@ static void version()
453
574
struct options {
454
575
char * tapname ; // argv[2]
455
576
char * cidr ; // --cidr
577
+ char * cidr6 ; // --cidr
456
578
char * api_socket ; // -a
457
579
char * netns_type ; // argv[1]
458
580
char * netns_path ; // --netns-path
@@ -813,6 +935,82 @@ static int parse_cidr(struct in_addr *network, struct in_addr *netmask,
813
935
return rc ;
814
936
}
815
937
938
+ static int parse_cidr6 (struct in6_addr * network , struct in6_addr * netmask ,
939
+ const char * cidr )
940
+ {
941
+ int rc = 0 ;
942
+ regex_t r ;
943
+ regmatch_t matches [4 ];
944
+ size_t nmatch = sizeof (matches ) / sizeof (matches [0 ]);
945
+ const char * cidr_regex = "^(([a-fA-F0-9]{1,4}):){1,4}:/([0-9]{1,3})" ;
946
+ char snetwork [INET6_ADDRSTRLEN ], sprefix [INET6_ADDRSTRLEN ];
947
+ int prefix ;
948
+ const char * random ;
949
+ rc = regcomp (& r , cidr_regex , REG_EXTENDED );
950
+ if (rc != 0 ) {
951
+ fprintf (stderr , "internal regex error\n" );
952
+ rc = -1 ;
953
+ goto finish ;
954
+ }
955
+ rc = regexec (& r , cidr , nmatch , matches , 0 );
956
+ if (rc != 0 ) {
957
+ fprintf (stderr , "invalid CIDR: %s\n" , cidr );
958
+ rc = -1 ;
959
+ goto finish ;
960
+ }
961
+ rc = from_regmatch (snetwork , sizeof (snetwork ), matches [1 ], cidr );
962
+ if (rc < 0 ) {
963
+ fprintf (stderr , "invalid CIDR: %s\n" , cidr );
964
+ goto finish ;
965
+ }
966
+ rc = from_regmatch (sprefix , sizeof (sprefix ), matches [3 ], cidr );
967
+ if (rc < 0 ) {
968
+ fprintf (stderr , "invalid CIDR: %s\n" , cidr );
969
+ goto finish ;
970
+ }
971
+ random = pseudo_random_global_id (NULL );
972
+ if (random == NULL ) {
973
+ fprintf (stderr , "cannot create pseudo random global id\n" );
974
+ rc = -1 ;
975
+ goto finish ;
976
+ }
977
+ strcpy (snetwork , random );
978
+ strcat (snetwork , "0" );
979
+
980
+ if (inet_pton (AF_INET6 , snetwork , network ) != 1 ) {
981
+ fprintf (stderr , "invalid network address: %s\n" , snetwork );
982
+ rc = -1 ;
983
+ goto finish ;
984
+ }
985
+ errno = 0 ;
986
+ prefix = strtoul (sprefix , NULL , 10 );
987
+ if (errno ) {
988
+ fprintf (stderr , "invalid prefix length: %s\n" , sprefix );
989
+ rc = -1 ;
990
+ goto finish ;
991
+ }
992
+ if (prefix < NETWORK_PREFIX_MIN6 || prefix > NETWORK_PREFIX_MAX6 ) {
993
+ fprintf (stderr , "prefix length needs to be %d-%d\n" , NETWORK_PREFIX_MIN6 ,
994
+ NETWORK_PREFIX_MAX6 );
995
+ rc = -1 ;
996
+ goto finish ;
997
+ }
998
+
999
+ for (int i = 0 ; i < 4 ; i ++ , prefix -= 32 ) {
1000
+ if (prefix >= 32 ) {
1001
+ netmask -> __in6_u .__u6_addr32 [i ] = 0xffffffff ;
1002
+ } else if (prefix > 0 ) {
1003
+ netmask -> __in6_u .__u6_addr32 [i ] = htonl (~((1 << (32 - prefix )) - 1 ));
1004
+ } else {
1005
+ netmask -> __in6_u .__u6_addr32 [i ] = 0 ;
1006
+ }
1007
+ }
1008
+
1009
+ finish :
1010
+ regfree (& r );
1011
+ return rc ;
1012
+ }
1013
+
816
1014
static int slirp4netns_config_from_cidr (struct slirp4netns_config * cfg ,
817
1015
const char * cidr )
818
1016
{
@@ -833,6 +1031,49 @@ static int slirp4netns_config_from_cidr(struct slirp4netns_config *cfg,
833
1031
return rc ;
834
1032
}
835
1033
1034
+ static int slirp4netns_config_from_cidr6 (struct slirp4netns_config * cfg ,
1035
+ const char * cidr )
1036
+ {
1037
+ int rc ;
1038
+ char net [INET6_ADDRSTRLEN ];
1039
+ char tmp [INET6_ADDRSTRLEN ];
1040
+ rc = parse_cidr6 (& cfg -> vnetwork6 , & cfg -> vnetmask6 , cidr );
1041
+ if (rc < 0 ) {
1042
+ goto finish ;
1043
+ }
1044
+
1045
+ if (inet_ntop (AF_INET6 , & cfg -> vnetwork6 , net , INET6_ADDRSTRLEN ) == NULL ) {
1046
+ return -1 ;
1047
+ }
1048
+
1049
+ strcpy (tmp , net );
1050
+ strcat (tmp , DEFAULT_VHOST_OFFSET6 );
1051
+ if (inet_pton (AF_INET6 , tmp , & cfg -> vhost6 ) != 1 ) {
1052
+ return -1 ;
1053
+ }
1054
+
1055
+ strcpy (tmp , net );
1056
+ strcat (tmp , DEFAULT_VDHCPSTART_OFFSET6 );
1057
+ if (inet_pton (AF_INET6 , tmp , & cfg -> vdhcp_start6 ) != 1 ) {
1058
+ return -1 ;
1059
+ }
1060
+
1061
+ strcpy (tmp , net );
1062
+ strcat (tmp , DEFAULT_VNAMESERVER_OFFSET6 );
1063
+ if (inet_pton (AF_INET6 , tmp , & cfg -> vnameserver6 ) != 1 ) {
1064
+ return -1 ;
1065
+ }
1066
+
1067
+ strcpy (tmp , net );
1068
+ strcat (tmp , DEFAULT_RECOMMENDED_VGUEST_OFFSET6 );
1069
+ if (inet_pton (AF_INET6 , tmp , & cfg -> recommended_vguest6 ) != 1 ) {
1070
+ return -1 ;
1071
+ }
1072
+
1073
+ finish :
1074
+ return rc ;
1075
+ }
1076
+
836
1077
static int get_interface_addr (const char * interface , int af , void * addr )
837
1078
{
838
1079
struct ifaddrs * ifaddr , * ifa ;
@@ -909,6 +1150,14 @@ static int slirp4netns_config_from_options(struct slirp4netns_config *cfg,
909
1150
cfg -> enable_sandbox = opt -> enable_sandbox ;
910
1151
cfg -> enable_seccomp = opt -> enable_seccomp ;
911
1152
1153
+ if (cfg -> enable_ipv6 ) {
1154
+ rc = slirp4netns_config_from_cidr6 (cfg , opt -> cidr6 == NULL ? DEFAULT_CIDR6 :
1155
+ opt -> cidr6 );
1156
+ if (rc < 0 ) {
1157
+ goto finish ;
1158
+ }
1159
+ }
1160
+
912
1161
#if SLIRP_CONFIG_VERSION_MAX >= 2
913
1162
cfg -> enable_outbound_addr = false;
914
1163
cfg -> enable_outbound_addr6 = false;
0 commit comments