hv_kvp_daemon.c 46 KB

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