2 Unix SMB/Netbios implementation.
5 Copyright (C) Andrew Tridgell 1994-1998
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 2 of the License, or
10 (at your option) any later version.
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.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 extern int DEBUGLEVEL;
29 /****************************************************************************
30 interpret a node status response
31 ****************************************************************************/
32 static void _interpret_node_status(char *p, char *master,char *rname)
34 int numnames = CVAL(p,0);
35 DEBUG(1,("received %d names\n",numnames));
37 if (rname) *rname = 0;
38 if (master) *master = 0;
52 strcat(flags, (p[0] & 0x80) ? "<GROUP> " : " ");
53 if ((p[0] & 0x60) == 0x00) strcat(flags,"B ");
54 if ((p[0] & 0x60) == 0x20) strcat(flags,"P ");
55 if ((p[0] & 0x60) == 0x40) strcat(flags,"M ");
56 if ((p[0] & 0x60) == 0x60) strcat(flags,"H ");
57 if (p[0] & 0x10) strcat(flags,"<DEREGISTERING> ");
58 if (p[0] & 0x08) strcat(flags,"<CONFLICT> ");
59 if (p[0] & 0x04) strcat(flags,"<ACTIVE> ");
60 if (p[0] & 0x02) strcat(flags,"<PERMANENT> ");
62 if (master && !*master && type == 0x1d) {
63 StrnCpy(master,qname,15);
64 trim_string(master,NULL," ");
67 if (rname && !*rname && type == 0x20 && !(p[0]&0x80)) {
68 StrnCpy(rname,qname,15);
69 trim_string(rname,NULL," ");
72 for (i = strlen( qname) ; --i >= 0 ; ) {
73 if (!isprint(qname[i])) qname[i] = '.';
75 DEBUG(1,("\t%-15s <%02x> - %s\n",qname,type,flags));
78 DEBUG(1,("num_good_sends=%d num_good_receives=%d\n",
79 IVAL(p,20),IVAL(p,24)));
83 /****************************************************************************
84 do a netbios name status query on a host
86 the "master" parameter is a hack used for finding workgroups.
87 **************************************************************************/
88 BOOL name_status(int fd,char *name,int name_type,BOOL recurse,
89 struct in_addr to_ip,char *master,char *rname,
94 int retry_time = 5000;
96 struct packet_struct p;
97 struct packet_struct *p2;
98 struct nmb_packet *nmb = &p.packet.nmb;
99 static int name_trn_id = 0;
101 bzero((char *)&p,sizeof(p));
103 if (!name_trn_id) name_trn_id = (time(NULL)%(unsigned)0x7FFF) +
104 (getpid()%(unsigned)100);
105 name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF;
107 nmb->header.name_trn_id = name_trn_id;
108 nmb->header.opcode = 0;
109 nmb->header.response = False;
110 nmb->header.nm_flags.bcast = False;
111 nmb->header.nm_flags.recursion_available = False;
112 nmb->header.nm_flags.recursion_desired = False;
113 nmb->header.nm_flags.trunc = False;
114 nmb->header.nm_flags.authoritative = False;
115 nmb->header.rcode = 0;
116 nmb->header.qdcount = 1;
117 nmb->header.ancount = 0;
118 nmb->header.nscount = 0;
119 nmb->header.arcount = 0;
121 make_nmb_name(&nmb->question.question_name,name,name_type,scope);
123 nmb->question.question_type = 0x21;
124 nmb->question.question_class = 0x1;
129 p.timestamp = time(NULL);
130 p.packet_type = NMB_PACKET;
134 if (!send_packet(&p))
141 struct timeval tval2;
142 GetTimeOfDay(&tval2);
143 if (TvalDiff(&tval,&tval2) > retry_time) {
145 if (!found && !send_packet(&p))
151 if ((p2=receive_packet(fd,NMB_PACKET,90)))
153 struct nmb_packet *nmb2 = &p2->packet.nmb;
154 debug_nmb_packet(p2);
156 if (nmb->header.name_trn_id != nmb2->header.name_trn_id ||
157 !nmb2->header.response) {
158 /* its not for us - maybe deal with it later */
166 if (nmb2->header.opcode != 0 ||
167 nmb2->header.nm_flags.bcast ||
168 nmb2->header.rcode ||
169 !nmb2->header.ancount ||
170 nmb2->answers->rr_type != 0x21) {
171 /* XXXX what do we do with this? could be a redirect, but
172 we'll discard it for the moment */
177 _interpret_node_status(&nmb2->answers->rdata[0], master,rname);
184 DEBUG(0,("No status response (this is not unusual)\n"));
190 /****************************************************************************
191 do a netbios name query to find someones IP
192 returns an array of IP addresses or NULL if none
193 *count will be set to the number of addresses returned
194 ****************************************************************************/
195 struct in_addr *name_query(int fd,char *name,int name_type,
196 BOOL bcast,BOOL recurse,
197 struct in_addr to_ip, int *count, void (*fn)())
201 int retry_time = bcast?250:2000;
203 struct packet_struct p;
204 struct packet_struct *p2;
205 struct nmb_packet *nmb = &p.packet.nmb;
206 static int name_trn_id = 0;
207 struct in_addr *ip_list = NULL;
209 bzero((char *)&p,sizeof(p));
212 if (!name_trn_id) name_trn_id = (time(NULL)%(unsigned)0x7FFF) +
213 (getpid()%(unsigned)100);
214 name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF;
216 nmb->header.name_trn_id = name_trn_id;
217 nmb->header.opcode = 0;
218 nmb->header.response = False;
219 nmb->header.nm_flags.bcast = bcast;
220 nmb->header.nm_flags.recursion_available = False;
221 nmb->header.nm_flags.recursion_desired = recurse;
222 nmb->header.nm_flags.trunc = False;
223 nmb->header.nm_flags.authoritative = False;
224 nmb->header.rcode = 0;
225 nmb->header.qdcount = 1;
226 nmb->header.ancount = 0;
227 nmb->header.nscount = 0;
228 nmb->header.arcount = 0;
230 make_nmb_name(&nmb->question.question_name,name,name_type,scope);
232 nmb->question.question_type = 0x20;
233 nmb->question.question_class = 0x1;
238 p.timestamp = time(NULL);
239 p.packet_type = NMB_PACKET;
243 if (!send_packet(&p))
250 struct timeval tval2;
251 GetTimeOfDay(&tval2);
252 if (TvalDiff(&tval,&tval2) > retry_time) {
254 if (!found && !send_packet(&p))
260 if ((p2=receive_packet(fd,NMB_PACKET,90)))
262 struct nmb_packet *nmb2 = &p2->packet.nmb;
263 debug_nmb_packet(p2);
265 if (nmb->header.name_trn_id != nmb2->header.name_trn_id ||
266 !nmb2->header.response) {
267 /* its not for us - maybe deal with it later
268 (put it on the queue?) */
276 if (nmb2->header.opcode != 0 ||
277 nmb2->header.nm_flags.bcast ||
278 nmb2->header.rcode ||
279 !nmb2->header.ancount) {
280 /* XXXX what do we do with this? could be a redirect, but
281 we'll discard it for the moment */
286 ip_list = (struct in_addr *)Realloc(ip_list, sizeof(ip_list[0]) *
287 ((*count)+nmb2->answers->rdlength/6));
289 DEBUG(fn?3:2,("Got a positive name query response from %s ( ",
291 for (i=0;i<nmb2->answers->rdlength/6;i++) {
292 putip((char *)&ip_list[(*count)],&nmb2->answers->rdata[2+i*6]);
293 DEBUG(fn?3:2,("%s ",inet_ntoa(ip_list[(*count)])));
296 DEBUG(fn?3:2,(")\n"));
298 found=True; retries=0;