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 3 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, see <http://www.gnu.org/licenses/>.
25 #include "lib/cmdline/popt_common.h"
26 #include "lib/socket/socket.h"
27 #include "lib/events/events.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"
33 #include "param/param.h"
37 #define MAX_NETBIOSNAME_LEN 16
39 /* command line options */
41 const char *broadcast_address
;
42 const char *unicast_address
;
52 clean any binary from a node name
54 static const char *clean_name(TALLOC_CTX
*mem_ctx
, const char *name
)
56 char *ret
= talloc_strdup(mem_ctx
, name
);
58 for (i
=0;ret
[i
];i
++) {
59 if (!isprint((unsigned char)ret
[i
])) ret
[i
] = '.';
65 turn a node status flags field into a string
67 static char *node_status_flags(TALLOC_CTX
*mem_ctx
, uint16_t flags
)
70 const char *group
= " ";
71 const char *type
= "B";
73 if (flags
& NBT_NM_GROUP
) {
77 switch (flags
& NBT_NM_OWNER_TYPE
) {
92 ret
= talloc_asprintf(mem_ctx
, "%s %s", group
, type
);
94 if (flags
& NBT_NM_DEREGISTER
) {
95 ret
= talloc_asprintf_append_buffer(ret
, " <DEREGISTERING>");
97 if (flags
& NBT_NM_CONFLICT
) {
98 ret
= talloc_asprintf_append_buffer(ret
, " <CONFLICT>");
100 if (flags
& NBT_NM_ACTIVE
) {
101 ret
= talloc_asprintf_append_buffer(ret
, " <ACTIVE>");
103 if (flags
& NBT_NM_PERMANENT
) {
104 ret
= talloc_asprintf_append_buffer(ret
, " <PERMANENT>");
110 /* do a single node status */
111 static bool do_node_status(struct nbt_name_socket
*nbtsock
,
112 const char *addr
, uint16_t port
)
114 struct nbt_name_status io
;
117 io
.in
.name
.name
= "*";
118 io
.in
.name
.type
= NBT_NAME_CLIENT
;
119 io
.in
.name
.scope
= NULL
;
120 io
.in
.dest_addr
= addr
;
121 io
.in
.dest_port
= port
;
125 status
= nbt_name_status(nbtsock
, nbtsock
, &io
);
126 if (NT_STATUS_IS_OK(status
)) {
128 printf("Node status reply from %s\n",
130 for (i
=0;i
<io
.out
.status
.num_names
;i
++) {
131 d_printf("\t%-16s <%02x> %s\n",
132 clean_name(nbtsock
, io
.out
.status
.names
[i
].name
),
133 io
.out
.status
.names
[i
].type
,
134 node_status_flags(nbtsock
, io
.out
.status
.names
[i
].nb_flags
));
136 printf("\n\tMAC Address = %02X-%02X-%02X-%02X-%02X-%02X\n",
137 io
.out
.status
.statistics
.unit_id
[0],
138 io
.out
.status
.statistics
.unit_id
[1],
139 io
.out
.status
.statistics
.unit_id
[2],
140 io
.out
.status
.statistics
.unit_id
[3],
141 io
.out
.status
.statistics
.unit_id
[4],
142 io
.out
.status
.statistics
.unit_id
[5]);
149 /* do a single node query */
150 static NTSTATUS
do_node_query(struct nbt_name_socket
*nbtsock
,
153 const char *node_name
,
154 enum nbt_name_type node_type
,
157 struct nbt_name_query io
;
161 io
.in
.name
.name
= node_name
;
162 io
.in
.name
.type
= node_type
;
163 io
.in
.name
.scope
= NULL
;
164 io
.in
.dest_addr
= addr
;
165 io
.in
.dest_port
= port
;
166 io
.in
.broadcast
= broadcast
;
167 io
.in
.wins_lookup
= options
.wins_lookup
;
171 status
= nbt_name_query(nbtsock
, nbtsock
, &io
);
172 NT_STATUS_NOT_OK_RETURN(status
);
174 for (i
=0;i
<io
.out
.num_addrs
;i
++) {
175 printf("%s %s<%02x>\n",
176 io
.out
.reply_addrs
[i
],
180 if (options
.node_status
&& io
.out
.num_addrs
> 0) {
181 do_node_status(nbtsock
, io
.out
.reply_addrs
[0], port
);
188 static bool process_one(struct loadparm_context
*lp_ctx
, struct tevent_context
*ev
,
189 struct interface
*ifaces
, const char *name
, int nbt_port
)
191 TALLOC_CTX
*tmp_ctx
= talloc_new(NULL
);
192 enum nbt_name_type node_type
= NBT_NAME_CLIENT
;
194 struct socket_address
*all_zero_addr
;
195 struct nbt_name_socket
*nbtsock
;
196 NTSTATUS status
= NT_STATUS_OK
;
200 if (!options
.case_sensitive
) {
201 name
= strupper_talloc(tmp_ctx
, name
);
204 if (options
.find_master
) {
205 node_type
= NBT_NAME_MASTER
;
206 if (*name
== '-' || *name
== '_') {
207 name
= "\01\02__MSBROWSE__\02";
208 node_type
= NBT_NAME_MS
;
212 p
= strchr(name
, '#');
214 node_name
= talloc_strndup(tmp_ctx
, name
, PTR_DIFF(p
,name
));
215 node_type
= (enum nbt_name_type
)strtol(p
+1, NULL
, 16);
217 node_name
= talloc_strdup(tmp_ctx
, name
);
220 nbt_len
= strlen(node_name
);
221 if (nbt_len
> MAX_NETBIOSNAME_LEN
- 1) {
222 printf("The specified netbios name [%s] is too long.\n",
224 talloc_free(tmp_ctx
);
228 nbtsock
= nbt_name_socket_init(tmp_ctx
, ev
);
230 if (options
.root_port
) {
231 all_zero_addr
= socket_address_from_strings(tmp_ctx
, nbtsock
->sock
->backend_name
,
232 "0.0.0.0", NBT_NAME_SERVICE_PORT
);
234 if (!all_zero_addr
) {
235 talloc_free(tmp_ctx
);
239 status
= socket_listen(nbtsock
->sock
, all_zero_addr
, 0, 0);
240 if (!NT_STATUS_IS_OK(status
)) {
241 printf("Failed to bind to local port 137 - %s\n", nt_errstr(status
));
242 talloc_free(tmp_ctx
);
247 if (options
.lookup_by_ip
) {
248 ret
= do_node_status(nbtsock
, name
, nbt_port
);
249 talloc_free(tmp_ctx
);
253 if (options
.broadcast_address
) {
254 status
= do_node_query(nbtsock
, options
.broadcast_address
, nbt_port
,
255 node_name
, node_type
, true);
256 } else if (options
.unicast_address
) {
257 status
= do_node_query(nbtsock
, options
.unicast_address
,
258 nbt_port
, node_name
, node_type
, false);
260 int i
, num_interfaces
;
262 num_interfaces
= iface_list_count(ifaces
);
263 for (i
=0;i
<num_interfaces
;i
++) {
264 const char *bcast
= iface_list_n_bcast(ifaces
, i
);
265 if (bcast
== NULL
) continue;
266 status
= do_node_query(nbtsock
, bcast
, nbt_port
,
267 node_name
, node_type
, true);
268 if (NT_STATUS_IS_OK(status
)) break;
272 if (!NT_STATUS_IS_OK(status
)) {
273 printf("Lookup failed - %s\n", nt_errstr(status
));
277 talloc_free(tmp_ctx
);
284 int main(int argc
, const char *argv
[])
287 struct interface
*ifaces
;
288 struct tevent_context
*ev
;
292 OPT_BROADCAST_ADDRESS
= 1000,
301 struct poptOption long_options
[] = {
303 { "broadcast", 'B', POPT_ARG_STRING
, NULL
, OPT_BROADCAST_ADDRESS
,
304 "Specify address to use for broadcasts", "BROADCAST-ADDRESS" },
306 { "unicast", 'U', POPT_ARG_STRING
, NULL
, OPT_UNICAST_ADDRESS
,
307 "Specify address to use for unicast", NULL
},
309 { "master-browser", 'M', POPT_ARG_NONE
, NULL
, OPT_FIND_MASTER
,
310 "Search for a master browser", NULL
},
312 { "wins", 'W', POPT_ARG_NONE
, NULL
, OPT_WINS_LOOKUP
,
313 "Do a WINS lookup", NULL
},
315 { "status", 'S', POPT_ARG_NONE
, NULL
, OPT_NODE_STATUS
,
316 "Lookup node status as well", NULL
},
318 { "root-port", 'r', POPT_ARG_NONE
, NULL
, OPT_ROOT_PORT
,
319 "Use root port 137 (Win95 only replies to this)", NULL
},
321 { "lookup-by-ip", 'A', POPT_ARG_NONE
, NULL
, OPT_LOOKUP_BY_IP
,
322 "Do a node status on <name> as an IP Address", NULL
},
324 { "case-sensitive", 0, POPT_ARG_NONE
, NULL
, OPT_CASE_SENSITIVE
,
325 "Don't uppercase the name before sending", NULL
},
331 pc
= poptGetContext("nmblookup", argc
, argv
, long_options
,
332 POPT_CONTEXT_KEEP_FIRST
);
334 poptSetOtherOptionHelp(pc
, "<NODE> ...");
336 while ((opt
= poptGetNextOpt(pc
)) != -1) {
338 case OPT_BROADCAST_ADDRESS
:
339 options
.broadcast_address
= poptGetOptArg(pc
);
341 case OPT_UNICAST_ADDRESS
:
342 options
.unicast_address
= poptGetOptArg(pc
);
344 case OPT_FIND_MASTER
:
345 options
.find_master
= true;
347 case OPT_WINS_LOOKUP
:
348 options
.wins_lookup
= true;
350 case OPT_NODE_STATUS
:
351 options
.node_status
= true;
354 options
.root_port
= true;
356 case OPT_LOOKUP_BY_IP
:
357 options
.lookup_by_ip
= true;
359 case OPT_CASE_SENSITIVE
:
360 options
.case_sensitive
= true;
365 /* swallow argv[0] */
368 if(!poptPeekArg(pc
)) {
369 poptPrintUsage(pc
, stderr
, 0);
373 load_interface_list(NULL
, cmdline_lp_ctx
, &ifaces
);
375 ev
= s4_event_context_init(talloc_autofree_context());
377 while (poptPeekArg(pc
)) {
378 const char *name
= poptGetArg(pc
);
380 ret
&= process_one(cmdline_lp_ctx
, ev
, ifaces
, name
, lpcfg_nbt_port(cmdline_lp_ctx
));