📄 nmbd_packets.c
字号:
/* Unix SMB/CIFS implementation. NBT netbios routines and daemon - version 2 Copyright (C) Andrew Tridgell 1994-1998 Copyright (C) Luke Kenneth Casson Leighton 1994-1998 Copyright (C) Jeremy Allison 1994-2003 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 2 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, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */#include "includes.h"extern int ClientNMB;extern int ClientDGRAM;extern int global_nmb_port;extern int num_response_packets;extern struct in_addr loopback_ip;static void queue_packet(struct packet_struct *packet);BOOL rescan_listen_set = False;/******************************************************************* The global packet linked-list. Incoming entries are added to the end of this list. It is supposed to remain fairly short so we won't bother with an end pointer.******************************************************************/static struct packet_struct *packet_queue = NULL;/***************************************************************************Utility function to find the specific fd to send a packet out on.**************************************************************************/static int find_subnet_fd_for_address( struct in_addr local_ip ){ struct subnet_record *subrec; for( subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) if(ip_equal(local_ip, subrec->myip)) return subrec->nmb_sock; return ClientNMB;}/***************************************************************************Utility function to find the specific fd to send a mailslot packet out on.**************************************************************************/static int find_subnet_mailslot_fd_for_address( struct in_addr local_ip ){ struct subnet_record *subrec; for( subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) if(ip_equal(local_ip, subrec->myip)) return subrec->dgram_sock; return ClientDGRAM;}/***************************************************************************Get/Set problematic nb_flags as network byte order 16 bit int.**************************************************************************/uint16 get_nb_flags(char *buf){ return ((((uint16)*buf)&0xFFFF) & NB_FLGMSK);}void set_nb_flags(char *buf, uint16 nb_flags){ *buf++ = ((nb_flags & NB_FLGMSK) & 0xFF); *buf = '\0';}/***************************************************************************Dumps out the browse packet data.**************************************************************************/static void debug_browse_data(char *outbuf, int len){ int i,j; DEBUG( 4, ( "debug_browse_data():\n" ) ); for (i = 0; i < len; i+= 16) { DEBUGADD( 4, ( "%3x char ", i ) ); for (j = 0; j < 16; j++) { unsigned char x; if (i+j >= len) break; x = outbuf[i+j]; if (x < 32 || x > 127) x = '.'; DEBUGADD( 4, ( "%c", x ) ); } DEBUGADD( 4, ( "%*s hex", 16-j, "" ) ); for (j = 0; j < 16; j++) { if (i+j >= len) break; DEBUGADD( 4, ( " %02x", (unsigned char)outbuf[i+j] ) ); } DEBUGADD( 4, ("\n") ); }}/*************************************************************************** Generates the unique transaction identifier**************************************************************************/static uint16 name_trn_id=0;static uint16 generate_name_trn_id(void){ if (!name_trn_id) { name_trn_id = ((unsigned)time(NULL)%(unsigned)0x7FFF) + ((unsigned)sys_getpid()%(unsigned)100); } name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF; return name_trn_id;}/*************************************************************************** Either loops back or sends out a completed NetBIOS packet.**************************************************************************/static BOOL send_netbios_packet(struct packet_struct *p){ BOOL loopback_this_packet = False; /* Check if we are sending to or from ourselves as a WINS server. */ if(ismyip(p->ip) && (p->port == global_nmb_port)) loopback_this_packet = True; if(loopback_this_packet) { struct packet_struct *lo_packet = NULL; DEBUG(5,("send_netbios_packet: sending packet to ourselves.\n")); if((lo_packet = copy_packet(p)) == NULL) return False; queue_packet(lo_packet); } else if (!send_packet(p)) { DEBUG(0,("send_netbios_packet: send_packet() to IP %s port %d failed\n", inet_ntoa(p->ip),p->port)); return False; } return True;} /*************************************************************************** Sets up the common elements of an outgoing NetBIOS packet. Note: do not attempt to rationalise whether rec_des should be set or not in a particular situation. Just follow rfc_1002 or look at examples from WinXX. It does NOT follow the rule that requests to the wins server always have rec_des true. See for example name releases and refreshes**************************************************************************/static struct packet_struct *create_and_init_netbios_packet(struct nmb_name *nmbname, BOOL bcast, BOOL rec_des, struct in_addr to_ip){ struct packet_struct *packet = NULL; struct nmb_packet *nmb = NULL; /* Allocate the packet_struct we will return. */ if((packet = SMB_MALLOC_P(struct packet_struct)) == NULL) { DEBUG(0,("create_and_init_netbios_packet: malloc fail (1) for packet struct.\n")); return NULL; } memset((char *)packet,'\0',sizeof(*packet)); nmb = &packet->packet.nmb; nmb->header.name_trn_id = generate_name_trn_id(); nmb->header.response = False; nmb->header.nm_flags.recursion_desired = rec_des; nmb->header.nm_flags.recursion_available = False; nmb->header.nm_flags.trunc = False; nmb->header.nm_flags.authoritative = False; nmb->header.nm_flags.bcast = bcast; nmb->header.rcode = 0; nmb->header.qdcount = 1; nmb->header.ancount = 0; nmb->header.nscount = 0; nmb->question.question_name = *nmbname; nmb->question.question_type = QUESTION_TYPE_NB_QUERY; nmb->question.question_class = QUESTION_CLASS_IN; packet->ip = to_ip; packet->port = NMB_PORT; packet->fd = ClientNMB; packet->timestamp = time(NULL); packet->packet_type = NMB_PACKET; packet->locked = False; return packet; /* Caller must free. */}/*************************************************************************** Sets up the common elements of register, refresh or release packet.**************************************************************************/static BOOL create_and_init_additional_record(struct packet_struct *packet, uint16 nb_flags, struct in_addr *register_ip){ struct nmb_packet *nmb = &packet->packet.nmb; if((nmb->additional = SMB_MALLOC_P(struct res_rec)) == NULL) { DEBUG(0,("initiate_name_register_packet: malloc fail for additional record.\n")); return False; } memset((char *)nmb->additional,'\0',sizeof(struct res_rec)); nmb->additional->rr_name = nmb->question.question_name; nmb->additional->rr_type = RR_TYPE_NB; nmb->additional->rr_class = RR_CLASS_IN; /* See RFC 1002, sections 5.1.1.1, 5.1.1.2 and 5.1.1.3 */ if (nmb->header.nm_flags.bcast) nmb->additional->ttl = PERMANENT_TTL; else nmb->additional->ttl = lp_max_ttl(); nmb->additional->rdlength = 6; set_nb_flags(nmb->additional->rdata,nb_flags); /* Set the address for the name we are registering. */ putip(&nmb->additional->rdata[2], register_ip); /* it turns out that Jeremys code was correct, we are supposed to send registrations from the IP we are registering. The trick is what to do on timeouts! When we send on a non-routable IP then the reply will timeout, and we should treat this as success, not failure. That means we go into our standard refresh cycle for that name which copes nicely with disconnected networks. */ packet->fd = find_subnet_fd_for_address(*register_ip); return True;}/*************************************************************************** Sends out a name query.**************************************************************************/static BOOL initiate_name_query_packet( struct packet_struct *packet){ struct nmb_packet *nmb = NULL; nmb = &packet->packet.nmb; nmb->header.opcode = NMB_NAME_QUERY_OPCODE; nmb->header.arcount = 0; nmb->header.nm_flags.recursion_desired = True; DEBUG(4,("initiate_name_query_packet: sending query for name %s (bcast=%s) to IP %s\n", nmb_namestr(&nmb->question.question_name), BOOLSTR(nmb->header.nm_flags.bcast), inet_ntoa(packet->ip))); return send_netbios_packet( packet );}/*************************************************************************** Sends out a name query - from a WINS server. **************************************************************************/static BOOL initiate_name_query_packet_from_wins_server( struct packet_struct *packet){ struct nmb_packet *nmb = NULL; nmb = &packet->packet.nmb; nmb->header.opcode = NMB_NAME_QUERY_OPCODE; nmb->header.arcount = 0; nmb->header.nm_flags.recursion_desired = False; DEBUG(4,("initiate_name_query_packet_from_wins_server: sending query for name %s (bcast=%s) to IP %s\n", nmb_namestr(&nmb->question.question_name), BOOLSTR(nmb->header.nm_flags.bcast), inet_ntoa(packet->ip))); return send_netbios_packet( packet );} /*************************************************************************** Sends out a name register.**************************************************************************/static BOOL initiate_name_register_packet( struct packet_struct *packet, uint16 nb_flags, struct in_addr *register_ip){ struct nmb_packet *nmb = &packet->packet.nmb; nmb->header.opcode = NMB_NAME_REG_OPCODE; nmb->header.arcount = 1; nmb->header.nm_flags.recursion_desired = True; if(create_and_init_additional_record(packet, nb_flags, register_ip) == False) return False; DEBUG(4,("initiate_name_register_packet: sending registration for name %s (bcast=%s) to IP %s\n", nmb_namestr(&nmb->additional->rr_name), BOOLSTR(nmb->header.nm_flags.bcast), inet_ntoa(packet->ip))); return send_netbios_packet( packet );}/*************************************************************************** Sends out a multihomed name register.**************************************************************************/static BOOL initiate_multihomed_name_register_packet(struct packet_struct *packet, uint16 nb_flags, struct in_addr *register_ip){ struct nmb_packet *nmb = &packet->packet.nmb; fstring second_ip_buf; fstrcpy(second_ip_buf, inet_ntoa(packet->ip)); nmb->header.opcode = NMB_NAME_MULTIHOMED_REG_OPCODE; nmb->header.arcount = 1; nmb->header.nm_flags.recursion_desired = True; if(create_and_init_additional_record(packet, nb_flags, register_ip) == False) return False; DEBUG(4,("initiate_multihomed_name_register_packet: sending registration \for name %s IP %s (bcast=%s) to IP %s\n", nmb_namestr(&nmb->additional->rr_name), inet_ntoa(*register_ip), BOOLSTR(nmb->header.nm_flags.bcast), second_ip_buf )); return send_netbios_packet( packet );} /*************************************************************************** Sends out a name refresh.**************************************************************************/static BOOL initiate_name_refresh_packet( struct packet_struct *packet, uint16 nb_flags, struct in_addr *refresh_ip){ struct nmb_packet *nmb = &packet->packet.nmb; nmb->header.opcode = NMB_NAME_REFRESH_OPCODE_8; nmb->header.arcount = 1; nmb->header.nm_flags.recursion_desired = False; if(create_and_init_additional_record(packet, nb_flags, refresh_ip) == False) return False; DEBUG(4,("initiate_name_refresh_packet: sending refresh for name %s (bcast=%s) to IP %s\n", nmb_namestr(&nmb->additional->rr_name), BOOLSTR(nmb->header.nm_flags.bcast), inet_ntoa(packet->ip)));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -