diff options
Diffstat (limited to 'source4/nbt_server/packet.c')
-rw-r--r-- | source4/nbt_server/packet.c | 387 |
1 files changed, 387 insertions, 0 deletions
diff --git a/source4/nbt_server/packet.c b/source4/nbt_server/packet.c new file mode 100644 index 0000000..b9aea56 --- /dev/null +++ b/source4/nbt_server/packet.c @@ -0,0 +1,387 @@ +/* + Unix SMB/CIFS implementation. + + packet utility functions + + Copyright (C) Andrew Tridgell 2005 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "nbt_server/nbt_server.h" +#include "samba/service_task.h" +#include "lib/socket/socket.h" +#include "librpc/gen_ndr/ndr_nbt.h" +#include "param/param.h" + +/* + we received a badly formed packet - log it +*/ +void nbtd_bad_packet(struct nbt_name_packet *packet, + const struct socket_address *src, const char *reason) +{ + DEBUG(2,("nbtd: bad packet '%s' from %s:%d\n", reason, src->addr, src->port)); + if (DEBUGLVL(5)) { + NDR_PRINT_DEBUG(nbt_name_packet, packet); + } +} + + +/* + see if an incoming packet is a broadcast packet from one of our own + interfaces +*/ +bool nbtd_self_packet_and_bcast(struct nbt_name_socket *nbtsock, + struct nbt_name_packet *packet, + const struct socket_address *src) +{ + struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data, + struct nbtd_interface); + + /* if its not a broadcast then its not considered a self packet */ + if (!(packet->operation & NBT_FLAG_BROADCAST)) { + return false; + } + + /* + * this uses the fact that iface->nbtsock is the unicast listen address + * if the interface isn't the global bcast interface + * + * so if the request was directed to the unicast address it isn't a broadcast + * message + */ + if (iface->nbtsock == nbtsock && + iface != iface->nbtsrv->bcast_interface) { + return false; + } + + return nbtd_self_packet(nbtsock, packet, src); +} + +bool nbtd_self_packet(struct nbt_name_socket *nbtsock, + struct nbt_name_packet *packet, + const struct socket_address *src) +{ + struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data, + struct nbtd_interface); + struct nbtd_server *nbtsrv = iface->nbtsrv; + + /* if its not from the nbt port, then it wasn't a broadcast from us */ + if (src->port != lpcfg_nbt_port(iface->nbtsrv->task->lp_ctx)) { + return false; + } + + /* we have to loop over our interface list, seeing if its from + one of our own interfaces */ + for (iface=nbtsrv->interfaces;iface;iface=iface->next) { + if (strcmp(src->addr, iface->ip_address) == 0) { + return true; + } + } + + return false; +} + +struct nbt_name_packet *nbtd_name_query_reply_packet( + TALLOC_CTX *mem_ctx, + uint16_t trn_id, + uint32_t ttl, + uint16_t nb_flags, + const struct nbt_name *name, + const char **addresses, + size_t num_addresses) +{ + struct nbt_name_packet *packet; + size_t i; + struct nbt_res_rec *answer; + struct nbt_rdata_netbios *rdata; + NTSTATUS status; + + if (num_addresses == 0) { + return NULL; + } + + packet = talloc_zero(mem_ctx, struct nbt_name_packet); + if (packet == NULL) { + return NULL; + } + + packet->name_trn_id = trn_id; + packet->ancount = 1; + packet->operation = + NBT_FLAG_REPLY | + NBT_OPCODE_QUERY | + NBT_FLAG_AUTHORITATIVE | + NBT_FLAG_RECURSION_DESIRED | + NBT_FLAG_RECURSION_AVAIL; + + packet->answers = talloc_array(packet, struct nbt_res_rec, 1); + if (packet->answers == NULL) { + goto failed; + } + answer = packet->answers; + + status = nbt_name_dup(packet->answers, name, &answer->name); + if (!NT_STATUS_IS_OK(status)) { + goto failed; + } + answer->rr_type = NBT_QTYPE_NETBIOS; + answer->rr_class = NBT_QCLASS_IP; + answer->ttl = ttl; + + rdata = &answer->rdata.netbios; + rdata->length = num_addresses*6; + rdata->addresses = talloc_array( + packet->answers, + struct nbt_rdata_address, + num_addresses); + if (rdata->addresses == NULL) { + goto failed; + } + + for (i=0; i<num_addresses; i++) { + struct nbt_rdata_address *addr = &rdata->addresses[i]; + addr->nb_flags = nb_flags; + addr->ipaddr = talloc_strdup(packet->answers, addresses[i]); + if (addr->ipaddr == NULL) { + goto failed; + } + } + + return packet; + +failed: + TALLOC_FREE(packet); + return NULL; +} + +/* + send a name query reply +*/ +void nbtd_name_query_reply(struct nbt_name_socket *nbtsock, + struct nbt_name_packet *request_packet, + struct socket_address *src, + struct nbt_name *name, uint32_t ttl, + uint16_t nb_flags, const char **addresses) +{ + struct nbt_name_packet *packet; + struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data, + struct nbtd_interface); + struct nbtd_server *nbtsrv = iface->nbtsrv; + + packet = nbtd_name_query_reply_packet( + nbtsock, + request_packet->name_trn_id, + ttl, + nb_flags, + name, + addresses, + str_list_length(addresses)); + if (packet == NULL) { + return; + } + + DEBUG(7,("Sending name query reply for %s at %s to %s:%d\n", + nbt_name_string(packet, name), addresses[0], src->addr, src->port)); + + nbtsrv->stats.total_sent++; + nbt_name_reply_send(nbtsock, src, packet); + + talloc_free(packet); +} + + +/* + send a negative name query reply +*/ +void nbtd_negative_name_query_reply(struct nbt_name_socket *nbtsock, + struct nbt_name_packet *request_packet, + struct socket_address *src) +{ + struct nbt_name_packet *packet; + struct nbt_name *name = &request_packet->questions[0].name; + struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data, + struct nbtd_interface); + struct nbtd_server *nbtsrv = iface->nbtsrv; + + packet = talloc_zero(nbtsock, struct nbt_name_packet); + if (packet == NULL) return; + + packet->name_trn_id = request_packet->name_trn_id; + packet->ancount = 1; + packet->operation = + NBT_FLAG_REPLY | + NBT_OPCODE_QUERY | + NBT_FLAG_AUTHORITATIVE | + NBT_RCODE_NAM; + + packet->answers = talloc_array(packet, struct nbt_res_rec, 1); + if (packet->answers == NULL) goto failed; + + packet->answers[0].name = *name; + packet->answers[0].rr_type = NBT_QTYPE_NULL; + packet->answers[0].rr_class = NBT_QCLASS_IP; + packet->answers[0].ttl = 0; + ZERO_STRUCT(packet->answers[0].rdata); + + DEBUG(7,("Sending negative name query reply for %s to %s:%d\n", + nbt_name_string(packet, name), src->addr, src->port)); + + nbtsrv->stats.total_sent++; + nbt_name_reply_send(nbtsock, src, packet); + +failed: + talloc_free(packet); +} + +/* + send a name registration reply +*/ +void nbtd_name_registration_reply(struct nbt_name_socket *nbtsock, + struct nbt_name_packet *request_packet, + struct socket_address *src, + uint8_t rcode) +{ + struct nbt_name_packet *packet; + struct nbt_name *name = &request_packet->questions[0].name; + struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data, + struct nbtd_interface); + struct nbtd_server *nbtsrv = iface->nbtsrv; + + packet = talloc_zero(nbtsock, struct nbt_name_packet); + if (packet == NULL) return; + + packet->name_trn_id = request_packet->name_trn_id; + packet->ancount = 1; + packet->operation = + NBT_FLAG_REPLY | + NBT_OPCODE_REGISTER | + NBT_FLAG_AUTHORITATIVE | + NBT_FLAG_RECURSION_DESIRED | + NBT_FLAG_RECURSION_AVAIL | + rcode; + + packet->answers = talloc_array(packet, struct nbt_res_rec, 1); + if (packet->answers == NULL) goto failed; + + packet->answers[0].name = *name; + packet->answers[0].rr_type = NBT_QTYPE_NETBIOS; + packet->answers[0].rr_class = NBT_QCLASS_IP; + packet->answers[0].ttl = request_packet->additional[0].ttl; + packet->answers[0].rdata = request_packet->additional[0].rdata; + + DEBUG(7,("Sending %s name registration reply for %s to %s:%d\n", + rcode==0?"positive":"negative", + nbt_name_string(packet, name), src->addr, src->port)); + + nbtsrv->stats.total_sent++; + nbt_name_reply_send(nbtsock, src, packet); + +failed: + talloc_free(packet); +} + + +/* + send a name release reply +*/ +void nbtd_name_release_reply(struct nbt_name_socket *nbtsock, + struct nbt_name_packet *request_packet, + struct socket_address *src, + uint8_t rcode) +{ + struct nbt_name_packet *packet; + struct nbt_name *name = &request_packet->questions[0].name; + struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data, + struct nbtd_interface); + struct nbtd_server *nbtsrv = iface->nbtsrv; + + packet = talloc_zero(nbtsock, struct nbt_name_packet); + if (packet == NULL) return; + + packet->name_trn_id = request_packet->name_trn_id; + packet->ancount = 1; + packet->operation = + NBT_FLAG_REPLY | + NBT_OPCODE_RELEASE | + NBT_FLAG_AUTHORITATIVE | + rcode; + + packet->answers = talloc_array(packet, struct nbt_res_rec, 1); + if (packet->answers == NULL) goto failed; + + packet->answers[0].name = *name; + packet->answers[0].rr_type = NBT_QTYPE_NETBIOS; + packet->answers[0].rr_class = NBT_QCLASS_IP; + packet->answers[0].ttl = request_packet->additional[0].ttl; + packet->answers[0].rdata = request_packet->additional[0].rdata; + + DEBUG(7,("Sending %s name release reply for %s to %s:%d\n", + rcode==0?"positive":"negative", + nbt_name_string(packet, name), src->addr, src->port)); + + nbtsrv->stats.total_sent++; + nbt_name_reply_send(nbtsock, src, packet); + +failed: + talloc_free(packet); +} + + +/* + send a WACK reply +*/ +void nbtd_wack_reply(struct nbt_name_socket *nbtsock, + struct nbt_name_packet *request_packet, + struct socket_address *src, + uint32_t ttl) +{ + struct nbt_name_packet *packet; + struct nbt_name *name = &request_packet->questions[0].name; + struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data, + struct nbtd_interface); + struct nbtd_server *nbtsrv = iface->nbtsrv; + + packet = talloc_zero(nbtsock, struct nbt_name_packet); + if (packet == NULL) return; + + packet->name_trn_id = request_packet->name_trn_id; + packet->ancount = 1; + packet->operation = + NBT_FLAG_REPLY | + NBT_OPCODE_WACK | + NBT_FLAG_AUTHORITATIVE; + + packet->answers = talloc_array(packet, struct nbt_res_rec, 1); + if (packet->answers == NULL) goto failed; + + packet->answers[0].name = *name; + packet->answers[0].rr_type = NBT_QTYPE_NETBIOS; + packet->answers[0].rr_class = NBT_QCLASS_IP; + packet->answers[0].ttl = ttl; + packet->answers[0].rdata.data.length = 2; + packet->answers[0].rdata.data.data = talloc_array(packet, uint8_t, 2); + if (packet->answers[0].rdata.data.data == NULL) goto failed; + RSSVAL(packet->answers[0].rdata.data.data, 0, request_packet->operation); + + DEBUG(7,("Sending WACK reply for %s to %s:%d\n", + nbt_name_string(packet, name), src->addr, src->port)); + + nbtsrv->stats.total_sent++; + nbt_name_reply_send(nbtsock, src, packet); + +failed: + talloc_free(packet); +} |