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"
35 /* command line options */
37 const char *broadcast_address
;
38 const char *unicast_address
;
48 clean any binary from a node name
50 static const char *clean_name(TALLOC_CTX
*mem_ctx
, const char *name
)
52 char *ret
= talloc_strdup(mem_ctx
, name
);
54 for (i
=0;ret
[i
];i
++) {
55 if (!isprint((unsigned char)ret
[i
])) ret
[i
] = '.';
61 turn a node status flags field into a string
63 static char *node_status_flags(TALLOC_CTX
*mem_ctx
, uint16_t flags
)
66 const char *group
= " ";
67 const char *type
= "B";
69 if (flags
& NBT_NM_GROUP
) {
73 switch (flags
& NBT_NM_OWNER_TYPE
) {
88 ret
= talloc_asprintf(mem_ctx
, "%s %s", group
, type
);
90 if (flags
& NBT_NM_DEREGISTER
) {
91 ret
= talloc_asprintf_append_buffer(ret
, " <DEREGISTERING>");
93 if (flags
& NBT_NM_CONFLICT
) {
94 ret
= talloc_asprintf_append_buffer(ret
, " <CONFLICT>");
96 if (flags
& NBT_NM_ACTIVE
) {
97 ret
= talloc_asprintf_append_buffer(ret
, " <ACTIVE>");
99 if (flags
& NBT_NM_PERMANENT
) {
100 ret
= talloc_asprintf_append_buffer(ret
, " <PERMANENT>");
106 /* do a single node status */
107 static bool do_node_status(struct nbt_name_socket
*nbtsock
,
108 const char *addr
, uint16_t port
)
110 struct nbt_name_status io
;
113 io
.in
.name
.name
= "*";
114 io
.in
.name
.type
= NBT_NAME_CLIENT
;
115 io
.in
.name
.scope
= NULL
;
116 io
.in
.dest_addr
= addr
;
117 io
.in
.dest_port
= port
;
121 status
= nbt_name_status(nbtsock
, nbtsock
, &io
);
122 if (NT_STATUS_IS_OK(status
)) {
124 printf("Node status reply from %s\n",
126 for (i
=0;i
<io
.out
.status
.num_names
;i
++) {
127 d_printf("\t%-16s <%02x> %s\n",
128 clean_name(nbtsock
, io
.out
.status
.names
[i
].name
),
129 io
.out
.status
.names
[i
].type
,
130 node_status_flags(nbtsock
, io
.out
.status
.names
[i
].nb_flags
));
132 printf("\n\tMAC Address = %02X-%02X-%02X-%02X-%02X-%02X\n",
133 io
.out
.status
.statistics
.unit_id
[0],
134 io
.out
.status
.statistics
.unit_id
[1],
135 io
.out
.status
.statistics
.unit_id
[2],
136 io
.out
.status
.statistics
.unit_id
[3],
137 io
.out
.status
.statistics
.unit_id
[4],
138 io
.out
.status
.statistics
.unit_id
[5]);
145 /* do a single node query */
146 static NTSTATUS
do_node_query(struct nbt_name_socket
*nbtsock
,
149 const char *node_name
,
150 enum nbt_name_type node_type
,
153 struct nbt_name_query io
;
157 io
.in
.name
.name
= node_name
;
158 io
.in
.name
.type
= node_type
;
159 io
.in
.name
.scope
= NULL
;
160 io
.in
.dest_addr
= addr
;
161 io
.in
.dest_port
= port
;
162 io
.in
.broadcast
= broadcast
;
163 io
.in
.wins_lookup
= options
.wins_lookup
;
167 status
= nbt_name_query(nbtsock
, nbtsock
, &io
);
168 NT_STATUS_NOT_OK_RETURN(status
);
170 for (i
=0;i
<io
.out
.num_addrs
;i
++) {
171 printf("%s %s<%02x>\n",
172 io
.out
.reply_addrs
[i
],
176 if (options
.node_status
&& io
.out
.num_addrs
> 0) {
177 do_node_status(nbtsock
, io
.out
.reply_addrs
[0], port
);
184 static bool process_one(struct loadparm_context
*lp_ctx
, struct event_context
*ev
,
185 struct interface
*ifaces
, const char *name
, int nbt_port
)
187 TALLOC_CTX
*tmp_ctx
= talloc_new(NULL
);
188 enum nbt_name_type node_type
= NBT_NAME_CLIENT
;
190 struct socket_address
*all_zero_addr
;
191 struct nbt_name_socket
*nbtsock
;
192 NTSTATUS status
= NT_STATUS_OK
;
195 if (!options
.case_sensitive
) {
196 name
= strupper_talloc(tmp_ctx
, name
);
199 if (options
.find_master
) {
200 node_type
= NBT_NAME_MASTER
;
201 if (*name
== '-' || *name
== '_') {
202 name
= "\01\02__MSBROWSE__\02";
203 node_type
= NBT_NAME_MS
;
207 p
= strchr(name
, '#');
209 node_name
= talloc_strndup(tmp_ctx
, name
, PTR_DIFF(p
,name
));
210 node_type
= (enum nbt_name_type
)strtol(p
+1, NULL
, 16);
212 node_name
= talloc_strdup(tmp_ctx
, name
);
215 nbtsock
= nbt_name_socket_init(tmp_ctx
, ev
, lp_iconv_convenience(lp_ctx
));
217 if (options
.root_port
) {
218 all_zero_addr
= socket_address_from_strings(tmp_ctx
, nbtsock
->sock
->backend_name
,
219 "0.0.0.0", NBT_NAME_SERVICE_PORT
);
221 if (!all_zero_addr
) {
222 talloc_free(tmp_ctx
);
226 status
= socket_listen(nbtsock
->sock
, all_zero_addr
, 0, 0);
227 if (!NT_STATUS_IS_OK(status
)) {
228 printf("Failed to bind to local port 137 - %s\n", nt_errstr(status
));
229 talloc_free(tmp_ctx
);
234 if (options
.lookup_by_ip
) {
235 ret
= do_node_status(nbtsock
, name
, nbt_port
);
236 talloc_free(tmp_ctx
);
240 if (options
.broadcast_address
) {
241 status
= do_node_query(nbtsock
, options
.broadcast_address
, nbt_port
,
242 node_name
, node_type
, true);
243 } else if (options
.unicast_address
) {
244 status
= do_node_query(nbtsock
, options
.unicast_address
,
245 nbt_port
, node_name
, node_type
, false);
247 int i
, num_interfaces
;
249 num_interfaces
= iface_count(ifaces
);
250 for (i
=0;i
<num_interfaces
;i
++) {
251 const char *bcast
= iface_n_bcast(ifaces
, i
);
252 if (bcast
== NULL
) continue;
253 status
= do_node_query(nbtsock
, bcast
, nbt_port
,
254 node_name
, node_type
, true);
255 if (NT_STATUS_IS_OK(status
)) break;
259 if (!NT_STATUS_IS_OK(status
)) {
260 printf("Lookup failed - %s\n", nt_errstr(status
));
264 talloc_free(tmp_ctx
);
271 int main(int argc
, const char *argv
[])
274 struct interface
*ifaces
;
275 struct event_context
*ev
;
279 OPT_BROADCAST_ADDRESS
= 1000,
288 struct poptOption long_options
[] = {
290 { "broadcast", 'B', POPT_ARG_STRING
, NULL
, OPT_BROADCAST_ADDRESS
,
291 "Specify address to use for broadcasts", "BROADCAST-ADDRESS" },
293 { "unicast", 'U', POPT_ARG_STRING
, NULL
, OPT_UNICAST_ADDRESS
,
294 "Specify address to use for unicast", NULL
},
296 { "master-browser", 'M', POPT_ARG_NONE
, NULL
, OPT_FIND_MASTER
,
297 "Search for a master browser", NULL
},
299 { "wins", 'W', POPT_ARG_NONE
, NULL
, OPT_WINS_LOOKUP
,
300 "Do a WINS lookup", NULL
},
302 { "status", 'S', POPT_ARG_NONE
, NULL
, OPT_NODE_STATUS
,
303 "Lookup node status as well", NULL
},
305 { "root-port", 'r', POPT_ARG_NONE
, NULL
, OPT_ROOT_PORT
,
306 "Use root port 137 (Win95 only replies to this)", NULL
},
308 { "lookup-by-ip", 'A', POPT_ARG_NONE
, NULL
, OPT_LOOKUP_BY_IP
,
309 "Do a node status on <name> as an IP Address", NULL
},
311 { "case-sensitive", 0, POPT_ARG_NONE
, NULL
, OPT_CASE_SENSITIVE
,
312 "Don't uppercase the name before sending", NULL
},
318 pc
= poptGetContext("nmblookup", argc
, argv
, long_options
,
319 POPT_CONTEXT_KEEP_FIRST
);
321 poptSetOtherOptionHelp(pc
, "<NODE> ...");
323 while ((opt
= poptGetNextOpt(pc
)) != -1) {
325 case OPT_BROADCAST_ADDRESS
:
326 options
.broadcast_address
= poptGetOptArg(pc
);
328 case OPT_UNICAST_ADDRESS
:
329 options
.unicast_address
= poptGetOptArg(pc
);
331 case OPT_FIND_MASTER
:
332 options
.find_master
= true;
334 case OPT_WINS_LOOKUP
:
335 options
.wins_lookup
= true;
337 case OPT_NODE_STATUS
:
338 options
.node_status
= true;
341 options
.root_port
= true;
343 case OPT_LOOKUP_BY_IP
:
344 options
.lookup_by_ip
= true;
346 case OPT_CASE_SENSITIVE
:
347 options
.case_sensitive
= true;
352 /* swallow argv[0] */
355 if(!poptPeekArg(pc
)) {
356 poptPrintUsage(pc
, stderr
, 0);
360 load_interfaces(NULL
, lp_interfaces(cmdline_lp_ctx
), &ifaces
);
362 ev
= s4_event_context_init(talloc_autofree_context());
364 while (poptPeekArg(pc
)) {
365 const char *name
= poptGetArg(pc
);
367 ret
&= process_one(cmdline_lp_ctx
, ev
, ifaces
, name
, lp_nbt_port(cmdline_lp_ctx
));