123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968 |
- /*
- Unix SMB/Netbios implementation.
- Version 1.9.
- NBT netbios library routines
- Copyright (C) Andrew Tridgell 1994-1998
-
- 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
- */
- #include "includes.h"
- const char *unix_error_string (int error_num);
- extern int DEBUGLEVEL;
- int num_good_sends = 0;
- int num_good_receives = 0;
- static struct opcode_names {
- const char *nmb_opcode_name;
- int opcode;
- } const nmb_header_opcode_names[] = {
- {"Query", 0 },
- {"Registration", 5 },
- {"Release", 6 },
- {"WACK", 7 },
- {"Refresh", 8 },
- {"Refresh(altcode)", 9 },
- {"Multi-homed Registration", 15 },
- {0, -1 }
- };
- /****************************************************************************
- * Lookup a nmb opcode name.
- ****************************************************************************/
- static const char *lookup_opcode_name( int opcode )
- {
- const struct opcode_names *op_namep = nmb_header_opcode_names;
- while(op_namep->nmb_opcode_name) {
- if(opcode == op_namep->opcode)
- return op_namep->nmb_opcode_name;
- op_namep++;
- }
- return "<unknown opcode>";
- }
- /****************************************************************************
- print out a res_rec structure
- ****************************************************************************/
- static void debug_nmb_res_rec(struct res_rec *res, const char *hdr)
- {
- int i, j;
- DEBUGADD( 4, ( " %s: nmb_name=%s rr_type=%d rr_class=%d ttl=%d\n",
- hdr,
- nmb_namestr(&res->rr_name),
- res->rr_type,
- res->rr_class,
- res->ttl ) );
- if( res->rdlength == 0 || res->rdata == NULL )
- return;
- for (i = 0; i < res->rdlength; i+= 16)
- {
- DEBUGADD(4, (" %s %3x char ", hdr, i));
- for (j = 0; j < 16; j++)
- {
- unsigned char x = res->rdata[i+j];
- if (x < 32 || x > 127) x = '.';
-
- if (i+j >= res->rdlength) break;
- DEBUGADD(4, ("%c", x));
- }
-
- DEBUGADD(4, (" hex "));
- for (j = 0; j < 16; j++)
- {
- if (i+j >= res->rdlength) break;
- DEBUGADD(4, ("%02X", (unsigned char)res->rdata[i+j]));
- }
-
- DEBUGADD(4, ("\n"));
- }
- }
- /****************************************************************************
- process a nmb packet
- ****************************************************************************/
- void debug_nmb_packet(struct packet_struct *p)
- {
- struct nmb_packet *nmb = &p->packet.nmb;
- if( DEBUGLVL( 4 ) )
- {
- dbgtext( "nmb packet from %s(%d) header: id=%d opcode=%s(%d) response=%s\n",
- inet_ntoa(p->ip), p->port,
- nmb->header.name_trn_id,
- lookup_opcode_name(nmb->header.opcode),
- nmb->header.opcode,
- BOOLSTR(nmb->header.response) );
- dbgtext( " header: flags: bcast=%s rec_avail=%s rec_des=%s trunc=%s auth=%s\n",
- BOOLSTR(nmb->header.nm_flags.bcast),
- BOOLSTR(nmb->header.nm_flags.recursion_available),
- BOOLSTR(nmb->header.nm_flags.recursion_desired),
- BOOLSTR(nmb->header.nm_flags.trunc),
- BOOLSTR(nmb->header.nm_flags.authoritative) );
- dbgtext( " header: rcode=%d qdcount=%d ancount=%d nscount=%d arcount=%d\n",
- nmb->header.rcode,
- nmb->header.qdcount,
- nmb->header.ancount,
- nmb->header.nscount,
- nmb->header.arcount );
- }
- if (nmb->header.qdcount)
- {
- DEBUGADD( 4, ( " question: q_name=%s q_type=%d q_class=%d\n",
- nmb_namestr(&nmb->question.question_name),
- nmb->question.question_type,
- nmb->question.question_class) );
- }
- if (nmb->answers && nmb->header.ancount)
- {
- debug_nmb_res_rec(nmb->answers,"answers");
- }
- if (nmb->nsrecs && nmb->header.nscount)
- {
- debug_nmb_res_rec(nmb->nsrecs,"nsrecs");
- }
- if (nmb->additional && nmb->header.arcount)
- {
- debug_nmb_res_rec(nmb->additional,"additional");
- }
- }
- /*******************************************************************
- handle "compressed" name pointers
- ******************************************************************/
- static BOOL handle_name_ptrs(unsigned char *ubuf,int *offset,int length,
- BOOL *got_pointer,int *ret)
- {
- int loop_count=0;
-
- while ((ubuf[*offset] & 0xC0) == 0xC0) {
- if (!*got_pointer) (*ret) += 2;
- (*got_pointer)=True;
- (*offset) = ((ubuf[*offset] & ~0xC0)<<8) | ubuf[(*offset)+1];
- if (loop_count++ == 10 || (*offset) < 0 || (*offset)>(length-2)) {
- return(False);
- }
- }
- return(True);
- }
- /*******************************************************************
- parse a nmb name from "compressed" format to something readable
- return the space taken by the name, or 0 if the name is invalid
- ******************************************************************/
- static int parse_nmb_name(char *inbuf,int offset,int length, struct nmb_name *name)
- {
- int m,n=0;
- unsigned char *ubuf = (unsigned char *)inbuf;
- int ret = 0;
- BOOL got_pointer=False;
- if (length - offset < 2)
- return(0);
- /* handle initial name pointers */
- if (!handle_name_ptrs(ubuf,&offset,length,&got_pointer,&ret))
- return(0);
-
- m = ubuf[offset];
- if (!m)
- return(0);
- if ((m & 0xC0) || offset+m+2 > length)
- return(0);
- memset((char *)name,'\0',sizeof(*name));
- /* the "compressed" part */
- if (!got_pointer)
- ret += m + 2;
- offset++;
- while (m > 0) {
- unsigned char c1,c2;
- c1 = ubuf[offset++]-'A';
- c2 = ubuf[offset++]-'A';
- if ((c1 & 0xF0) || (c2 & 0xF0) || ((size_t) n > sizeof(name->name)-1))
- return(0);
- name->name[n++] = (c1<<4) | c2;
- m -= 2;
- }
- name->name[n] = 0;
- if (n==16) {
- /* parse out the name type,
- its always in the 16th byte of the name */
- name->name_type = ((unsigned char)name->name[15]) & 0xff;
-
- /* remove trailing spaces */
- name->name[15] = 0;
- n = 14;
- while (n && name->name[n]==' ')
- name->name[n--] = 0;
- }
- /* now the domain parts (if any) */
- n = 0;
- while (ubuf[offset]) {
- /* we can have pointers within the domain part as well */
- if (!handle_name_ptrs(ubuf,&offset,length,&got_pointer,&ret))
- return(0);
- m = ubuf[offset];
- if (!got_pointer)
- ret += m+1;
- if (n)
- name->scope[n++] = '.';
- if (m+2+offset>length || (size_t) n+m+1 >sizeof(name->scope))
- return(0);
- offset++;
- while (m--)
- name->scope[n++] = (char)ubuf[offset++];
- }
- name->scope[n++] = 0;
- return(ret);
- }
- /*******************************************************************
- put a compressed nmb name into a buffer. return the length of the
- compressed name
- compressed names are really weird. The "compression" doubles the
- size. The idea is that it also means that compressed names conform
- to the doman name system. See RFC1002.
- ******************************************************************/
- static int put_nmb_name(char *buf,int offset,struct nmb_name *name)
- {
- int ret,m;
- fstring buf1;
- char *p;
- if (strcmp(name->name,"*") == 0) {
- /* special case for wildcard name */
- memset(buf1,'\0',20);
- buf1[0] = '*';
- buf1[15] = name->name_type;
- } else {
- slprintf(buf1, sizeof(buf1) - 1,"%-15.15s%c",name->name,name->name_type);
- }
- buf[offset] = 0x20;
- ret = 34;
- for (m=0;m<16;m++) {
- buf[offset+1+2*m] = 'A' + ((buf1[m]>>4)&0xF);
- buf[offset+2+2*m] = 'A' + (buf1[m]&0xF);
- }
- offset += 33;
- buf[offset] = 0;
- if (name->scope[0]) {
- /* XXXX this scope handling needs testing */
- ret += strlen(name->scope) + 1;
- pstrcpy(&buf[offset+1],name->scope);
-
- p = &buf[offset+1];
- while ((p = strchr(p,'.'))) {
- buf[offset] = PTR_DIFF(p,&buf[offset+1]);
- offset += (buf[offset] + 1);
- p = &buf[offset+1];
- }
- buf[offset] = strlen(&buf[offset+1]);
- }
- return(ret);
- }
- /*******************************************************************
- useful for debugging messages
- ******************************************************************/
- char *nmb_namestr(struct nmb_name *n)
- {
- static int i=0;
- static fstring ret[4];
- char *p = ret[i];
- if (!n->scope[0])
- slprintf(p,sizeof(fstring)-1, "%s<%02x>",n->name,n->name_type);
- else
- slprintf(p,sizeof(fstring)-1, "%s<%02x>.%s",n->name,n->name_type,n->scope);
- i = (i+1)%4;
- return(p);
- }
- /*******************************************************************
- allocate and parse some resource records
- ******************************************************************/
- static BOOL parse_alloc_res_rec(char *inbuf,int *offset,int length,
- struct res_rec **recs, int count)
- {
- int i;
- *recs = (struct res_rec *)malloc(sizeof(**recs)*count);
- if (!*recs) return(False);
- memset((char *)*recs,'\0',sizeof(**recs)*count);
- for (i=0;i<count;i++) {
- int l = parse_nmb_name(inbuf,*offset,length,&(*recs)[i].rr_name);
- (*offset) += l;
- if (!l || (*offset)+10 > length) {
- free(*recs);
- return(False);
- }
- (*recs)[i].rr_type = RSVAL(inbuf,(*offset));
- (*recs)[i].rr_class = RSVAL(inbuf,(*offset)+2);
- (*recs)[i].ttl = RIVAL(inbuf,(*offset)+4);
- (*recs)[i].rdlength = RSVAL(inbuf,(*offset)+8);
- (*offset) += 10;
- if ((size_t)(*recs)[i].rdlength>sizeof((*recs)[i].rdata) ||
- (*offset)+(*recs)[i].rdlength > length) {
- free(*recs);
- return(False);
- }
- memcpy((*recs)[i].rdata,inbuf+(*offset),(*recs)[i].rdlength);
- (*offset) += (*recs)[i].rdlength;
- }
- return(True);
- }
- /*******************************************************************
- put a resource record into a packet
- ******************************************************************/
- static int put_res_rec(char *buf,int offset,struct res_rec *recs,int count)
- {
- int ret=0;
- int i;
- for (i=0;i<count;i++) {
- int l = put_nmb_name(buf,offset,&recs[i].rr_name);
- offset += l;
- ret += l;
- RSSVAL(buf,offset,recs[i].rr_type);
- RSSVAL(buf,offset+2,recs[i].rr_class);
- RSIVAL(buf,offset+4,recs[i].ttl);
- RSSVAL(buf,offset+8,recs[i].rdlength);
- memcpy(buf+offset+10,recs[i].rdata,recs[i].rdlength);
- offset += 10+recs[i].rdlength;
- ret += 10+recs[i].rdlength;
- }
- return(ret);
- }
- /*******************************************************************
- put a compressed name pointer record into a packet
- ******************************************************************/
- static int put_compressed_name_ptr(unsigned char *buf,int offset,struct res_rec *rec,int ptr_offset)
- {
- int ret=0;
- buf[offset] = (0xC0 | ((ptr_offset >> 8) & 0xFF));
- buf[offset+1] = (ptr_offset & 0xFF);
- offset += 2;
- ret += 2;
- RSSVAL(buf,offset,rec->rr_type);
- RSSVAL(buf,offset+2,rec->rr_class);
- RSIVAL(buf,offset+4,rec->ttl);
- RSSVAL(buf,offset+8,rec->rdlength);
- memcpy(buf+offset+10,rec->rdata,rec->rdlength);
- offset += 10+rec->rdlength;
- ret += 10+rec->rdlength;
-
- return(ret);
- }
- /*******************************************************************
- parse a dgram packet. Return False if the packet can't be parsed
- or is invalid for some reason, True otherwise
- this is documented in section 4.4.1 of RFC1002
- ******************************************************************/
- static BOOL parse_dgram(char *inbuf,int length,struct dgram_packet *dgram)
- {
- int offset;
- int flags;
- memset((char *)dgram,'\0',sizeof(*dgram));
- 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 || ((size_t)length-offset > sizeof(dgram->data)))
- return(False);
- dgram->datasize = length-offset;
- memcpy(dgram->data,inbuf+offset,dgram->datasize);
- 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);
- }
- #if 0
- /*******************************************************************
- '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;
- }
- #endif /* 0 */
- /*******************************************************************
- 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. */
- (void) nmb;
- }
- /*******************************************************************
- 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, unix_error_string (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
- ******************************************************************/
- #if 0
- 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));
- }
- #endif /* 0 */
- /*******************************************************************
- 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);
- }
- #if 0
- /****************************************************************************
- 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 that
- have 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);
- }
- #endif /*0 */
|