Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : NBT client - used to lookup netbios names
4 : Copyright (C) Andrew Tridgell 1994-1998
5 : Copyright (C) Jelmer Vernooij 2003 (Conversion to popt)
6 :
7 : This program is free software; you can redistribute it and/or modify
8 : it under the terms of the GNU General Public License as published by
9 : the Free Software Foundation; either version 3 of the License, or
10 : (at your option) any later version.
11 :
12 : This program is distributed in the hope that it will be useful,
13 : but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : GNU General Public License for more details.
16 :
17 : You should have received a copy of the GNU General Public License
18 : along with this program. If not, see <http://www.gnu.org/licenses/>.
19 :
20 : */
21 :
22 : #include "includes.h"
23 : #include "lib/cmdline/cmdline.h"
24 : #include "libsmb/nmblib.h"
25 : #include "libsmb/namequery.h"
26 : #include "lib/util/string_wrappers.h"
27 :
28 : static bool give_flags = false;
29 : static bool use_bcast = true;
30 : static bool got_bcast = false;
31 : static struct sockaddr_storage bcast_addr;
32 : static bool recursion_desired = false;
33 : static bool translate_addresses = false;
34 : static int ServerFD= -1;
35 : static bool RootPort = false;
36 : static bool find_status = false;
37 :
38 : /****************************************************************************
39 : Open the socket communication.
40 : **************************************************************************/
41 :
42 333 : static bool open_sockets(void)
43 : {
44 : struct sockaddr_storage ss;
45 333 : const char *sock_addr = lp_nbt_client_socket_address();
46 :
47 333 : if (!interpret_string_addr(&ss, sock_addr,
48 : AI_NUMERICHOST|AI_PASSIVE)) {
49 0 : DEBUG(0,("open_sockets: unable to get socket address "
50 : "from string %s\n", sock_addr));
51 0 : return false;
52 : }
53 333 : ServerFD = open_socket_in(
54 333 : SOCK_DGRAM, &ss, (RootPort ? 137 : 0), true);
55 333 : if (ServerFD < 0) {
56 0 : if (RootPort) {
57 0 : DBG_ERR("open_socket_in failed: %s\n",
58 : strerror(-ServerFD));
59 : } else {
60 0 : DBG_NOTICE("open_socket_in failed: %s\n",
61 : strerror(-ServerFD));
62 : }
63 0 : return false;
64 : }
65 :
66 333 : set_socket_options( ServerFD, "SO_BROADCAST" );
67 :
68 333 : DEBUG(3, ("Socket opened.\n"));
69 333 : return true;
70 : }
71 :
72 : /****************************************************************************
73 : turn a node status flags field into a string
74 : ****************************************************************************/
75 0 : static char *node_status_flags(unsigned char flags)
76 : {
77 : static fstring ret;
78 0 : fstrcpy(ret,"");
79 :
80 0 : fstrcat(ret, (flags & 0x80) ? "<GROUP> " : " ");
81 0 : if ((flags & 0x60) == 0x00) fstrcat(ret,"B ");
82 0 : if ((flags & 0x60) == 0x20) fstrcat(ret,"P ");
83 0 : if ((flags & 0x60) == 0x40) fstrcat(ret,"M ");
84 0 : if ((flags & 0x60) == 0x60) fstrcat(ret,"H ");
85 0 : if (flags & 0x10) fstrcat(ret,"<DEREGISTERING> ");
86 0 : if (flags & 0x08) fstrcat(ret,"<CONFLICT> ");
87 0 : if (flags & 0x04) fstrcat(ret,"<ACTIVE> ");
88 0 : if (flags & 0x02) fstrcat(ret,"<PERMANENT> ");
89 :
90 0 : return ret;
91 : }
92 :
93 : /****************************************************************************
94 : Turn the NMB Query flags into a string.
95 : ****************************************************************************/
96 :
97 0 : static char *query_flags(int flags)
98 : {
99 : static fstring ret1;
100 0 : fstrcpy(ret1, "");
101 :
102 0 : if (flags & NM_FLAGS_RS) fstrcat(ret1, "Response ");
103 0 : if (flags & NM_FLAGS_AA) fstrcat(ret1, "Authoritative ");
104 0 : if (flags & NM_FLAGS_TC) fstrcat(ret1, "Truncated ");
105 0 : if (flags & NM_FLAGS_RD) fstrcat(ret1, "Recursion_Desired ");
106 0 : if (flags & NM_FLAGS_RA) fstrcat(ret1, "Recursion_Available ");
107 0 : if (flags & NM_FLAGS_B) fstrcat(ret1, "Broadcast ");
108 :
109 0 : return ret1;
110 : }
111 :
112 : /****************************************************************************
113 : Do a node status query.
114 : ****************************************************************************/
115 :
116 0 : static bool do_node_status(const char *name,
117 : int type,
118 : struct sockaddr_storage *pss)
119 : {
120 : struct nmb_name nname;
121 0 : size_t count = 0;
122 : size_t i, j;
123 : struct node_status *addrs;
124 : struct node_status_extra extra;
125 : fstring cleanname;
126 : char addr[INET6_ADDRSTRLEN];
127 : NTSTATUS status;
128 :
129 0 : print_sockaddr(addr, sizeof(addr), pss);
130 0 : d_printf("Looking up status of %s\n",addr);
131 0 : make_nmb_name(&nname, name, type);
132 0 : status = node_status_query(talloc_tos(), &nname, pss,
133 : &addrs, &count, &extra);
134 0 : if (NT_STATUS_IS_OK(status)) {
135 0 : for (i=0;i<count;i++) {
136 0 : pull_ascii_fstring(cleanname, addrs[i].name);
137 0 : for (j=0;cleanname[j];j++) {
138 0 : if (!isprint((int)cleanname[j])) {
139 0 : cleanname[j] = '.';
140 : }
141 : }
142 0 : d_printf("\t%-15s <%02x> - %s\n",
143 0 : cleanname,addrs[i].type,
144 0 : node_status_flags(addrs[i].flags));
145 : }
146 0 : d_printf("\n\tMAC Address = %02X-%02X-%02X-%02X-%02X-%02X\n",
147 0 : extra.mac_addr[0], extra.mac_addr[1],
148 0 : extra.mac_addr[2], extra.mac_addr[3],
149 0 : extra.mac_addr[4], extra.mac_addr[5]);
150 0 : d_printf("\n");
151 0 : TALLOC_FREE(addrs);
152 0 : return true;
153 : } else {
154 0 : d_printf("No reply from %s\n\n",addr);
155 0 : return false;
156 : }
157 : }
158 :
159 :
160 : /****************************************************************************
161 : Send out one query.
162 : ****************************************************************************/
163 :
164 333 : static bool query_one(const char *lookup, unsigned int lookup_type)
165 : {
166 333 : size_t j, count = 0;
167 333 : uint8_t flags = 0;
168 333 : struct sockaddr_storage *ip_list=NULL;
169 333 : NTSTATUS status = NT_STATUS_NOT_FOUND;
170 :
171 333 : if (got_bcast) {
172 : char addr[INET6_ADDRSTRLEN];
173 129 : print_sockaddr(addr, sizeof(addr), &bcast_addr);
174 129 : d_printf("querying %s on %s\n", lookup, addr);
175 258 : status = name_query(lookup,lookup_type,use_bcast,
176 129 : use_bcast?true:recursion_desired,
177 : &bcast_addr, talloc_tos(),
178 : &ip_list, &count, &flags);
179 : } else {
180 204 : status = name_resolve_bcast(talloc_tos(),
181 : lookup,
182 : lookup_type,
183 : &ip_list,
184 : &count);
185 : }
186 :
187 333 : if (!NT_STATUS_IS_OK(status)) {
188 115 : return false;
189 : }
190 :
191 218 : if (give_flags) {
192 0 : d_printf("Flags: %s\n", query_flags(flags));
193 : }
194 :
195 440 : for (j=0;j<count;j++) {
196 : char addr[INET6_ADDRSTRLEN];
197 222 : if (translate_addresses) {
198 : char h_name[MAX_DNS_NAME_LENGTH];
199 0 : h_name[0] = '\0';
200 0 : if (sys_getnameinfo((const struct sockaddr *)&ip_list[j],
201 : sizeof(struct sockaddr_storage),
202 : h_name, sizeof(h_name),
203 : NULL, 0,
204 : NI_NAMEREQD)) {
205 0 : continue;
206 : }
207 0 : d_printf("%s, ", h_name);
208 : }
209 222 : print_sockaddr(addr, sizeof(addr), &ip_list[j]);
210 222 : d_printf("%s %s<%02x>\n", addr,lookup, lookup_type);
211 : /* We can only do find_status if the ip address returned
212 : was valid - ie. name_query returned true.
213 : */
214 222 : if (find_status) {
215 0 : if (!do_node_status(lookup, lookup_type, &ip_list[j])) {
216 0 : status = NT_STATUS_UNSUCCESSFUL;
217 : }
218 : }
219 : }
220 :
221 218 : TALLOC_FREE(ip_list);
222 :
223 218 : return NT_STATUS_IS_OK(status);
224 : }
225 :
226 :
227 : /****************************************************************************
228 : main program
229 : ****************************************************************************/
230 : enum nmblookup_cmdline_options {
231 : CMDLINE_RECURSIVE = 1,
232 : };
233 :
234 333 : int main(int argc, const char *argv[])
235 : {
236 : int opt;
237 333 : unsigned int lookup_type = 0x0;
238 : fstring lookup;
239 : static bool find_master=False;
240 : static bool lookup_by_ip = False;
241 333 : poptContext pc = NULL;
242 333 : TALLOC_CTX *frame = talloc_stackframe();
243 333 : int rc = 0;
244 : bool ok;
245 :
246 1332 : struct poptOption long_options[] = {
247 : POPT_AUTOHELP
248 : {
249 : .longName = "broadcast",
250 : .shortName = 'B',
251 : .argInfo = POPT_ARG_STRING,
252 : .arg = NULL,
253 : .val = 'B',
254 : .descrip = "Specify address to use for broadcasts",
255 : .argDescrip = "BROADCAST-ADDRESS",
256 : },
257 : {
258 : .longName = "flags",
259 : .shortName = 'f',
260 : .argInfo = POPT_ARG_NONE,
261 : .arg = NULL,
262 : .val = 'f',
263 : .descrip = "List the NMB flags returned",
264 : },
265 : {
266 : .longName = "unicast",
267 : .shortName = 'U',
268 : .argInfo = POPT_ARG_STRING,
269 : .arg = NULL,
270 : .val = 'U',
271 : .descrip = "Specify address to use for unicast",
272 : },
273 : {
274 : .longName = "master-browser",
275 : .shortName = 'M',
276 : .argInfo = POPT_ARG_NONE,
277 : .arg = NULL,
278 : .val = 'M',
279 : .descrip = "Search for a master browser",
280 : },
281 : {
282 : .longName = "recursion",
283 : .shortName = 0,
284 : .argInfo = POPT_ARG_NONE,
285 : .arg = NULL,
286 : .val = CMDLINE_RECURSIVE,
287 : .descrip = "Set recursion desired in package",
288 : },
289 : {
290 : .longName = "status",
291 : .shortName = 'S',
292 : .argInfo = POPT_ARG_NONE,
293 : .arg = NULL,
294 : .val = 'S',
295 : .descrip = "Lookup node status as well",
296 : },
297 : {
298 : .longName = "translate",
299 : .shortName = 'T',
300 : .argInfo = POPT_ARG_NONE,
301 : .arg = NULL,
302 : .val = 'T',
303 : .descrip = "Translate IP addresses into names",
304 : },
305 : {
306 : .longName = "root-port",
307 : .shortName = 'r',
308 : .argInfo = POPT_ARG_NONE,
309 : .arg = NULL,
310 : .val = 'r',
311 : .descrip = "Use root port 137 (Win95 only replies to this)",
312 : },
313 : {
314 : .longName = "lookup-by-ip",
315 : .shortName = 'A',
316 : .argInfo = POPT_ARG_NONE,
317 : .arg = NULL,
318 : .val = 'A',
319 : .descrip = "Do a node status on <name> as an IP Address",
320 : },
321 333 : POPT_COMMON_SAMBA
322 333 : POPT_COMMON_CONNECTION
323 333 : POPT_COMMON_VERSION
324 : POPT_TABLEEND
325 : };
326 :
327 333 : *lookup = 0;
328 :
329 333 : smb_init_locale();
330 :
331 333 : ok = samba_cmdline_init(frame,
332 : SAMBA_CMDLINE_CONFIG_CLIENT,
333 : false /* require_smbconf */);
334 333 : if (!ok) {
335 0 : DBG_ERR("Failed to init cmdline parser!\n");
336 0 : TALLOC_FREE(frame);
337 0 : exit(1);
338 : }
339 :
340 333 : pc = samba_popt_get_context(getprogname(),
341 : argc,
342 : argv,
343 : long_options,
344 : POPT_CONTEXT_KEEP_FIRST);
345 333 : if (pc == NULL) {
346 0 : DBG_ERR("Failed to setup popt context!\n");
347 0 : TALLOC_FREE(frame);
348 0 : exit(1);
349 : }
350 :
351 333 : poptSetOtherOptionHelp(pc, "<NODE> ...");
352 :
353 539 : while ((opt = poptGetNextOpt(pc)) != -1) {
354 129 : switch (opt) {
355 0 : case 'f':
356 0 : give_flags = true;
357 0 : break;
358 0 : case 'M':
359 0 : find_master = true;
360 0 : break;
361 0 : case CMDLINE_RECURSIVE:
362 0 : recursion_desired = true;
363 0 : break;
364 0 : case 'S':
365 0 : find_status = true;
366 0 : break;
367 0 : case 'r':
368 0 : RootPort = true;
369 0 : break;
370 0 : case 'A':
371 0 : lookup_by_ip = true;
372 0 : break;
373 0 : case 'B':
374 0 : if (interpret_string_addr(&bcast_addr,
375 0 : poptGetOptArg(pc),
376 : NI_NUMERICHOST)) {
377 0 : got_bcast = True;
378 0 : use_bcast = True;
379 : }
380 0 : break;
381 129 : case 'U':
382 129 : if (interpret_string_addr(&bcast_addr,
383 129 : poptGetOptArg(pc),
384 : 0)) {
385 129 : got_bcast = True;
386 129 : use_bcast = False;
387 : }
388 129 : break;
389 0 : case 'T':
390 0 : translate_addresses = !translate_addresses;
391 0 : break;
392 0 : case POPT_ERROR_BADOPT:
393 0 : fprintf(stderr, "\nInvalid option %s: %s\n\n",
394 : poptBadOption(pc, 0), poptStrerror(opt));
395 0 : poptPrintUsage(pc, stderr, 0);
396 0 : exit(1);
397 : }
398 : }
399 :
400 333 : poptGetArg(pc); /* Remove argv[0] */
401 :
402 333 : if(!poptPeekArg(pc)) {
403 0 : poptPrintUsage(pc, stderr, 0);
404 0 : rc = 1;
405 0 : goto out;
406 : }
407 :
408 333 : if (!open_sockets()) {
409 0 : rc = 1;
410 0 : goto out;
411 : }
412 :
413 666 : while(poptPeekArg(pc)) {
414 : char *p;
415 : struct in_addr ip;
416 : size_t nbt_len;
417 :
418 333 : fstrcpy(lookup,poptGetArg(pc));
419 :
420 333 : if(lookup_by_ip) {
421 : struct sockaddr_storage ss;
422 0 : ip = interpret_addr2(lookup);
423 0 : in_addr_to_sockaddr_storage(&ss, ip);
424 0 : fstrcpy(lookup,"*");
425 0 : if (!do_node_status(lookup, lookup_type, &ss)) {
426 0 : rc = 1;
427 : }
428 0 : continue;
429 : }
430 :
431 333 : if (find_master) {
432 0 : if (*lookup == '-') {
433 0 : fstrcpy(lookup,"\01\02__MSBROWSE__\02");
434 0 : lookup_type = 1;
435 : } else {
436 0 : lookup_type = 0x1d;
437 : }
438 : }
439 :
440 333 : p = strchr_m(lookup,'#');
441 333 : if (p) {
442 3 : *p = '\0';
443 3 : sscanf(++p,"%x",&lookup_type);
444 : }
445 :
446 333 : nbt_len = strlen(lookup);
447 333 : if (nbt_len > MAX_NETBIOSNAME_LEN - 1) {
448 0 : d_printf("The specified netbios name [%s] is too long!\n",
449 : lookup);
450 0 : continue;
451 : }
452 :
453 :
454 333 : if (!query_one(lookup, lookup_type)) {
455 115 : rc = 1;
456 115 : d_printf( "name_query failed to find name %s", lookup );
457 115 : if( 0 != lookup_type ) {
458 0 : d_printf( "#%02x", lookup_type );
459 : }
460 115 : d_printf( "\n" );
461 : }
462 : }
463 :
464 333 : out:
465 333 : poptFreeContext(pc);
466 333 : TALLOC_FREE(frame);
467 333 : return rc;
468 : }
|