1 /* 2 * An implementation of key value pair (KVP) functionality for Linux. 3 * 4 * 5 * Copyright (C) 2010, Novell, Inc. 6 * Author : K. Y. Srinivasan <ksrinivasan@novell.com> 7 * 8 * This program is free software; you can redistribute it and/or modify it 9 * under the terms of the GNU General Public License version 2 as published 10 * by the Free Software Foundation. 11 * 12 * This program is distributed in the hope that it will be useful, but 13 * WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or 15 * NON INFRINGEMENT. See the GNU General Public License for more 16 * details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21 * 22 */ 23 24 25 #include <sys/poll.h> 26 #include <sys/utsname.h> 27 #include <stdbool.h> 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <unistd.h> 31 #include <string.h> 32 #include <ctype.h> 33 #include <errno.h> 34 #include <arpa/inet.h> 35 #include <linux/hyperv.h> 36 #include <ifaddrs.h> 37 #include <netdb.h> 38 #include <syslog.h> 39 #include <sys/stat.h> 40 #include <fcntl.h> 41 #include <dirent.h> 42 #include <net/if.h> 43 #include <limits.h> 44 #include <getopt.h> 45 46 /* 47 * KVP protocol: The user mode component first registers with the 48 * kernel component. Subsequently, the kernel component requests, data 49 * for the specified keys. In response to this message the user mode component 50 * fills in the value corresponding to the specified key. We overload the 51 * sequence field in the cn_msg header to define our KVP message types. 52 * 53 * We use this infrastructure for also supporting queries from user mode 54 * application for state that may be maintained in the KVP kernel component. 55 * 56 */ 57 58 59 enum key_index { 60 FullyQualifiedDomainName = 0, 61 IntegrationServicesVersion, /*This key is serviced in the kernel*/ 62 NetworkAddressIPv4, 63 NetworkAddressIPv6, 64 OSBuildNumber, 65 OSName, 66 OSMajorVersion, 67 OSMinorVersion, 68 OSVersion, 69 ProcessorArchitecture 70 }; 71 72 73 enum { 74 IPADDR = 0, 75 NETMASK, 76 GATEWAY, 77 DNS 78 }; 79 80 enum { 81 IPV4 = 1, 82 IPV6, 83 IP_TYPE_MAX 84 }; 85 86 static int in_hand_shake; 87 static int debug; 88 89 static char *os_name = ""; 90 static char *os_major = ""; 91 static char *os_minor = ""; 92 static char *processor_arch; 93 static char *os_build; 94 static char *os_version; 95 static char *lic_version = "Unknown version"; 96 static char full_domain_name[HV_KVP_EXCHANGE_MAX_VALUE_SIZE]; 97 static struct utsname uts_buf; 98 99 /* 100 * The location of the interface configuration file. 101 */ 102 103 #define KVP_CONFIG_LOC "/var/lib/hyperv" 104 105 #ifndef KVP_SCRIPTS_PATH 106 #define KVP_SCRIPTS_PATH "/usr/libexec/hypervkvpd/" 107 #endif 108 109 #define KVP_NET_DIR "/sys/class/net/" 110 111 #define MAX_FILE_NAME 100 112 #define ENTRIES_PER_BLOCK 50 113 /* 114 * Change this entry if the number of addresses increases in future 115 */ 116 #define MAX_IP_ENTRIES 64 117 #define OUTSTR_BUF_SIZE ((INET6_ADDRSTRLEN + 1) * MAX_IP_ENTRIES) 118 119 struct kvp_record { 120 char key[HV_KVP_EXCHANGE_MAX_KEY_SIZE]; 121 char value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE]; 122 }; 123 124 struct kvp_file_state { 125 int fd; 126 int num_blocks; 127 struct kvp_record *records; 128 int num_records; 129 char fname[MAX_FILE_NAME]; 130 }; 131 132 static struct kvp_file_state kvp_file_info[KVP_POOL_COUNT]; 133 134 static void kvp_acquire_lock(int pool) 135 { 136 struct flock fl = {F_WRLCK, SEEK_SET, 0, 0, 0}; 137 fl.l_pid = getpid(); 138 139 if (fcntl(kvp_file_info[pool].fd, F_SETLKW, &fl) == -1) { 140 syslog(LOG_ERR, "Failed to acquire the lock pool: %d; error: %d %s", pool, 141 errno, strerror(errno)); 142 exit(EXIT_FAILURE); 143 } 144 } 145 146 static void kvp_release_lock(int pool) 147 { 148 struct flock fl = {F_UNLCK, SEEK_SET, 0, 0, 0}; 149 fl.l_pid = getpid(); 150 151 if (fcntl(kvp_file_info[pool].fd, F_SETLK, &fl) == -1) { 152 syslog(LOG_ERR, "Failed to release the lock pool: %d; error: %d %s", pool, 153 errno, strerror(errno)); 154 exit(EXIT_FAILURE); 155 } 156 } 157 158 static void kvp_update_file(int pool) 159 { 160 FILE *filep; 161 162 /* 163 * We are going to write our in-memory registry out to 164 * disk; acquire the lock first. 165 */ 166 kvp_acquire_lock(pool); 167 168 filep = fopen(kvp_file_info[pool].fname, "we"); 169 if (!filep) { 170 syslog(LOG_ERR, "Failed to open file, pool: %d; error: %d %s", pool, 171 errno, strerror(errno)); 172 kvp_release_lock(pool); 173 exit(EXIT_FAILURE); 174 } 175 176 fwrite(kvp_file_info[pool].records, sizeof(struct kvp_record), 177 kvp_file_info[pool].num_records, filep); 178 179 if (ferror(filep) || fclose(filep)) { 180 kvp_release_lock(pool); 181 syslog(LOG_ERR, "Failed to write file, pool: %d", pool); 182 exit(EXIT_FAILURE); 183 } 184 185 kvp_release_lock(pool); 186 } 187 188 static void kvp_dump_initial_pools(int pool) 189 { 190 int i; 191 192 syslog(LOG_DEBUG, "===Start dumping the contents of pool %d ===\n", 193 pool); 194 195 for (i = 0; i < kvp_file_info[pool].num_records; i++) 196 syslog(LOG_DEBUG, "pool: %d, %d/%d key=%s val=%s\n", 197 pool, i + 1, kvp_file_info[pool].num_records, 198 kvp_file_info[pool].records[i].key, 199 kvp_file_info[pool].records[i].value); 200 } 201 202 static void kvp_update_mem_state(int pool) 203 { 204 FILE *filep; 205 size_t records_read = 0; 206 struct kvp_record *record = kvp_file_info[pool].records; 207 struct kvp_record *readp; 208 int num_blocks = kvp_file_info[pool].num_blocks; 209 int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK; 210 211 kvp_acquire_lock(pool); 212 213 filep = fopen(kvp_file_info[pool].fname, "re"); 214 if (!filep) { 215 syslog(LOG_ERR, "Failed to open file, pool: %d; error: %d %s", pool, 216 errno, strerror(errno)); 217 kvp_release_lock(pool); 218 exit(EXIT_FAILURE); 219 } 220 for (;;) { 221 readp = &record[records_read]; 222 records_read += fread(readp, sizeof(struct kvp_record), 223 ENTRIES_PER_BLOCK * num_blocks - records_read, 224 filep); 225 226 if (ferror(filep)) { 227 syslog(LOG_ERR, 228 "Failed to read file, pool: %d; error: %d %s", 229 pool, errno, strerror(errno)); 230 kvp_release_lock(pool); 231 exit(EXIT_FAILURE); 232 } 233 234 if (!feof(filep)) { 235 /* 236 * We have more data to read. 237 */ 238 num_blocks++; 239 record = realloc(record, alloc_unit * num_blocks); 240 241 if (record == NULL) { 242 syslog(LOG_ERR, "malloc failed"); 243 kvp_release_lock(pool); 244 exit(EXIT_FAILURE); 245 } 246 continue; 247 } 248 break; 249 } 250 251 kvp_file_info[pool].num_blocks = num_blocks; 252 kvp_file_info[pool].records = record; 253 kvp_file_info[pool].num_records = records_read; 254 255 fclose(filep); 256 kvp_release_lock(pool); 257 } 258 259 static int kvp_file_init(void) 260 { 261 int fd; 262 char *fname; 263 int i; 264 int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK; 265 266 if (access(KVP_CONFIG_LOC, F_OK)) { 267 if (mkdir(KVP_CONFIG_LOC, 0755 /* rwxr-xr-x */)) { 268 syslog(LOG_ERR, "Failed to create '%s'; error: %d %s", KVP_CONFIG_LOC, 269 errno, strerror(errno)); 270 exit(EXIT_FAILURE); 271 } 272 } 273 274 for (i = 0; i < KVP_POOL_COUNT; i++) { 275 fname = kvp_file_info[i].fname; 276 sprintf(fname, "%s/.kvp_pool_%d", KVP_CONFIG_LOC, i); 277 fd = open(fname, O_RDWR | O_CREAT | O_CLOEXEC, 0644 /* rw-r--r-- */); 278 279 if (fd == -1) 280 return 1; 281 282 kvp_file_info[i].fd = fd; 283 kvp_file_info[i].num_blocks = 1; 284 kvp_file_info[i].records = malloc(alloc_unit); 285 if (kvp_file_info[i].records == NULL) 286 return 1; 287 kvp_file_info[i].num_records = 0; 288 kvp_update_mem_state(i); 289 if (debug) 290 kvp_dump_initial_pools(i); 291 } 292 293 return 0; 294 } 295 296 static int kvp_key_delete(int pool, const __u8 *key, int key_size) 297 { 298 int i; 299 int j, k; 300 int num_records; 301 struct kvp_record *record; 302 303 /* 304 * First update the in-memory state. 305 */ 306 kvp_update_mem_state(pool); 307 308 num_records = kvp_file_info[pool].num_records; 309 record = kvp_file_info[pool].records; 310 311 for (i = 0; i < num_records; i++) { 312 if (memcmp(key, record[i].key, key_size)) 313 continue; 314 /* 315 * Found a match; just move the remaining 316 * entries up. 317 */ 318 if (debug) 319 syslog(LOG_DEBUG, "%s: deleting the KVP: pool=%d key=%s val=%s", 320 __func__, pool, record[i].key, record[i].value); 321 if (i == (num_records - 1)) { 322 kvp_file_info[pool].num_records--; 323 kvp_update_file(pool); 324 return 0; 325 } 326 327 j = i; 328 k = j + 1; 329 for (; k < num_records; k++) { 330 strcpy(record[j].key, record[k].key); 331 strcpy(record[j].value, record[k].value); 332 j++; 333 } 334 335 kvp_file_info[pool].num_records--; 336 kvp_update_file(pool); 337 return 0; 338 } 339 340 if (debug) 341 syslog(LOG_DEBUG, "%s: could not delete KVP: pool=%d key=%s. Record not found", 342 __func__, pool, key); 343 344 return 1; 345 } 346 347 static int kvp_key_add_or_modify(int pool, const __u8 *key, int key_size, 348 const __u8 *value, int value_size) 349 { 350 struct kvp_record *record; 351 int num_records; 352 int num_blocks; 353 int i; 354 355 if (debug) 356 syslog(LOG_DEBUG, "%s: got a KVP: pool=%d key=%s val=%s", 357 __func__, pool, key, value); 358 359 if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) || 360 (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE)) { 361 syslog(LOG_ERR, "%s: Too long key or value: key=%s, val=%s", 362 __func__, key, value); 363 364 if (debug) 365 syslog(LOG_DEBUG, "%s: Too long key or value: pool=%d, key=%s, val=%s", 366 __func__, pool, key, value); 367 return 1; 368 } 369 370 /* 371 * First update the in-memory state. 372 */ 373 kvp_update_mem_state(pool); 374 375 num_records = kvp_file_info[pool].num_records; 376 record = kvp_file_info[pool].records; 377 num_blocks = kvp_file_info[pool].num_blocks; 378 379 for (i = 0; i < num_records; i++) { 380 if (memcmp(key, record[i].key, key_size)) 381 continue; 382 /* 383 * Found a match; just update the value - 384 * this is the modify case. 385 */ 386 memcpy(record[i].value, value, value_size); 387 kvp_update_file(pool); 388 if (debug) 389 syslog(LOG_DEBUG, "%s: updated: pool=%d key=%s val=%s", 390 __func__, pool, key, value); 391 return 0; 392 } 393 394 /* 395 * Need to add a new entry; 396 */ 397 if (num_records == (ENTRIES_PER_BLOCK * num_blocks)) { 398 /* Need to allocate a larger array for reg entries. */ 399 record = realloc(record, sizeof(struct kvp_record) * 400 ENTRIES_PER_BLOCK * (num_blocks + 1)); 401 402 if (!record) { 403 syslog(LOG_ERR, "%s: Memory alloc failure", __func__); 404 return 1; 405 } 406 kvp_file_info[pool].num_blocks++; 407 408 } 409 memcpy(record[i].value, value, value_size); 410 memcpy(record[i].key, key, key_size); 411 kvp_file_info[pool].records = record; 412 kvp_file_info[pool].num_records++; 413 414 if (debug) 415 syslog(LOG_DEBUG, "%s: added: pool=%d key=%s val=%s", 416 __func__, pool, key, value); 417 418 kvp_update_file(pool); 419 return 0; 420 } 421 422 static int kvp_get_value(int pool, const __u8 *key, int key_size, __u8 *value, 423 int value_size) 424 { 425 int i; 426 int num_records; 427 struct kvp_record *record; 428 429 if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) || 430 (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE)) 431 return 1; 432 433 /* 434 * First update the in-memory state. 435 */ 436 kvp_update_mem_state(pool); 437 438 num_records = kvp_file_info[pool].num_records; 439 record = kvp_file_info[pool].records; 440 441 for (i = 0; i < num_records; i++) { 442 if (memcmp(key, record[i].key, key_size)) 443 continue; 444 /* 445 * Found a match; just copy the value out. 446 */ 447 memcpy(value, record[i].value, value_size); 448 return 0; 449 } 450 451 return 1; 452 } 453 454 static int kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size, 455 __u8 *value, int value_size) 456 { 457 struct kvp_record *record; 458 459 /* 460 * First update our in-memory database. 461 */ 462 kvp_update_mem_state(pool); 463 record = kvp_file_info[pool].records; 464 465 if (index >= kvp_file_info[pool].num_records) { 466 return 1; 467 } 468 469 memcpy(key, record[index].key, key_size); 470 memcpy(value, record[index].value, value_size); 471 return 0; 472 } 473 474 475 void kvp_get_os_info(void) 476 { 477 FILE *file; 478 char *p, buf[512]; 479 480 uname(&uts_buf); 481 os_version = uts_buf.release; 482 os_build = strdup(uts_buf.release); 483 484 os_name = uts_buf.sysname; 485 processor_arch = uts_buf.machine; 486 487 /* 488 * The current windows host (win7) expects the build 489 * string to be of the form: x.y.z 490 * Strip additional information we may have. 491 */ 492 p = strchr(os_version, '-'); 493 if (p) 494 *p = '\0'; 495 496 /* 497 * Parse the /etc/os-release file if present: 498 * https://www.freedesktop.org/software/systemd/man/os-release.html 499 */ 500 file = fopen("/etc/os-release", "r"); 501 if (file != NULL) { 502 while (fgets(buf, sizeof(buf), file)) { 503 char *value, *q; 504 505 /* Ignore comments */ 506 if (buf[0] == '#') 507 continue; 508 509 /* Split into name=value */ 510 p = strchr(buf, '='); 511 if (!p) 512 continue; 513 *p++ = 0; 514 515 /* Remove quotes and newline; un-escape */ 516 value = p; 517 q = p; 518 while (*p) { 519 if (*p == '\\') { 520 ++p; 521 if (!*p) 522 break; 523 *q++ = *p++; 524 } else if (*p == '\'' || *p == '"' || 525 *p == '\n') { 526 ++p; 527 } else { 528 *q++ = *p++; 529 } 530 } 531 *q = 0; 532 533 if (!strcmp(buf, "NAME")) { 534 p = strdup(value); 535 if (!p) 536 break; 537 os_name = p; 538 } else if (!strcmp(buf, "VERSION_ID")) { 539 p = strdup(value); 540 if (!p) 541 break; 542 os_major = p; 543 } 544 } 545 fclose(file); 546 return; 547 } 548 549 /* Fallback for older RH/SUSE releases */ 550 file = fopen("/etc/SuSE-release", "r"); 551 if (file != NULL) 552 goto kvp_osinfo_found; 553 file = fopen("/etc/redhat-release", "r"); 554 if (file != NULL) 555 goto kvp_osinfo_found; 556 557 /* 558 * We don't have information about the os. 559 */ 560 return; 561 562 kvp_osinfo_found: 563 /* up to three lines */ 564 p = fgets(buf, sizeof(buf), file); 565 if (p) { 566 p = strchr(buf, '\n'); 567 if (p) 568 *p = '\0'; 569 p = strdup(buf); 570 if (!p) 571 goto done; 572 os_name = p; 573 574 /* second line */ 575 p = fgets(buf, sizeof(buf), file); 576 if (p) { 577 p = strchr(buf, '\n'); 578 if (p) 579 *p = '\0'; 580 p = strdup(buf); 581 if (!p) 582 goto done; 583 os_major = p; 584 585 /* third line */ 586 p = fgets(buf, sizeof(buf), file); 587 if (p) { 588 p = strchr(buf, '\n'); 589 if (p) 590 *p = '\0'; 591 p = strdup(buf); 592 if (p) 593 os_minor = p; 594 } 595 } 596 } 597 598 done: 599 fclose(file); 600 return; 601 } 602 603 604 605 /* 606 * Retrieve an interface name corresponding to the specified guid. 607 * If there is a match, the function returns a pointer 608 * to the interface name and if not, a NULL is returned. 609 * If a match is found, the caller is responsible for 610 * freeing the memory. 611 */ 612 613 static char *kvp_get_if_name(char *guid) 614 { 615 DIR *dir; 616 struct dirent *entry; 617 FILE *file; 618 char *p, *x; 619 char *if_name = NULL; 620 char buf[256]; 621 char dev_id[PATH_MAX]; 622 623 dir = opendir(KVP_NET_DIR); 624 if (dir == NULL) 625 return NULL; 626 627 while ((entry = readdir(dir)) != NULL) { 628 /* 629 * Set the state for the next pass. 630 */ 631 snprintf(dev_id, sizeof(dev_id), "%s%s/device/device_id", 632 KVP_NET_DIR, entry->d_name); 633 634 file = fopen(dev_id, "r"); 635 if (file == NULL) 636 continue; 637 638 p = fgets(buf, sizeof(buf), file); 639 if (p) { 640 x = strchr(p, '\n'); 641 if (x) 642 *x = '\0'; 643 644 if (!strcmp(p, guid)) { 645 /* 646 * Found the guid match; return the interface 647 * name. The caller will free the memory. 648 */ 649 if_name = strdup(entry->d_name); 650 fclose(file); 651 break; 652 } 653 } 654 fclose(file); 655 } 656 657 closedir(dir); 658 return if_name; 659 } 660 661 /* 662 * Retrieve the MAC address given the interface name. 663 */ 664 665 static char *kvp_if_name_to_mac(char *if_name) 666 { 667 FILE *file; 668 char *p, *x; 669 char buf[256]; 670 char addr_file[PATH_MAX]; 671 unsigned int i; 672 char *mac_addr = NULL; 673 674 snprintf(addr_file, sizeof(addr_file), "%s%s%s", KVP_NET_DIR, 675 if_name, "/address"); 676 677 file = fopen(addr_file, "r"); 678 if (file == NULL) 679 return NULL; 680 681 p = fgets(buf, sizeof(buf), file); 682 if (p) { 683 x = strchr(p, '\n'); 684 if (x) 685 *x = '\0'; 686 for (i = 0; i < strlen(p); i++) 687 p[i] = toupper(p[i]); 688 mac_addr = strdup(p); 689 } 690 691 fclose(file); 692 return mac_addr; 693 } 694 695 static void kvp_process_ipconfig_file(char *cmd, 696 char *config_buf, unsigned int len, 697 int element_size, int offset) 698 { 699 char buf[256]; 700 char *p; 701 char *x; 702 FILE *file; 703 704 /* 705 * First execute the command. 706 */ 707 file = popen(cmd, "r"); 708 if (file == NULL) 709 return; 710 711 if (offset == 0) 712 memset(config_buf, 0, len); 713 while ((p = fgets(buf, sizeof(buf), file)) != NULL) { 714 if (len < strlen(config_buf) + element_size + 1) 715 break; 716 717 x = strchr(p, '\n'); 718 if (x) 719 *x = '\0'; 720 721 strcat(config_buf, p); 722 strcat(config_buf, ";"); 723 } 724 pclose(file); 725 } 726 727 static bool kvp_verify_ip_address(const void *address_string) 728 { 729 char verify_buf[sizeof(struct in6_addr)]; 730 731 if (inet_pton(AF_INET, address_string, verify_buf) == 1) 732 return true; 733 if (inet_pton(AF_INET6, address_string, verify_buf) == 1) 734 return true; 735 return false; 736 } 737 738 static void kvp_extract_routes(const char *line, void **output, size_t *remaining) 739 { 740 static const char needle[] = "via "; 741 const char *match, *haystack = line; 742 743 while ((match = strstr(haystack, needle))) { 744 const char *address, *next_char; 745 746 /* Address starts after needle. */ 747 address = match + strlen(needle); 748 749 /* The char following address is a space or end of line. */ 750 next_char = strpbrk(address, " \t\\"); 751 if (!next_char) 752 next_char = address + strlen(address) + 1; 753 754 /* Enough room for address and semicolon. */ 755 if (*remaining >= (next_char - address) + 1) { 756 memcpy(*output, address, next_char - address); 757 /* Terminate string for verification. */ 758 memcpy(*output + (next_char - address), "", 1); 759 if (kvp_verify_ip_address(*output)) { 760 /* Advance output buffer. */ 761 *output += next_char - address; 762 *remaining -= next_char - address; 763 764 /* Each address needs a trailing semicolon. */ 765 memcpy(*output, ";", 1); 766 *output += 1; 767 *remaining -= 1; 768 } 769 } 770 haystack = next_char; 771 } 772 } 773 774 static void kvp_get_gateway(void *buffer, size_t buffer_len) 775 { 776 static const char needle[] = "default "; 777 FILE *f; 778 void *output = buffer; 779 char *line = NULL; 780 size_t alloc_size = 0, remaining = buffer_len - 1; 781 ssize_t num_chars; 782 783 /* Show route information in a single line, for each address family */ 784 f = popen("ip --oneline -4 route show;ip --oneline -6 route show", "r"); 785 if (!f) { 786 /* Convert buffer into C-String. */ 787 memcpy(output, "", 1); 788 return; 789 } 790 while ((num_chars = getline(&line, &alloc_size, f)) > 0) { 791 /* Skip short lines. */ 792 if (num_chars <= strlen(needle)) 793 continue; 794 /* Skip lines without default route. */ 795 if (memcmp(line, needle, strlen(needle))) 796 continue; 797 /* Remove trailing newline to simplify further parsing. */ 798 if (line[num_chars - 1] == '\n') 799 line[num_chars - 1] = '\0'; 800 /* Search routes after match. */ 801 kvp_extract_routes(line + strlen(needle), &output, &remaining); 802 } 803 /* Convert buffer into C-String. */ 804 memcpy(output, "", 1); 805 free(line); 806 pclose(f); 807 } 808 809 static void kvp_get_ipconfig_info(char *if_name, 810 struct hv_kvp_ipaddr_value *buffer) 811 { 812 char cmd[512]; 813 char dhcp_info[128]; 814 char *p; 815 FILE *file; 816 817 kvp_get_gateway(buffer->gate_way, sizeof(buffer->gate_way)); 818 819 /* 820 * Gather the DNS state. 821 * Since there is no standard way to get this information 822 * across various distributions of interest; we just invoke 823 * an external script that needs to be ported across distros 824 * of interest. 825 * 826 * Following is the expected format of the information from the script: 827 * 828 * ipaddr1 (nameserver1) 829 * ipaddr2 (nameserver2) 830 * . 831 * . 832 */ 833 834 sprintf(cmd, "exec %s %s", KVP_SCRIPTS_PATH "hv_get_dns_info", if_name); 835 836 /* 837 * Execute the command to gather DNS info. 838 */ 839 kvp_process_ipconfig_file(cmd, (char *)buffer->dns_addr, 840 (MAX_IP_ADDR_SIZE * 2), INET_ADDRSTRLEN, 0); 841 842 /* 843 * Gather the DHCP state. 844 * We will gather this state by invoking an external script. 845 * The parameter to the script is the interface name. 846 * Here is the expected output: 847 * 848 * Enabled: DHCP enabled. 849 */ 850 851 sprintf(cmd, "exec %s %s", KVP_SCRIPTS_PATH "hv_get_dhcp_info", if_name); 852 853 file = popen(cmd, "r"); 854 if (file == NULL) 855 return; 856 857 p = fgets(dhcp_info, sizeof(dhcp_info), file); 858 if (p == NULL) { 859 pclose(file); 860 return; 861 } 862 863 if (!strncmp(p, "Enabled", 7)) 864 buffer->dhcp_enabled = 1; 865 else 866 buffer->dhcp_enabled = 0; 867 868 pclose(file); 869 } 870 871 872 static unsigned int hweight32(unsigned int *w) 873 { 874 unsigned int res = *w - ((*w >> 1) & 0x55555555); 875 res = (res & 0x33333333) + ((res >> 2) & 0x33333333); 876 res = (res + (res >> 4)) & 0x0F0F0F0F; 877 res = res + (res >> 8); 878 return (res + (res >> 16)) & 0x000000FF; 879 } 880 881 static int kvp_process_ip_address(void *addrp, 882 int family, char *buffer, 883 int length, int *offset) 884 { 885 struct sockaddr_in *addr; 886 struct sockaddr_in6 *addr6; 887 int addr_length; 888 char tmp[50]; 889 const char *str; 890 891 if (family == AF_INET) { 892 addr = addrp; 893 str = inet_ntop(family, &addr->sin_addr, tmp, 50); 894 addr_length = INET_ADDRSTRLEN; 895 } else { 896 addr6 = addrp; 897 str = inet_ntop(family, &addr6->sin6_addr.s6_addr, tmp, 50); 898 addr_length = INET6_ADDRSTRLEN; 899 } 900 901 if ((length - *offset) < addr_length + 2) 902 return HV_E_FAIL; 903 if (str == NULL) { 904 strcpy(buffer, "inet_ntop failed\n"); 905 return HV_E_FAIL; 906 } 907 if (*offset == 0) 908 strcpy(buffer, tmp); 909 else { 910 strcat(buffer, ";"); 911 strcat(buffer, tmp); 912 } 913 914 *offset += strlen(str) + 1; 915 916 return 0; 917 } 918 919 static int 920 kvp_get_ip_info(int family, char *if_name, int op, 921 void *out_buffer, unsigned int length) 922 { 923 struct ifaddrs *ifap; 924 struct ifaddrs *curp; 925 int offset = 0; 926 int sn_offset = 0; 927 int error = 0; 928 char *buffer; 929 struct hv_kvp_ipaddr_value *ip_buffer = NULL; 930 char cidr_mask[5]; /* /xyz */ 931 int weight; 932 int i; 933 unsigned int *w; 934 char *sn_str; 935 struct sockaddr_in6 *addr6; 936 937 if (op == KVP_OP_ENUMERATE) { 938 buffer = out_buffer; 939 } else { 940 ip_buffer = out_buffer; 941 buffer = (char *)ip_buffer->ip_addr; 942 ip_buffer->addr_family = 0; 943 } 944 /* 945 * On entry into this function, the buffer is capable of holding the 946 * maximum key value. 947 */ 948 949 if (getifaddrs(&ifap)) { 950 strcpy(buffer, "getifaddrs failed\n"); 951 return HV_E_FAIL; 952 } 953 954 curp = ifap; 955 while (curp != NULL) { 956 if (curp->ifa_addr == NULL) { 957 curp = curp->ifa_next; 958 continue; 959 } 960 961 if ((if_name != NULL) && 962 (strncmp(curp->ifa_name, if_name, strlen(if_name)))) { 963 /* 964 * We want info about a specific interface; 965 * just continue. 966 */ 967 curp = curp->ifa_next; 968 continue; 969 } 970 971 /* 972 * We only support two address families: AF_INET and AF_INET6. 973 * If a family value of 0 is specified, we collect both 974 * supported address families; if not we gather info on 975 * the specified address family. 976 */ 977 if ((((family != 0) && 978 (curp->ifa_addr->sa_family != family))) || 979 (curp->ifa_flags & IFF_LOOPBACK)) { 980 curp = curp->ifa_next; 981 continue; 982 } 983 if ((curp->ifa_addr->sa_family != AF_INET) && 984 (curp->ifa_addr->sa_family != AF_INET6)) { 985 curp = curp->ifa_next; 986 continue; 987 } 988 989 if (op == KVP_OP_GET_IP_INFO) { 990 /* 991 * Gather info other than the IP address. 992 * IP address info will be gathered later. 993 */ 994 if (curp->ifa_addr->sa_family == AF_INET) { 995 ip_buffer->addr_family |= ADDR_FAMILY_IPV4; 996 /* 997 * Get subnet info. 998 */ 999 error = kvp_process_ip_address( 1000 curp->ifa_netmask, 1001 AF_INET, 1002 (char *) 1003 ip_buffer->sub_net, 1004 length, 1005 &sn_offset); 1006 if (error) 1007 goto gather_ipaddr; 1008 } else { 1009 ip_buffer->addr_family |= ADDR_FAMILY_IPV6; 1010 1011 /* 1012 * Get subnet info in CIDR format. 1013 */ 1014 weight = 0; 1015 sn_str = (char *)ip_buffer->sub_net; 1016 addr6 = (struct sockaddr_in6 *) 1017 curp->ifa_netmask; 1018 w = addr6->sin6_addr.s6_addr32; 1019 1020 for (i = 0; i < 4; i++) 1021 weight += hweight32(&w[i]); 1022 1023 sprintf(cidr_mask, "/%d", weight); 1024 if (length < sn_offset + strlen(cidr_mask) + 1) 1025 goto gather_ipaddr; 1026 1027 if (sn_offset == 0) 1028 strcpy(sn_str, cidr_mask); 1029 else { 1030 strcat((char *)ip_buffer->sub_net, ";"); 1031 strcat(sn_str, cidr_mask); 1032 } 1033 sn_offset += strlen(sn_str) + 1; 1034 } 1035 1036 /* 1037 * Collect other ip related configuration info. 1038 */ 1039 1040 kvp_get_ipconfig_info(if_name, ip_buffer); 1041 } 1042 1043 gather_ipaddr: 1044 error = kvp_process_ip_address(curp->ifa_addr, 1045 curp->ifa_addr->sa_family, 1046 buffer, 1047 length, &offset); 1048 if (error) 1049 goto getaddr_done; 1050 1051 curp = curp->ifa_next; 1052 } 1053 1054 getaddr_done: 1055 freeifaddrs(ifap); 1056 return error; 1057 } 1058 1059 /* 1060 * Retrieve the IP given the MAC address. 1061 */ 1062 static int kvp_mac_to_ip(struct hv_kvp_ipaddr_value *kvp_ip_val) 1063 { 1064 char *mac = (char *)kvp_ip_val->adapter_id; 1065 DIR *dir; 1066 struct dirent *entry; 1067 FILE *file; 1068 char *p, *x; 1069 char *if_name = NULL; 1070 char buf[256]; 1071 char dev_id[PATH_MAX]; 1072 unsigned int i; 1073 int error = HV_E_FAIL; 1074 1075 dir = opendir(KVP_NET_DIR); 1076 if (dir == NULL) 1077 return HV_E_FAIL; 1078 1079 while ((entry = readdir(dir)) != NULL) { 1080 /* 1081 * Set the state for the next pass. 1082 */ 1083 snprintf(dev_id, sizeof(dev_id), "%s%s/address", KVP_NET_DIR, 1084 entry->d_name); 1085 1086 file = fopen(dev_id, "r"); 1087 if (file == NULL) 1088 continue; 1089 1090 p = fgets(buf, sizeof(buf), file); 1091 fclose(file); 1092 if (!p) 1093 continue; 1094 1095 x = strchr(p, '\n'); 1096 if (x) 1097 *x = '\0'; 1098 1099 for (i = 0; i < strlen(p); i++) 1100 p[i] = toupper(p[i]); 1101 1102 if (strcmp(p, mac)) 1103 continue; 1104 1105 /* 1106 * Found the MAC match. 1107 * A NIC (e.g. VF) matching the MAC, but without IP, is skipped. 1108 */ 1109 if_name = entry->d_name; 1110 if (!if_name) 1111 continue; 1112 1113 error = kvp_get_ip_info(0, if_name, KVP_OP_GET_IP_INFO, 1114 kvp_ip_val, MAX_IP_ADDR_SIZE * 2); 1115 1116 if (!error && strlen((char *)kvp_ip_val->ip_addr)) 1117 break; 1118 } 1119 1120 closedir(dir); 1121 return error; 1122 } 1123 1124 static int expand_ipv6(char *addr, int type) 1125 { 1126 int ret; 1127 struct in6_addr v6_addr; 1128 1129 ret = inet_pton(AF_INET6, addr, &v6_addr); 1130 1131 if (ret != 1) { 1132 if (type == NETMASK) 1133 return 1; 1134 return 0; 1135 } 1136 1137 sprintf(addr, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:" 1138 "%02x%02x:%02x%02x:%02x%02x", 1139 (int)v6_addr.s6_addr[0], (int)v6_addr.s6_addr[1], 1140 (int)v6_addr.s6_addr[2], (int)v6_addr.s6_addr[3], 1141 (int)v6_addr.s6_addr[4], (int)v6_addr.s6_addr[5], 1142 (int)v6_addr.s6_addr[6], (int)v6_addr.s6_addr[7], 1143 (int)v6_addr.s6_addr[8], (int)v6_addr.s6_addr[9], 1144 (int)v6_addr.s6_addr[10], (int)v6_addr.s6_addr[11], 1145 (int)v6_addr.s6_addr[12], (int)v6_addr.s6_addr[13], 1146 (int)v6_addr.s6_addr[14], (int)v6_addr.s6_addr[15]); 1147 1148 return 1; 1149 1150 } 1151 1152 static int is_ipv4(char *addr) 1153 { 1154 int ret; 1155 struct in_addr ipv4_addr; 1156 1157 ret = inet_pton(AF_INET, addr, &ipv4_addr); 1158 1159 if (ret == 1) 1160 return 1; 1161 return 0; 1162 } 1163 1164 static int parse_ip_val_buffer(char *in_buf, int *offset, 1165 char *out_buf, int out_len) 1166 { 1167 char *x; 1168 char *start; 1169 1170 /* 1171 * in_buf has sequence of characters that are separated by 1172 * the character ';'. The last sequence does not have the 1173 * terminating ";" character. 1174 */ 1175 start = in_buf + *offset; 1176 1177 x = strchr(start, ';'); 1178 if (x) 1179 *x = 0; 1180 else 1181 x = start + strlen(start); 1182 1183 if (strlen(start) != 0) { 1184 int i = 0; 1185 /* 1186 * Get rid of leading spaces. 1187 */ 1188 while (start[i] == ' ') 1189 i++; 1190 1191 if ((x - start) <= out_len) { 1192 strcpy(out_buf, (start + i)); 1193 *offset += (x - start) + 1; 1194 return 1; 1195 } 1196 } 1197 return 0; 1198 } 1199 1200 static int kvp_write_file(FILE *f, char *s1, char *s2, char *s3) 1201 { 1202 int ret; 1203 1204 ret = fprintf(f, "%s%s%s%s\n", s1, s2, "=", s3); 1205 1206 if (ret < 0) 1207 return HV_E_FAIL; 1208 1209 return 0; 1210 } 1211 1212 1213 static int process_ip_string(FILE *f, char *ip_string, int type) 1214 { 1215 int error = 0; 1216 char addr[INET6_ADDRSTRLEN]; 1217 int i = 0; 1218 int j = 0; 1219 char str[256]; 1220 char sub_str[13]; 1221 int offset = 0; 1222 1223 memset(addr, 0, sizeof(addr)); 1224 1225 while (parse_ip_val_buffer(ip_string, &offset, addr, 1226 (MAX_IP_ADDR_SIZE * 2))) { 1227 1228 sub_str[0] = 0; 1229 if (is_ipv4(addr)) { 1230 switch (type) { 1231 case IPADDR: 1232 snprintf(str, sizeof(str), "%s", "IPADDR"); 1233 break; 1234 case NETMASK: 1235 snprintf(str, sizeof(str), "%s", "NETMASK"); 1236 break; 1237 case GATEWAY: 1238 snprintf(str, sizeof(str), "%s", "GATEWAY"); 1239 break; 1240 case DNS: 1241 snprintf(str, sizeof(str), "%s", "DNS"); 1242 break; 1243 } 1244 1245 if (type == DNS) { 1246 snprintf(sub_str, sizeof(sub_str), "%d", ++i); 1247 } else if (type == GATEWAY && i == 0) { 1248 ++i; 1249 } else { 1250 snprintf(sub_str, sizeof(sub_str), "%d", i++); 1251 } 1252 1253 1254 } else if (expand_ipv6(addr, type)) { 1255 switch (type) { 1256 case IPADDR: 1257 snprintf(str, sizeof(str), "%s", "IPV6ADDR"); 1258 break; 1259 case NETMASK: 1260 snprintf(str, sizeof(str), "%s", "IPV6NETMASK"); 1261 break; 1262 case GATEWAY: 1263 snprintf(str, sizeof(str), "%s", 1264 "IPV6_DEFAULTGW"); 1265 break; 1266 case DNS: 1267 snprintf(str, sizeof(str), "%s", "DNS"); 1268 break; 1269 } 1270 1271 if (type == DNS) { 1272 snprintf(sub_str, sizeof(sub_str), "%d", ++i); 1273 } else if (j == 0) { 1274 ++j; 1275 } else { 1276 snprintf(sub_str, sizeof(sub_str), "_%d", j++); 1277 } 1278 } else { 1279 return HV_INVALIDARG; 1280 } 1281 1282 error = kvp_write_file(f, str, sub_str, addr); 1283 if (error) 1284 return error; 1285 memset(addr, 0, sizeof(addr)); 1286 } 1287 1288 return 0; 1289 } 1290 1291 int ip_version_check(const char *input_addr) 1292 { 1293 struct in6_addr addr; 1294 1295 if (inet_pton(AF_INET, input_addr, &addr)) 1296 return IPV4; 1297 else if (inet_pton(AF_INET6, input_addr, &addr)) 1298 return IPV6; 1299 1300 return -EINVAL; 1301 } 1302 1303 /* 1304 * Only IPv4 subnet strings needs to be converted to plen 1305 * For IPv6 the subnet is already privided in plen format 1306 */ 1307 static int kvp_subnet_to_plen(char *subnet_addr_str) 1308 { 1309 int plen = 0; 1310 struct in_addr subnet_addr4; 1311 1312 /* 1313 * Convert subnet address to binary representation 1314 */ 1315 if (inet_pton(AF_INET, subnet_addr_str, &subnet_addr4) == 1) { 1316 uint32_t subnet_mask = ntohl(subnet_addr4.s_addr); 1317 1318 while (subnet_mask & 0x80000000) { 1319 plen++; 1320 subnet_mask <<= 1; 1321 } 1322 } else { 1323 return -1; 1324 } 1325 1326 return plen; 1327 } 1328 1329 static int process_dns_gateway_nm(FILE *f, char *ip_string, int type, 1330 int ip_sec) 1331 { 1332 char addr[INET6_ADDRSTRLEN], *output_str; 1333 int ip_offset = 0, error = 0, ip_ver; 1334 char *param_name; 1335 1336 if (type == DNS) 1337 param_name = "dns"; 1338 else if (type == GATEWAY) 1339 param_name = "gateway"; 1340 else 1341 return -EINVAL; 1342 1343 output_str = (char *)calloc(OUTSTR_BUF_SIZE, sizeof(char)); 1344 if (!output_str) 1345 return -ENOMEM; 1346 1347 while (1) { 1348 memset(addr, 0, sizeof(addr)); 1349 1350 if (!parse_ip_val_buffer(ip_string, &ip_offset, addr, 1351 (MAX_IP_ADDR_SIZE * 2))) 1352 break; 1353 1354 ip_ver = ip_version_check(addr); 1355 if (ip_ver < 0) 1356 continue; 1357 1358 if ((ip_ver == IPV4 && ip_sec == IPV4) || 1359 (ip_ver == IPV6 && ip_sec == IPV6)) { 1360 /* 1361 * do a bound check to avoid out-of bound writes 1362 */ 1363 if ((OUTSTR_BUF_SIZE - strlen(output_str)) > 1364 (strlen(addr) + 1)) { 1365 strncat(output_str, addr, 1366 OUTSTR_BUF_SIZE - 1367 strlen(output_str) - 1); 1368 strncat(output_str, ",", 1369 OUTSTR_BUF_SIZE - 1370 strlen(output_str) - 1); 1371 } 1372 } else { 1373 continue; 1374 } 1375 } 1376 1377 if (strlen(output_str)) { 1378 /* 1379 * This is to get rid of that extra comma character 1380 * in the end of the string 1381 */ 1382 output_str[strlen(output_str) - 1] = '\0'; 1383 error = fprintf(f, "%s=%s\n", param_name, output_str); 1384 } 1385 1386 free(output_str); 1387 return error; 1388 } 1389 1390 static int process_ip_string_nm(FILE *f, char *ip_string, char *subnet, 1391 int ip_sec) 1392 { 1393 char addr[INET6_ADDRSTRLEN]; 1394 char subnet_addr[INET6_ADDRSTRLEN]; 1395 int error = 0, i = 0; 1396 int ip_offset = 0, subnet_offset = 0; 1397 int plen, ip_ver; 1398 1399 memset(addr, 0, sizeof(addr)); 1400 memset(subnet_addr, 0, sizeof(subnet_addr)); 1401 1402 while (parse_ip_val_buffer(ip_string, &ip_offset, addr, 1403 (MAX_IP_ADDR_SIZE * 2)) && 1404 parse_ip_val_buffer(subnet, 1405 &subnet_offset, 1406 subnet_addr, 1407 (MAX_IP_ADDR_SIZE * 1408 2))) { 1409 ip_ver = ip_version_check(addr); 1410 if (ip_ver < 0) 1411 continue; 1412 1413 if (ip_ver == IPV4 && ip_sec == IPV4) 1414 plen = kvp_subnet_to_plen((char *)subnet_addr); 1415 else if (ip_ver == IPV6 && ip_sec == IPV6) 1416 plen = atoi(subnet_addr); 1417 else 1418 continue; 1419 1420 if (plen < 0) 1421 return plen; 1422 1423 error = fprintf(f, "address%d=%s/%d\n", ++i, (char *)addr, 1424 plen); 1425 if (error < 0) 1426 return error; 1427 1428 memset(addr, 0, sizeof(addr)); 1429 memset(subnet_addr, 0, sizeof(subnet_addr)); 1430 } 1431 1432 return error; 1433 } 1434 1435 static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val) 1436 { 1437 int error = 0, ip_ver; 1438 char if_filename[PATH_MAX]; 1439 char nm_filename[PATH_MAX]; 1440 FILE *ifcfg_file, *nmfile; 1441 char cmd[PATH_MAX]; 1442 char *mac_addr; 1443 int str_len; 1444 1445 /* 1446 * Set the configuration for the specified interface with 1447 * the information provided. Since there is no standard 1448 * way to configure an interface, we will have an external 1449 * script that does the job of configuring the interface and 1450 * flushing the configuration. 1451 * 1452 * The parameters passed to this external script are: 1453 * 1. A configuration file that has the specified configuration. 1454 * 1455 * We will embed the name of the interface in the configuration 1456 * file: ifcfg-ethx (where ethx is the interface name). 1457 * 1458 * The information provided here may be more than what is needed 1459 * in a given distro to configure the interface and so are free 1460 * ignore information that may not be relevant. 1461 * 1462 * Here is the ifcfg format of the ip configuration file: 1463 * 1464 * HWADDR=macaddr 1465 * DEVICE=interface name 1466 * BOOTPROTO=<protocol> (where <protocol> is "dhcp" if DHCP is configured 1467 * or "none" if no boot-time protocol should be used) 1468 * 1469 * IPADDR0=ipaddr1 1470 * IPADDR1=ipaddr2 1471 * IPADDRx=ipaddry (where y = x + 1) 1472 * 1473 * NETMASK0=netmask1 1474 * NETMASKx=netmasky (where y = x + 1) 1475 * 1476 * GATEWAY=ipaddr1 1477 * GATEWAYx=ipaddry (where y = x + 1) 1478 * 1479 * DNSx=ipaddrx (where first DNS address is tagged as DNS1 etc) 1480 * 1481 * IPV6 addresses will be tagged as IPV6ADDR, IPV6 gateway will be 1482 * tagged as IPV6_DEFAULTGW and IPV6 NETMASK will be tagged as 1483 * IPV6NETMASK. 1484 * 1485 * Here is the keyfile format of the ip configuration file: 1486 * 1487 * [ethernet] 1488 * mac-address=macaddr 1489 * [connection] 1490 * interface-name=interface name 1491 * 1492 * [ipv4] 1493 * method=<protocol> (where <protocol> is "auto" if DHCP is configured 1494 * or "manual" if no boot-time protocol should be used) 1495 * 1496 * address1=ipaddr1/plen 1497 * address2=ipaddr2/plen 1498 * 1499 * gateway=gateway1;gateway2 1500 * 1501 * dns=dns1;dns2 1502 * 1503 * [ipv6] 1504 * address1=ipaddr1/plen 1505 * address2=ipaddr2/plen 1506 * 1507 * gateway=gateway1;gateway2 1508 * 1509 * dns=dns1;dns2 1510 * 1511 * The host can specify multiple ipv4 and ipv6 addresses to be 1512 * configured for the interface. Furthermore, the configuration 1513 * needs to be persistent. A subsequent GET call on the interface 1514 * is expected to return the configuration that is set via the SET 1515 * call. 1516 */ 1517 1518 /* 1519 * We are populating both ifcfg and nmconnection files 1520 */ 1521 snprintf(if_filename, sizeof(if_filename), "%s%s%s", KVP_CONFIG_LOC, 1522 "/ifcfg-", if_name); 1523 1524 ifcfg_file = fopen(if_filename, "w"); 1525 1526 if (!ifcfg_file) { 1527 syslog(LOG_ERR, "Failed to open config file; error: %d %s", 1528 errno, strerror(errno)); 1529 return HV_E_FAIL; 1530 } 1531 1532 snprintf(nm_filename, sizeof(nm_filename), "%s%s%s%s", KVP_CONFIG_LOC, 1533 "/", if_name, ".nmconnection"); 1534 1535 nmfile = fopen(nm_filename, "w"); 1536 1537 if (!nmfile) { 1538 syslog(LOG_ERR, "Failed to open config file; error: %d %s", 1539 errno, strerror(errno)); 1540 fclose(ifcfg_file); 1541 return HV_E_FAIL; 1542 } 1543 1544 /* 1545 * First write out the MAC address. 1546 */ 1547 1548 mac_addr = kvp_if_name_to_mac(if_name); 1549 if (mac_addr == NULL) { 1550 error = HV_E_FAIL; 1551 goto setval_error; 1552 } 1553 1554 error = kvp_write_file(ifcfg_file, "HWADDR", "", mac_addr); 1555 if (error < 0) 1556 goto setmac_error; 1557 1558 error = kvp_write_file(ifcfg_file, "DEVICE", "", if_name); 1559 if (error < 0) 1560 goto setmac_error; 1561 1562 error = fprintf(nmfile, "\n[connection]\n"); 1563 if (error < 0) 1564 goto setmac_error; 1565 1566 error = kvp_write_file(nmfile, "interface-name", "", if_name); 1567 if (error) 1568 goto setmac_error; 1569 1570 error = fprintf(nmfile, "\n[ethernet]\n"); 1571 if (error < 0) 1572 goto setmac_error; 1573 1574 error = kvp_write_file(nmfile, "mac-address", "", mac_addr); 1575 if (error) 1576 goto setmac_error; 1577 1578 free(mac_addr); 1579 1580 /* 1581 * The dhcp_enabled flag is only for IPv4. In the case the host only 1582 * injects an IPv6 address, the flag is true, but we still need to 1583 * proceed to parse and pass the IPv6 information to the 1584 * disto-specific script hv_set_ifconfig. 1585 */ 1586 1587 /* 1588 * First populate the ifcfg file format 1589 */ 1590 if (new_val->dhcp_enabled) { 1591 error = kvp_write_file(ifcfg_file, "BOOTPROTO", "", "dhcp"); 1592 if (error) 1593 goto setval_error; 1594 } else { 1595 error = kvp_write_file(ifcfg_file, "BOOTPROTO", "", "none"); 1596 if (error) 1597 goto setval_error; 1598 } 1599 1600 error = process_ip_string(ifcfg_file, (char *)new_val->ip_addr, 1601 IPADDR); 1602 if (error) 1603 goto setval_error; 1604 1605 error = process_ip_string(ifcfg_file, (char *)new_val->sub_net, 1606 NETMASK); 1607 if (error) 1608 goto setval_error; 1609 1610 error = process_ip_string(ifcfg_file, (char *)new_val->gate_way, 1611 GATEWAY); 1612 if (error) 1613 goto setval_error; 1614 1615 error = process_ip_string(ifcfg_file, (char *)new_val->dns_addr, DNS); 1616 if (error) 1617 goto setval_error; 1618 1619 /* 1620 * Now we populate the keyfile format 1621 * 1622 * The keyfile format expects the IPv6 and IPv4 configuration in 1623 * different sections. Therefore we iterate through the list twice, 1624 * once to populate the IPv4 section and the next time for IPv6 1625 */ 1626 ip_ver = IPV4; 1627 do { 1628 if (ip_ver == IPV4) { 1629 error = fprintf(nmfile, "\n[ipv4]\n"); 1630 if (error < 0) 1631 goto setval_error; 1632 } else { 1633 error = fprintf(nmfile, "\n[ipv6]\n"); 1634 if (error < 0) 1635 goto setval_error; 1636 } 1637 1638 /* 1639 * Write the configuration for ipaddress, netmask, gateway and 1640 * name services 1641 */ 1642 error = process_ip_string_nm(nmfile, (char *)new_val->ip_addr, 1643 (char *)new_val->sub_net, 1644 ip_ver); 1645 if (error < 0) 1646 goto setval_error; 1647 1648 /* 1649 * As dhcp_enabled is only valid for ipv4, we do not set dhcp 1650 * methods for ipv6 based on dhcp_enabled flag. 1651 * 1652 * For ipv4, set method to manual only when dhcp_enabled is 1653 * false and specific ipv4 addresses are configured. If neither 1654 * dhcp_enabled is true and no ipv4 addresses are configured, 1655 * set method to 'disabled'. 1656 * 1657 * For ipv6, set method to manual when we configure ipv6 1658 * addresses. Otherwise set method to 'auto' so that SLAAC from 1659 * RA may be used. 1660 */ 1661 if (ip_ver == IPV4) { 1662 if (new_val->dhcp_enabled) { 1663 error = kvp_write_file(nmfile, "method", "", 1664 "auto"); 1665 if (error < 0) 1666 goto setval_error; 1667 } else if (error) { 1668 error = kvp_write_file(nmfile, "method", "", 1669 "manual"); 1670 if (error < 0) 1671 goto setval_error; 1672 } else { 1673 error = kvp_write_file(nmfile, "method", "", 1674 "disabled"); 1675 if (error < 0) 1676 goto setval_error; 1677 } 1678 } else if (ip_ver == IPV6) { 1679 if (error) { 1680 error = kvp_write_file(nmfile, "method", "", 1681 "manual"); 1682 if (error < 0) 1683 goto setval_error; 1684 } else { 1685 error = kvp_write_file(nmfile, "method", "", 1686 "auto"); 1687 if (error < 0) 1688 goto setval_error; 1689 } 1690 } 1691 1692 error = process_dns_gateway_nm(nmfile, 1693 (char *)new_val->gate_way, 1694 GATEWAY, ip_ver); 1695 if (error < 0) 1696 goto setval_error; 1697 1698 error = process_dns_gateway_nm(nmfile, 1699 (char *)new_val->dns_addr, DNS, 1700 ip_ver); 1701 if (error < 0) 1702 goto setval_error; 1703 1704 ip_ver++; 1705 } while (ip_ver < IP_TYPE_MAX); 1706 1707 fclose(nmfile); 1708 fclose(ifcfg_file); 1709 1710 /* 1711 * Now that we have populated the configuration file, 1712 * invoke the external script to do its magic. 1713 */ 1714 1715 str_len = snprintf(cmd, sizeof(cmd), "exec %s %s %s", 1716 KVP_SCRIPTS_PATH "hv_set_ifconfig", 1717 if_filename, nm_filename); 1718 /* 1719 * This is a little overcautious, but it's necessary to suppress some 1720 * false warnings from gcc 8.0.1. 1721 */ 1722 if (str_len <= 0 || (unsigned int)str_len >= sizeof(cmd)) { 1723 syslog(LOG_ERR, "Cmd '%s' (len=%d) may be too long", 1724 cmd, str_len); 1725 return HV_E_FAIL; 1726 } 1727 1728 if (system(cmd)) { 1729 syslog(LOG_ERR, "Failed to execute cmd '%s'; error: %d %s", 1730 cmd, errno, strerror(errno)); 1731 return HV_E_FAIL; 1732 } 1733 return 0; 1734 setmac_error: 1735 free(mac_addr); 1736 setval_error: 1737 syslog(LOG_ERR, "Failed to write config file"); 1738 fclose(ifcfg_file); 1739 fclose(nmfile); 1740 return error; 1741 } 1742 1743 1744 static void 1745 kvp_get_domain_name(char *buffer, int length) 1746 { 1747 struct addrinfo hints, *info ; 1748 int error = 0; 1749 1750 gethostname(buffer, length); 1751 memset(&hints, 0, sizeof(hints)); 1752 hints.ai_family = AF_INET; /*Get only ipv4 addrinfo. */ 1753 hints.ai_socktype = SOCK_STREAM; 1754 hints.ai_flags = AI_CANONNAME; 1755 1756 error = getaddrinfo(buffer, NULL, &hints, &info); 1757 if (error != 0) { 1758 snprintf(buffer, length, "getaddrinfo failed: 0x%x %s", 1759 error, gai_strerror(error)); 1760 return; 1761 } 1762 snprintf(buffer, length, "%s", info->ai_canonname); 1763 freeaddrinfo(info); 1764 } 1765 1766 void print_usage(char *argv[]) 1767 { 1768 fprintf(stderr, "Usage: %s [options]\n" 1769 "Options are:\n" 1770 " -n, --no-daemon stay in foreground, don't daemonize\n" 1771 " -d, --debug Enable debug logs(syslog debug by default)\n" 1772 " -h, --help print this help\n", argv[0]); 1773 } 1774 1775 int main(int argc, char *argv[]) 1776 { 1777 int kvp_fd = -1, len; 1778 int error; 1779 struct pollfd pfd; 1780 char *p; 1781 struct hv_kvp_msg hv_msg[1]; 1782 char *key_value; 1783 char *key_name; 1784 int op; 1785 int pool; 1786 char *if_name; 1787 struct hv_kvp_ipaddr_value *kvp_ip_val; 1788 int daemonize = 1, long_index = 0, opt; 1789 1790 static struct option long_options[] = { 1791 {"help", no_argument, 0, 'h' }, 1792 {"no-daemon", no_argument, 0, 'n' }, 1793 {"debug", no_argument, 0, 'd' }, 1794 {0, 0, 0, 0 } 1795 }; 1796 1797 while ((opt = getopt_long(argc, argv, "hnd", long_options, 1798 &long_index)) != -1) { 1799 switch (opt) { 1800 case 'n': 1801 daemonize = 0; 1802 break; 1803 case 'h': 1804 print_usage(argv); 1805 exit(0); 1806 case 'd': 1807 debug = 1; 1808 break; 1809 default: 1810 print_usage(argv); 1811 exit(EXIT_FAILURE); 1812 } 1813 } 1814 1815 if (daemonize && daemon(1, 0)) 1816 return 1; 1817 1818 openlog("KVP", 0, LOG_USER); 1819 syslog(LOG_INFO, "KVP starting; pid is:%d", getpid()); 1820 1821 /* 1822 * Retrieve OS release information. 1823 */ 1824 kvp_get_os_info(); 1825 /* 1826 * Cache Fully Qualified Domain Name because getaddrinfo takes an 1827 * unpredictable amount of time to finish. 1828 */ 1829 kvp_get_domain_name(full_domain_name, sizeof(full_domain_name)); 1830 1831 if (debug) 1832 syslog(LOG_INFO, "Logging debug info in syslog(debug)"); 1833 1834 if (kvp_file_init()) { 1835 syslog(LOG_ERR, "Failed to initialize the pools"); 1836 exit(EXIT_FAILURE); 1837 } 1838 1839 reopen_kvp_fd: 1840 if (kvp_fd != -1) 1841 close(kvp_fd); 1842 in_hand_shake = 1; 1843 kvp_fd = open("/dev/vmbus/hv_kvp", O_RDWR | O_CLOEXEC); 1844 1845 if (kvp_fd < 0) { 1846 syslog(LOG_ERR, "open /dev/vmbus/hv_kvp failed; error: %d %s", 1847 errno, strerror(errno)); 1848 exit(EXIT_FAILURE); 1849 } 1850 1851 /* 1852 * Register ourselves with the kernel. 1853 */ 1854 hv_msg->kvp_hdr.operation = KVP_OP_REGISTER1; 1855 len = write(kvp_fd, hv_msg, sizeof(struct hv_kvp_msg)); 1856 if (len != sizeof(struct hv_kvp_msg)) { 1857 syslog(LOG_ERR, "registration to kernel failed; error: %d %s", 1858 errno, strerror(errno)); 1859 close(kvp_fd); 1860 exit(EXIT_FAILURE); 1861 } 1862 1863 pfd.fd = kvp_fd; 1864 1865 while (1) { 1866 pfd.events = POLLIN; 1867 pfd.revents = 0; 1868 1869 if (poll(&pfd, 1, -1) < 0) { 1870 syslog(LOG_ERR, "poll failed; error: %d %s", errno, strerror(errno)); 1871 if (errno == EINVAL) { 1872 close(kvp_fd); 1873 exit(EXIT_FAILURE); 1874 } 1875 else 1876 continue; 1877 } 1878 1879 len = read(kvp_fd, hv_msg, sizeof(struct hv_kvp_msg)); 1880 1881 if (len != sizeof(struct hv_kvp_msg)) { 1882 syslog(LOG_ERR, "read failed; error:%d %s", 1883 errno, strerror(errno)); 1884 goto reopen_kvp_fd; 1885 } 1886 1887 /* 1888 * We will use the KVP header information to pass back 1889 * the error from this daemon. So, first copy the state 1890 * and set the error code to success. 1891 */ 1892 op = hv_msg->kvp_hdr.operation; 1893 pool = hv_msg->kvp_hdr.pool; 1894 hv_msg->error = HV_S_OK; 1895 1896 if ((in_hand_shake) && (op == KVP_OP_REGISTER1)) { 1897 /* 1898 * Driver is registering with us; stash away the version 1899 * information. 1900 */ 1901 in_hand_shake = 0; 1902 p = (char *)hv_msg->body.kvp_register.version; 1903 lic_version = malloc(strlen(p) + 1); 1904 if (lic_version) { 1905 strcpy(lic_version, p); 1906 syslog(LOG_INFO, "KVP LIC Version: %s", 1907 lic_version); 1908 } else { 1909 syslog(LOG_ERR, "malloc failed"); 1910 } 1911 continue; 1912 } 1913 1914 switch (op) { 1915 case KVP_OP_GET_IP_INFO: 1916 kvp_ip_val = &hv_msg->body.kvp_ip_val; 1917 1918 error = kvp_mac_to_ip(kvp_ip_val); 1919 1920 if (error) 1921 hv_msg->error = error; 1922 1923 break; 1924 1925 case KVP_OP_SET_IP_INFO: 1926 kvp_ip_val = &hv_msg->body.kvp_ip_val; 1927 if_name = kvp_get_if_name( 1928 (char *)kvp_ip_val->adapter_id); 1929 if (if_name == NULL) { 1930 /* 1931 * We could not map the guid to an 1932 * interface name; return error. 1933 */ 1934 hv_msg->error = HV_GUID_NOTFOUND; 1935 break; 1936 } 1937 error = kvp_set_ip_info(if_name, kvp_ip_val); 1938 if (error) 1939 hv_msg->error = error; 1940 1941 free(if_name); 1942 break; 1943 1944 case KVP_OP_SET: 1945 if (kvp_key_add_or_modify(pool, 1946 hv_msg->body.kvp_set.data.key, 1947 hv_msg->body.kvp_set.data.key_size, 1948 hv_msg->body.kvp_set.data.value, 1949 hv_msg->body.kvp_set.data.value_size)) 1950 hv_msg->error = HV_S_CONT; 1951 break; 1952 1953 case KVP_OP_GET: 1954 if (kvp_get_value(pool, 1955 hv_msg->body.kvp_set.data.key, 1956 hv_msg->body.kvp_set.data.key_size, 1957 hv_msg->body.kvp_set.data.value, 1958 hv_msg->body.kvp_set.data.value_size)) 1959 hv_msg->error = HV_S_CONT; 1960 break; 1961 1962 case KVP_OP_DELETE: 1963 if (kvp_key_delete(pool, 1964 hv_msg->body.kvp_delete.key, 1965 hv_msg->body.kvp_delete.key_size)) 1966 hv_msg->error = HV_S_CONT; 1967 break; 1968 1969 default: 1970 break; 1971 } 1972 1973 if (op != KVP_OP_ENUMERATE) 1974 goto kvp_done; 1975 1976 /* 1977 * If the pool is KVP_POOL_AUTO, dynamically generate 1978 * both the key and the value; if not read from the 1979 * appropriate pool. 1980 */ 1981 if (pool != KVP_POOL_AUTO) { 1982 if (kvp_pool_enumerate(pool, 1983 hv_msg->body.kvp_enum_data.index, 1984 hv_msg->body.kvp_enum_data.data.key, 1985 HV_KVP_EXCHANGE_MAX_KEY_SIZE, 1986 hv_msg->body.kvp_enum_data.data.value, 1987 HV_KVP_EXCHANGE_MAX_VALUE_SIZE)) 1988 hv_msg->error = HV_S_CONT; 1989 goto kvp_done; 1990 } 1991 1992 key_name = (char *)hv_msg->body.kvp_enum_data.data.key; 1993 key_value = (char *)hv_msg->body.kvp_enum_data.data.value; 1994 1995 switch (hv_msg->body.kvp_enum_data.index) { 1996 case FullyQualifiedDomainName: 1997 strcpy(key_value, full_domain_name); 1998 strcpy(key_name, "FullyQualifiedDomainName"); 1999 break; 2000 case IntegrationServicesVersion: 2001 strcpy(key_name, "IntegrationServicesVersion"); 2002 strcpy(key_value, lic_version); 2003 break; 2004 case NetworkAddressIPv4: 2005 kvp_get_ip_info(AF_INET, NULL, KVP_OP_ENUMERATE, 2006 key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE); 2007 strcpy(key_name, "NetworkAddressIPv4"); 2008 break; 2009 case NetworkAddressIPv6: 2010 kvp_get_ip_info(AF_INET6, NULL, KVP_OP_ENUMERATE, 2011 key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE); 2012 strcpy(key_name, "NetworkAddressIPv6"); 2013 break; 2014 case OSBuildNumber: 2015 strcpy(key_value, os_build); 2016 strcpy(key_name, "OSBuildNumber"); 2017 break; 2018 case OSName: 2019 strcpy(key_value, os_name); 2020 strcpy(key_name, "OSName"); 2021 break; 2022 case OSMajorVersion: 2023 strcpy(key_value, os_major); 2024 strcpy(key_name, "OSMajorVersion"); 2025 break; 2026 case OSMinorVersion: 2027 strcpy(key_value, os_minor); 2028 strcpy(key_name, "OSMinorVersion"); 2029 break; 2030 case OSVersion: 2031 strcpy(key_value, os_version); 2032 strcpy(key_name, "OSVersion"); 2033 break; 2034 case ProcessorArchitecture: 2035 strcpy(key_value, processor_arch); 2036 strcpy(key_name, "ProcessorArchitecture"); 2037 break; 2038 default: 2039 hv_msg->error = HV_S_CONT; 2040 break; 2041 } 2042 2043 /* 2044 * Send the value back to the kernel. Note: the write() may 2045 * return an error due to hibernation; we can ignore the error 2046 * by resetting the dev file, i.e. closing and re-opening it. 2047 */ 2048 kvp_done: 2049 len = write(kvp_fd, hv_msg, sizeof(struct hv_kvp_msg)); 2050 if (len != sizeof(struct hv_kvp_msg)) { 2051 syslog(LOG_ERR, "write failed; error: %d %s", errno, 2052 strerror(errno)); 2053 goto reopen_kvp_fd; 2054 } 2055 } 2056 2057 close(kvp_fd); 2058 exit(0); 2059 } 2060