@@ -76,6 +76,12 @@ enum {
76
76
DNS
77
77
};
78
78
79
+ enum {
80
+ IPV4 = 1 ,
81
+ IPV6 ,
82
+ IP_TYPE_MAX
83
+ };
84
+
79
85
static int in_hand_shake ;
80
86
81
87
static char * os_name = "" ;
@@ -102,6 +108,11 @@ static struct utsname uts_buf;
102
108
103
109
#define MAX_FILE_NAME 100
104
110
#define ENTRIES_PER_BLOCK 50
111
+ /*
112
+ * Change this entry if the number of addresses increases in future
113
+ */
114
+ #define MAX_IP_ENTRIES 64
115
+ #define OUTSTR_BUF_SIZE ((INET6_ADDRSTRLEN + 1) * MAX_IP_ENTRIES)
105
116
106
117
struct kvp_record {
107
118
char key [HV_KVP_EXCHANGE_MAX_KEY_SIZE ];
@@ -1171,6 +1182,18 @@ static int process_ip_string(FILE *f, char *ip_string, int type)
1171
1182
return 0 ;
1172
1183
}
1173
1184
1185
+ int ip_version_check (const char * input_addr )
1186
+ {
1187
+ struct in6_addr addr ;
1188
+
1189
+ if (inet_pton (AF_INET , input_addr , & addr ))
1190
+ return IPV4 ;
1191
+ else if (inet_pton (AF_INET6 , input_addr , & addr ))
1192
+ return IPV6 ;
1193
+
1194
+ return - EINVAL ;
1195
+ }
1196
+
1174
1197
/*
1175
1198
* Only IPv4 subnet strings needs to be converted to plen
1176
1199
* For IPv6 the subnet is already privided in plen format
@@ -1197,14 +1220,75 @@ static int kvp_subnet_to_plen(char *subnet_addr_str)
1197
1220
return plen ;
1198
1221
}
1199
1222
1223
+ static int process_dns_gateway_nm (FILE * f , char * ip_string , int type ,
1224
+ int ip_sec )
1225
+ {
1226
+ char addr [INET6_ADDRSTRLEN ], * output_str ;
1227
+ int ip_offset = 0 , error = 0 , ip_ver ;
1228
+ char * param_name ;
1229
+
1230
+ if (type == DNS )
1231
+ param_name = "dns" ;
1232
+ else if (type == GATEWAY )
1233
+ param_name = "gateway" ;
1234
+ else
1235
+ return - EINVAL ;
1236
+
1237
+ output_str = (char * )calloc (OUTSTR_BUF_SIZE , sizeof (char ));
1238
+ if (!output_str )
1239
+ return - ENOMEM ;
1240
+
1241
+ while (1 ) {
1242
+ memset (addr , 0 , sizeof (addr ));
1243
+
1244
+ if (!parse_ip_val_buffer (ip_string , & ip_offset , addr ,
1245
+ (MAX_IP_ADDR_SIZE * 2 )))
1246
+ break ;
1247
+
1248
+ ip_ver = ip_version_check (addr );
1249
+ if (ip_ver < 0 )
1250
+ continue ;
1251
+
1252
+ if ((ip_ver == IPV4 && ip_sec == IPV4 ) ||
1253
+ (ip_ver == IPV6 && ip_sec == IPV6 )) {
1254
+ /*
1255
+ * do a bound check to avoid out-of bound writes
1256
+ */
1257
+ if ((OUTSTR_BUF_SIZE - strlen (output_str )) >
1258
+ (strlen (addr ) + 1 )) {
1259
+ strncat (output_str , addr ,
1260
+ OUTSTR_BUF_SIZE -
1261
+ strlen (output_str ) - 1 );
1262
+ strncat (output_str , "," ,
1263
+ OUTSTR_BUF_SIZE -
1264
+ strlen (output_str ) - 1 );
1265
+ }
1266
+ } else {
1267
+ continue ;
1268
+ }
1269
+ }
1270
+
1271
+ if (strlen (output_str )) {
1272
+ /*
1273
+ * This is to get rid of that extra comma character
1274
+ * in the end of the string
1275
+ */
1276
+ output_str [strlen (output_str ) - 1 ] = '\0' ;
1277
+ error = fprintf (f , "%s=%s\n" , param_name , output_str );
1278
+ }
1279
+
1280
+ free (output_str );
1281
+ return error ;
1282
+ }
1283
+
1200
1284
static int process_ip_string_nm (FILE * f , char * ip_string , char * subnet ,
1201
- int is_ipv6 )
1285
+ int ip_sec )
1202
1286
{
1203
1287
char addr [INET6_ADDRSTRLEN ];
1204
1288
char subnet_addr [INET6_ADDRSTRLEN ];
1205
- int error , i = 0 ;
1289
+ int error = 0 , i = 0 ;
1206
1290
int ip_offset = 0 , subnet_offset = 0 ;
1207
- int plen ;
1291
+ int plen , ip_ver ;
1208
1292
1209
1293
memset (addr , 0 , sizeof (addr ));
1210
1294
memset (subnet_addr , 0 , sizeof (subnet_addr ));
@@ -1216,10 +1300,16 @@ static int process_ip_string_nm(FILE *f, char *ip_string, char *subnet,
1216
1300
subnet_addr ,
1217
1301
(MAX_IP_ADDR_SIZE *
1218
1302
2 ))) {
1219
- if (!is_ipv6 )
1303
+ ip_ver = ip_version_check (addr );
1304
+ if (ip_ver < 0 )
1305
+ continue ;
1306
+
1307
+ if (ip_ver == IPV4 && ip_sec == IPV4 )
1220
1308
plen = kvp_subnet_to_plen ((char * )subnet_addr );
1221
- else
1309
+ else if ( ip_ver == IPV6 && ip_sec == IPV6 )
1222
1310
plen = atoi (subnet_addr );
1311
+ else
1312
+ continue ;
1223
1313
1224
1314
if (plen < 0 )
1225
1315
return plen ;
@@ -1233,17 +1323,16 @@ static int process_ip_string_nm(FILE *f, char *ip_string, char *subnet,
1233
1323
memset (subnet_addr , 0 , sizeof (subnet_addr ));
1234
1324
}
1235
1325
1236
- return 0 ;
1326
+ return error ;
1237
1327
}
1238
1328
1239
1329
static int kvp_set_ip_info (char * if_name , struct hv_kvp_ipaddr_value * new_val )
1240
1330
{
1241
- int error = 0 ;
1331
+ int error = 0 , ip_ver ;
1242
1332
char if_filename [PATH_MAX ];
1243
1333
char nm_filename [PATH_MAX ];
1244
1334
FILE * ifcfg_file , * nmfile ;
1245
1335
char cmd [PATH_MAX ];
1246
- int is_ipv6 = 0 ;
1247
1336
char * mac_addr ;
1248
1337
int str_len ;
1249
1338
@@ -1421,52 +1510,94 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
1421
1510
if (error )
1422
1511
goto setval_error ;
1423
1512
1424
- if (new_val -> addr_family & ADDR_FAMILY_IPV6 ) {
1425
- error = fprintf (nmfile , "\n[ipv6]\n" );
1426
- if (error < 0 )
1427
- goto setval_error ;
1428
- is_ipv6 = 1 ;
1429
- } else {
1430
- error = fprintf (nmfile , "\n[ipv4]\n" );
1431
- if (error < 0 )
1432
- goto setval_error ;
1433
- }
1434
-
1435
1513
/*
1436
1514
* Now we populate the keyfile format
1515
+ *
1516
+ * The keyfile format expects the IPv6 and IPv4 configuration in
1517
+ * different sections. Therefore we iterate through the list twice,
1518
+ * once to populate the IPv4 section and the next time for IPv6
1437
1519
*/
1520
+ ip_ver = IPV4 ;
1521
+ do {
1522
+ if (ip_ver == IPV4 ) {
1523
+ error = fprintf (nmfile , "\n[ipv4]\n" );
1524
+ if (error < 0 )
1525
+ goto setval_error ;
1526
+ } else {
1527
+ error = fprintf (nmfile , "\n[ipv6]\n" );
1528
+ if (error < 0 )
1529
+ goto setval_error ;
1530
+ }
1438
1531
1439
- if (new_val -> dhcp_enabled ) {
1440
- error = kvp_write_file (nmfile , "method" , "" , "auto" );
1441
- if (error < 0 )
1442
- goto setval_error ;
1443
- } else {
1444
- error = kvp_write_file (nmfile , "method" , "" , "manual" );
1532
+ /*
1533
+ * Write the configuration for ipaddress, netmask, gateway and
1534
+ * name services
1535
+ */
1536
+ error = process_ip_string_nm (nmfile , (char * )new_val -> ip_addr ,
1537
+ (char * )new_val -> sub_net ,
1538
+ ip_ver );
1445
1539
if (error < 0 )
1446
1540
goto setval_error ;
1447
- }
1448
1541
1449
- /*
1450
- * Write the configuration for ipaddress, netmask, gateway and
1451
- * name services
1452
- */
1453
- error = process_ip_string_nm (nmfile , (char * )new_val -> ip_addr ,
1454
- (char * )new_val -> sub_net , is_ipv6 );
1455
- if (error < 0 )
1456
- goto setval_error ;
1542
+ /*
1543
+ * As dhcp_enabled is only valid for ipv4, we do not set dhcp
1544
+ * methods for ipv6 based on dhcp_enabled flag.
1545
+ *
1546
+ * For ipv4, set method to manual only when dhcp_enabled is
1547
+ * false and specific ipv4 addresses are configured. If neither
1548
+ * dhcp_enabled is true and no ipv4 addresses are configured,
1549
+ * set method to 'disabled'.
1550
+ *
1551
+ * For ipv6, set method to manual when we configure ipv6
1552
+ * addresses. Otherwise set method to 'auto' so that SLAAC from
1553
+ * RA may be used.
1554
+ */
1555
+ if (ip_ver == IPV4 ) {
1556
+ if (new_val -> dhcp_enabled ) {
1557
+ error = kvp_write_file (nmfile , "method" , "" ,
1558
+ "auto" );
1559
+ if (error < 0 )
1560
+ goto setval_error ;
1561
+ } else if (error ) {
1562
+ error = kvp_write_file (nmfile , "method" , "" ,
1563
+ "manual" );
1564
+ if (error < 0 )
1565
+ goto setval_error ;
1566
+ } else {
1567
+ error = kvp_write_file (nmfile , "method" , "" ,
1568
+ "disabled" );
1569
+ if (error < 0 )
1570
+ goto setval_error ;
1571
+ }
1572
+ } else if (ip_ver == IPV6 ) {
1573
+ if (error ) {
1574
+ error = kvp_write_file (nmfile , "method" , "" ,
1575
+ "manual" );
1576
+ if (error < 0 )
1577
+ goto setval_error ;
1578
+ } else {
1579
+ error = kvp_write_file (nmfile , "method" , "" ,
1580
+ "auto" );
1581
+ if (error < 0 )
1582
+ goto setval_error ;
1583
+ }
1584
+ }
1457
1585
1458
- /* we do not want ipv4 addresses in ipv6 section and vice versa */
1459
- if ( is_ipv6 != is_ipv4 (( char * )new_val -> gate_way )) {
1460
- error = fprintf ( nmfile , "gateway=%s\n" , ( char * ) new_val -> gate_way );
1586
+ error = process_dns_gateway_nm ( nmfile ,
1587
+ ( char * )new_val -> gate_way ,
1588
+ GATEWAY , ip_ver );
1461
1589
if (error < 0 )
1462
1590
goto setval_error ;
1463
- }
1464
1591
1465
- if (is_ipv6 != is_ipv4 ((char * )new_val -> dns_addr )) {
1466
- error = fprintf (nmfile , "dns=%s\n" , (char * )new_val -> dns_addr );
1592
+ error = process_dns_gateway_nm (nmfile ,
1593
+ (char * )new_val -> dns_addr , DNS ,
1594
+ ip_ver );
1467
1595
if (error < 0 )
1468
1596
goto setval_error ;
1469
- }
1597
+
1598
+ ip_ver ++ ;
1599
+ } while (ip_ver < IP_TYPE_MAX );
1600
+
1470
1601
fclose (nmfile );
1471
1602
fclose (ifcfg_file );
1472
1603
0 commit comments