netbios_ns.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973
  1. /*****************************************************************************
  2. * __________________ _________ _____ _____ .__ ._.
  3. * \______ \______ \ / _____/ / \ / _ \ |__| ____ | |
  4. * | | _/| | \ \_____ \ / \ / \ / /_\ \| _/ __ \ | |
  5. * | | \| ` \/ / Y \ / | | \ ___/ \|
  6. * |______ /_______ /_______ \____|__ / /\ \____|__ |__|\___ | __
  7. * \/ \/ \/ \/ )/ \/ \/ \/
  8. *
  9. * This file is part of liBDSM. Copyright © 2014-2015 VideoLabs SAS
  10. *
  11. * Author: Julien 'Lta' BALLET <contact@lta.io>
  12. * Thomas Guillem <tguillem@videolabs.io>
  13. *
  14. * liBDSM is released under LGPLv2.1 (or later) and is also available
  15. * under a commercial license.
  16. *****************************************************************************
  17. * This program is free software; you can redistribute it and/or modify it
  18. * under the terms of the GNU Lesser General Public License as published by
  19. * the Free Software Foundation; either version 2.1 of the License, or
  20. * (at your option) any later version.
  21. *
  22. * This program is distributed in the hope that it will be useful,
  23. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  24. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  25. * GNU Lesser General Public License for more details.
  26. *
  27. * You should have received a copy of the GNU Lesser General Public License
  28. * along with this program; if not, write to the Free Software Foundation,
  29. * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  30. *****************************************************************************/
  31. #include "config.h"
  32. #include <stdlib.h>
  33. #include <stdio.h>
  34. #include <string.h>
  35. #include <stdbool.h>
  36. #include <pthread.h>
  37. #ifdef HAVE_SYS_TIME_H
  38. #include <sys/time.h>
  39. #endif
  40. #include <unistd.h>
  41. #include <fcntl.h>
  42. #include <errno.h>
  43. #include <assert.h>
  44. #ifdef HAVE_SYS_QUEUE_H
  45. # include <sys/queue.h>
  46. #endif
  47. #ifdef HAVE_ARPA_INET_H
  48. # include <arpa/inet.h>
  49. #endif
  50. #ifdef _WIN32
  51. # include <winsock2.h>
  52. # include <ws2tcpip.h>
  53. #endif
  54. #ifdef HAVE_SYS_SOCKET_H
  55. # include <sys/socket.h>
  56. #endif
  57. #ifndef _WIN32
  58. # include <sys/types.h>
  59. # ifdef HAVE_IFADDRS_H
  60. # include <ifaddrs.h>
  61. # endif
  62. # include <net/if.h>
  63. #endif
  64. #include <bdsm/netbios_ns.h>
  65. #include "bdsm_debug.h"
  66. #include "netbios_query.h"
  67. #include "netbios_utils.h"
  68. #include "compat.h"
  69. enum name_query_type {
  70. NAME_QUERY_TYPE_INVALID,
  71. NAME_QUERY_TYPE_NB,
  72. NAME_QUERY_TYPE_NBSTAT
  73. };
  74. static char name_query_broadcast[] = NETBIOS_WILDCARD;
  75. enum ns_entry_flag {
  76. NS_ENTRY_FLAG_INVALID = 0x00,
  77. NS_ENTRY_FLAG_VALID_IP = 0x01,
  78. NS_ENTRY_FLAG_VALID_NAME = 0x02,
  79. };
  80. struct netbios_ns_entry
  81. {
  82. TAILQ_ENTRY(netbios_ns_entry) next;
  83. struct in_addr address;
  84. char name[NETBIOS_NAME_LENGTH + 1];
  85. char group[NETBIOS_NAME_LENGTH + 1];
  86. char type;
  87. int flag;
  88. time_t last_time_seen;
  89. };
  90. typedef TAILQ_HEAD(, netbios_ns_entry) NS_ENTRY_QUEUE;
  91. #define RECV_BUFFER_SIZE 1500 // Max MTU frame size for ethernet
  92. struct netbios_ns
  93. {
  94. int socket;
  95. struct sockaddr_in addr;
  96. uint16_t last_trn_id; // Last transaction id used;
  97. NS_ENTRY_QUEUE entry_queue;
  98. uint8_t buffer[RECV_BUFFER_SIZE];
  99. #ifdef HAVE_PIPE
  100. int abort_pipe[2];
  101. #else
  102. pthread_mutex_t abort_lock;
  103. bool aborted;
  104. #endif
  105. unsigned int discover_broadcast_timeout;
  106. pthread_t discover_thread;
  107. bool discover_started;
  108. netbios_ns_discover_callbacks discover_callbacks;
  109. };
  110. typedef struct netbios_ns_name_query netbios_ns_name_query;
  111. struct netbios_ns_name_query
  112. {
  113. enum name_query_type type;
  114. union {
  115. struct {
  116. uint32_t ip;
  117. } nb;
  118. struct {
  119. const char *name;
  120. const char *group;
  121. char type;
  122. } nbstat;
  123. }u;
  124. };
  125. static int ns_open_socket(netbios_ns *ns)
  126. {
  127. int sock_opt;
  128. if ((ns->socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
  129. goto error;
  130. sock_opt = 1;
  131. if (setsockopt(ns->socket, SOL_SOCKET, SO_BROADCAST,
  132. (void *)&sock_opt, sizeof(sock_opt)) < 0)
  133. goto error;
  134. sock_opt = 0;
  135. if (setsockopt(ns->socket, IPPROTO_IP, IP_MULTICAST_LOOP,
  136. (void *)&sock_opt, sizeof(sock_opt)) < 0)
  137. goto error;
  138. ns->addr.sin_family = AF_INET;
  139. ns->addr.sin_port = htons(0);
  140. ns->addr.sin_addr.s_addr = INADDR_ANY;
  141. if (bind(ns->socket, (struct sockaddr *)&ns->addr, sizeof(ns->addr)) < 0)
  142. goto error;
  143. return 1;
  144. error:
  145. BDSM_perror("netbios_ns_new, open_socket: ");
  146. return 0;
  147. }
  148. #ifdef HAVE_PIPE
  149. static int ns_open_abort_pipe(netbios_ns *ns)
  150. {
  151. int flags;
  152. if (pipe(ns->abort_pipe) == -1)
  153. return -1;
  154. #ifndef _WIN32
  155. if ((flags = fcntl(ns->abort_pipe[0], F_GETFL, 0)) == -1)
  156. return -1;
  157. if (fcntl(ns->abort_pipe[0], F_SETFL, flags | O_NONBLOCK) == -1)
  158. return -1;
  159. #endif
  160. return 0;
  161. }
  162. static void ns_close_abort_pipe(netbios_ns *ns)
  163. {
  164. if (ns->abort_pipe[0] != -1 && ns->abort_pipe[1] != -1)
  165. {
  166. closesocket(ns->abort_pipe[0]);
  167. closesocket(ns->abort_pipe[1]);
  168. ns->abort_pipe[0] = ns->abort_pipe[1] = -1;
  169. }
  170. }
  171. static bool netbios_ns_is_aborted(netbios_ns *ns)
  172. {
  173. fd_set read_fds;
  174. int res;
  175. struct timeval timeout = {0, 0};
  176. FD_ZERO(&read_fds);
  177. FD_SET(ns->abort_pipe[0], &read_fds);
  178. res = select(ns->abort_pipe[0] + 1, &read_fds, NULL, NULL, &timeout);
  179. return (res < 0 || FD_ISSET(ns->abort_pipe[0], &read_fds));
  180. }
  181. static void netbios_ns_abort(netbios_ns *ns)
  182. {
  183. uint8_t buf = '\0';
  184. write(ns->abort_pipe[1], &buf, sizeof(uint8_t));
  185. }
  186. #else
  187. static int ns_open_abort_pipe(netbios_ns *ns)
  188. {
  189. return pthread_mutex_init(&ns->abort_lock, NULL);
  190. }
  191. static void ns_close_abort_pipe(netbios_ns *ns)
  192. {
  193. pthread_mutex_destroy(&ns->abort_lock);
  194. }
  195. static bool netbios_ns_is_aborted(netbios_ns *ns)
  196. {
  197. pthread_mutex_lock(&ns->abort_lock);
  198. bool res = ns->aborted;
  199. pthread_mutex_unlock(&ns->abort_lock);
  200. return res;
  201. }
  202. static void netbios_ns_abort(netbios_ns *ns)
  203. {
  204. pthread_mutex_lock(&ns->abort_lock);
  205. ns->aborted = true;
  206. pthread_mutex_unlock(&ns->abort_lock);
  207. }
  208. #endif
  209. static uint16_t query_type_nb = 0x2000;
  210. static uint16_t query_type_nbstat = 0x2100;
  211. static uint16_t query_class_in = 0x0100;
  212. static ssize_t netbios_ns_send_packet(netbios_ns* ns, netbios_query* q, uint32_t ip)
  213. {
  214. struct sockaddr_in addr;
  215. addr.sin_addr.s_addr = ip;
  216. addr.sin_family = AF_INET;
  217. addr.sin_port = htons(NETBIOS_PORT_NAME);
  218. BDSM_dbg("Sending netbios packet to %s\n", inet_ntoa(addr.sin_addr));
  219. return sendto(ns->socket, (void *)q->packet,
  220. sizeof(netbios_query_packet) + q->cursor, 0,
  221. (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
  222. }
  223. #ifndef _WIN32
  224. #ifdef HAVE_GETIFADDRS
  225. static void netbios_ns_broadcast_packet(netbios_ns* ns, netbios_query* q)
  226. {
  227. struct ifaddrs *addrs;
  228. if (getifaddrs(&addrs) != 0)
  229. return;
  230. for (struct ifaddrs *a = addrs; a != NULL; a = a->ifa_next)
  231. {
  232. if ((a->ifa_flags & IFF_BROADCAST) == 0 || (a->ifa_flags & IFF_UP) == 0)
  233. continue;
  234. if (a->ifa_addr->sa_family != PF_INET)
  235. continue;
  236. struct sockaddr_in* sin = (struct sockaddr_in*)a->ifa_broadaddr;
  237. uint32_t ip = sin->sin_addr.s_addr;
  238. if (netbios_ns_send_packet(ns, q, ip) == -1)
  239. BDSM_perror("Failed to broadcast");
  240. }
  241. freeifaddrs(addrs);
  242. }
  243. #else
  244. static void netbios_ns_broadcast_packet(netbios_ns* ns, netbios_query* q)
  245. {
  246. netbios_ns_send_packet(ns, q, INADDR_BROADCAST);
  247. }
  248. #endif
  249. #else
  250. static void netbios_ns_broadcast_packet(netbios_ns* ns, netbios_query* q)
  251. {
  252. INTERFACE_INFO infolist[16];
  253. DWORD dwBytesReturned = 0;
  254. if (WSAIoctl(ns->socket, SIO_GET_INTERFACE_LIST, NULL, 0, (void*)infolist, sizeof(infolist), &dwBytesReturned, NULL, NULL) != 0)
  255. return;
  256. unsigned int dwNumInterfaces = dwBytesReturned / sizeof(INTERFACE_INFO);
  257. for (unsigned int index = 0; index < dwNumInterfaces; index++)
  258. {
  259. if (infolist[index].iiAddress.Address.sa_family == AF_INET)
  260. {
  261. uint32_t broadcast = infolist[index].iiAddress.AddressIn.sin_addr.s_addr & infolist[index].iiNetmask.AddressIn.sin_addr.s_addr;
  262. broadcast |= ~ infolist[index].iiNetmask.AddressIn.sin_addr.S_un.S_addr;
  263. if (netbios_ns_send_packet(ns, q, broadcast) == -1)
  264. BDSM_perror("Failed to broadcast");
  265. }
  266. }
  267. }
  268. #endif
  269. static int netbios_ns_send_name_query(netbios_ns *ns,
  270. uint32_t ip,
  271. enum name_query_type type,
  272. const char *name,
  273. uint16_t query_flag)
  274. {
  275. uint16_t query_type;
  276. netbios_query *q;
  277. assert(ns != NULL);
  278. switch (type)
  279. {
  280. case NAME_QUERY_TYPE_NB:
  281. query_type = query_type_nb;
  282. break;
  283. case NAME_QUERY_TYPE_NBSTAT:
  284. query_type = query_type_nbstat; // NBSTAT/IP;
  285. break;
  286. default:
  287. BDSM_dbg("netbios_ns_send_name_query: unknow name_query_type");
  288. return -1;
  289. }
  290. // Prepare packet
  291. q = netbios_query_new(34 + 4, 1, NETBIOS_OP_NAME_QUERY);
  292. if (query_flag)
  293. netbios_query_set_flag(q, query_flag, 1);
  294. // Append the queried name to the packet
  295. netbios_query_append(q, name, strlen(name) + 1);
  296. // Magic footer (i.e. Question type (Netbios) / class (IP)
  297. netbios_query_append(q, (const char *)&query_type, 2);
  298. netbios_query_append(q, (const char *)&query_class_in, 2);
  299. q->packet->queries = htons(1);
  300. // Increment transaction ID, not to reuse them
  301. q->packet->trn_id = htons(ns->last_trn_id + 1);
  302. if (ip != 0)
  303. {
  304. ssize_t sent = netbios_ns_send_packet(ns, q, ip);
  305. if (sent < 0)
  306. {
  307. BDSM_perror("netbios_ns_send_name_query: ");
  308. netbios_query_destroy(q);
  309. return -1;
  310. }
  311. else
  312. BDSM_dbg("netbios_ns_send_name_query, name query sent for '*'.\n");
  313. }
  314. else
  315. {
  316. netbios_ns_broadcast_packet(ns, q);
  317. }
  318. netbios_query_destroy(q);
  319. ns->last_trn_id++; // Remember the last transaction id.
  320. return 0;
  321. }
  322. static int netbios_ns_handle_query(netbios_ns *ns, size_t size,
  323. bool check_trn_id, uint32_t recv_ip,
  324. netbios_ns_name_query *out_name_query)
  325. {
  326. netbios_query_packet *q;
  327. uint8_t name_size;
  328. uint16_t *p_type, type;
  329. uint16_t *p_data_length, data_length;
  330. char *p_data;
  331. // check for packet size
  332. if (size < sizeof(netbios_query_packet))
  333. {
  334. BDSM_dbg("netbios_ns_handle_query, invalid size !\n");
  335. return -1;
  336. }
  337. q = (netbios_query_packet *)ns->buffer;
  338. if (check_trn_id)
  339. {
  340. // check if trn_id corresponds
  341. if (ntohs(q->trn_id) != ns->last_trn_id) {
  342. BDSM_dbg("netbios_ns_handle_query, invalid trn_id: %d vs %d\n",
  343. ntohs(q->trn_id), ns->last_trn_id);
  344. return -1;
  345. }
  346. }
  347. if (!out_name_query)
  348. return 0;
  349. // get Name size, should be 0x20
  350. if (size < sizeof(netbios_query_packet) + 1)
  351. return -1;
  352. name_size = q->payload[0];
  353. if (name_size != 0x20)
  354. return -1;
  355. // get type and data_length
  356. if (size < sizeof(netbios_query_packet) + name_size + 11)
  357. return -1;
  358. p_type = (uint16_t *) (q->payload + name_size + 2);
  359. type = *p_type;
  360. p_data_length = (uint16_t *) (q->payload + name_size + 10);
  361. data_length = ntohs(*p_data_length);
  362. if (size < sizeof(netbios_query_packet) + name_size + 12 + data_length)
  363. return -1;
  364. p_data = q->payload + name_size + 12;
  365. if (type == query_type_nb) {
  366. out_name_query->type = NAME_QUERY_TYPE_NB;
  367. out_name_query->u.nb.ip = recv_ip;
  368. } else if (type == query_type_nbstat) {
  369. uint8_t name_count;
  370. const char *names = NULL;
  371. const char *group = NULL, *name = NULL;;
  372. // get the number of names
  373. if (data_length < 1)
  374. return -1;
  375. name_count = *(p_data);
  376. names = p_data + 1;
  377. if (data_length < name_count * 18)
  378. return -1;
  379. // first search for a group in the name list
  380. for (uint8_t name_idx = 0; name_idx < name_count; name_idx++)
  381. {
  382. const char *current_name = names + name_idx * 18;
  383. uint16_t current_flags = (current_name[16] << 8) | current_name[17];
  384. if (current_flags & NETBIOS_NAME_FLAG_GROUP) {
  385. group = current_name;
  386. break;
  387. }
  388. }
  389. // then search for file servers
  390. for (uint8_t name_idx = 0; name_idx < name_count; name_idx++)
  391. {
  392. const char *current_name = names + name_idx * 18;
  393. char current_type = current_name[15];
  394. uint16_t current_flags = (current_name[16] << 8) | current_name[17];
  395. if (current_flags & NETBIOS_NAME_FLAG_GROUP)
  396. continue;
  397. if (current_type == NETBIOS_FILESERVER)
  398. {
  399. name = current_name;
  400. BDSM_dbg("netbios_ns_handle_query, Found name: '%.*s' in group: '%.*s'\n",
  401. NETBIOS_NAME_LENGTH, name, NETBIOS_NAME_LENGTH, group);
  402. break;
  403. }
  404. }
  405. if (name)
  406. {
  407. out_name_query->type = NAME_QUERY_TYPE_NBSTAT;
  408. out_name_query->u.nbstat.name = name;
  409. out_name_query->u.nbstat.group = group;
  410. out_name_query->u.nbstat.type = NETBIOS_FILESERVER;
  411. }
  412. }
  413. return 0;
  414. }
  415. static ssize_t netbios_ns_recv(netbios_ns *ns,
  416. struct timeval *timeout,
  417. struct sockaddr_in *out_addr,
  418. bool check_trn_id,
  419. uint32_t wait_ip,
  420. netbios_ns_name_query *out_name_query)
  421. {
  422. int sock;
  423. assert(ns != NULL);
  424. sock = ns->socket;
  425. #ifdef HAVE_PIPE
  426. int abort_fd = ns->abort_pipe[0];
  427. #else
  428. int abort_fd = -1;
  429. #endif
  430. if (out_name_query)
  431. out_name_query->type = NAME_QUERY_TYPE_INVALID;
  432. while (true)
  433. {
  434. fd_set read_fds, error_fds;
  435. int res, nfds;
  436. FD_ZERO(&read_fds);
  437. FD_ZERO(&error_fds);
  438. FD_SET(sock, &read_fds);
  439. #ifdef HAVE_PIPE
  440. FD_SET(abort_fd, &read_fds);
  441. #endif
  442. FD_SET(sock, &error_fds);
  443. nfds = (sock > abort_fd ? sock : abort_fd) + 1;
  444. res = select(nfds, &read_fds, 0, &error_fds, timeout);
  445. if (res < 0)
  446. goto error;
  447. if (FD_ISSET(sock, &error_fds))
  448. goto error;
  449. #ifdef HAVE_PIPE
  450. if (FD_ISSET(abort_fd, &read_fds))
  451. return -1;
  452. #else
  453. if (netbios_ns_is_aborted(ns))
  454. return -1;
  455. #endif
  456. else if (FD_ISSET(sock, &read_fds))
  457. {
  458. struct sockaddr_in addr;
  459. socklen_t addr_len = sizeof(struct sockaddr_in);
  460. ssize_t size;
  461. size = recvfrom(sock, ns->buffer, RECV_BUFFER_SIZE, 0,
  462. (struct sockaddr *)&addr, &addr_len);
  463. if (size < 0)
  464. return -1;
  465. if (wait_ip != 0 && addr_len >= sizeof(struct sockaddr_in))
  466. {
  467. // wait for a reply from a specific ip
  468. if (wait_ip != addr.sin_addr.s_addr)
  469. {
  470. BDSM_dbg("netbios_ns_recv, invalid ip");
  471. continue;
  472. }
  473. }
  474. if (netbios_ns_handle_query(ns, (size_t)size, check_trn_id,
  475. addr.sin_addr.s_addr,
  476. out_name_query) == -1)
  477. {
  478. BDSM_dbg("netbios_ns_recv, invalid query\n");
  479. continue;
  480. }
  481. if (out_addr)
  482. *out_addr = addr;
  483. return size;
  484. }
  485. else
  486. return 0;
  487. }
  488. error:
  489. BDSM_perror("netbios_ns_recv: ");
  490. return -1;
  491. }
  492. static void netbios_ns_copy_name(char *dest, const char *src)
  493. {
  494. memcpy(dest, src, NETBIOS_NAME_LENGTH);
  495. dest[NETBIOS_NAME_LENGTH] = 0;
  496. for (int i = 1; i < NETBIOS_NAME_LENGTH; i++ )
  497. if (dest[NETBIOS_NAME_LENGTH - i] == ' ')
  498. dest[NETBIOS_NAME_LENGTH - i] = 0;
  499. else
  500. break;
  501. }
  502. static void netbios_ns_entry_set_name(netbios_ns_entry *entry,
  503. const char *name, const char *group,
  504. char type)
  505. {
  506. if (name != NULL)
  507. netbios_ns_copy_name(entry->name, name);
  508. if (group != NULL)
  509. netbios_ns_copy_name(entry->group, group);
  510. entry->type = type;
  511. entry->flag |= NS_ENTRY_FLAG_VALID_NAME;
  512. }
  513. static netbios_ns_entry *netbios_ns_entry_add(netbios_ns *ns, uint32_t ip)
  514. {
  515. netbios_ns_entry *entry;
  516. entry = calloc(1, sizeof(netbios_ns_entry));
  517. if (!entry)
  518. return NULL;
  519. entry->address.s_addr = ip;
  520. entry->flag |= NS_ENTRY_FLAG_VALID_IP;
  521. TAILQ_INSERT_HEAD(&ns->entry_queue, entry, next);
  522. return entry;
  523. }
  524. // Find an entry in the list. Search by name if name is not NULL,
  525. // or by ip otherwise
  526. static netbios_ns_entry *netbios_ns_entry_find(netbios_ns *ns, const char *by_name,
  527. uint32_t ip)
  528. {
  529. netbios_ns_entry *iter;
  530. assert(ns != NULL);
  531. TAILQ_FOREACH(iter, &ns->entry_queue, next)
  532. {
  533. if (by_name != NULL)
  534. {
  535. if (iter->flag & NS_ENTRY_FLAG_VALID_NAME
  536. && !strncmp(by_name, iter->name, NETBIOS_NAME_LENGTH))
  537. return iter;
  538. }
  539. else if (iter->flag & NS_ENTRY_FLAG_VALID_IP
  540. && iter->address.s_addr == ip)
  541. return iter;
  542. }
  543. return NULL;
  544. }
  545. static void netbios_ns_entry_clear(netbios_ns *ns)
  546. {
  547. netbios_ns_entry *entry, *entry_next;
  548. assert(ns != NULL);
  549. for (entry = TAILQ_FIRST(&ns->entry_queue);
  550. entry != NULL; entry = entry_next)
  551. {
  552. entry_next = TAILQ_NEXT(entry, next);
  553. TAILQ_REMOVE(&ns->entry_queue, entry, next);
  554. free(entry);
  555. }
  556. }
  557. netbios_ns *netbios_ns_new()
  558. {
  559. netbios_ns *ns;
  560. ns = calloc(1, sizeof(netbios_ns));
  561. if (!ns)
  562. return NULL;
  563. #ifdef HAVE_PIPE
  564. // Don't initialize this in ns_open_abort_pipe, as it would lead to
  565. // fd 0 to be closed (twice) in case of ns_open_socket error
  566. ns->abort_pipe[0] = ns->abort_pipe[1] = -1;
  567. #endif
  568. if (!ns_open_socket(ns) || ns_open_abort_pipe(ns) == -1)
  569. {
  570. netbios_ns_destroy(ns);
  571. return NULL;
  572. }
  573. TAILQ_INIT(&ns->entry_queue);
  574. ns->last_trn_id = rand();
  575. return ns;
  576. }
  577. void netbios_ns_destroy(netbios_ns *ns)
  578. {
  579. if (!ns)
  580. return;
  581. netbios_ns_entry_clear(ns);
  582. if (ns->socket != -1)
  583. closesocket(ns->socket);
  584. ns_close_abort_pipe(ns);
  585. free(ns);
  586. }
  587. int netbios_ns_resolve(netbios_ns *ns, const char *name, char type, uint32_t *addr)
  588. {
  589. netbios_ns_entry *cached;
  590. struct timeval timeout;
  591. char *encoded_name;
  592. ssize_t recv;
  593. netbios_ns_name_query name_query;
  594. assert(ns != NULL && !ns->discover_started);
  595. if ((cached = netbios_ns_entry_find(ns, name, 0)) != NULL)
  596. {
  597. *addr = cached->address.s_addr;
  598. return 0;
  599. }
  600. if ((encoded_name = netbios_name_encode(name, 0, type)) == NULL)
  601. return -1;
  602. if (netbios_ns_send_name_query(ns, 0, NAME_QUERY_TYPE_NB, encoded_name,
  603. NETBIOS_FLAG_RECURSIVE |
  604. NETBIOS_FLAG_BROADCAST) == -1)
  605. {
  606. free(encoded_name);
  607. return -1;
  608. }
  609. free(encoded_name);
  610. // Now wait for a reply and pray
  611. timeout.tv_sec = 2;
  612. timeout.tv_usec = 420;
  613. recv = netbios_ns_recv(ns, &timeout, NULL, true, 0, &name_query);
  614. if (recv < 0)
  615. BDSM_perror("netbios_ns_resolve:");
  616. else
  617. {
  618. if (name_query.type == NAME_QUERY_TYPE_NB)
  619. {
  620. *addr = name_query.u.nb.ip;
  621. BDSM_dbg("netbios_ns_resolve, received a reply for '%s', ip: 0x%X!\n", name, *addr);
  622. return 0;
  623. } else
  624. BDSM_dbg("netbios_ns_resolve, wrong query type received\n");
  625. }
  626. return -1;
  627. }
  628. // Perform inverse name resolution. Grap an IP and return the first <20> field
  629. // returned by the host
  630. static netbios_ns_entry *netbios_ns_inverse_internal(netbios_ns *ns, uint32_t ip)
  631. {
  632. netbios_ns_entry *cached;
  633. struct timeval timeout;
  634. ssize_t recv;
  635. netbios_ns_name_query name_query;
  636. netbios_ns_entry *entry;
  637. if ((cached = netbios_ns_entry_find(ns, NULL, ip)) != NULL)
  638. return cached;
  639. if (netbios_ns_send_name_query(ns, ip, NAME_QUERY_TYPE_NBSTAT,
  640. name_query_broadcast, 0) == -1)
  641. goto error;
  642. // Now wait for a reply and pray
  643. timeout.tv_sec = 1;
  644. timeout.tv_usec = 500;
  645. recv = netbios_ns_recv(ns, &timeout, NULL, true, ip, &name_query);
  646. if (recv <= 0)
  647. goto error;
  648. if (name_query.type != NAME_QUERY_TYPE_NBSTAT)
  649. {
  650. BDSM_dbg("netbios_ns_inverse, wrong query type received\n");
  651. goto error;
  652. }
  653. else
  654. BDSM_dbg("netbios_ns_inverse, received a reply for '%s' !\n",
  655. inet_ntoa(*(struct in_addr *)&ip));
  656. entry = netbios_ns_entry_add(ns, ip);
  657. if (entry)
  658. netbios_ns_entry_set_name(entry, name_query.u.nbstat.name,
  659. name_query.u.nbstat.group,
  660. name_query.u.nbstat.type);
  661. return entry;
  662. error:
  663. BDSM_perror("netbios_ns_inverse: ");
  664. return NULL;
  665. }
  666. const char *netbios_ns_inverse(netbios_ns *ns, uint32_t ip)
  667. {
  668. assert(ns != NULL && ip != 0 && !ns->discover_started);
  669. netbios_ns_entry *entry = netbios_ns_inverse_internal(ns, ip);
  670. return entry ? entry->name : NULL;
  671. }
  672. const char *netbios_ns_entry_name(netbios_ns_entry *entry)
  673. {
  674. return entry ? entry->name : NULL;
  675. }
  676. const char *netbios_ns_entry_group(netbios_ns_entry *entry)
  677. {
  678. return entry ? entry->group : NULL;
  679. }
  680. uint32_t netbios_ns_entry_ip(netbios_ns_entry *entry)
  681. {
  682. return entry ? entry->address.s_addr : 0;
  683. }
  684. char netbios_ns_entry_type(netbios_ns_entry *entry)
  685. {
  686. return entry ? entry->type : -1;
  687. }
  688. static void *netbios_ns_discover_thread(void *opaque)
  689. {
  690. netbios_ns *ns = (netbios_ns *) opaque;
  691. while (true)
  692. {
  693. struct timespec tp;
  694. const int remove_timeout = 5 * ns->discover_broadcast_timeout;
  695. netbios_ns_entry *entry, *entry_next;
  696. if (netbios_ns_is_aborted(ns))
  697. return NULL;
  698. // check if cached entries timeout, the timeout value is 5 times the
  699. // broadcast timeout.
  700. clock_gettime(CLOCK_REALTIME, &tp);
  701. for (entry = TAILQ_FIRST(&ns->entry_queue);
  702. entry != NULL; entry = entry_next)
  703. {
  704. entry_next = TAILQ_NEXT(entry, next);
  705. if (tp.tv_sec - entry->last_time_seen > remove_timeout)
  706. {
  707. if (entry->flag & NS_ENTRY_FLAG_VALID_NAME)
  708. {
  709. BDSM_dbg("Discover: on_entry_removed: %s\n", entry->name);
  710. ns->discover_callbacks.pf_on_entry_removed(
  711. ns->discover_callbacks.p_opaque, entry);
  712. }
  713. TAILQ_REMOVE(&ns->entry_queue, entry, next);
  714. free(entry);
  715. }
  716. }
  717. // send broadbast
  718. if (netbios_ns_send_name_query(ns, 0, NAME_QUERY_TYPE_NB,
  719. name_query_broadcast, 0) == -1)
  720. return NULL;
  721. while (true)
  722. {
  723. struct timeval timeout;
  724. struct sockaddr_in recv_addr;
  725. int res;
  726. netbios_ns_name_query name_query;
  727. timeout.tv_sec = ns->discover_broadcast_timeout;
  728. timeout.tv_usec = 0;
  729. // receive NB or NBSTAT answers
  730. res = netbios_ns_recv(ns, ns->discover_broadcast_timeout == 0 ?
  731. NULL : &timeout,
  732. &recv_addr,
  733. false, 0, &name_query);
  734. // error or abort
  735. if (res == -1)
  736. return NULL;
  737. // timeout reached, broadcast again
  738. if (res == 0)
  739. break;
  740. clock_gettime(CLOCK_REALTIME, &tp);
  741. if (name_query.type == NAME_QUERY_TYPE_NB)
  742. {
  743. uint32_t ip = name_query.u.nb.ip;
  744. entry = netbios_ns_entry_find(ns, NULL, ip);
  745. if (!entry)
  746. {
  747. entry = netbios_ns_entry_add(ns, ip);
  748. if (!entry)
  749. return NULL;
  750. }
  751. entry->last_time_seen = tp.tv_sec;
  752. // if entry is already valid, don't send NBSTAT query
  753. if (entry->flag & NS_ENTRY_FLAG_VALID_NAME)
  754. continue;
  755. // send NBSTAT query
  756. if (netbios_ns_send_name_query(ns, ip, NAME_QUERY_TYPE_NBSTAT,
  757. name_query_broadcast, 0) == -1)
  758. return NULL;
  759. }
  760. else if (name_query.type == NAME_QUERY_TYPE_NBSTAT)
  761. {
  762. bool send_callback;
  763. entry = netbios_ns_entry_find(ns, NULL,
  764. recv_addr.sin_addr.s_addr);
  765. // ignore NBSTAT answers that didn't answered to NB query first.
  766. if (!entry)
  767. continue;
  768. entry->last_time_seen = tp.tv_sec;
  769. send_callback = !(entry->flag & NS_ENTRY_FLAG_VALID_NAME);
  770. netbios_ns_entry_set_name(entry, name_query.u.nbstat.name,
  771. name_query.u.nbstat.group,
  772. name_query.u.nbstat.type);
  773. if (send_callback)
  774. ns->discover_callbacks.pf_on_entry_added(
  775. ns->discover_callbacks.p_opaque, entry);
  776. }
  777. }
  778. if (ns->discover_broadcast_timeout == 0)
  779. break;
  780. }
  781. return NULL;
  782. }
  783. int netbios_ns_discover_start(netbios_ns *ns,
  784. unsigned int broadcast_timeout,
  785. netbios_ns_discover_callbacks *callbacks)
  786. {
  787. if (ns->discover_started || !callbacks)
  788. return -1;
  789. ns->discover_callbacks = *callbacks;
  790. ns->discover_broadcast_timeout = broadcast_timeout;
  791. if (pthread_create(&ns->discover_thread, NULL,
  792. netbios_ns_discover_thread, ns) != 0)
  793. return -1;
  794. ns->discover_started = true;
  795. return 0;
  796. }
  797. int netbios_ns_discover_stop(netbios_ns *ns)
  798. {
  799. if (ns->discover_started)
  800. {
  801. netbios_ns_abort(ns);
  802. pthread_join(ns->discover_thread, NULL);
  803. ns->discover_started = false;
  804. return 0;
  805. }
  806. else
  807. return -1;
  808. }