2005-01-26 06:19:42 +03:00
/*
Unix SMB / CIFS implementation .
2005-01-28 14:26:51 +03:00
2005-01-26 06:19:42 +03:00
NBT client - used to lookup netbios names
2005-01-28 14:26:51 +03:00
Copyright ( C ) Andrew Tridgell 1994 - 2005
2005-01-26 06:19:42 +03:00
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
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
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 0213 9 , USA .
*/
# include "includes.h"
2005-01-28 14:26:51 +03:00
# include "lib/cmdline/popt_common.h"
2005-02-10 09:59:29 +03:00
# include "lib/socket/socket.h"
2006-03-07 14:07:23 +03:00
# include "system/network.h"
2006-05-13 23:14:12 +04:00
# include "system/locale.h"
2006-03-07 14:07:23 +03:00
# include "netif/netif.h"
2006-03-18 18:42:57 +03:00
# include "librpc/gen_ndr/nbt.h"
# include "libcli/nbt/libnbt.h"
2005-01-28 14:26:51 +03:00
/* command line options */
static struct {
const char * broadcast_address ;
const char * unicast_address ;
BOOL find_master ;
BOOL wins_lookup ;
BOOL node_status ;
BOOL root_port ;
BOOL lookup_by_ip ;
2005-02-11 10:54:20 +03:00
BOOL case_sensitive ;
2005-01-28 14:26:51 +03:00
} options ;
/*
clean any binary from a node name
*/
static const char * clean_name ( TALLOC_CTX * mem_ctx , const char * name )
{
char * ret = talloc_strdup ( mem_ctx , name ) ;
int i ;
for ( i = 0 ; ret [ i ] ; i + + ) {
2005-07-13 02:22:59 +04:00
if ( ! isprint ( ( unsigned char ) ret [ i ] ) ) ret [ i ] = ' . ' ;
2005-01-28 14:26:51 +03:00
}
return ret ;
}
2005-01-26 06:19:42 +03:00
2005-01-28 14:26:51 +03:00
/*
turn a node status flags field into a string
*/
static char * node_status_flags ( TALLOC_CTX * mem_ctx , uint16_t flags )
2005-01-26 06:19:42 +03:00
{
2005-01-28 14:26:51 +03:00
char * ret ;
const char * group = " " ;
const char * type = " B " ;
2005-01-26 06:19:42 +03:00
2005-01-28 14:26:51 +03:00
if ( flags & NBT_NM_GROUP ) {
group = " <GROUP> " ;
}
2005-01-26 06:19:42 +03:00
2005-01-28 14:26:51 +03:00
switch ( flags & NBT_NM_OWNER_TYPE ) {
case NBT_NODE_B :
type = " B " ;
break ;
case NBT_NODE_P :
type = " P " ;
break ;
case NBT_NODE_M :
type = " M " ;
break ;
case NBT_NODE_H :
type = " H " ;
break ;
}
2005-01-26 06:19:42 +03:00
2005-01-28 14:26:51 +03:00
ret = talloc_asprintf ( mem_ctx , " %s %s " , group , type ) ;
2005-01-26 06:19:42 +03:00
2005-01-28 14:26:51 +03:00
if ( flags & NBT_NM_DEREGISTER ) {
ret = talloc_asprintf_append ( ret , " <DEREGISTERING> " ) ;
}
if ( flags & NBT_NM_CONFLICT ) {
ret = talloc_asprintf_append ( ret , " <CONFLICT> " ) ;
}
if ( flags & NBT_NM_ACTIVE ) {
ret = talloc_asprintf_append ( ret , " <ACTIVE> " ) ;
}
if ( flags & NBT_NM_PERMANENT ) {
ret = talloc_asprintf_append ( ret , " <PERMANENT> " ) ;
}
2005-01-26 06:19:42 +03:00
return ret ;
}
2005-01-28 14:26:51 +03:00
/* do a single node status */
2005-11-07 18:07:41 +03:00
static BOOL do_node_status ( struct nbt_name_socket * nbtsock ,
2005-01-28 14:26:51 +03:00
const char * addr )
2005-01-26 06:19:42 +03:00
{
2005-01-28 14:26:51 +03:00
struct nbt_name_status io ;
NTSTATUS status ;
io . in . name . name = " * " ;
2005-05-22 13:43:20 +04:00
io . in . name . type = NBT_NAME_CLIENT ;
2005-01-28 14:26:51 +03:00
io . in . name . scope = NULL ;
io . in . dest_addr = addr ;
2005-02-06 11:27:12 +03:00
io . in . timeout = 1 ;
io . in . retries = 2 ;
2005-01-28 14:26:51 +03:00
status = nbt_name_status ( nbtsock , nbtsock , & io ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
int i ;
printf ( " Node status reply from %s \n " ,
io . out . reply_from ) ;
for ( i = 0 ; i < io . out . status . num_names ; i + + ) {
d_printf ( " \t %-16s <%02x> %s \n " ,
clean_name ( nbtsock , io . out . status . names [ i ] . name ) ,
io . out . status . names [ i ] . type ,
node_status_flags ( nbtsock , io . out . status . names [ i ] . nb_flags ) ) ;
}
printf ( " \n \t MAC Address = %02X-%02X-%02X-%02X-%02X-%02X \n " ,
io . out . status . statistics . unit_id [ 0 ] ,
io . out . status . statistics . unit_id [ 1 ] ,
io . out . status . statistics . unit_id [ 2 ] ,
io . out . status . statistics . unit_id [ 3 ] ,
io . out . status . statistics . unit_id [ 4 ] ,
io . out . status . statistics . unit_id [ 5 ] ) ;
2005-11-07 18:07:41 +03:00
return True ;
2005-01-28 14:26:51 +03:00
}
2005-11-07 18:07:41 +03:00
return False ;
2005-01-26 06:19:42 +03:00
}
2005-01-28 14:26:51 +03:00
/* do a single node query */
static NTSTATUS do_node_query ( struct nbt_name_socket * nbtsock ,
const char * addr ,
const char * node_name ,
enum nbt_name_type node_type ,
BOOL broadcast )
2005-01-26 06:19:42 +03:00
{
2005-01-28 14:26:51 +03:00
struct nbt_name_query io ;
NTSTATUS status ;
2005-01-31 04:57:58 +03:00
int i ;
2005-01-28 14:26:51 +03:00
io . in . name . name = node_name ;
io . in . name . type = node_type ;
io . in . name . scope = NULL ;
io . in . dest_addr = addr ;
io . in . broadcast = broadcast ;
io . in . wins_lookup = options . wins_lookup ;
2005-02-06 11:27:12 +03:00
io . in . timeout = 1 ;
io . in . retries = 2 ;
2005-01-28 14:26:51 +03:00
status = nbt_name_query ( nbtsock , nbtsock , & io ) ;
2005-01-31 04:57:58 +03:00
NT_STATUS_NOT_OK_RETURN ( status ) ;
2005-02-07 15:10:38 +03:00
2005-01-31 04:57:58 +03:00
for ( i = 0 ; i < io . out . num_addrs ; i + + ) {
2005-01-28 14:26:51 +03:00
printf ( " %s %s<%02x> \n " ,
2005-01-31 04:57:58 +03:00
io . out . reply_addrs [ i ] ,
2005-01-28 14:26:51 +03:00
io . out . name . name ,
io . out . name . type ) ;
2005-01-31 04:57:58 +03:00
}
if ( options . node_status & & io . out . num_addrs > 0 ) {
do_node_status ( nbtsock , io . out . reply_addrs [ 0 ] ) ;
2005-01-26 06:19:42 +03:00
}
2005-01-28 14:26:51 +03:00
return status ;
2005-01-26 06:19:42 +03:00
}
2005-11-07 18:07:41 +03:00
static BOOL process_one ( const char * name )
2005-01-26 06:19:42 +03:00
{
2005-01-28 14:26:51 +03:00
TALLOC_CTX * tmp_ctx = talloc_new ( NULL ) ;
enum nbt_name_type node_type = NBT_NAME_CLIENT ;
char * node_name , * p ;
2006-01-10 01:12:53 +03:00
struct socket_address * all_zero_addr ;
2005-01-28 14:26:51 +03:00
struct nbt_name_socket * nbtsock ;
2005-08-24 12:33:56 +04:00
NTSTATUS status = NT_STATUS_OK ;
2005-11-07 18:07:41 +03:00
BOOL ret = True ;
2005-02-11 10:54:20 +03:00
if ( ! options . case_sensitive ) {
name = strupper_talloc ( tmp_ctx , name ) ;
}
2005-01-28 14:26:51 +03:00
if ( options . find_master ) {
node_type = NBT_NAME_MASTER ;
2006-01-13 19:49:00 +03:00
if ( * name = = ' - ' | | * name = = ' _ ' ) {
2005-01-28 14:26:51 +03:00
name = " \01 \02 __MSBROWSE__ \02 " ;
node_type = NBT_NAME_MS ;
2005-01-26 06:19:42 +03:00
}
}
2005-01-28 14:26:51 +03:00
p = strchr ( name , ' # ' ) ;
if ( p ) {
node_name = talloc_strndup ( tmp_ctx , name , PTR_DIFF ( p , name ) ) ;
node_type = ( enum nbt_name_type ) strtol ( p + 1 , NULL , 16 ) ;
} else {
node_name = talloc_strdup ( tmp_ctx , name ) ;
}
2005-01-26 06:19:42 +03:00
2005-01-28 14:26:51 +03:00
nbtsock = nbt_name_socket_init ( tmp_ctx , NULL ) ;
2006-01-10 01:12:53 +03:00
2005-01-28 14:26:51 +03:00
if ( options . root_port ) {
2006-01-10 01:12:53 +03:00
all_zero_addr = socket_address_from_strings ( tmp_ctx , nbtsock - > sock - > backend_name ,
" 0.0.0.0 " , NBT_NAME_SERVICE_PORT ) ;
if ( ! all_zero_addr ) {
talloc_free ( tmp_ctx ) ;
return False ;
}
status = socket_listen ( nbtsock - > sock , all_zero_addr , 0 , 0 ) ;
2005-01-28 14:26:51 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
printf ( " Failed to bind to local port 137 - %s \n " , nt_errstr ( status ) ) ;
2005-11-07 18:07:41 +03:00
talloc_free ( tmp_ctx ) ;
return False ;
2005-01-26 06:19:42 +03:00
}
}
2005-01-28 14:26:51 +03:00
if ( options . lookup_by_ip ) {
2005-11-07 18:07:41 +03:00
ret = do_node_status ( nbtsock , name ) ;
2005-01-28 14:26:51 +03:00
talloc_free ( tmp_ctx ) ;
2005-11-07 18:07:41 +03:00
return ret ;
2005-01-26 06:19:42 +03:00
}
2005-01-28 14:26:51 +03:00
if ( options . broadcast_address ) {
2005-02-07 14:56:34 +03:00
status = do_node_query ( nbtsock , options . broadcast_address , node_name , node_type , True ) ;
2005-01-28 14:26:51 +03:00
} else if ( options . unicast_address ) {
2005-02-07 14:56:34 +03:00
status = do_node_query ( nbtsock , options . unicast_address , node_name , node_type , False ) ;
2005-01-28 14:26:51 +03:00
} else {
int i , num_interfaces = iface_count ( ) ;
for ( i = 0 ; i < num_interfaces ; i + + ) {
2005-02-10 06:22:47 +03:00
const char * bcast = iface_n_bcast ( i ) ;
2006-02-15 07:18:11 +03:00
if ( bcast = = NULL ) continue ;
2005-02-07 14:56:34 +03:00
status = do_node_query ( nbtsock , bcast , node_name , node_type , True ) ;
2005-01-28 14:26:51 +03:00
if ( NT_STATUS_IS_OK ( status ) ) break ;
}
}
2005-01-26 06:19:42 +03:00
2005-02-07 14:56:34 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
printf ( " Lookup failed - %s \n " , nt_errstr ( status ) ) ;
2005-11-07 18:07:41 +03:00
ret = False ;
2005-02-07 14:56:34 +03:00
}
2005-01-28 14:26:51 +03:00
talloc_free ( tmp_ctx ) ;
2005-11-07 18:07:41 +03:00
return ret ;
}
2005-01-26 06:19:42 +03:00
2005-01-28 14:26:51 +03:00
/*
2005-01-26 06:19:42 +03:00
main program
2005-01-28 14:26:51 +03:00
*/
2005-01-26 06:19:42 +03:00
int main ( int argc , char * argv [ ] )
{
2005-11-07 18:07:41 +03:00
BOOL ret = True ;
2005-01-28 14:26:51 +03:00
poptContext pc ;
struct poptOption long_options [ ] = {
POPT_AUTOHELP
{ " broadcast " , ' B ' , POPT_ARG_STRING , & options . broadcast_address ,
' B ' , " Specify address to use for broadcasts " , " BROADCAST-ADDRESS " } ,
{ " unicast " , ' U ' , POPT_ARG_STRING , & options . unicast_address ,
' U ' , " Specify address to use for unicast " } ,
{ " master-browser " , ' M ' , POPT_ARG_VAL , & options . find_master ,
True , " Search for a master browser " } ,
{ " wins " , ' W ' , POPT_ARG_VAL , & options . wins_lookup , True , " Do a WINS lookup " } ,
{ " status " , ' S ' , POPT_ARG_VAL , & options . node_status ,
True , " Lookup node status as well " } ,
{ " root-port " , ' r ' , POPT_ARG_VAL , & options . root_port ,
True , " Use root port 137 (Win95 only replies to this) " } ,
{ " lookup-by-ip " , ' A ' , POPT_ARG_VAL , & options . lookup_by_ip ,
True , " Do a node status on <name> as an IP Address " } ,
2005-02-11 10:54:20 +03:00
{ " case-sensitive " , 0 , POPT_ARG_VAL , & options . case_sensitive ,
True , " Don't uppercase the name before sending " } ,
2005-01-28 14:26:51 +03:00
POPT_COMMON_SAMBA
{ 0 , 0 , 0 , 0 }
} ;
pc = poptGetContext ( " nmblookup " , argc , ( const char * * ) argv , long_options ,
POPT_CONTEXT_KEEP_FIRST ) ;
2005-01-26 06:19:42 +03:00
2005-01-28 14:26:51 +03:00
poptSetOtherOptionHelp ( pc , " <NODE> ... " ) ;
while ( ( poptGetNextOpt ( pc ) ! = - 1 ) ) /* noop */ ;
/* swallow argv[0] */
poptGetArg ( pc ) ;
if ( ! poptPeekArg ( pc ) ) {
poptPrintUsage ( pc , stderr , 0 ) ;
exit ( 1 ) ;
}
while ( poptPeekArg ( pc ) ) {
const char * name = poptGetArg ( pc ) ;
2005-11-07 18:07:41 +03:00
ret & = process_one ( name ) ;
2005-01-28 14:26:51 +03:00
}
poptFreeContext ( pc ) ;
2005-11-07 18:07:41 +03:00
if ( ! ret ) {
return 1 ;
}
2005-01-28 14:26:51 +03:00
return 0 ;
2005-01-26 06:19:42 +03:00
}