1 /* 2 * Copyright (c) 2000, Boris Popov 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by Boris Popov. 16 * 4. Neither the name of the author nor the names of any co-contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * $Id: nbns_rq.c,v 1.5 2001/02/17 03:07:24 bp Exp $ 33 */ 34 #include <sys/param.h> 35 #include <sys/socket.h> 36 #include <sys/time.h> 37 38 #include <ctype.h> 39 #include <netdb.h> 40 #include <err.h> 41 #include <errno.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <stdio.h> 45 #include <unistd.h> 46 47 #define NB_NEEDRESOLVER 48 #include <netsmb/netbios.h> 49 #include <netsmb/smb_lib.h> 50 #include <netsmb/nb_lib.h> 51 52 53 static int nbns_rq_create(int opcode, struct nb_ctx *ctx, struct nbns_rq **rqpp); 54 static void nbns_rq_done(struct nbns_rq *rqp); 55 static int nbns_rq_getrr(struct nbns_rq *rqp, struct nbns_rr *rrp); 56 static int nbns_rq_prepare(struct nbns_rq *rqp); 57 static int nbns_rq(struct nbns_rq *rqp); 58 59 static struct nb_ifdesc *nb_iflist; 60 61 int 62 nbns_resolvename(const char *name, struct nb_ctx *ctx, struct sockaddr **adpp) 63 { 64 struct nbns_rq *rqp; 65 struct nb_name nn; 66 struct nbns_rr rr; 67 struct sockaddr_in *dest; 68 int error, rdrcount, len; 69 70 if (strlen(name) > NB_NAMELEN) 71 return NBERROR(NBERR_NAMETOOLONG); 72 error = nbns_rq_create(NBNS_OPCODE_QUERY, ctx, &rqp); 73 if (error) 74 return error; 75 bzero(&nn, sizeof(nn)); 76 strlcpy(nn.nn_name, name, sizeof(nn.nn_name)); 77 nn.nn_scope = ctx->nb_scope; 78 nn.nn_type = NBT_SERVER; 79 rqp->nr_nmflags = NBNS_NMFLAG_RD; 80 rqp->nr_qdname = &nn; 81 rqp->nr_qdtype = NBNS_QUESTION_TYPE_NB; 82 rqp->nr_qdclass = NBNS_QUESTION_CLASS_IN; 83 rqp->nr_qdcount = 1; 84 dest = &rqp->nr_dest; 85 *dest = ctx->nb_ns; 86 dest->sin_family = AF_INET; 87 dest->sin_len = sizeof(*dest); 88 if (dest->sin_port == 0) 89 dest->sin_port = htons(137); 90 if (dest->sin_addr.s_addr == INADDR_ANY) 91 dest->sin_addr.s_addr = htonl(INADDR_BROADCAST); 92 if (dest->sin_addr.s_addr == INADDR_BROADCAST) 93 rqp->nr_flags |= NBRQF_BROADCAST; 94 error = nbns_rq_prepare(rqp); 95 if (error) { 96 nbns_rq_done(rqp); 97 return error; 98 } 99 rdrcount = NBNS_MAXREDIRECTS; 100 for (;;) { 101 error = nbns_rq(rqp); 102 if (error) 103 break; 104 if ((rqp->nr_rpnmflags & NBNS_NMFLAG_AA) == 0) { 105 if (rdrcount-- == 0) { 106 error = NBERROR(NBERR_TOOMANYREDIRECTS); 107 break; 108 } 109 error = nbns_rq_getrr(rqp, &rr); 110 if (error) 111 break; 112 error = nbns_rq_getrr(rqp, &rr); 113 if (error) 114 break; 115 bcopy(rr.rr_data, &dest->sin_addr, 4); 116 rqp->nr_flags &= ~NBRQF_BROADCAST; 117 continue; 118 } 119 if (rqp->nr_rpancount == 0) { 120 error = NBERROR(NBERR_HOSTNOTFOUND); 121 break; 122 } 123 error = nbns_rq_getrr(rqp, &rr); 124 if (error) 125 break; 126 len = sizeof(struct sockaddr_in); 127 dest = malloc(len); 128 if (dest == NULL) 129 return ENOMEM; 130 bzero(dest, len); 131 dest->sin_len = len; 132 dest->sin_family = AF_INET; 133 bcopy(rr.rr_data + 2, &dest->sin_addr.s_addr, 4); 134 dest->sin_port = htons(SMB_TCP_PORT); 135 *adpp = (struct sockaddr*)dest; 136 ctx->nb_lastns = rqp->nr_sender; 137 break; 138 } 139 nbns_rq_done(rqp); 140 return error; 141 } 142 143 int 144 nbns_rq_create(int opcode, struct nb_ctx *ctx, struct nbns_rq **rqpp) 145 { 146 struct nbns_rq *rqp; 147 static u_int16_t trnid; 148 int error; 149 150 rqp = malloc(sizeof(*rqp)); 151 if (rqp == NULL) 152 return ENOMEM; 153 bzero(rqp, sizeof(*rqp)); 154 error = mb_init(&rqp->nr_rq, NBDG_MAXSIZE); 155 if (error) { 156 free(rqp); 157 return error; 158 } 159 rqp->nr_opcode = opcode; 160 rqp->nr_nbd = ctx; 161 rqp->nr_trnid = trnid++; 162 *rqpp = rqp; 163 return 0; 164 } 165 166 void 167 nbns_rq_done(struct nbns_rq *rqp) 168 { 169 if (rqp == NULL) 170 return; 171 if (rqp->nr_fd >= 0) 172 close(rqp->nr_fd); 173 mb_done(&rqp->nr_rq); 174 mb_done(&rqp->nr_rp); 175 free(rqp); 176 } 177 178 /* 179 * Extract resource record from the packet. Assume that there is only 180 * one mbuf. 181 */ 182 int 183 nbns_rq_getrr(struct nbns_rq *rqp, struct nbns_rr *rrp) 184 { 185 struct mbdata *mbp = &rqp->nr_rp; 186 u_char *cp; 187 int error, len; 188 189 bzero(rrp, sizeof(*rrp)); 190 cp = mbp->mb_pos; 191 len = nb_encname_len(cp); 192 if (len < 1) 193 return NBERROR(NBERR_INVALIDRESPONSE); 194 rrp->rr_name = cp; 195 error = mb_get_mem(mbp, NULL, len); 196 if (error) 197 return error; 198 mb_get_uint16be(mbp, &rrp->rr_type); 199 mb_get_uint16be(mbp, &rrp->rr_class); 200 mb_get_uint32be(mbp, &rrp->rr_ttl); 201 mb_get_uint16be(mbp, &rrp->rr_rdlength); 202 rrp->rr_data = mbp->mb_pos; 203 error = mb_get_mem(mbp, NULL, rrp->rr_rdlength); 204 return error; 205 } 206 207 int 208 nbns_rq_prepare(struct nbns_rq *rqp) 209 { 210 struct nb_ctx *ctx = rqp->nr_nbd; 211 struct mbdata *mbp = &rqp->nr_rq; 212 u_int8_t nmflags; 213 u_char *cp; 214 int len, error; 215 216 error = mb_init(&rqp->nr_rp, NBDG_MAXSIZE); 217 if (error) 218 return error; 219 if (rqp->nr_dest.sin_addr.s_addr == INADDR_BROADCAST) { 220 rqp->nr_nmflags |= NBNS_NMFLAG_BCAST; 221 if (nb_iflist == NULL) { 222 error = nb_enum_if(&nb_iflist, 100); 223 if (error) 224 return error; 225 } 226 } else 227 rqp->nr_nmflags &= ~NBNS_NMFLAG_BCAST; 228 mb_put_uint16be(mbp, rqp->nr_trnid); 229 nmflags = ((rqp->nr_opcode & 0x1F) << 3) | ((rqp->nr_nmflags & 0x70) >> 4); 230 mb_put_uint8(mbp, nmflags); 231 mb_put_uint8(mbp, (rqp->nr_nmflags & 0x0f) << 4 /* rcode */); 232 mb_put_uint16be(mbp, rqp->nr_qdcount); 233 mb_put_uint16be(mbp, rqp->nr_ancount); 234 mb_put_uint16be(mbp, rqp->nr_nscount); 235 mb_put_uint16be(mbp, rqp->nr_arcount); 236 if (rqp->nr_qdcount) { 237 if (rqp->nr_qdcount > 1) 238 return EINVAL; 239 len = nb_name_len(rqp->nr_qdname); 240 error = mb_fit(mbp, len, (char**)&cp); 241 if (error) 242 return error; 243 nb_name_encode(rqp->nr_qdname, cp); 244 mb_put_uint16be(mbp, rqp->nr_qdtype); 245 mb_put_uint16be(mbp, rqp->nr_qdclass); 246 } 247 m_lineup(mbp->mb_top, &mbp->mb_top); 248 if (ctx->nb_timo == 0) 249 ctx->nb_timo = 1; /* by default 1 second */ 250 return 0; 251 } 252 253 static int 254 nbns_rq_recv(struct nbns_rq *rqp) 255 { 256 struct mbdata *mbp = &rqp->nr_rp; 257 void *rpdata = mtod(mbp->mb_top, void *); 258 fd_set rd, wr, ex; 259 struct timeval tv; 260 struct sockaddr_in sender; 261 int s = rqp->nr_fd; 262 int n, len; 263 264 FD_ZERO(&rd); 265 FD_ZERO(&wr); 266 FD_ZERO(&ex); 267 FD_SET(s, &rd); 268 269 tv.tv_sec = rqp->nr_nbd->nb_timo; 270 tv.tv_usec = 0; 271 272 n = select(s + 1, &rd, &wr, &ex, &tv); 273 if (n == -1) 274 return -1; 275 if (n == 0) 276 return ETIMEDOUT; 277 if (FD_ISSET(s, &rd) == 0) 278 return ETIMEDOUT; 279 len = sizeof(sender); 280 n = recvfrom(s, rpdata, mbp->mb_top->m_maxlen, 0, 281 (struct sockaddr*)&sender, &len); 282 if (n < 0) 283 return errno; 284 mbp->mb_top->m_len = mbp->mb_count = n; 285 rqp->nr_sender = sender; 286 return 0; 287 } 288 289 static int 290 nbns_rq_opensocket(struct nbns_rq *rqp) 291 { 292 struct sockaddr_in locaddr; 293 int opt, s; 294 295 s = rqp->nr_fd = socket(AF_INET, SOCK_DGRAM, 0); 296 if (s < 0) 297 return errno; 298 if (rqp->nr_flags & NBRQF_BROADCAST) { 299 opt = 1; 300 if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt)) < 0) 301 return errno; 302 if (rqp->nr_if == NULL) 303 return NBERROR(NBERR_NOBCASTIFS); 304 bzero(&locaddr, sizeof(locaddr)); 305 locaddr.sin_family = AF_INET; 306 locaddr.sin_len = sizeof(locaddr); 307 locaddr.sin_addr = rqp->nr_if->id_addr; 308 rqp->nr_dest.sin_addr.s_addr = rqp->nr_if->id_addr.s_addr | ~rqp->nr_if->id_mask.s_addr; 309 if (bind(s, (struct sockaddr*)&locaddr, sizeof(locaddr)) < 0) 310 return errno; 311 } 312 return 0; 313 } 314 315 static int 316 nbns_rq_send(struct nbns_rq *rqp) 317 { 318 struct mbdata *mbp = &rqp->nr_rq; 319 int s = rqp->nr_fd; 320 321 if (sendto(s, mtod(mbp->mb_top, char *), mbp->mb_count, 0, 322 (struct sockaddr*)&rqp->nr_dest, sizeof(rqp->nr_dest)) < 0) 323 return errno; 324 return 0; 325 } 326 327 int 328 nbns_rq(struct nbns_rq *rqp) 329 { 330 struct mbdata *mbp = &rqp->nr_rq; 331 u_int16_t rpid; 332 u_int8_t nmflags; 333 int error, retrycount; 334 335 rqp->nr_if = nb_iflist; 336 again: 337 error = nbns_rq_opensocket(rqp); 338 if (error) 339 return error; 340 retrycount = 3; /* XXX - configurable */ 341 for (;;) { 342 error = nbns_rq_send(rqp); 343 if (error) 344 return error; 345 error = nbns_rq_recv(rqp); 346 if (error) { 347 if (error != ETIMEDOUT || retrycount == 0) { 348 if ((rqp->nr_nmflags & NBNS_NMFLAG_BCAST) && 349 rqp->nr_if != NULL && 350 rqp->nr_if->id_next != NULL) { 351 rqp->nr_if = rqp->nr_if->id_next; 352 close(rqp->nr_fd); 353 goto again; 354 } else 355 return error; 356 } 357 retrycount--; 358 continue; 359 } 360 mbp = &rqp->nr_rp; 361 if (mbp->mb_count < 12) 362 return NBERROR(NBERR_INVALIDRESPONSE); 363 mb_get_uint16be(mbp, &rpid); 364 if (rpid != rqp->nr_trnid) 365 return NBERROR(NBERR_INVALIDRESPONSE); 366 break; 367 } 368 mb_get_uint8(mbp, &nmflags); 369 rqp->nr_rpnmflags = (nmflags & 7) << 4; 370 mb_get_uint8(mbp, &nmflags); 371 rqp->nr_rpnmflags |= (nmflags & 0xf0) >> 4; 372 rqp->nr_rprcode = nmflags & 0xf; 373 if (rqp->nr_rprcode) 374 return NBERROR(rqp->nr_rprcode); 375 mb_get_uint16be(mbp, &rpid); /* QDCOUNT */ 376 mb_get_uint16be(mbp, &rqp->nr_rpancount); 377 mb_get_uint16be(mbp, &rqp->nr_rpnscount); 378 mb_get_uint16be(mbp, &rqp->nr_rparcount); 379 return 0; 380 } 381