dealing with name queries and dns lookups etc.
[samba.git] / source3 / namedbname.c
index c06d10f60c4848397f342fa9187b286794093bf8..8bf65117374913ed28079da4cd4b036e11ad0a3e 100644 (file)
@@ -41,6 +41,27 @@ extern struct subnet_record *subnetlist;
 
 #define WINS_LIST "wins.dat"
 
+uint16 nb_type = 0; /* samba's NetBIOS name type */
+
+
+/****************************************************************************
+  samba's NetBIOS name type
+
+  XXXX maybe functionality could be set: B, M, P or H name registration
+  and resolution could be set through nb_type. just a thought.  
+  ****************************************************************************/
+void set_samba_nb_type(void)
+{
+       if (lp_wins_support() || (*lp_wins_server()))
+       {
+               nb_type = NB_MFLAG; /* samba is a 'hybrid' node type */
+       }
+       else
+       {
+               nb_type = NB_BFLAG; /* samba is broadcast-only node type */
+       }
+}
+
 
 /****************************************************************************
   true if two netbios names are equal
@@ -129,7 +150,8 @@ struct name_record *find_name(struct name_record *n,
                if (name_equal(&ret->name,name))
                {
                        /* self search: self names only */
-                       if ((search&FIND_SELF) == FIND_SELF && ret->source != SELF)
+                       if ((search&FIND_SELF) == FIND_SELF && 
+                           ret->source != SELF)
                                continue;
          
                        return ret;
@@ -152,34 +174,25 @@ struct name_record *find_name_search(struct subnet_record **d,
 {
        if (d == NULL) return NULL; /* bad error! */
        
-    if ((search & FIND_LOCAL) == FIND_LOCAL)
-       {
-               if (*d != NULL)
-        {
-                       DEBUG(4,("find_name on local: %s %s search %x\n",
-                                               namestr(name),inet_ntoa(ip), search));
-                       return find_name((*d)->namelist, name, search);
-               }
-        else
-        {
-                       DEBUG(4,("local find_name_search with a NULL subnet pointer\n"));
-            return NULL;
-               }
-       }
-
-       if ((search & FIND_WINS) != FIND_WINS) return NULL;
-
-       if (*d == NULL)
-       {
-               /* find WINS subnet record */
-               *d = find_subnet(ipgrp);
+    if (search & FIND_LOCAL) {
+      if (*d != NULL) {
+       struct name_record *n = find_name((*d)->namelist, name, search);
+       DEBUG(4,("find_name on local: %s %s search %x\n",
+                namestr(name),inet_ntoa(ip), search));
+       if (n) return n;
+      }
     }
 
-       if (*d == NULL) return NULL;
+    if (!(search & FIND_WINS)) return NULL;
 
-       DEBUG(4,("find_name on WINS: %s %s search %x\n",
-                                               namestr(name),inet_ntoa(ip), search));
-       return find_name((*d)->namelist, name, search);
+    /* find WINS subnet record. */
+    *d = find_subnet(ipgrp);
+    
+    if (*d == NULL) return NULL;
+    
+    DEBUG(4,("find_name on WINS: %s %s search %x\n",
+            namestr(name),inet_ntoa(ip), search));
+    return find_name((*d)->namelist, name, search);
 }
 
 
@@ -214,28 +227,41 @@ void dump_names(void)
   for (d = subnetlist; d; d = d->next)
    for (n = d->namelist; n; n = n->next)
     {
+      int i;
+
+         DEBUG(3,("%15s ", inet_ntoa(d->bcast_ip)));
+         DEBUG(3,("%15s ", inet_ntoa(d->mask_ip)));
+      DEBUG(3,("%-19s TTL=%ld ",
+              namestr(&n->name),
+              n->death_time?n->death_time-t:0));
+
+        for (i = 0; i < n->num_ips; i++)
+        {
+           DEBUG(3,("%15s NB=%2x source=%d",
+                   inet_ntoa(n->ip_flgs[i].ip),
+                   n->ip_flgs[i].nb_flags,n->source));
+
+        }
+               DEBUG(3,("\n"));
+
       if (f && ip_equal(d->bcast_ip, ipgrp) && n->source == REGISTER)
       {
-        fstring data;
-
       /* XXXX i have little imagination as to how to output nb_flags as
          anything other than as a hexadecimal number :-) */
 
-        sprintf(data, "%s#%02x %s %2x %ld",
-              n->name.name,n->name.name_type, /* XXXX ignore the scope for now */
-              inet_ntoa(n->ip),
-              n->nb_flags,
+        fprintf(f, "%s#%02x %ld ",
+              n->name.name,n->name.name_type, /* XXXX ignore scope for now */
               n->death_time);
-           fprintf(f, "%s\n", data);
+
+        for (i = 0; i < n->num_ips; i++)
+        {
+           fprintf(f, "%s %2x ",
+                                               inet_ntoa(n->ip_flgs[i].ip),
+                                               n->ip_flgs[i].nb_flags);
+        }
+               fprintf(f, "\n");
       }
 
-         DEBUG(3,("%15s ", inet_ntoa(d->bcast_ip)));
-         DEBUG(3,("%15s ", inet_ntoa(d->mask_ip)));
-      DEBUG(3,("%-19s %15s NB=%2x TTL=%ld \n",
-              namestr(&n->name),
-              inet_ntoa(n->ip),
-              n->nb_flags,
-           n->death_time?n->death_time-t:0));
     }
 
   fclose(f);
@@ -248,8 +274,10 @@ void dump_names(void)
 
 
 /****************************************************************************
-load a netbios name database file
-****************************************************************************/
+  load a netbios name database file
+
+  XXXX we cannot cope with loading Internet Group names, yet
+  ****************************************************************************/
 void load_netbios_names(void)
 {
   struct subnet_record *d = find_subnet(ipgrp);
@@ -278,7 +306,7 @@ void load_netbios_names(void)
 
       pstring name;
       int type = 0;
-      int nb_flags;
+      unsigned int nb_flags;
       time_t ttd;
          struct in_addr ipaddr;
 
@@ -296,15 +324,15 @@ void load_netbios_names(void)
        ptr = line;
 
        if (next_token(&ptr,name_str    ,NULL)) ++count;
-       if (next_token(&ptr,ip_str      ,NULL)) ++count;
        if (next_token(&ptr,ttd_str     ,NULL)) ++count;
+       if (next_token(&ptr,ip_str      ,NULL)) ++count;
        if (next_token(&ptr,nb_flags_str,NULL)) ++count;
 
        if (count <= 0) continue;
 
        if (count != 4) {
          DEBUG(0,("Ill formed wins line"));
-         DEBUG(0,("[%s]: name#type ip nb_flags abs_time\n",line));
+         DEBUG(0,("[%s]: name#type abs_time ip nb_flags\n",line));
          continue;
        }
 
@@ -332,11 +360,11 @@ void load_netbios_names(void)
          source = REGISTER;
       }
 
-      DEBUG(4, ("add WINS line: %s#%02x %s %ld %2x\n",
-              name,type, inet_ntoa(ipaddr), ttd, nb_flags));
+      DEBUG(4, ("add WINS line: %s#%02x %ld %s %2x\n",
+              name,type, ttd, inet_ntoa(ipaddr), nb_flags));
 
       /* add all entries that have 60 seconds or more to live */
-      if (ttd - 60 < time(NULL) || ttd == 0)
+      if (ttd - 60 > time(NULL) || ttd == 0)
       {
         time_t t = (ttd?ttd-time(NULL):0) / 3;
 
@@ -397,7 +425,7 @@ struct name_record *add_netbios_entry(struct subnet_record *d,
     if (!wins && type != 0x1b)
     {
        /* the only broadcast (non-WINS) names we are adding are ours
-          (SELF) and PDC type names */
+          (SELF) and Domain Master type names */
        return NULL;
     }
   }
@@ -407,10 +435,19 @@ struct name_record *add_netbios_entry(struct subnet_record *d,
 
   bzero((char *)n,sizeof(*n));
 
+  n->num_ips = 1; /* XXXX ONLY USE THIS FUNCTION FOR ONE ENTRY */
+  n->ip_flgs = (struct nmb_ip*)malloc(sizeof(*n->ip_flgs) * n->num_ips);
+  if (!n->ip_flgs)
+  {
+     free(n);
+     return NULL;
+  }
+
   make_nmb_name(&n->name,name,type,scope);
 
   if ((n2 = find_name_search(&d, &n->name, search, new_only?ipzero:ip)))
   {
+    free(n->ip_flgs);
     free(n);
     if (new_only || (n2->source==SELF && source!=SELF)) return n2;
     n = n2;
@@ -420,8 +457,10 @@ struct name_record *add_netbios_entry(struct subnet_record *d,
      n->death_time = time(NULL)+ttl*3;
   n->refresh_time = time(NULL)+GET_TTL(ttl);
 
-  n->ip = ip;
-  n->nb_flags = nb_flags;
+  /* XXXX only one entry expected with this function */
+  n->ip_flgs[0].ip = ip;
+  n->ip_flgs[0].nb_flags = nb_flags;
+
   n->source = source;
   
   if (!n2) add_name(d,n);
@@ -446,25 +485,26 @@ void expire_names(time_t t)
        for (d = subnetlist; d; d = d->next)
        {
          for (n = d->namelist; n; n = next)
+           {
+             next = n->next;
+             if (n->death_time && n->death_time < t)
                {
-                 if (n->death_time && n->death_time < t)
-               {
+                 if (n->source == SELF) {
+                   DEBUG(3,("not expiring SELF name %s\n", namestr(&n->name)));
+                   n->death_time += 300;
+                   continue;
+                 }
                  DEBUG(3,("Removing dead name %s\n", namestr(&n->name)));
                  
-                 next = n->next;
-                 
                  if (n->prev) n->prev->next = n->next;
                  if (n->next) n->next->prev = n->prev;
                  
                  if (d->namelist == n) d->namelist = n->next; 
                  
+                 free(n->ip_flgs);
                  free(n);
                }
-                 else
-               {
-                 next = n->next;
-               }
-               }
+           }
        }
 }
 
@@ -472,30 +512,32 @@ void expire_names(time_t t)
 /***************************************************************************
   reply to a name query
   ****************************************************************************/
-struct name_record *search_for_name(struct subnet_record **d,
-                                       struct nmb_name *question,
-                                   struct in_addr ip, int Time, int search)
+struct name_record *dns_name_search(struct nmb_name *question,
+                                   int Time, int search)
 {
+  struct subnet_record *d = find_subnet(ipgrp);
   int name_type = question->name_type;
   char *qname = question->name;
-  BOOL dns_type = name_type == 0x20 || name_type == 0;
-  
+  BOOL dns_type = (name_type == 0x20 || name_type == 0);
   struct name_record *n;
   
+  if (d == NULL) return NULL;
+
   DEBUG(3,("Search for %s from %s - ", namestr(question), inet_ntoa(ip)));
   
-  /* first look up name in cache */
-  n = find_name_search(d,question,search,ip);
-  
-  if (*d == NULL) return NULL;
-
-  DEBUG(4,("subnet %s ", inet_ntoa((*d)->bcast_ip)));
+  if (!n && (search & FIND_SELF))
+  {
+    if (!lp_wins_proxy())
+      DEBUG(3,("wins proxy not enabled - failing lookup\n"));
+    else
+      DEBUG(3,("FIND_SELF set - failing lookup\n"));
+    return NULL;
+  }
 
   /* now try DNS lookup. */
   if (!n)
     {
       struct in_addr dns_ip;
-      unsigned long a;
       
       /* only do DNS lookups if the query is for type 0x20 or type 0x0 */
       if (!dns_type && name_type != 0x1b)
@@ -505,11 +547,9 @@ struct name_record *search_for_name(struct subnet_record **d,
        }
       
       /* look it up with DNS */      
-      a = interpret_addr(qname);
+      dns_ip.s_addr = interpret_addr(qname);
       
-      putip((char *)&dns_ip,(char *)&a);
-      
-      if (!a)
+      if (dns_ip.s_addr)
        {
          /* no luck with DNS. We could possibly recurse here XXXX */
          DEBUG(3,("no recursion.\n"));
@@ -527,21 +567,6 @@ struct name_record *search_for_name(struct subnet_record **d,
       if (!n) return NULL;
     }
   
-  /* is our entry already dead? */
-  if (n->death_time)
-    {
-      if (n->death_time < Time) return False;
-    }
-  
-  /* it may have been an earlier failure */
-  if (n->source == DNSFAIL)
-    {
-      DEBUG(3,("DNSFAIL\n"));
-      return NULL;
-    }
-  
-  DEBUG(3,("OK %s\n",inet_ntoa(n->ip)));      
-  
   return n;
 }