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
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
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., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "system/time.h"
27 This is pretty much a complete rewrite of the earlier code. The main
28 aim of the rewrite is to add support for having multiple wins server
29 lists, so Samba can register with multiple groups of wins servers
30 and each group has a failover list of wins servers.
32 Central to the way it all works is the idea of a wins server
33 'tag'. A wins tag is a label for a group of wins servers. For
36 wins server = fred:192.168.2.10 mary:192.168.3.199 fred:192.168.2.61
38 then you would have two groups of wins servers, one tagged with the
39 name 'fred' and the other with the name 'mary'. I would usually
40 recommend using interface names instead of 'fred' and 'mary' but
41 they can be any alpha string.
43 Now, how does it all work. Well, nmbd needs to register each of its
44 IPs with each of its names once with each group of wins servers. So
45 it tries registering with the first one mentioned in the list, then
46 if that fails it marks that WINS server dead and moves onto the next
49 In the client code things are a bit different. As each of the groups
50 of wins servers is a separate name space we need to try each of the
51 groups until we either succeed or we run out of wins servers to
52 try. If we get a negative response from a wins server then that
53 means the name doesn't exist in that group, so we give up on that
54 group and move to the next group. If we don't get a response at all
55 then maybe the wins server is down, in which case we need to
56 failover to the next one for that group.
58 confused yet? (tridge)
61 /* how long a server is marked dead for */
62 #define DEATH_TIME 600
64 /* The list of dead wins servers is stored in gencache.tdb. Each server is
65 marked dead from the point of view of a given source address. We keep a
66 separate dead list for each src address to cope with multiple interfaces
67 that are not routable to each other.
70 #define WINS_SRV_FMT "WINS_SRV_DEAD/%s,%s" /* wins_ip,src_ip */
72 static char *wins_srv_keystr(struct ipv4_addr wins_ip, struct ipv4_addr src_ip)
76 if (asprintf(&keystr, WINS_SRV_FMT, sys_inet_ntoa(wins_ip),
77 sys_inet_ntoa(src_ip)) == -1) {
78 DEBUG(0, ("wins_srv_is_dead: malloc error\n"));
86 see if an ip is on the dead list
89 BOOL wins_srv_is_dead(struct ipv4_addr wins_ip, struct ipv4_addr src_ip)
91 char *keystr = wins_srv_keystr(wins_ip, src_ip);
94 /* If the key exists then the WINS server has been marked as dead */
96 result = gencache_get(keystr, NULL, NULL);
99 DEBUG(4, ("wins_srv_is_dead: %s is %s\n", sys_inet_ntoa(wins_ip),
100 result ? "dead" : "alive"));
107 mark a wins server as being alive (for the moment)
109 void wins_srv_alive(struct ipv4_addr wins_ip, struct ipv4_addr src_ip)
111 char *keystr = wins_srv_keystr(wins_ip, src_ip);
113 gencache_del(keystr);
116 DEBUG(4, ("wins_srv_alive: marking wins server %s alive\n",
117 sys_inet_ntoa(wins_ip)));
121 mark a wins server as temporarily dead
123 void wins_srv_died(struct ipv4_addr wins_ip, struct ipv4_addr src_ip)
127 if (is_zero_ip(wins_ip) || wins_srv_is_dead(wins_ip, src_ip))
130 keystr = wins_srv_keystr(wins_ip, src_ip);
132 gencache_set(keystr, "DOWN", time(NULL) + DEATH_TIME);
136 DEBUG(4,("Marking wins server %s dead for %u seconds from source %s\n",
137 sys_inet_ntoa(wins_ip), DEATH_TIME, sys_inet_ntoa(src_ip)));
141 return the total number of wins servers, dead or not
143 uint_t wins_srv_count(void)
148 if (lp_wins_support()) {
149 /* simple - just talk to ourselves */
153 list = lp_wins_server_list();
154 for (count=0; list && list[count]; count++)
160 /* an internal convenience structure for an IP with a short string tag
168 parse an IP string that might be in tagged format
169 the result is a tagged_ip structure containing the tag
170 and the ip in in_addr format. If there is no tag then
173 static void parse_ip(TALLOC_CTX *mem_ctx, struct tagged_ip *ip, const char *str)
175 char *s = strchr(str, ':');
177 fstrcpy(ip->tag, "*");
178 ip->ip = interpret_addr2(str);
182 ip->ip = interpret_addr2(s+1);
183 fstrcpy(ip->tag, str);
184 s = strchr(ip->tag, ':');
191 return the list of wins server tags. A 'tag' is used to distinguish
192 wins server as either belonging to the same name space or a separate
193 name space. Usually you would setup your 'wins server' option to
194 list one or more wins server per interface and use the interface
195 name as your tag, but you are free to use any tag you like.
197 char **wins_srv_tags(void)
204 if (lp_wins_support()) {
205 /* give the caller something to chew on. This makes
206 the rest of the logic simpler (ie. less special cases) */
207 ret = (char **)malloc(sizeof(char *)*2);
208 if (!ret) return NULL;
209 ret[0] = strdup("*");
214 list = lp_wins_server_list();
218 mem_ctx = talloc_init("wins_ssrv_tags");
222 /* yes, this is O(n^2) but n is very small */
223 for (i=0;list[i];i++) {
224 struct tagged_ip t_ip;
226 parse_ip(mem_ctx, &t_ip, list[i]);
228 /* see if we already have it */
229 for (j=0;j<count;j++) {
230 if (strcmp(ret[j], t_ip.tag) == 0) {
236 /* we already have it. Move along */
240 /* add it to the list */
241 ret = (char **)Realloc(ret, (count+2) * sizeof(char *));
242 ret[count] = strdup(t_ip.tag);
243 if (!ret[count]) break;
248 /* make sure we null terminate */
255 /* free a list of wins server tags given by wins_srv_tags */
256 void wins_srv_tags_free(char **list)
260 for (i=0; list[i]; i++) {
268 return the IP of the currently active wins server for the given tag,
269 or the zero IP otherwise
271 struct ipv4_addr wins_srv_ip_tag(const char *tag, struct ipv4_addr src_ip)
275 struct tagged_ip t_ip;
278 /* if we are a wins server then we always just talk to ourselves */
279 if (lp_wins_support()) {
280 extern struct ipv4_addr loopback_ip;
284 list = lp_wins_server_list();
285 if (!list || !list[0]) {
291 mem_ctx = talloc_init("wins_srv_ip_tag");
292 /* find the first live one for this tag */
293 for (i=0; list[i]; i++) {
294 parse_ip(mem_ctx, &t_ip, list[i]);
295 if (strcmp(tag, t_ip.tag) != 0) {
296 /* not for the right tag. Move along */
299 if (!wins_srv_is_dead(t_ip.ip, src_ip)) {
301 src_name = talloc_strdup(mem_ctx, sys_inet_ntoa(src_ip));
302 DEBUG(6,("Current wins server for tag '%s' with source %s is %s\n",
305 sys_inet_ntoa(t_ip.ip)));
310 /* they're all dead - try the first one until they revive */
311 for (i=0; list[i]; i++) {
312 parse_ip(mem_ctx, &t_ip, list[i]);
313 if (strcmp(tag, t_ip.tag) != 0) {
319 /* this can't happen?? */
322 talloc_destroy(mem_ctx);
328 return a count of the number of IPs for a particular tag, including
331 uint_t wins_srv_count_tag(const char *tag)
337 /* if we are a wins server then we always just talk to ourselves */
338 if (lp_wins_support()) {
342 list = lp_wins_server_list();
343 if (!list || !list[0]) {
347 /* find the first live one for this tag */
348 mem_ctx = talloc_init("wins_srv_count_tag");
352 for (i=0; list[i]; i++) {
353 struct tagged_ip t_ip;
354 parse_ip(mem_ctx, &t_ip, list[i]);
355 if (strcmp(tag, t_ip.tag) == 0) {
359 talloc_destroy(mem_ctx);