📄 nmblib.c
字号:
if (length < 14) return(False); dgram->header.msg_type = CVAL(inbuf,0); flags = CVAL(inbuf,1); dgram->header.flags.node_type = (enum node_type)((flags>>2)&3); if (flags & 1) dgram->header.flags.more = True; if (flags & 2) dgram->header.flags.first = True; dgram->header.dgm_id = RSVAL(inbuf,2); putip((char *)&dgram->header.source_ip,inbuf+4); dgram->header.source_port = RSVAL(inbuf,8); dgram->header.dgm_length = RSVAL(inbuf,10); dgram->header.packet_offset = RSVAL(inbuf,12); offset = 14; if (dgram->header.msg_type == 0x10 || dgram->header.msg_type == 0x11 || dgram->header.msg_type == 0x12) { offset += parse_nmb_name(inbuf,offset,length,&dgram->source_name); offset += parse_nmb_name(inbuf,offset,length,&dgram->dest_name); } if (offset >= length || (length-offset > sizeof(dgram->data))) return(False); dgram->datasize = length-offset; memcpy(dgram->data,inbuf+offset,dgram->datasize); /* Paranioa. Ensure the last 2 bytes in the dgram buffer are zero. This should be true anyway, just enforce it for paranioa sake. JRA. */ SMB_ASSERT(dgram->datasize <= (sizeof(dgram->data)-2)); memset(&dgram->data[sizeof(dgram->data)-2], '\0', 2); return(True);}/******************************************************************* Parse a nmb packet. Return False if the packet can't be parsed or is invalid for some reason, True otherwise.******************************************************************/static BOOL parse_nmb(char *inbuf,int length,struct nmb_packet *nmb){ int nm_flags,offset; memset((char *)nmb,'\0',sizeof(*nmb)); if (length < 12) return(False); /* parse the header */ nmb->header.name_trn_id = RSVAL(inbuf,0); DEBUG(10,("parse_nmb: packet id = %d\n", nmb->header.name_trn_id)); nmb->header.opcode = (CVAL(inbuf,2) >> 3) & 0xF; nmb->header.response = ((CVAL(inbuf,2)>>7)&1)?True:False; nm_flags = ((CVAL(inbuf,2) & 0x7) << 4) + (CVAL(inbuf,3)>>4); nmb->header.nm_flags.bcast = (nm_flags&1)?True:False; nmb->header.nm_flags.recursion_available = (nm_flags&8)?True:False; nmb->header.nm_flags.recursion_desired = (nm_flags&0x10)?True:False; nmb->header.nm_flags.trunc = (nm_flags&0x20)?True:False; nmb->header.nm_flags.authoritative = (nm_flags&0x40)?True:False; nmb->header.rcode = CVAL(inbuf,3) & 0xF; nmb->header.qdcount = RSVAL(inbuf,4); nmb->header.ancount = RSVAL(inbuf,6); nmb->header.nscount = RSVAL(inbuf,8); nmb->header.arcount = RSVAL(inbuf,10); if (nmb->header.qdcount) { offset = parse_nmb_name(inbuf,12,length,&nmb->question.question_name); if (!offset) return(False); if (length - (12+offset) < 4) return(False); nmb->question.question_type = RSVAL(inbuf,12+offset); nmb->question.question_class = RSVAL(inbuf,12+offset+2); offset += 12+4; } else { offset = 12; } /* and any resource records */ if (nmb->header.ancount && !parse_alloc_res_rec(inbuf,&offset,length,&nmb->answers, nmb->header.ancount)) return(False); if (nmb->header.nscount && !parse_alloc_res_rec(inbuf,&offset,length,&nmb->nsrecs, nmb->header.nscount)) return(False); if (nmb->header.arcount && !parse_alloc_res_rec(inbuf,&offset,length,&nmb->additional, nmb->header.arcount)) return(False); return(True);}/******************************************************************* 'Copy constructor' for an nmb packet.******************************************************************/static struct packet_struct *copy_nmb_packet(struct packet_struct *packet){ struct nmb_packet *nmb; struct nmb_packet *copy_nmb; struct packet_struct *pkt_copy; if(( pkt_copy = SMB_MALLOC_P(struct packet_struct)) == NULL) { DEBUG(0,("copy_nmb_packet: malloc fail.\n")); return NULL; } /* Structure copy of entire thing. */ *pkt_copy = *packet; /* Ensure this copy is not locked. */ pkt_copy->locked = False; /* Ensure this copy has no resource records. */ nmb = &packet->packet.nmb; copy_nmb = &pkt_copy->packet.nmb; copy_nmb->answers = NULL; copy_nmb->nsrecs = NULL; copy_nmb->additional = NULL; /* Now copy any resource records. */ if (nmb->answers) { if((copy_nmb->answers = SMB_MALLOC_ARRAY(struct res_rec,nmb->header.ancount)) == NULL) goto free_and_exit; memcpy((char *)copy_nmb->answers, (char *)nmb->answers, nmb->header.ancount * sizeof(struct res_rec)); } if (nmb->nsrecs) { if((copy_nmb->nsrecs = SMB_MALLOC_ARRAY(struct res_rec, nmb->header.nscount)) == NULL) goto free_and_exit; memcpy((char *)copy_nmb->nsrecs, (char *)nmb->nsrecs, nmb->header.nscount * sizeof(struct res_rec)); } if (nmb->additional) { if((copy_nmb->additional = SMB_MALLOC_ARRAY(struct res_rec, nmb->header.arcount)) == NULL) goto free_and_exit; memcpy((char *)copy_nmb->additional, (char *)nmb->additional, nmb->header.arcount * sizeof(struct res_rec)); } return pkt_copy; free_and_exit: SAFE_FREE(copy_nmb->answers); SAFE_FREE(copy_nmb->nsrecs); SAFE_FREE(copy_nmb->additional); SAFE_FREE(pkt_copy); DEBUG(0,("copy_nmb_packet: malloc fail in resource records.\n")); return NULL;}/******************************************************************* 'Copy constructor' for a dgram packet.******************************************************************/static struct packet_struct *copy_dgram_packet(struct packet_struct *packet){ struct packet_struct *pkt_copy; if(( pkt_copy = SMB_MALLOC_P(struct packet_struct)) == NULL) { DEBUG(0,("copy_dgram_packet: malloc fail.\n")); return NULL; } /* Structure copy of entire thing. */ *pkt_copy = *packet; /* Ensure this copy is not locked. */ pkt_copy->locked = False; /* There are no additional pointers in a dgram packet, we are finished. */ return pkt_copy;}/******************************************************************* 'Copy constructor' for a generic packet.******************************************************************/struct packet_struct *copy_packet(struct packet_struct *packet){ if(packet->packet_type == NMB_PACKET) return copy_nmb_packet(packet); else if (packet->packet_type == DGRAM_PACKET) return copy_dgram_packet(packet); return NULL;} /******************************************************************* Free up any resources associated with an nmb packet.******************************************************************/static void free_nmb_packet(struct nmb_packet *nmb){ SAFE_FREE(nmb->answers); SAFE_FREE(nmb->nsrecs); SAFE_FREE(nmb->additional);}/******************************************************************* Free up any resources associated with a dgram packet.******************************************************************/static void free_dgram_packet(struct dgram_packet *nmb){ /* We have nothing to do for a dgram packet. */}/******************************************************************* Free up any resources associated with a packet.******************************************************************/void free_packet(struct packet_struct *packet){ if (packet->locked) return; if (packet->packet_type == NMB_PACKET) free_nmb_packet(&packet->packet.nmb); else if (packet->packet_type == DGRAM_PACKET) free_dgram_packet(&packet->packet.dgram); ZERO_STRUCTPN(packet); SAFE_FREE(packet);}/******************************************************************* Parse a packet buffer into a packet structure.******************************************************************/struct packet_struct *parse_packet(char *buf,int length, enum packet_type packet_type){ struct packet_struct *p; BOOL ok=False; p = SMB_MALLOC_P(struct packet_struct); if (!p) return(NULL); p->next = NULL; p->prev = NULL; p->ip = lastip; p->port = lastport; p->locked = False; p->timestamp = time(NULL); p->packet_type = packet_type; switch (packet_type) { case NMB_PACKET: ok = parse_nmb(buf,length,&p->packet.nmb); break; case DGRAM_PACKET: ok = parse_dgram(buf,length,&p->packet.dgram); break; } if (!ok) { free_packet(p); return NULL; } return p;}/******************************************************************* Read a packet from a socket and parse it, returning a packet ready to be used or put on the queue. This assumes a UDP socket.******************************************************************/struct packet_struct *read_packet(int fd,enum packet_type packet_type){ struct packet_struct *packet; char buf[MAX_DGRAM_SIZE]; int length; length = read_udp_socket(fd,buf,sizeof(buf)); if (length < MIN_DGRAM_SIZE) return(NULL); packet = parse_packet(buf, length, packet_type); if (!packet) return NULL; packet->fd = fd; num_good_receives++; DEBUG(5,("Received a packet of len %d from (%s) port %d\n", length, inet_ntoa(packet->ip), packet->port ) ); return(packet);} /******************************************************************* Send a udp packet on a already open socket.******************************************************************/static BOOL send_udp(int fd,char *buf,int len,struct in_addr ip,int port){ BOOL ret = False; int i; struct sockaddr_in sock_out; /* set the address and port */ memset((char *)&sock_out,'\0',sizeof(sock_out)); putip((char *)&sock_out.sin_addr,(char *)&ip); sock_out.sin_port = htons( port ); sock_out.sin_family = AF_INET; DEBUG( 5, ( "Sending a packet of len %d to (%s) on port %d\n", len, inet_ntoa(ip), port ) ); /* * Patch to fix asynch error notifications from Linux kernel. */ for (i = 0; i < 5; i++) { ret = (sendto(fd,buf,len,0,(struct sockaddr *)&sock_out, sizeof(sock_out)) >= 0); if (ret || errno != ECONNREFUSED) break; } if (!ret) DEBUG(0,("Packet send failed to %s(%d) ERRNO=%s\n", inet_ntoa(ip),port,strerror(errno))); if (ret) num_good_sends++; return(ret);}/******************************************************************* Build a dgram packet ready for sending. XXXX This currently doesn't handle packets too big for one datagram. It should split them and use the packet_offset, more and first flags to handle the fragmentation. Yuck. [...but it isn't clear that we would ever need to send a a fragmented NBT Datagram. The IP layer does its own fragmentation to ensure that messages can fit into the path MTU. It *is* important to be able to receive and rebuild fragmented NBT datagrams, just in case someone out there really has implemented this 'feature'. crh -)------ ]******************************************************************/static int build_dgram(char *buf,struct packet_struct *p){ struct dgram_packet *dgram = &p->packet.dgram; unsigned char *ubuf = (unsigned char *)buf; int offset=0; /* put in the header */ ubuf[0] = dgram->header.msg_type; ubuf[1] = (((int)dgram->header.flags.node_type)<<2); if (dgram->header.flags.more) ubuf[1] |= 1; if (dgram->header.flags.first) ubuf[1] |= 2; RSSVAL(ubuf,2,dgram->header.dgm_id); putip(ubuf+4,(char *)&dgram->header.source_ip); RSSVAL(ubuf,8,dgram->header.source_port); RSSVAL(ubuf,12,dgram->header.packet_offset); offset = 14; if (dgram->header.msg_type == 0x10 || dgram->header.msg_type == 0x11 || dgram->header.msg_type == 0x12) { offset += put_nmb_name((char *)ubuf,offset,&dgram->source_name); offset += put_nmb_name((char *)ubuf,offset,&dgram->dest_name); } memcpy(ubuf+offset,dgram->data,dgram->datasize); offset += dgram->datasize; /* automatically set the dgm_length * NOTE: RFC1002 says the dgm_length does *not* * include the fourteen-byte header. crh */ dgram->header.dgm_length = (offset - 14); RSSVAL(ubuf,10,dgram->header.dgm_length); return(offset);}/******************************************************************* Build a nmb name*******************************************************************/void make_nmb_name( struct nmb_name *n, const char *name, int type){ fstring unix_name; memset( (char *)n, '\0', sizeof(struct nmb_name) ); fstrcpy(unix_name, name); strupper_m(unix_name); push_ascii(n->name, unix_name, sizeof(n->name), STR_TERMINATE); n->name_type = (unsigned int)type & 0xFF; push_ascii(n->scope, global_scope(), 64, STR_TERMINATE);}/******************************************************************* Compare two nmb names******************************************************************/BOOL nmb_name_equal(struct nmb_name *n1, struct nmb_name *n2){ return ((n1->name_type == n2->name_type) && strequal(n1->name ,n2->name ) && strequal(n1->scope,n2->scope));}/******************************************************************* Build a nmb packet ready for sending. XXXX this currently relies on not being passed something that expands to a packet too big for the buffer. Eventually this should be changed to set the trunc bit so the receiver can request the rest via tcp (when that becomes supported)******************************************************************/static int build_nmb(char *buf,struct packet_struct *p){ struct nmb_packet *nmb = &p->packet.nmb; unsigned char *ubuf = (unsigned char *)buf; int offset=0; /* put in the header */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -