@@ -76,6 +76,12 @@ enum {
7676 DNS
7777};
7878
79+ enum {
80+ IPV4 = 1 ,
81+ IPV6 ,
82+ IP_TYPE_MAX
83+ };
84+
7985static int in_hand_shake ;
8086
8187static char * os_name = "" ;
@@ -102,6 +108,11 @@ static struct utsname uts_buf;
102108
103109#define MAX_FILE_NAME 100
104110#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)
105116
106117struct kvp_record {
107118 char key [HV_KVP_EXCHANGE_MAX_KEY_SIZE ];
@@ -1171,6 +1182,18 @@ static int process_ip_string(FILE *f, char *ip_string, int type)
11711182 return 0 ;
11721183}
11731184
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+
11741197/*
11751198 * Only IPv4 subnet strings needs to be converted to plen
11761199 * For IPv6 the subnet is already privided in plen format
@@ -1197,14 +1220,75 @@ static int kvp_subnet_to_plen(char *subnet_addr_str)
11971220 return plen ;
11981221}
11991222
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+
12001284static int process_ip_string_nm (FILE * f , char * ip_string , char * subnet ,
1201- int is_ipv6 )
1285+ int ip_sec )
12021286{
12031287 char addr [INET6_ADDRSTRLEN ];
12041288 char subnet_addr [INET6_ADDRSTRLEN ];
1205- int error , i = 0 ;
1289+ int error = 0 , i = 0 ;
12061290 int ip_offset = 0 , subnet_offset = 0 ;
1207- int plen ;
1291+ int plen , ip_ver ;
12081292
12091293 memset (addr , 0 , sizeof (addr ));
12101294 memset (subnet_addr , 0 , sizeof (subnet_addr ));
@@ -1216,10 +1300,16 @@ static int process_ip_string_nm(FILE *f, char *ip_string, char *subnet,
12161300 subnet_addr ,
12171301 (MAX_IP_ADDR_SIZE *
12181302 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 )
12201308 plen = kvp_subnet_to_plen ((char * )subnet_addr );
1221- else
1309+ else if ( ip_ver == IPV6 && ip_sec == IPV6 )
12221310 plen = atoi (subnet_addr );
1311+ else
1312+ continue ;
12231313
12241314 if (plen < 0 )
12251315 return plen ;
@@ -1233,17 +1323,16 @@ static int process_ip_string_nm(FILE *f, char *ip_string, char *subnet,
12331323 memset (subnet_addr , 0 , sizeof (subnet_addr ));
12341324 }
12351325
1236- return 0 ;
1326+ return error ;
12371327}
12381328
12391329static int kvp_set_ip_info (char * if_name , struct hv_kvp_ipaddr_value * new_val )
12401330{
1241- int error = 0 ;
1331+ int error = 0 , ip_ver ;
12421332 char if_filename [PATH_MAX ];
12431333 char nm_filename [PATH_MAX ];
12441334 FILE * ifcfg_file , * nmfile ;
12451335 char cmd [PATH_MAX ];
1246- int is_ipv6 = 0 ;
12471336 char * mac_addr ;
12481337 int str_len ;
12491338
@@ -1421,52 +1510,94 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
14211510 if (error )
14221511 goto setval_error ;
14231512
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-
14351513 /*
14361514 * 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
14371519 */
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+ }
14381531
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 );
14451539 if (error < 0 )
14461540 goto setval_error ;
1447- }
14481541
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+ }
14571585
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 );
14611589 if (error < 0 )
14621590 goto setval_error ;
1463- }
14641591
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 );
14671595 if (error < 0 )
14681596 goto setval_error ;
1469- }
1597+
1598+ ip_ver ++ ;
1599+ } while (ip_ver < IP_TYPE_MAX );
1600+
14701601 fclose (nmfile );
14711602 fclose (ifcfg_file );
14721603
0 commit comments