root/source3/lib/wins_srv.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. wins_srv_keystr
  2. wins_srv_is_dead
  3. wins_srv_alive
  4. wins_srv_died
  5. wins_srv_count
  6. parse_ip
  7. wins_srv_tags
  8. wins_srv_tags_free
  9. wins_srv_ip_tag
  10. wins_srv_count_tag

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

/* [<][>][^][v][top][bottom][index][help] */