PageRenderTime 24ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/source3/lib/wins_srv.c

https://gitlab.com/miztake/samba
C | 409 lines | 229 code | 67 blank | 113 comment | 56 complexity | 42199ba9ddf91bb30a60211334427fad MD5 | raw file
  1. /*
  2. Unix SMB/CIFS implementation.
  3. Samba wins server helper functions
  4. Copyright (C) Andrew Tridgell 1992-2002
  5. Copyright (C) Christopher R. Hertel 2000
  6. Copyright (C) Tim Potter 2003
  7. This program is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 3 of the License, or
  10. (at your option) any later version.
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. GNU General Public License for more details.
  15. You should have received a copy of the GNU General Public License
  16. along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include "includes.h"
  19. #include "lib/gencache.h"
  20. #include "lib/util/string_wrappers.h"
  21. /*
  22. This is pretty much a complete rewrite of the earlier code. The main
  23. aim of the rewrite is to add support for having multiple wins server
  24. lists, so Samba can register with multiple groups of wins servers
  25. and each group has a failover list of wins servers.
  26. Central to the way it all works is the idea of a wins server
  27. 'tag'. A wins tag is a label for a group of wins servers. For
  28. example if you use
  29. wins server = fred:192.168.2.10 mary:192.168.3.199 fred:192.168.2.61
  30. then you would have two groups of wins servers, one tagged with the
  31. name 'fred' and the other with the name 'mary'. I would usually
  32. recommend using interface names instead of 'fred' and 'mary' but
  33. they can be any alpha string.
  34. Now, how does it all work. Well, nmbd needs to register each of its
  35. IPs with each of its names once with each group of wins servers. So
  36. it tries registering with the first one mentioned in the list, then
  37. if that fails it marks that WINS server dead and moves onto the next
  38. one.
  39. In the client code things are a bit different. As each of the groups
  40. of wins servers is a separate name space we need to try each of the
  41. groups until we either succeed or we run out of wins servers to
  42. try. If we get a negative response from a wins server then that
  43. means the name doesn't exist in that group, so we give up on that
  44. group and move to the next group. If we don't get a response at all
  45. then maybe the wins server is down, in which case we need to
  46. failover to the next one for that group.
  47. confused yet? (tridge)
  48. */
  49. /* how long a server is marked dead for */
  50. #define DEATH_TIME 600
  51. /* The list of dead wins servers is stored in gencache.tdb. Each server is
  52. marked dead from the point of view of a given source address. We keep a
  53. separate dead list for each src address to cope with multiple interfaces
  54. that are not routable to each other.
  55. */
  56. #define WINS_SRV_FMT "WINS_SRV_DEAD/%s,%s" /* wins_ip,src_ip */
  57. static char *wins_srv_keystr(struct in_addr wins_ip, struct in_addr src_ip)
  58. {
  59. char *keystr = NULL, *wins_ip_addr = NULL, *src_ip_addr = NULL;
  60. wins_ip_addr = SMB_STRDUP(inet_ntoa(wins_ip));
  61. src_ip_addr = SMB_STRDUP(inet_ntoa(src_ip));
  62. if ( !wins_ip_addr || !src_ip_addr ) {
  63. DEBUG(0,("wins_srv_keystr: malloc error\n"));
  64. goto done;
  65. }
  66. if (asprintf(&keystr, WINS_SRV_FMT, wins_ip_addr, src_ip_addr) == -1) {
  67. DEBUG(0, (": ns_srv_keystr: malloc error for key string\n"));
  68. }
  69. done:
  70. SAFE_FREE(wins_ip_addr);
  71. SAFE_FREE(src_ip_addr);
  72. return keystr;
  73. }
  74. /*
  75. see if an ip is on the dead list
  76. */
  77. bool wins_srv_is_dead(struct in_addr wins_ip, struct in_addr src_ip)
  78. {
  79. char *keystr = wins_srv_keystr(wins_ip, src_ip);
  80. bool result;
  81. /* If the key exists then the WINS server has been marked as dead */
  82. result = gencache_get(keystr, NULL, NULL, NULL);
  83. SAFE_FREE(keystr);
  84. DEBUG(4, ("wins_srv_is_dead: %s is %s\n", inet_ntoa(wins_ip),
  85. result ? "dead" : "alive"));
  86. return result;
  87. }
  88. /*
  89. mark a wins server as being alive (for the moment)
  90. */
  91. void wins_srv_alive(struct in_addr wins_ip, struct in_addr src_ip)
  92. {
  93. char *keystr = wins_srv_keystr(wins_ip, src_ip);
  94. gencache_del(keystr);
  95. SAFE_FREE(keystr);
  96. DEBUG(4, ("wins_srv_alive: marking wins server %s alive\n",
  97. inet_ntoa(wins_ip)));
  98. }
  99. /*
  100. mark a wins server as temporarily dead
  101. */
  102. void wins_srv_died(struct in_addr wins_ip, struct in_addr src_ip)
  103. {
  104. char *keystr;
  105. if (is_zero_ip_v4(wins_ip) || wins_srv_is_dead(wins_ip, src_ip))
  106. return;
  107. keystr = wins_srv_keystr(wins_ip, src_ip);
  108. gencache_set(keystr, "DOWN", time(NULL) + DEATH_TIME);
  109. SAFE_FREE(keystr);
  110. DEBUG(4,("Marking wins server %s dead for %u seconds from source %s\n",
  111. inet_ntoa(wins_ip), DEATH_TIME, inet_ntoa(src_ip)));
  112. }
  113. /*
  114. return the total number of wins servers, dead or not
  115. */
  116. unsigned wins_srv_count(void)
  117. {
  118. const char **list;
  119. int count = 0;
  120. if (lp_we_are_a_wins_server()) {
  121. /* simple - just talk to ourselves */
  122. return 1;
  123. }
  124. list = lp_wins_server_list();
  125. for (count=0; list && list[count]; count++)
  126. /* nop */ ;
  127. return count;
  128. }
  129. /* an internal convenience structure for an IP with a short string tag
  130. attached */
  131. struct tagged_ip {
  132. fstring tag;
  133. struct in_addr ip;
  134. };
  135. /*
  136. parse an IP string that might be in tagged format
  137. the result is a tagged_ip structure containing the tag
  138. and the ip in in_addr format. If there is no tag then
  139. use the tag '*'
  140. */
  141. static void parse_ip(struct tagged_ip *ip, const char *str)
  142. {
  143. char *s = strchr(str, ':');
  144. if (!s) {
  145. fstrcpy(ip->tag, "*");
  146. ip->ip = interpret_addr2(str);
  147. return;
  148. }
  149. ip->ip = interpret_addr2(s+1);
  150. fstrcpy(ip->tag, str);
  151. s = strchr(ip->tag, ':');
  152. if (s) {
  153. *s = 0;
  154. }
  155. }
  156. /*
  157. return the list of wins server tags. A 'tag' is used to distinguish
  158. wins server as either belonging to the same name space or a separate
  159. name space. Usually you would setup your 'wins server' option to
  160. list one or more wins server per interface and use the interface
  161. name as your tag, but you are free to use any tag you like.
  162. */
  163. char **wins_srv_tags(void)
  164. {
  165. char **ret = NULL;
  166. unsigned int count=0, i, j;
  167. const char **list;
  168. if (lp_we_are_a_wins_server()) {
  169. /* give the caller something to chew on. This makes
  170. the rest of the logic simpler (ie. less special cases) */
  171. ret = SMB_MALLOC_ARRAY(char *, 2);
  172. if (!ret) return NULL;
  173. ret[0] = SMB_STRDUP("*");
  174. ret[1] = NULL;
  175. return ret;
  176. }
  177. list = lp_wins_server_list();
  178. if (!list)
  179. return NULL;
  180. /* yes, this is O(n^2) but n is very small */
  181. for (i=0;list[i];i++) {
  182. struct tagged_ip t_ip;
  183. parse_ip(&t_ip, list[i]);
  184. /* see if we already have it */
  185. for (j=0;j<count;j++) {
  186. if (strcmp(ret[j], t_ip.tag) == 0) {
  187. break;
  188. }
  189. }
  190. if (j != count) {
  191. /* we already have it. Move along */
  192. continue;
  193. }
  194. /* add it to the list */
  195. ret = SMB_REALLOC_ARRAY(ret, char *, count+2);
  196. if (!ret) {
  197. return NULL;
  198. }
  199. ret[count] = SMB_STRDUP(t_ip.tag);
  200. if (!ret[count]) break;
  201. count++;
  202. }
  203. if (count) {
  204. /* make sure we null terminate */
  205. ret[count] = NULL;
  206. }
  207. return ret;
  208. }
  209. /* free a list of wins server tags given by wins_srv_tags */
  210. void wins_srv_tags_free(char **list)
  211. {
  212. int i;
  213. if (!list) return;
  214. for (i=0; list[i]; i++) {
  215. free(list[i]);
  216. }
  217. free(list);
  218. }
  219. /*
  220. return the IP of the currently active wins server for the given tag,
  221. or the zero IP otherwise
  222. */
  223. struct in_addr wins_srv_ip_tag(const char *tag, struct in_addr src_ip)
  224. {
  225. const char **list;
  226. int i;
  227. struct tagged_ip t_ip;
  228. /* if we are a wins server then we always just talk to ourselves */
  229. if (lp_we_are_a_wins_server()) {
  230. struct in_addr loopback_ip;
  231. loopback_ip.s_addr = htonl(INADDR_LOOPBACK);
  232. return loopback_ip;
  233. }
  234. list = lp_wins_server_list();
  235. if (!list || !list[0]) {
  236. struct in_addr ip;
  237. zero_ip_v4(&ip);
  238. return ip;
  239. }
  240. /* find the first live one for this tag */
  241. for (i=0; list[i]; i++) {
  242. parse_ip(&t_ip, list[i]);
  243. if (strcmp(tag, t_ip.tag) != 0) {
  244. /* not for the right tag. Move along */
  245. continue;
  246. }
  247. if (!wins_srv_is_dead(t_ip.ip, src_ip)) {
  248. fstring src_name;
  249. fstrcpy(src_name, inet_ntoa(src_ip));
  250. DEBUG(6,("Current wins server for tag '%s' with source %s is %s\n",
  251. tag,
  252. src_name,
  253. inet_ntoa(t_ip.ip)));
  254. return t_ip.ip;
  255. }
  256. }
  257. /* they're all dead - try the first one until they revive */
  258. for (i=0; list[i]; i++) {
  259. parse_ip(&t_ip, list[i]);
  260. if (strcmp(tag, t_ip.tag) != 0) {
  261. continue;
  262. }
  263. return t_ip.ip;
  264. }
  265. /* this can't happen?? */
  266. zero_ip_v4(&t_ip.ip);
  267. return t_ip.ip;
  268. }
  269. bool wins_server_tag_ips(const char *tag, TALLOC_CTX *mem_ctx,
  270. struct in_addr **pservers, size_t *pnum_servers)
  271. {
  272. const char **list;
  273. size_t i, num_servers;
  274. struct in_addr *servers;
  275. list = lp_wins_server_list();
  276. if ((list == NULL) || (list[0] == NULL)) {
  277. return false;
  278. }
  279. num_servers = 0;
  280. for (i=0; list[i] != NULL; i++) {
  281. struct tagged_ip t_ip;
  282. parse_ip(&t_ip, list[i]);
  283. if (strcmp(tag, t_ip.tag) == 0) {
  284. /* Wrap check. */
  285. if (num_servers + 1 < num_servers) {
  286. return false;
  287. }
  288. num_servers += 1;
  289. }
  290. }
  291. servers = talloc_array(mem_ctx, struct in_addr, num_servers);
  292. if (servers == NULL) {
  293. return false;
  294. }
  295. num_servers = 0;
  296. for (i=0; list[i] != NULL; i++) {
  297. struct tagged_ip t_ip;
  298. parse_ip(&t_ip, list[i]);
  299. if (strcmp(tag, t_ip.tag) == 0) {
  300. servers[num_servers] = t_ip.ip;
  301. num_servers += 1;
  302. }
  303. }
  304. *pnum_servers = num_servers;
  305. *pservers = servers;
  306. return true;
  307. }
  308. /*
  309. return a count of the number of IPs for a particular tag, including
  310. dead ones
  311. */
  312. unsigned wins_srv_count_tag(const char *tag)
  313. {
  314. const char **list;
  315. int i, count=0;
  316. /* if we are a wins server then we always just talk to ourselves */
  317. if (lp_we_are_a_wins_server()) {
  318. return 1;
  319. }
  320. list = lp_wins_server_list();
  321. if (!list || !list[0]) {
  322. return 0;
  323. }
  324. /* find the first live one for this tag */
  325. for (i=0; list[i]; i++) {
  326. struct tagged_ip t_ip;
  327. parse_ip(&t_ip, list[i]);
  328. if (strcmp(tag, t_ip.tag) == 0) {
  329. count++;
  330. }
  331. }
  332. return count;
  333. }