📄 nmblib.c
字号:
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 = (struct packet_struct *)malloc(sizeof(*packet))) == 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 = (struct res_rec *) malloc(nmb->header.ancount * sizeof(struct res_rec))) == 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 = (struct res_rec *) malloc(nmb->header.nscount * sizeof(struct res_rec))) == 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 = (struct res_rec *) malloc(nmb->header.arcount * sizeof(struct res_rec))) == 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: if(copy_nmb->answers) free((char *)copy_nmb->answers); if(copy_nmb->nsrecs) free((char *)copy_nmb->nsrecs); if(copy_nmb->additional) free((char *)copy_nmb->additional); free((char *)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 = (struct packet_struct *)malloc(sizeof(*packet))) == 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){ if (nmb->answers) free(nmb->answers); if (nmb->nsrecs) free(nmb->nsrecs); if (nmb->additional) 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); free(packet);}/******************************************************************* 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){ extern struct in_addr lastip; extern int lastport; struct packet_struct *packet; char buf[MAX_DGRAM_SIZE]; int length; BOOL ok=False; length = read_udp_socket(fd,buf,sizeof(buf)); if (length < MIN_DGRAM_SIZE) return(NULL); packet = (struct packet_struct *)malloc(sizeof(*packet)); if (!packet) return(NULL); packet->next = NULL; packet->prev = NULL; packet->ip = lastip; packet->port = lastport; packet->fd = fd; packet->locked = False; packet->timestamp = time(NULL); packet->packet_type = packet_type; switch (packet_type) { case NMB_PACKET: ok = parse_nmb(buf,length,&packet->packet.nmb); break; case DGRAM_PACKET: ok = parse_dgram(buf,length,&packet->packet.dgram); break; } if (!ok) { DEBUG(10,("read_packet: discarding packet id = %d\n", packet->packet.nmb.header.name_trn_id)); free_packet(packet); return(NULL); } 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; 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 ) ); ret = (sendto(fd,buf,len,0,(struct sockaddr *)&sock_out, sizeof(sock_out)) >= 0); 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. ******************************************************************/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 */ dgram->header.dgm_length = offset; 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 ){ extern pstring global_scope; memset( (char *)n, '\0', sizeof(struct nmb_name) ); StrnCpy( n->name, name, 15 ); strupper( n->name ); n->name_type = (unsigned int)type & 0xFF; StrnCpy( n->scope, global_scope, 63 ); strupper( n->scope );}/******************************************************************* 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 */ RSSVAL(ubuf,offset,nmb->header.name_trn_id); ubuf[offset+2] = (nmb->header.opcode & 0xF) << 3; if (nmb->header.response) ubuf[offset+2] |= (1<<7); if (nmb->header.nm_flags.authoritative && nmb->header.response) ubuf[offset+2] |= 0x4; if (nmb->header.nm_flags.trunc) ubuf[offset+2] |= 0x2; if (nmb->header.nm_flags.recursion_desired) ubuf[offset+2] |= 0x1; if (nmb->header.nm_flags.recursion_available && nmb->header.response) ubuf[offset+3] |= 0x80; if (nmb->header.nm_flags.bcast) ubuf[offset+3] |= 0x10; ubuf[offset+3] |= (nmb->header.rcode & 0xF); RSSVAL(ubuf,offset+4,nmb->header.qdcount); RSSVAL(ubuf,offset+6,nmb->header.ancount); RSSVAL(ubuf,offset+8,nmb->header.nscount); RSSVAL(ubuf,offset+10,nmb->header.arcount); offset += 12; if (nmb->header.qdcount) { /* XXXX this doesn't handle a qdcount of > 1 */ offset += put_nmb_name((char *)ubuf,offset,&nmb->question.question_name); RSSVAL(ubuf,offset,nmb->question.question_type); RSSVAL(ubuf,offset+2,nmb->question.question_class); offset += 4; } if (nmb->header.ancount) offset += put_res_rec((char *)ubuf,offset,nmb->answers, nmb->header.ancount); if (nmb->header.nscount) offset += put_res_rec((char *)ubuf,offset,nmb->nsrecs, nmb->header.nscount); /* * The spec says we must put compressed name pointers * in the following outgoing packets : * NAME_REGISTRATION_REQUEST, NAME_REFRESH_REQUEST, * NAME_RELEASE_REQUEST. */ if((nmb->header.response == False) && ((nmb->header.opcode == NMB_NAME_REG_OPCODE) || (nmb->header.opcode == NMB_NAME_RELEASE_OPCODE) || (nmb->header.opcode == NMB_NAME_REFRESH_OPCODE_8) || (nmb->header.opcode == NMB_NAME_REFRESH_OPCODE_9) || (nmb->header.opcode == NMB_NAME_MULTIHOMED_REG_OPCODE)) && (nmb->header.arcount == 1)) { offset += put_compressed_name_ptr(ubuf,offset,nmb->additional,12); } else if (nmb->header.arcount) { offset += put_res_rec((char *)ubuf,offset,nmb->additional, nmb->header.arcount); } return(offset);}/******************************************************************* send a packet_struct ******************************************************************/BOOL send_packet(struct packet_struct *p){ char buf[1024]; int len=0; memset(buf,'\0',sizeof(buf)); switch (p->packet_type) { case NMB_PACKET: len = build_nmb(buf,p); debug_nmb_packet(p); break; case DGRAM_PACKET: len = build_dgram(buf,p); break; } if (!len) return(False); return(send_udp(p->fd,buf,len,p->ip,p->port));}/**************************************************************************** receive a packet with timeout on a open UDP filedescriptor The timeout is in milliseconds ***************************************************************************/struct packet_struct *receive_packet(int fd,enum packet_type type,int t){ fd_set fds; struct timeval timeout; FD_ZERO(&fds); FD_SET(fd,&fds); timeout.tv_sec = t/1000; timeout.tv_usec = 1000*(t%1000); sys_select(fd+1,&fds,&timeout); if (FD_ISSET(fd,&fds)) return(read_packet(fd,type)); return(NULL);}/****************************************************************************return the number of bits that match between two 4 character buffers ***************************************************************************/static int matching_bits(uchar *p1, uchar *p2){ int i, j, ret = 0; for (i=0; i<4; i++) { if (p1[i] != p2[i]) break; ret += 8; } if (i==4) return ret; for (j=0; j<8; j++) { if ((p1[i] & (1<<(7-j))) != (p2[i] & (1<<(7-j)))) break; ret++; } return ret;}static uchar sort_ip[4];/****************************************************************************compare two query reply records ***************************************************************************/static int name_query_comp(uchar *p1, uchar *p2){ return matching_bits(p2+2, sort_ip) - matching_bits(p1+2, sort_ip);}/****************************************************************************sort a set of 6 byte name query response records so that the IPs thathave the most leading bits in common with the specified address come first ***************************************************************************/void sort_query_replies(char *data, int n, struct in_addr ip){ if (n <= 1) return; putip(sort_ip, (char *)&ip); qsort(data, n, 6, QSORT_CAST name_query_comp);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -