r23784: use the GPLv3 boilerplate as recommended by the FSF and the license text
[samba.git] / source3 / utils / nmblookup.c
index 6289ef74b1e027169388629724de58d8d4c13ae3..8bb80239174e5e273a912b19a524f0e51b19aa94 100644 (file)
@@ -1,12 +1,12 @@
 /* 
-   Unix SMB/Netbios implementation.
-   Version 1.9.
+   Unix SMB/CIFS implementation.
    NBT client - used to lookup netbios names
-   Copyright (C) Andrew Tridgell 1994-1995
+   Copyright (C) Andrew Tridgell 1994-1998
+   Copyright (C) Jelmer Vernooij 2003 (Conversion to popt)
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
    
 */
 
-#ifdef SYSLOG
-#undef SYSLOG
-#endif
-
 #include "includes.h"
 
-extern int DEBUGLEVEL;
-
-extern pstring scope;
-
-extern struct in_addr bcast_ip;
-extern pstring myhostname;
+extern BOOL AllowDebugChange;
 
+static BOOL give_flags = False;
+static BOOL use_bcast = True;
 static BOOL got_bcast = False;
-struct in_addr ipzero;
-
-int ServerFD= -1;
+static struct in_addr bcast_addr;
+static BOOL recursion_desired = False;
+static BOOL translate_addresses = False;
+static int ServerFD= -1;
+static int RootPort = False;
+static BOOL find_status=False;
 
 /****************************************************************************
   open the socket communication
   **************************************************************************/
 static BOOL open_sockets(void)
 {
-  struct hostent *hp;
-  /* get host info */
-  if ((hp = Get_Hostbyname(myhostname)) == 0) 
-    {
-      DEBUG(0,( "Get_Hostbyname: Unknown host. %s\n",myhostname));
-      return False;
-    }   
-
-  ServerFD = open_socket_in(SOCK_DGRAM, 0,3);
+  ServerFD = open_socket_in( SOCK_DGRAM,
+                             (RootPort ? 137 : 0),
+                             (RootPort ?   0 : 3),
+                             interpret_addr(lp_socket_address()), True );
 
   if (ServerFD == -1)
     return(False);
 
-  set_socket_options(ServerFD,"SO_BROADCAST");
+  set_socket_options( ServerFD, "SO_BROADCAST" );
 
   DEBUG(3, ("Socket opened.\n"));
   return True;
 }
 
-
 /****************************************************************************
-  initialise connect, service and file structs
+turn a node status flags field into a string
 ****************************************************************************/
-static BOOL init_structs(void )
+static char *node_status_flags(unsigned char flags)
 {
-  struct in_addr myip;
-
-  if (!get_myname(myhostname,&myip))
-    return(False);
-
-  /* Read the broadcast address from the interface */
-  {
-    struct in_addr ip0,ip2;
+       static fstring ret;
+       fstrcpy(ret,"");
+       
+       fstrcat(ret, (flags & 0x80) ? "<GROUP> " : "        ");
+       if ((flags & 0x60) == 0x00) fstrcat(ret,"B ");
+       if ((flags & 0x60) == 0x20) fstrcat(ret,"P ");
+       if ((flags & 0x60) == 0x40) fstrcat(ret,"M ");
+       if ((flags & 0x60) == 0x60) fstrcat(ret,"H ");
+       if (flags & 0x10) fstrcat(ret,"<DEREGISTERING> ");
+       if (flags & 0x08) fstrcat(ret,"<CONFLICT> ");
+       if (flags & 0x04) fstrcat(ret,"<ACTIVE> ");
+       if (flags & 0x02) fstrcat(ret,"<PERMANENT> ");
+       
+       return ret;
+}
 
-    ip0 = myip;
+/****************************************************************************
+turn the NMB Query flags into a string
+****************************************************************************/
+static char *query_flags(int flags)
+{
+       static fstring ret1;
+       fstrcpy(ret1, "");
 
-    if (!got_bcast) {
-      get_broadcast(&ip0,&bcast_ip,&ip2);
+       if (flags & NM_FLAGS_RS) fstrcat(ret1, "Response ");
+       if (flags & NM_FLAGS_AA) fstrcat(ret1, "Authoritative ");
+       if (flags & NM_FLAGS_TC) fstrcat(ret1, "Truncated ");
+       if (flags & NM_FLAGS_RD) fstrcat(ret1, "Recursion_Desired ");
+       if (flags & NM_FLAGS_RA) fstrcat(ret1, "Recursion_Available ");
+       if (flags & NM_FLAGS_B)  fstrcat(ret1, "Broadcast ");
 
-      DEBUG(2,("Using broadcast %s\n",inet_ntoa(bcast_ip)));
-    }
-  }
+       return ret1;
+}
 
-  return True;
+/****************************************************************************
+do a node status query
+****************************************************************************/
+static void do_node_status(int fd, const char *name, int type, struct in_addr ip)
+{
+       struct nmb_name nname;
+       int count, i, j;
+       NODE_STATUS_STRUCT *status;
+       struct node_status_extra extra;
+       fstring cleanname;
+
+       d_printf("Looking up status of %s\n",inet_ntoa(ip));
+       make_nmb_name(&nname, name, type);
+       status = node_status_query(fd,&nname,ip, &count, &extra);
+       if (status) {
+               for (i=0;i<count;i++) {
+                       pull_ascii_fstring(cleanname, status[i].name);
+                       for (j=0;cleanname[j];j++) {
+                               if (!isprint((int)cleanname[j])) cleanname[j] = '.';
+                       }
+                       d_printf("\t%-15s <%02x> - %s\n",
+                              cleanname,status[i].type,
+                              node_status_flags(status[i].flags));
+               }
+               d_printf("\n\tMAC Address = %02X-%02X-%02X-%02X-%02X-%02X\n",
+                               extra.mac_addr[0], extra.mac_addr[1],
+                               extra.mac_addr[2], extra.mac_addr[3],
+                               extra.mac_addr[4], extra.mac_addr[5]);
+               d_printf("\n");
+               SAFE_FREE(status);
+       } else {
+               d_printf("No reply from %s\n\n",inet_ntoa(ip));
+       }
 }
 
+
 /****************************************************************************
-usage on the program
+send out one query
 ****************************************************************************/
-static void usage(void)
+static BOOL query_one(const char *lookup, unsigned int lookup_type)
 {
-  printf("Usage: nmblookup [-M] [-B bcast address] [-d debuglevel] name\n");
-  printf("Version %s\n",VERSION);
-  printf("\t-d debuglevel         set the debuglevel\n");
-  printf("\t-B broadcast address  the address to use for broadcasts\n");
-  printf("\t-M                    searches for a master browser\n");
-  printf("\t-S                    lookup node status as well\n");
-  printf("\n");
+       int j, count, flags = 0;
+       struct in_addr *ip_list=NULL;
+
+       if (got_bcast) {
+               d_printf("querying %s on %s\n", lookup, inet_ntoa(bcast_addr));
+               ip_list = name_query(ServerFD,lookup,lookup_type,use_bcast,
+                                    use_bcast?True:recursion_desired,
+                                    bcast_addr,&count, &flags, NULL);
+       } else {
+               struct in_addr *bcast;
+               for (j=iface_count() - 1;
+                    !ip_list && j >= 0;
+                    j--) {
+                       bcast = iface_n_bcast(j);
+                       d_printf("querying %s on %s\n", 
+                              lookup, inet_ntoa(*bcast));
+                       ip_list = name_query(ServerFD,lookup,lookup_type,
+                                            use_bcast,
+                                            use_bcast?True:recursion_desired,
+                                            *bcast,&count, &flags, NULL);
+               }
+       }
+
+       if (!ip_list) return False;
+
+       if (give_flags)
+         d_printf("Flags: %s\n", query_flags(flags));
+
+       for (j=0;j<count;j++) {
+               if (translate_addresses) {
+                       struct hostent *host = gethostbyaddr((char *)&ip_list[j], sizeof(ip_list[j]), AF_INET);
+                       if (host) {
+                               d_printf("%s, ", host -> h_name);
+                       }
+               }
+               d_printf("%s %s<%02x>\n",inet_ntoa(ip_list[j]),lookup, lookup_type);
+               /* We can only do find_status if the ip address returned
+                  was valid - ie. name_query returned true.
+                */
+               if (find_status) {
+                       do_node_status(ServerFD, lookup, lookup_type, ip_list[j]);
+               }
+       }
+
+       safe_free(ip_list);
+
+       return (ip_list != NULL);
 }
 
 
@@ -111,109 +188,110 @@ static void usage(void)
 int main(int argc,char *argv[])
 {
   int opt;
-  unsigned int lookup_type = 0x20;
-  pstring lookup;
-  extern int optind;
-  extern char *optarg;
-  BOOL find_master=False;
-  BOOL find_status=False;
-  int i;
-  
-  DEBUGLEVEL = 1;
+  unsigned int lookup_type = 0x0;
+  fstring lookup;
+  static BOOL find_master=False;
+  static BOOL lookup_by_ip = False;
+  poptContext pc;
+
+  struct poptOption long_options[] = {
+         POPT_AUTOHELP
+         { "broadcast", 'B', POPT_ARG_STRING, NULL, 'B', "Specify address to use for broadcasts", "BROADCAST-ADDRESS" },
+         { "flags", 'f', POPT_ARG_VAL, &give_flags, True, "List the NMB flags returned" },
+         { "unicast", 'U', POPT_ARG_STRING, NULL, 'U', "Specify address to use for unicast" },
+         { "master-browser", 'M', POPT_ARG_VAL, &find_master, True, "Search for a master browser" },
+         { "recursion", 'R', POPT_ARG_VAL, &recursion_desired, True, "Set recursion desired in package" },
+         { "status", 'S', POPT_ARG_VAL, &find_status, True, "Lookup node status as well" },
+         { "translate", 'T', POPT_ARG_NONE, NULL, 'T', "Translate IP addresses into names" },
+         { "root-port", 'r', POPT_ARG_VAL, &RootPort, True, "Use root port 137 (Win95 only replies to this)" },
+         { "lookup-by-ip", 'A', POPT_ARG_VAL, &lookup_by_ip, True, "Do a node status on <name> as an IP Address" },
+         POPT_COMMON_SAMBA
+         POPT_COMMON_CONNECTION
+         { 0, 0, 0, 0 }
+  };
+       
   *lookup = 0;
 
-  TimeInit();
-
-  ipzero = *interpret_addr2("0.0.0.0");
+  load_case_tables();
 
   setup_logging(argv[0],True);
 
-  charset_initialise();
-
-  while ((opt = getopt(argc, argv, "p:d:B:i:SMh")) != EOF)
-    switch (opt)
-      {
-      case 'B':
-       {
-         unsigned long a = interpret_addr(optarg);
-         putip((char *)&bcast_ip,(char *)&a);
-         got_bcast = True;
-       }
-       break;
-      case 'i':
-       strcpy(scope,optarg);
-       strupper(scope);
-       break;
-      case 'M':
-       find_master = True;
-       break;
-      case 'S':
-       find_status = True;
-       break;
-      case 'd':
-       DEBUGLEVEL = atoi(optarg);
-       break;
-      case 'h':
-       usage();
-       exit(0);
-       break;
-      default:
-       usage();
-       exit(1);
-      }
-
-  if (argc < 2) {
-    usage();
-    exit(1);
+  pc = poptGetContext("nmblookup", argc, (const char **)argv, long_options, 
+                                         POPT_CONTEXT_KEEP_FIRST);
+
+  poptSetOtherOptionHelp(pc, "<NODE> ...");
+
+  while ((opt = poptGetNextOpt(pc)) != -1) {
+         switch (opt) {
+         case 'B':
+                 bcast_addr = *interpret_addr2(poptGetOptArg(pc));
+                 got_bcast = True;
+                 use_bcast = True;
+                 break;
+         case 'U':
+                 bcast_addr = *interpret_addr2(poptGetOptArg(pc));
+                 got_bcast = True;
+                 use_bcast = False;
+                 break;
+         case 'T':
+                 translate_addresses = !translate_addresses;
+                 break;
+         }
   }
 
-  init_structs();
-  if (!open_sockets()) return(1);
+  poptGetArg(pc); /* Remove argv[0] */
 
-  DEBUG(1,("Sending queries to %s\n",inet_ntoa(bcast_ip)));
+  if(!poptPeekArg(pc)) { 
+         poptPrintUsage(pc, stderr, 0);
+         exit(1);
+  }
 
+  if (!lp_load(dyn_CONFIGFILE,True,False,False,True)) {
+         fprintf(stderr, "Can't load %s - run testparm to debug it\n", dyn_CONFIGFILE);
+  }
 
-  for (i=optind;i<argc;i++)
-    {
-      BOOL bcast = True;
-      int retries = 2;
-      char *p;
-      struct in_addr ip;
+  load_interfaces();
+  if (!open_sockets()) return(1);
 
-      strcpy(lookup,argv[i]);
+  while(poptPeekArg(pc))
+  {
+         char *p;
+         struct in_addr ip;
+
+         fstrcpy(lookup,poptGetArg(pc));
+
+         if(lookup_by_ip)
+         {
+                 ip = *interpret_addr2(lookup);
+                 fstrcpy(lookup,"*");
+                 do_node_status(ServerFD, lookup, lookup_type, ip);
+                 continue;
+         }
+
+         if (find_master) {
+                 if (*lookup == '-') {
+                         fstrcpy(lookup,"\01\02__MSBROWSE__\02");
+                         lookup_type = 1;
+                 } else {
+                         lookup_type = 0x1d;
+                 }
+         }
+
+         p = strchr_m(lookup,'#');
+         if (p) {
+                 *p = '\0';
+                 sscanf(++p,"%x",&lookup_type);
+         }
+
+         if (!query_one(lookup, lookup_type)) {
+                 d_printf( "name_query failed to find name %s", lookup );
+                 if( 0 != lookup_type )
+                         d_printf( "#%02x", lookup_type );
+                 d_printf( "\n" );
+         }
+  }
 
-      if (find_master) {
-       if (*lookup == '-') {
-         strcpy(lookup,"\01\02__MSBROWSE__\02");
-         lookup_type = 1;
-       } else {
-         lookup_type = 0x1d;
-       }
-      }
-
-      p = strchr(lookup,'#');
-
-      if (p) {
-       *p = 0;
-       sscanf(p+1,"%x",&lookup_type);
-       bcast = False;
-       retries = 1;
-      }
-
-      if (name_query(ServerFD,lookup,lookup_type,bcast,True,
-                    bcast_ip,&ip,NULL)) 
-       {
-         printf("%s %s\n",inet_ntoa(ip),lookup);
-         if (find_status) 
-           {
-             printf("Looking up status of %s\n",inet_ntoa(ip));
-             name_status(ServerFD,lookup,lookup_type,True,ip,NULL,NULL,NULL);
-             printf("\n");
-           }
-      } else {
-       printf("couldn't find name %s\n",lookup);
-      }
-    }
+  poptFreeContext(pc);
 
   return(0);
 }