/* answer a name query */ void nbtd_request_query(struct nbt_name_socket *nbtsock, struct nbt_name_packet *packet, struct socket_address *src) { struct nbtd_iface_name *iname; struct nbt_name *name; struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data, struct nbtd_interface); /* see if its a node status query */ if (packet->qdcount == 1 && packet->questions[0].question_type == NBT_QTYPE_STATUS) { nbtd_query_status(nbtsock, packet, src); return; } NBTD_ASSERT_PACKET(packet, src, packet->qdcount == 1); NBTD_ASSERT_PACKET(packet, src, packet->questions[0].question_type == NBT_QTYPE_NETBIOS); NBTD_ASSERT_PACKET(packet, src, packet->questions[0].question_class == NBT_QCLASS_IP); /* see if we have the requested name on this interface */ name = &packet->questions[0].name; iname = nbtd_find_iname(iface, name, 0); if (iname == NULL) { /* don't send negative replies to broadcast queries */ if (packet->operation & NBT_FLAG_BROADCAST) { return; } if (packet->operation & NBT_FLAG_RECURSION_DESIRED) { nbtd_winsserver_request(nbtsock, packet, src); return; } /* otherwise send a negative reply */ nbtd_negative_name_query_reply(nbtsock, packet, src); return; } /* * normally we should forward all queries with the * recursion desired flag to the wins server, but this * breaks are winsclient code, when doing mhomed registrations */ if (!(packet->operation & NBT_FLAG_BROADCAST) && (packet->operation & NBT_FLAG_RECURSION_DESIRED) && (iname->nb_flags & NBT_NM_GROUP) && lpcfg_wins_support(iface->nbtsrv->task->lp_ctx)) { nbtd_winsserver_request(nbtsock, packet, src); return; } /* if the name is not yet active and its a broadcast query then ignore it for now */ if (!(iname->nb_flags & NBT_NM_ACTIVE) && (packet->operation & NBT_FLAG_BROADCAST)) { DEBUG(7,("Query for %s from %s - name not active yet on %s\n", nbt_name_string(packet, name), src->addr, iface->ip_address)); return; } nbtd_name_query_reply(nbtsock, packet, src, &iname->name, iname->ttl, iname->nb_flags, nbtd_address_list(iface, packet)); }
/* query a name */ static void nbtd_winsserver_query(struct loadparm_context *lp_ctx, struct nbt_name_socket *nbtsock, struct nbt_name_packet *packet, struct socket_address *src) { NTSTATUS status; struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data, struct nbtd_interface); struct wins_server *winssrv = iface->nbtsrv->winssrv; struct nbt_name *name = &packet->questions[0].name; struct winsdb_record *rec; struct winsdb_record *rec_1b = NULL; const char **addresses; const char **addresses_1b = NULL; uint16_t nb_flags = 0; if (name->type == NBT_NAME_MASTER) { goto notfound; } /* * w2k3 returns the first address of the 0x1B record as first address * to a 0x1C query * * since Windows 2000 Service Pack 2 there's on option to trigger this behavior: * * HKEY_LOCAL_MACHINE\System\CurrentControlset\Services\WINS\Parameters\Prepend1BTo1CQueries * Typ: Daten REG_DWORD * Value: 0 = deactivated, 1 = activated */ if (name->type == NBT_NAME_LOGON && lpcfg_parm_bool(lp_ctx, NULL, "nbtd", "wins_prepend1Bto1Cqueries", true)) { struct nbt_name name_1b; name_1b = *name; name_1b.type = NBT_NAME_PDC; status = winsdb_lookup(winssrv->wins_db, &name_1b, packet, &rec_1b); if (NT_STATUS_IS_OK(status)) { addresses_1b = winsdb_addr_string_list(packet, rec_1b->addresses); } } status = winsdb_lookup(winssrv->wins_db, name, packet, &rec); if (!NT_STATUS_IS_OK(status)) { if (!lpcfg_wins_dns_proxy(lp_ctx)) { goto notfound; } if (name->type != NBT_NAME_CLIENT && name->type != NBT_NAME_SERVER) { goto notfound; } nbtd_wins_dns_proxy_query(nbtsock, packet, src); return; } /* * for group's we always reply with * 255.255.255.255 as address, even if * the record is released or tombstoned */ if (rec->type == WREPL_TYPE_GROUP) { addresses = str_list_add(NULL, "255.255.255.255"); talloc_steal(packet, addresses); if (!addresses) { goto notfound; } nb_flags |= NBT_NM_GROUP; goto found; } if (rec->state != WREPL_STATE_ACTIVE) { goto notfound; } addresses = winsdb_addr_string_list(packet, rec->addresses); if (!addresses) { goto notfound; } /* * if addresses_1b isn't NULL, we have a 0x1C query and need to return the * first 0x1B address as first address */ if (addresses_1b && addresses_1b[0]) { const char **addresses_1c = addresses; uint32_t i; uint32_t num_addrs; addresses = str_list_add(NULL, addresses_1b[0]); if (!addresses) { goto notfound; } talloc_steal(packet, addresses); num_addrs = 1; for (i=0; addresses_1c[i]; i++) { if (strcmp(addresses_1b[0], addresses_1c[i]) == 0) continue; /* * stop when we already have 25 addresses */ if (num_addrs >= 25) break; num_addrs++; addresses = str_list_add(addresses, addresses_1c[i]); if (!addresses) { goto notfound; } } } if (rec->type == WREPL_TYPE_SGROUP) { nb_flags |= NBT_NM_GROUP; } else { nb_flags |= (rec->node <<13); } /* * since Windows 2000 Service Pack 2 there's on option to trigger this behavior: * * HKEY_LOCAL_MACHINE\System\CurrentControlset\Services\WINS\Parameters\Randomize1CList * Typ: Daten REG_DWORD * Value: 0 = deactivated, 1 = activated */ if (name->type == NBT_NAME_LOGON && lpcfg_parm_bool(lp_ctx, NULL, "nbtd", "wins_randomize1Clist", false)) { nbtd_wins_randomize1Clist(lp_ctx, addresses, src); } found: nbtd_name_query_reply(nbtsock, packet, src, name, 0, nb_flags, addresses); return; notfound: nbtd_negative_name_query_reply(nbtsock, packet, src); }