2 Unix SMB/CIFS implementation.
4 NBT client - used to lookup netbios names
6 Copyright (C) Andrew Tridgell 1994-2005
7 Copyright (C) Jelmer Vernooij 2003 (Conversion to popt)
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include "lib/cmdline/popt_common.h"
27 #include "lib/socket/socket.h"
28 #include "system/network.h"
29 #include "system/locale.h"
30 #include "lib/socket/netif.h"
31 #include "librpc/gen_ndr/nbt.h"
32 #include "libcli/nbt/libnbt.h"
34 /* command line options */
36 const char *broadcast_address
;
37 const char *unicast_address
;
47 clean any binary from a node name
49 static const char *clean_name(TALLOC_CTX
*mem_ctx
, const char *name
)
51 char *ret
= talloc_strdup(mem_ctx
, name
);
53 for (i
=0;ret
[i
];i
++) {
54 if (!isprint((unsigned char)ret
[i
])) ret
[i
] = '.';
60 turn a node status flags field into a string
62 static char *node_status_flags(TALLOC_CTX
*mem_ctx
, uint16_t flags
)
65 const char *group
= " ";
66 const char *type
= "B";
68 if (flags
& NBT_NM_GROUP
) {
72 switch (flags
& NBT_NM_OWNER_TYPE
) {
87 ret
= talloc_asprintf(mem_ctx
, "%s %s", group
, type
);
89 if (flags
& NBT_NM_DEREGISTER
) {
90 ret
= talloc_asprintf_append(ret
, " <DEREGISTERING>");
92 if (flags
& NBT_NM_CONFLICT
) {
93 ret
= talloc_asprintf_append(ret
, " <CONFLICT>");
95 if (flags
& NBT_NM_ACTIVE
) {
96 ret
= talloc_asprintf_append(ret
, " <ACTIVE>");
98 if (flags
& NBT_NM_PERMANENT
) {
99 ret
= talloc_asprintf_append(ret
, " <PERMANENT>");
105 /* do a single node status */
106 static BOOL
do_node_status(struct nbt_name_socket
*nbtsock
,
109 struct nbt_name_status io
;
112 io
.in
.name
.name
= "*";
113 io
.in
.name
.type
= NBT_NAME_CLIENT
;
114 io
.in
.name
.scope
= NULL
;
115 io
.in
.dest_addr
= addr
;
119 status
= nbt_name_status(nbtsock
, nbtsock
, &io
);
120 if (NT_STATUS_IS_OK(status
)) {
122 printf("Node status reply from %s\n",
124 for (i
=0;i
<io
.out
.status
.num_names
;i
++) {
125 d_printf("\t%-16s <%02x> %s\n",
126 clean_name(nbtsock
, io
.out
.status
.names
[i
].name
),
127 io
.out
.status
.names
[i
].type
,
128 node_status_flags(nbtsock
, io
.out
.status
.names
[i
].nb_flags
));
130 printf("\n\tMAC Address = %02X-%02X-%02X-%02X-%02X-%02X\n",
131 io
.out
.status
.statistics
.unit_id
[0],
132 io
.out
.status
.statistics
.unit_id
[1],
133 io
.out
.status
.statistics
.unit_id
[2],
134 io
.out
.status
.statistics
.unit_id
[3],
135 io
.out
.status
.statistics
.unit_id
[4],
136 io
.out
.status
.statistics
.unit_id
[5]);
143 /* do a single node query */
144 static NTSTATUS
do_node_query(struct nbt_name_socket
*nbtsock
,
146 const char *node_name
,
147 enum nbt_name_type node_type
,
150 struct nbt_name_query io
;
154 io
.in
.name
.name
= node_name
;
155 io
.in
.name
.type
= node_type
;
156 io
.in
.name
.scope
= NULL
;
157 io
.in
.dest_addr
= addr
;
158 io
.in
.broadcast
= broadcast
;
159 io
.in
.wins_lookup
= options
.wins_lookup
;
163 status
= nbt_name_query(nbtsock
, nbtsock
, &io
);
164 NT_STATUS_NOT_OK_RETURN(status
);
166 for (i
=0;i
<io
.out
.num_addrs
;i
++) {
167 printf("%s %s<%02x>\n",
168 io
.out
.reply_addrs
[i
],
172 if (options
.node_status
&& io
.out
.num_addrs
> 0) {
173 do_node_status(nbtsock
, io
.out
.reply_addrs
[0]);
180 static BOOL
process_one(const char *name
)
182 TALLOC_CTX
*tmp_ctx
= talloc_new(NULL
);
183 enum nbt_name_type node_type
= NBT_NAME_CLIENT
;
185 struct socket_address
*all_zero_addr
;
186 struct nbt_name_socket
*nbtsock
;
187 NTSTATUS status
= NT_STATUS_OK
;
190 if (!options
.case_sensitive
) {
191 name
= strupper_talloc(tmp_ctx
, name
);
194 if (options
.find_master
) {
195 node_type
= NBT_NAME_MASTER
;
196 if (*name
== '-' || *name
== '_') {
197 name
= "\01\02__MSBROWSE__\02";
198 node_type
= NBT_NAME_MS
;
202 p
= strchr(name
, '#');
204 node_name
= talloc_strndup(tmp_ctx
, name
, PTR_DIFF(p
,name
));
205 node_type
= (enum nbt_name_type
)strtol(p
+1, NULL
, 16);
207 node_name
= talloc_strdup(tmp_ctx
, name
);
210 nbtsock
= nbt_name_socket_init(tmp_ctx
, NULL
);
212 if (options
.root_port
) {
213 all_zero_addr
= socket_address_from_strings(tmp_ctx
, nbtsock
->sock
->backend_name
,
214 "0.0.0.0", NBT_NAME_SERVICE_PORT
);
216 if (!all_zero_addr
) {
217 talloc_free(tmp_ctx
);
221 status
= socket_listen(nbtsock
->sock
, all_zero_addr
, 0, 0);
222 if (!NT_STATUS_IS_OK(status
)) {
223 printf("Failed to bind to local port 137 - %s\n", nt_errstr(status
));
224 talloc_free(tmp_ctx
);
229 if (options
.lookup_by_ip
) {
230 ret
= do_node_status(nbtsock
, name
);
231 talloc_free(tmp_ctx
);
235 if (options
.broadcast_address
) {
236 status
= do_node_query(nbtsock
, options
.broadcast_address
, node_name
, node_type
, True
);
237 } else if (options
.unicast_address
) {
238 status
= do_node_query(nbtsock
, options
.unicast_address
, node_name
, node_type
, False
);
240 int i
, num_interfaces
= iface_count();
241 for (i
=0;i
<num_interfaces
;i
++) {
242 const char *bcast
= iface_n_bcast(i
);
243 if (bcast
== NULL
) continue;
244 status
= do_node_query(nbtsock
, bcast
, node_name
, node_type
, True
);
245 if (NT_STATUS_IS_OK(status
)) break;
249 if (!NT_STATUS_IS_OK(status
)) {
250 printf("Lookup failed - %s\n", nt_errstr(status
));
254 talloc_free(tmp_ctx
);
261 int main(int argc
, const char *argv
[])
267 OPT_BROADCAST_ADDRESS
= 1000,
276 struct poptOption long_options
[] = {
278 { "broadcast", 'B', POPT_ARG_STRING
, NULL
, OPT_BROADCAST_ADDRESS
,
279 "Specify address to use for broadcasts", "BROADCAST-ADDRESS" },
281 { "unicast", 'U', POPT_ARG_STRING
, NULL
, OPT_UNICAST_ADDRESS
,
282 "Specify address to use for unicast", NULL
},
284 { "master-browser", 'M', POPT_ARG_NONE
, NULL
, OPT_FIND_MASTER
,
285 "Search for a master browser", NULL
},
287 { "wins", 'W', POPT_ARG_NONE
, NULL
, OPT_WINS_LOOKUP
,
288 "Do a WINS lookup", NULL
},
290 { "status", 'S', POPT_ARG_NONE
, NULL
, OPT_NODE_STATUS
,
291 "Lookup node status as well", NULL
},
293 { "root-port", 'r', POPT_ARG_NONE
, NULL
, OPT_ROOT_PORT
,
294 "Use root port 137 (Win95 only replies to this)", NULL
},
296 { "lookup-by-ip", 'A', POPT_ARG_NONE
, NULL
, OPT_LOOKUP_BY_IP
,
297 "Do a node status on <name> as an IP Address", NULL
},
299 { "case-sensitive", 0, POPT_ARG_NONE
, NULL
, OPT_CASE_SENSITIVE
,
300 "Don't uppercase the name before sending", NULL
},
306 pc
= poptGetContext("nmblookup", argc
, argv
, long_options
,
307 POPT_CONTEXT_KEEP_FIRST
);
309 poptSetOtherOptionHelp(pc
, "<NODE> ...");
311 while ((opt
= poptGetNextOpt(pc
)) != -1) {
313 case OPT_BROADCAST_ADDRESS
:
314 options
.broadcast_address
= poptGetOptArg(pc
);
316 case OPT_UNICAST_ADDRESS
:
317 options
.unicast_address
= poptGetOptArg(pc
);
319 case OPT_FIND_MASTER
:
320 options
.find_master
= True
;
322 case OPT_WINS_LOOKUP
:
323 options
.wins_lookup
= True
;
325 case OPT_NODE_STATUS
:
326 options
.node_status
= True
;
329 options
.root_port
= True
;
331 case OPT_LOOKUP_BY_IP
:
332 options
.lookup_by_ip
= True
;
334 case OPT_CASE_SENSITIVE
:
335 options
.case_sensitive
= True
;
340 /* swallow argv[0] */
343 if(!poptPeekArg(pc
)) {
344 poptPrintUsage(pc
, stderr
, 0);
348 while (poptPeekArg(pc
)) {
349 const char *name
= poptGetArg(pc
);
351 ret
&= process_one(name
);