ethsock.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826
  1. #include <sys/types.h>
  2. #include <stdbool.h>
  3. #include <string.h>
  4. #include <stdlib.h>
  5. #include <stdio.h>
  6. #include "nmrpd.h"
  7. #if defined(NMRPFLASH_WINDOWS)
  8. #define NMRPFLASH_NETALIAS_PREFIX "net"
  9. #define WPCAP
  10. #include <pcap.h>
  11. #else
  12. #include <sys/ioctl.h>
  13. #include <ifaddrs.h>
  14. #include <unistd.h>
  15. #include <net/if.h>
  16. #include <pcap.h>
  17. #if defined(NMRPFLASH_LINUX)
  18. #define NMRPFLASH_AF_PACKET AF_PACKET
  19. #include <linux/if_packet.h>
  20. #else
  21. #define NMRPFLASH_AF_PACKET AF_LINK
  22. #include <net/if_types.h>
  23. #endif
  24. #endif
  25. struct ethsock
  26. {
  27. const char *intf;
  28. pcap_t *pcap;
  29. #ifndef NMRPFLASH_WINDOWS
  30. int fd;
  31. #else
  32. HANDLE handle;
  33. DWORD index;
  34. #endif
  35. unsigned timeout;
  36. uint8_t hwaddr[6];
  37. };
  38. struct ethsock_arp_undo
  39. {
  40. uint32_t ipaddr;
  41. uint8_t hwaddr[6];
  42. };
  43. struct ethsock_ip_undo
  44. {
  45. #ifndef NMRPFLASH_WINDOWS
  46. uint32_t ip[2];
  47. #else
  48. ULONG context;
  49. #endif
  50. };
  51. const char *mac_to_str(uint8_t *mac)
  52. {
  53. static char buf[18];
  54. snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x",
  55. mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
  56. return buf;
  57. }
  58. static int x_pcap_findalldevs(pcap_if_t **devs)
  59. {
  60. char errbuf[PCAP_ERRBUF_SIZE];
  61. if (pcap_findalldevs(devs, errbuf) != 0) {
  62. fprintf(stderr, "%s.\n", errbuf);
  63. return -1;
  64. }
  65. return 0;
  66. }
  67. #ifndef NMRPFLASH_WINDOWS
  68. static inline bool sockaddr_get_hwaddr(struct sockaddr *sa, uint8_t *hwaddr)
  69. {
  70. void *src;
  71. if (sa->sa_family != NMRPFLASH_AF_PACKET) {
  72. return false;
  73. }
  74. #ifndef NMRPFLASH_LINUX
  75. if (((struct sockaddr_dl*)sa)->sdl_type != IFT_ETHER) {
  76. return false;
  77. }
  78. src = LLADDR((struct sockaddr_dl*)sa);
  79. #else
  80. src = ((struct sockaddr_ll*)sa)->sll_addr;
  81. #endif
  82. memcpy(hwaddr, src, 6);
  83. return true;
  84. }
  85. static bool get_intf_info(const char *intf, uint8_t *hwaddr, void *dummy)
  86. {
  87. struct ifaddrs *ifas, *ifa;
  88. bool found;
  89. if (getifaddrs(&ifas) != 0) {
  90. perror("getifaddrs");
  91. return false;
  92. }
  93. found = false;
  94. for (ifa = ifas; ifa; ifa = ifa->ifa_next) {
  95. if (!strcmp(ifa->ifa_name, intf)) {
  96. if (sockaddr_get_hwaddr(ifa->ifa_addr, hwaddr)) {
  97. found = true;
  98. break;
  99. }
  100. }
  101. }
  102. freeifaddrs(ifas);
  103. return found;
  104. }
  105. #else
  106. void win_perror2(const char *msg, DWORD err)
  107. {
  108. char *buf = NULL;
  109. FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  110. FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
  111. NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  112. (LPTSTR)&buf, 0, NULL);
  113. if (buf) {
  114. /* FormatMessageA terminates buf with CRLF! */
  115. fprintf(stderr, "%s: %s", msg, buf);
  116. LocalFree(buf);
  117. } else {
  118. fprintf(stderr, "%s: error %d\n", msg, (int)err);
  119. }
  120. }
  121. static bool get_intf_info(const char *intf, uint8_t *hwaddr, DWORD *index)
  122. {
  123. PIP_ADAPTER_INFO adapters, adapter;
  124. DWORD ret;
  125. ULONG i, bufLen = 0;
  126. bool found = false;
  127. if ((ret = GetAdaptersInfo(NULL, &bufLen)) != ERROR_BUFFER_OVERFLOW) {
  128. win_perror2("GetAdaptersInfo", ret);
  129. return false;
  130. }
  131. adapters = malloc(bufLen);
  132. if (!adapters) {
  133. perror("malloc");
  134. return false;
  135. }
  136. if ((ret = GetAdaptersInfo(adapters, &bufLen) == NO_ERROR)) {
  137. for (adapter = adapters; adapter; adapter = adapter->Next) {
  138. if (adapter->Type != MIB_IF_TYPE_ETHERNET && adapter->Type != IF_TYPE_IEEE80211) {
  139. continue;
  140. }
  141. /* Interface names from WinPcap are "\Device\NPF_{GUID}", while
  142. * AdapterName from GetAdaptersInfo is just "{GUID}".*/
  143. if (strstr(intf, adapter->AdapterName)) {
  144. if (adapter->AddressLength == 6) {
  145. memcpy(hwaddr, adapter->Address, 6);
  146. if (index) {
  147. *index = adapter->Index;
  148. }
  149. found = true;
  150. break;
  151. }
  152. }
  153. }
  154. } else {
  155. win_perror2("GetAdaptersInfo", ret);
  156. }
  157. free(adapters);
  158. return found;
  159. }
  160. static const char *intf_alias_to_wpcap(const char *intf)
  161. {
  162. static char buf[128];
  163. pcap_if_t *devs, *dev;
  164. unsigned i = 0, dev_num = 0;
  165. if (intf[0] == '\\') {
  166. return intf;
  167. } else if (sscanf(intf, NMRPFLASH_NETALIAS_PREFIX "%u", &dev_num) != 1) {
  168. fprintf(stderr, "Invalid interface alias.\n");
  169. return NULL;
  170. }
  171. if (x_pcap_findalldevs(&devs) != 0) {
  172. return NULL;
  173. }
  174. for (dev = devs; dev; dev = dev->next, ++i) {
  175. if (i == dev_num) {
  176. if (verbosity) {
  177. printf("%s%u: %s\n", NMRPFLASH_NETALIAS_PREFIX, i, dev->name);
  178. }
  179. strncpy(buf, dev->name, sizeof(buf) - 1);
  180. buf[sizeof(buf) - 1] = '\0';
  181. break;
  182. }
  183. }
  184. pcap_freealldevs(devs);
  185. if (!dev) {
  186. fprintf(stderr, "Interface alias not found.\n");
  187. return NULL;
  188. }
  189. return buf;
  190. }
  191. static const char *intf_get_pretty_name(const char *intf)
  192. {
  193. static char buf[512];
  194. char *guid;
  195. HKEY hkey;
  196. LONG err;
  197. DWORD len;
  198. guid = strstr(intf, "NPF_{");
  199. if (!guid) {
  200. return NULL;
  201. }
  202. guid += 4;
  203. snprintf(buf, sizeof(buf),
  204. "System\\CurrentControlSet\\Control\\Network\\"
  205. "{4D36E972-E325-11CE-BFC1-08002BE10318}\\"
  206. "%s\\Connection", guid);
  207. err = RegOpenKeyExA(HKEY_LOCAL_MACHINE, buf, 0, KEY_READ, &hkey);
  208. if (err != ERROR_SUCCESS) {
  209. if (verbosity > 1) {
  210. win_perror2("RegOpenKeyExA", err);
  211. }
  212. return NULL;
  213. }
  214. len = sizeof(buf);
  215. err = RegQueryValueExA(hkey, "Name", NULL, NULL, (LPBYTE)buf, &len);
  216. if (err == ERROR_SUCCESS) {
  217. intf = buf;
  218. } else {
  219. if (verbosity > 1) {
  220. win_perror2("RegQueryValueExA", err);
  221. }
  222. intf = NULL;
  223. }
  224. RegCloseKey(hkey);
  225. return intf;
  226. }
  227. #endif
  228. inline uint8_t *ethsock_get_hwaddr(struct ethsock *sock)
  229. {
  230. return sock->hwaddr;
  231. }
  232. struct ethsock *ethsock_create(const char *intf, uint16_t protocol)
  233. {
  234. char buf[PCAP_ERRBUF_SIZE];
  235. struct bpf_program fp;
  236. struct ethsock *sock;
  237. int err;
  238. sock = malloc(sizeof(struct ethsock));
  239. if (!sock) {
  240. perror("malloc");
  241. return NULL;
  242. }
  243. #ifdef NMRPFLASH_WINDOWS
  244. intf = intf_alias_to_wpcap(intf);
  245. if (!intf) {
  246. return NULL;
  247. }
  248. #endif
  249. buf[0] = '\0';
  250. sock->intf = intf;
  251. sock->pcap = pcap_open_live(sock->intf, BUFSIZ, 1, 1, buf);
  252. if (!sock->pcap) {
  253. fprintf(stderr, "%s.\n", buf);
  254. goto cleanup_malloc;
  255. }
  256. if (*buf) {
  257. fprintf(stderr, "Warning: %s.\n", buf);
  258. }
  259. if (pcap_datalink(sock->pcap) != DLT_EN10MB) {
  260. fprintf(stderr, "%s is not an ethernet interface.\n",
  261. intf);
  262. goto cleanup_pcap;
  263. }
  264. #ifndef NMRPFLASH_WINDOWS
  265. err = !get_intf_info(intf, sock->hwaddr, NULL);
  266. #else
  267. err = !get_intf_info(intf, sock->hwaddr, &sock->index);
  268. #endif
  269. if (err) {
  270. fprintf(stderr, "Failed to get interface info.\n");
  271. goto cleanup_malloc;
  272. }
  273. #ifndef NMRPFLASH_WINDOWS
  274. sock->fd = pcap_get_selectable_fd(sock->pcap);
  275. if (sock->fd == -1) {
  276. pcap_perror(sock->pcap, "pcap_get_selectable_fd");
  277. goto cleanup_pcap;
  278. }
  279. #else
  280. sock->handle = pcap_getevent(sock->pcap);
  281. if (!sock->handle) {
  282. pcap_perror(sock->pcap, "pcap_getevent");
  283. goto cleanup_pcap;
  284. }
  285. err = pcap_setmintocopy(sock->pcap, 1);
  286. if (err) {
  287. pcap_perror(sock->pcap, "pcap_setmintocopy");
  288. goto cleanup_pcap;
  289. }
  290. #endif
  291. snprintf(buf, sizeof(buf), "ether proto 0x%04x and not ether src %s",
  292. protocol, mac_to_str(sock->hwaddr));
  293. err = pcap_compile(sock->pcap, &fp, buf, 0, 0);
  294. if (err) {
  295. pcap_perror(sock->pcap, "pcap_compile");
  296. goto cleanup_pcap;
  297. }
  298. err = pcap_setfilter(sock->pcap, &fp);
  299. pcap_freecode(&fp);
  300. if (err) {
  301. pcap_perror(sock->pcap, "pcap_setfilter");
  302. goto cleanup_pcap;
  303. }
  304. return sock;
  305. cleanup_pcap:
  306. pcap_close(sock->pcap);
  307. cleanup_malloc:
  308. free(sock);
  309. return NULL;
  310. }
  311. int select_fd(int fd, unsigned timeout)
  312. {
  313. struct timeval tv;
  314. int status;
  315. fd_set fds;
  316. FD_ZERO(&fds);
  317. FD_SET(fd, &fds);
  318. tv.tv_sec = timeout / 1000;
  319. tv.tv_usec = 1000 * (timeout % 1000);
  320. status = select(fd + 1, &fds, NULL, NULL, &tv);
  321. if (status < 0) {
  322. sock_perror("select");
  323. }
  324. return status;
  325. }
  326. ssize_t ethsock_recv(struct ethsock *sock, void *buf, size_t len)
  327. {
  328. struct pcap_pkthdr* hdr;
  329. const u_char *capbuf;
  330. int status;
  331. #ifdef NMRPFLASH_WINDOWS
  332. DWORD ret;
  333. if (sock->timeout) {
  334. ret = WaitForSingleObject(sock->handle, sock->timeout);
  335. if (ret == WAIT_TIMEOUT) {
  336. return 0;
  337. } else if (ret != WAIT_OBJECT_0) {
  338. win_perror2("WaitForSingleObject", ret);
  339. return -1;
  340. }
  341. }
  342. #else
  343. if (sock->timeout) {
  344. status = select_fd(sock->fd, sock->timeout);
  345. if (status < 0) {
  346. return -1;
  347. } else if (status == 0) {
  348. return 0;
  349. }
  350. }
  351. #endif
  352. status = pcap_next_ex(sock->pcap, &hdr, &capbuf);
  353. switch (status) {
  354. case 1:
  355. memcpy(buf, capbuf, MIN(len, hdr->caplen));
  356. return hdr->caplen;
  357. case 0:
  358. return 0;
  359. case -1:
  360. pcap_perror(sock->pcap, "pcap_next_ex");
  361. return -1;
  362. default:
  363. fprintf(stderr, "pcap_next_ex: returned %d.\n", status);
  364. return -1;
  365. }
  366. }
  367. int ethsock_send(struct ethsock *sock, void *buf, size_t len)
  368. {
  369. #ifdef NMRPFLASH_WINDOWS
  370. if (pcap_sendpacket(sock->pcap, buf, len) == 0) {
  371. return 0;
  372. } else {
  373. pcap_perror(sock->pcap, "pcap_sendpacket");
  374. return -1;
  375. }
  376. #else
  377. if (pcap_inject(sock->pcap, buf, len) == len) {
  378. return 0;
  379. } else {
  380. pcap_perror(sock->pcap, "pcap_inject");
  381. return -1;
  382. }
  383. #endif
  384. }
  385. int ethsock_close(struct ethsock *sock)
  386. {
  387. pcap_close(sock->pcap);
  388. free(sock);
  389. return 0;
  390. }
  391. inline int ethsock_set_timeout(struct ethsock *sock, unsigned msec)
  392. {
  393. sock->timeout = msec;
  394. return 0;
  395. }
  396. #ifndef NMRPFLASH_WINDOWS
  397. int ethsock_arp_add(struct ethsock *sock, uint8_t *hwaddr, uint32_t ipaddr, struct ethsock_arp_undo **undo)
  398. {
  399. return 0;
  400. }
  401. int ethsock_arp_del(struct ethsock *sock, struct ethsock_arp_undo **undo)
  402. {
  403. return 0;
  404. }
  405. #else
  406. static int ethsock_arp(struct ethsock *sock, uint8_t *hwaddr, uint32_t ipaddr, struct ethsock_arp_undo **undo)
  407. {
  408. DWORD ret;
  409. MIB_IPNETROW arp = {
  410. .dwIndex = sock->index,
  411. .dwPhysAddrLen = 6,
  412. .dwAddr = ipaddr,
  413. .dwType = MIB_IPNET_TYPE_STATIC
  414. };
  415. memcpy(arp.bPhysAddr, hwaddr, 6);
  416. if (undo) {
  417. ret = CreateIpNetEntry(&arp);
  418. if (ret != NO_ERROR) {
  419. win_perror2("CreateIpNetEntry", ret);
  420. return -1;
  421. }
  422. *undo = malloc(sizeof(struct ethsock_arp_undo));
  423. if (!*undo) {
  424. perror("malloc");
  425. return -1;
  426. }
  427. (*undo)->ipaddr = ipaddr;
  428. memcpy((*undo)->hwaddr, hwaddr, 6);
  429. } else {
  430. DeleteIpNetEntry(&arp);
  431. }
  432. return 0;
  433. }
  434. int ethsock_arp_add(struct ethsock *sock, uint8_t *hwaddr, uint32_t ipaddr, struct ethsock_arp_undo **undo)
  435. {
  436. ethsock_arp(sock, hwaddr, ipaddr, NULL);
  437. return undo ? ethsock_arp(sock, hwaddr, ipaddr, undo) : -1;
  438. }
  439. int ethsock_arp_del(struct ethsock *sock, struct ethsock_arp_undo **undo)
  440. {
  441. if (!*undo) {
  442. return 0;
  443. }
  444. int ret = ethsock_arp(sock, (*undo)->hwaddr, (*undo)->ipaddr, NULL);
  445. free(*undo);
  446. *undo = NULL;
  447. return ret;
  448. }
  449. #endif
  450. static bool get_hwaddr_from_pcap(const pcap_if_t *dev, uint8_t *hwaddr)
  451. {
  452. #ifndef NMRPFLASH_WINDOWS
  453. pcap_addr_t *addr;
  454. int i;
  455. for (addr = dev->addresses; addr; addr = addr->next) {
  456. if (verbosity > 1) {
  457. printf("%s: sa_family=%d, sa_data={ ", dev->name,
  458. addr->addr->sa_family);
  459. for (i = 0; i != sizeof(addr->addr->sa_data); ++i) {
  460. printf("%02x ", addr->addr->sa_data[i] & 0xff);
  461. }
  462. printf("}\n");
  463. }
  464. if (sockaddr_get_hwaddr(addr->addr, hwaddr)) {
  465. return true;
  466. }
  467. }
  468. #endif
  469. return get_intf_info(dev->name, hwaddr, NULL);
  470. }
  471. int ethsock_list_all(void)
  472. {
  473. pcap_if_t *devs, *dev;
  474. pcap_addr_t *addr;
  475. uint8_t hwaddr[6];
  476. unsigned dev_num = 0, dev_ok = 0;
  477. #ifdef NMRPFLASH_WINDOWS
  478. const char *pretty;
  479. #endif
  480. if (x_pcap_findalldevs(&devs) != 0) {
  481. return -1;
  482. }
  483. memset(hwaddr, 0, 6);
  484. for (dev = devs; dev; dev = dev->next, ++dev_num) {
  485. if (dev->flags & PCAP_IF_LOOPBACK) {
  486. if (verbosity) {
  487. printf("%-15s (loopback device)\n", dev->name);
  488. }
  489. continue;
  490. }
  491. if (!get_hwaddr_from_pcap(dev, hwaddr)) {
  492. if (verbosity) {
  493. printf("%-15s (not an ethernet device)\n",
  494. dev->name);
  495. }
  496. continue;
  497. }
  498. #ifndef NMRPFLASH_WINDOWS
  499. printf("%-15s", dev->name);
  500. #else
  501. /* Call this here so *_perror() calls don't happen within a line */
  502. pretty = intf_get_pretty_name(dev->name);
  503. if (!verbosity) {
  504. printf("%s%u", NMRPFLASH_NETALIAS_PREFIX, dev_num);
  505. } else {
  506. printf("%s", dev->name);
  507. }
  508. #endif
  509. for (addr = dev->addresses; addr; addr = addr->next) {
  510. if (addr->addr->sa_family == AF_INET) {
  511. printf(" %-15s",
  512. inet_ntoa(((struct sockaddr_in*)addr->addr)->sin_addr));
  513. break;
  514. }
  515. }
  516. if (!addr) {
  517. printf(" %-15s", "0.0.0.0");
  518. }
  519. printf(" %s", mac_to_str(hwaddr));
  520. #ifdef NMRPFLASH_WINDOWS
  521. if (pretty) {
  522. printf(" (%s)", pretty);
  523. } else if (dev->description) {
  524. printf(" (%s)", dev->description);
  525. }
  526. #endif
  527. printf("\n");
  528. ++dev_ok;
  529. }
  530. if (!dev_ok) {
  531. printf("No suitable network interfaces found.\n");
  532. }
  533. return 0;
  534. }
  535. int ethsock_for_each_ip(struct ethsock *sock, ethsock_ip_callback_t callback,
  536. void *arg)
  537. {
  538. struct ethsock_ip_callback_args args;
  539. pcap_if_t *devs, *dev;
  540. pcap_addr_t *addr;
  541. int status = 0;
  542. if (x_pcap_findalldevs(&devs) != 0) {
  543. return -1;
  544. }
  545. args.arg = arg;
  546. for (dev = devs; dev; dev = dev->next) {
  547. if (strcmp(sock->intf, dev->name)) {
  548. continue;
  549. }
  550. for (addr = dev->addresses; addr; addr = addr->next) {
  551. if (addr->addr->sa_family == AF_INET) {
  552. args.ipaddr = &((struct sockaddr_in*)addr->addr)->sin_addr;
  553. args.ipmask = &((struct sockaddr_in*)addr->netmask)->sin_addr;
  554. status = callback(&args);
  555. if (status <= 0) {
  556. break;
  557. }
  558. }
  559. }
  560. break;
  561. }
  562. pcap_freealldevs(devs);
  563. return status <= 0 ? status : 0;
  564. }
  565. static inline void set_addr(void *p, uint32_t addr)
  566. {
  567. struct sockaddr_in* sin = p;
  568. sin->sin_family = AF_INET;
  569. sin->sin_addr.s_addr = addr;
  570. }
  571. #ifndef NMRPFLASH_WINDOWS
  572. static bool set_interface_up(int fd, const char *intf, bool up)
  573. {
  574. struct ifreq ifr;
  575. strncpy(ifr.ifr_name, intf, IFNAMSIZ);
  576. if (ioctl(fd, SIOCGIFFLAGS, &ifr) != 0) {
  577. perror("ioctl(SIOCGIFFLAGS)");
  578. return false;
  579. }
  580. if (!up) {
  581. ifr.ifr_flags &= ~(IFF_UP | IFF_RUNNING);
  582. } else {
  583. ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
  584. }
  585. if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0) {
  586. perror("ioctl(SIOCSIFFLAGS)");
  587. return false;
  588. }
  589. return true;
  590. }
  591. #endif
  592. int ethsock_ip_add(struct ethsock *sock, uint32_t ipaddr, uint32_t ipmask, struct ethsock_ip_undo **undo)
  593. {
  594. if (undo && !(*undo = malloc(sizeof(struct ethsock_ip_undo)))) {
  595. perror("malloc");
  596. return -1;
  597. }
  598. int fd = socket(AF_INET, SOCK_DGRAM, 0);
  599. if (!fd) {
  600. sock_perror("socket");
  601. return -1;
  602. }
  603. int ret = -1;
  604. #ifndef NMRPFLASH_WINDOWS
  605. // XXX: undo is non-zero only if we're adding an IP
  606. bool add = undo;
  607. #ifdef NMRPFLASH_LINUX
  608. struct ifreq ifr;
  609. strncpy(ifr.ifr_name, sock->intf, IFNAMSIZ);
  610. // FIXME: automatically determine the next free alias
  611. strcat(ifr.ifr_name, ":42");
  612. if (add) {
  613. set_addr(&ifr.ifr_addr, ipaddr);
  614. if (ioctl(fd, SIOCSIFADDR, &ifr) != 0) {
  615. perror("ioctl(SIOSIFADDR)");
  616. goto out;
  617. }
  618. set_addr(&ifr.ifr_netmask, ipmask);
  619. if (ioctl(fd, SIOCSIFNETMASK, &ifr) != 0) {
  620. perror("ioctl(SIOCSIFNETMASK)");
  621. goto out;
  622. }
  623. (*undo)->ip[0] = ipaddr;
  624. (*undo)->ip[1] = ipmask;
  625. }
  626. if (!set_interface_up(fd, ifr.ifr_name, add ? true : false)) {
  627. goto out;
  628. }
  629. #else // NMRPFLASH_OSX (or any other BSD)
  630. struct ifaliasreq ifra;
  631. strncpy(ifra.ifra_name, sock->intf, IFNAMSIZ);
  632. set_addr(&ifra.ifra_addr, ipaddr);
  633. set_addr(&ifra.ifra_mask, ipmask);
  634. //set_addr(&ifra.ifra_broadaddr, (ipaddr & ipmask) | ~ipmask);
  635. memset(&ifra.ifra_broadaddr, 0, sizeof(ifra.ifra_broadaddr));
  636. if (ioctl(fd, add ? SIOCAIFADDR : SIOCDIFADDR, &ifra) != 0) {
  637. perror(add ? "ioctl(SIOCAIFADDR)" : "ioctl(SIOCDIFADDR)");
  638. goto out;
  639. }
  640. if (add) {
  641. (*undo)->ip[0] = ipaddr;
  642. (*undo)->ip[1] = ipmask;
  643. set_interface_up(fd, ifra.ifra_name, true);
  644. }
  645. #endif
  646. #else // NMRPFLASH_WINDOWS
  647. struct sockaddr_in sin;
  648. ULONG instance;
  649. (*undo)->context = 0;
  650. DWORD err = AddIPAddress(ipaddr, ipmask, sock->index, &(*undo)->context, &instance);
  651. if (err != NO_ERROR && err != ERROR_DUP_DOMAINNAME && err != ERROR_OBJECT_ALREADY_EXISTS) {
  652. win_perror2("AddIPAddress", err);
  653. goto out;
  654. }
  655. set_addr(&sin, ipaddr);
  656. time_t beg = time_monotonic();
  657. /* Wait until the new IP has actually been added */
  658. while (bind(fd, (struct sockaddr*)&sin, sizeof(sin)) != 0) {
  659. if ((time_monotonic() - beg) >= 5) {
  660. fprintf(stderr, "Failed to bind after 5 seconds: ");
  661. sock_perror("bind");
  662. DeleteIPAddress((*undo)->context);
  663. goto out;
  664. }
  665. }
  666. #endif
  667. ret = 0;
  668. out:
  669. #ifndef NMRPFLASH_WINDOWS
  670. close(fd);
  671. #else
  672. closesocket(fd);
  673. #endif
  674. return ret;
  675. }
  676. int ethsock_ip_del(struct ethsock *sock, struct ethsock_ip_undo **undo)
  677. {
  678. if (!*undo) {
  679. return 0;
  680. }
  681. int ret;
  682. #ifndef NMRPFLASH_WINDOWS
  683. if ((*undo)->ip[0] != INADDR_NONE) {
  684. ret = ethsock_ip_add(sock, (*undo)->ip[0], (*undo)->ip[1], NULL);
  685. } else {
  686. ret = 0;
  687. }
  688. #else
  689. DeleteIPAddress((*undo)->context);
  690. ret = 0;
  691. #endif
  692. free(*undo);
  693. *undo = NULL;
  694. return ret;
  695. }