---------------------[ previous ]---[ index ]---[ next ]---------------------- ============================================================================== -------------[ BFi numero 7, anno 2 - 25/12/1999 - file 7 di 22 ]------------- ============================================================================== -[ HACKiNG ]------------------------------------------------------------------ ---[ NETBi0S NAME SERViCE - pIGpEN ^-----^ Can I Play |--0-0--| with pI66Y ? -/\/\/| (* *) |\/\/\> \ p / ----- CONSUMO: 3 lattine di cocacola (ho intenzione di andare in Belgio a prendermi quelle sequestrate ;) MUSiCA: l'unica musica che sento e' quella di un Alpha dietro di me e di un server HP che ho a lato :P SALUTi: ins4ne ---> sapevo che i three mile pilot ti sarebbero stati a genio piggy power plant ---> la piantina grassa vicino al mio monitor chi mi ha cercato all'hack meeting .... non c'ero mi dispiace ... APPELLO: pig di "bella" presenza, tosato, pulito e in grado di vivere in appartamento cerca teknosacerdotessa per preghierine di fine millennio .... okok scherzavo :D uhm ... non ci sono comete che passano in questo periodo ...? TESTi & SOURCE CONSiGLIATI (come giustamente richiesto da voi lettori): GENERALi: - rfc1002 - rfc883 UNiX: - sorgenti di nat10 o altra versione (trovabile pure in sscan.tgz) - An analysis of TCP/IP NetBIOS file-sharing protocols CIFS: Common Insecurities Fail Scrutiny WINDOWS: - Aristocratic Communication: NetBIOS Ruediger R. Asche Microsoft Developer Network Technology Group Per capire il name service del NetBIOS basta prendere come punto di riferimento questa rappresentazione tratta dall'rfc 1002, il resto sara' facilmente comprensibile tenendo questo a mente o su un foglietto o dove volete (fatevelo tattuare (si dice cosi :) su una coscia ... ) 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | + ------ ------- + | HEADER | + ------ ------- + | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | / QUESTION ENTRIES / | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | / ANSWER RESOURCE RECORDS / | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | / AUTHORITY RESOURCE RECORDS / | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | / ADDITIONAL RESOURCE RECORDS / | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Andremo ora a vedere cosa contengono le varie parti e a definire le strutture che le caratterizzano: - HEADER - 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | NAME_TRN_ID | OPCODE | NM_FLAGS | RCODE | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | QDCOUNT | ANCOUNT | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | NSCOUNT | ARCOUNT | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ NAME_TRN_ID E' l'identificatore o meglio il TRANSACTiON ID: ovviamente il suo scopo e' quello di identificare il pacchetto di richiesta da un altro e nella risposta questo valore deve essere replicato. OPCODE Identifica il tipo di pacchetto inteso come operazione da svolgere.. se proprio vogliamo :) Symbol Bit(s) Description OPCODE 1-4 Operation specifier: 0 = query 5 = registration 6 = release 7 = WACK 8 = refresh R 0 RESPONSE flag: if bit == 0 then request packet if bit == 1 then response packet. NM_FLAGS Flags da settare per il tipo di operazione: The NM_FLAGS field is defined as: 0 1 2 3 4 5 6 +---+---+---+---+---+---+---+ |AA |TC |RD |RA | 0 | 0 | B | +---+---+---+---+---+---+---+ Symbol Bit(s) Description B 6 Broadcast Flag. = 1: packet was broadcast or multicast = 0: unicast RA 3 Recursion Available Flag. Only valid in responses from a NetBIOS Name Server -- must be zero in all other responses. If one (1) then the NBNS supports recursive query, registration, and release. If zero (0) then the end-node must iterate for query and challenge for registration. RD 2 Recursion Desired Flag. May only be set on a request to a NetBIOS Name Server. The NBNS will copy its state into the response packet. If one (1) the NBNS will iterate on the query, registration, or release. TC 1 Truncation Flag. Set if this message was truncated because the datagram carrying it would be greater than 576 bytes in length. Use TCP to get the information from the NetBIOS Name Server. AA 0 Authoritative Answer flag. Must be zero (0) if R flag of OPCODE is zero (0). If R flag is one (1) then if AA is one (1) then the node responding is an authority for the domain name. End nodes responding to queries always set this bit in responses. RCODE Codici di risposta del pacchetto inviato (0 nel caso in cui non si sono verificati errori): RCODE field values: Symbol Value Description: FMT_ERR 0x1 Format Error. Request was invalidly formatted. SRV_ERR 0x2 Server failure. Problem with NBNS, cannot process name. IMP_ERR 0x4 Unsupported request error. Allowable only for challenging NBNS when gets an Update type registration request. RFS_ERR 0x5 Refused error. For policy reasons server will not register this name from this host. ACT_ERR 0x6 Active error. Name is owned by another node. CFT_ERR 0x7 Name in conflict error. A UNIQUE name is owned by more than one node. QDCOUNT Contiene: 0 se si tratta di una pacchetto di risposta; N = numero delle entrate nella "question entries" se e' un pacchetto di richiesta; ANCOUNT Contiene il numero di records della answer section del pacchetto (vedi primo disegnetto articolo, tratto dall'rfc 1002). NSCOUNT Contiene il numero di record di tipo authority del pacchetto. ARCOUNT Contiene il numero di record di tipo additional del pacchetto. Concretizzando otteniamo la struttura seguente: struct { int name_trn_id; int opcode; BOOL response; struct { BOOL bcast; BOOL recursion_available; BOOL recursion_desired; BOOL trunc; BOOL authoritative; } nm_flags; int rcode; int qdcount; int ancount; int nscount; int arcount; } header; Wow, l'header e' finito. Dobbiamo ora analizzare le QUESTION ENTRIES settate nell'header su QDCOUNT... sembra che tutto acquisti logica... :) QUESTION ENTRIES 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | / QUESTION_NAME / / / | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | QUESTION_TYPE | QUESTION_CLASS | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ QUESTION_NAME Il nome compresso del NetBIOS name per la richiesta. Il metodo di compressione del nome e' probabilmente frutto di erba nel cervello... non essendo un drogato probabilmente non posso spiegarvelo :P (PS: Avete mai notato come molte volte le RFC non vengono cagate dai produttori ? :) Intanto tenetevi a mente questa struttura: struct nmb_name { char name[17]; char scope[64]; int name_type; }; Poi, per quanto riguarda il metodo di conversione, limitatevi ad usare la funzione e a capire che l'acido lisergico fa male! (PS: Ritornando ai tattuaggi fatevi tattuare questa funzione che tanto ricordarla non serve a niente perche' su nat la trovate in almeno due situazioni: le funzioni avranno nomi diversi, ma lo scopo e' lo stesso). QUESTION_TYPE Il tipo di richiesta: NB 0x0020 NetBIOS general Name Service Resource Record NBSTAT 0x0021 NetBIOS NODE STATUS Resource Record QUESTION_CLASS Definito 0x0001 : Symbol Value Description: IN 0x0001 Internet class Alla struttura ci arrivate da soli comunque eccola qui: struct{ struct nmb_name question_name; int question_type; int question_class; } question; RESOURCE RECORD Rimane da capire come e' stutturato un Resource Record... chiariamo subito che: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | / ANSWER RESOURCE RECORDS / | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | / AUTHORITY RESOURCE RECORDS / | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | / ADDITIONAL RESOURCE RECORDS / | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Questa parte del disegnetto iniziale viene risolta con un puntatore a struttura, il quale contiene i seguenti membri: 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | / RR_NAME / / / | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | RR_TYPE | RR_CLASS | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | TTL | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | RDLENGTH | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | / / / RDATA / | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ (se pensavate di non dover piu' incontrare questi disegnetti dopo tcp/udp/icmp/ip o che gia' li' ce ne fossero troppi... :) RR_NAME Il mitico nome psichedelico gia' presente nella question entry ... con campo QUESTION_NAME . RR_TYPE Il tipo di codice: A 0x0001 IP address Resource Record NS 0x0002 Name Server Resource Record NULL 0x000A NULL Resource Record NB 0x0020 NetBIOS general Name Service Resource Record NBSTAT 0x0021 NetBIOS NODE STATUS Resource Record RR_CLASS 0x0001 come nelle question entries in QUESTION_CLASS : IN 0x0001 Internet class TTL Time To Live ... vi dovrebbe gia' essere familiare :) RD_LENGTH Lunghezza di RDATA. RDATA Dipende da RR_DATA e da RR_TYPE. La struttura che otteniamo e' quindi la seguente: struct res_rec { struct nmb_name rr_name; int rr_type; int rr_class; int ttl; int rdlength; char rdata[MAX_DGRAM_SIZE]; }; E possiamo definire answer, authority e additional resource records cosi': struct res_rec *answers; struct res_rec *nsrecs; //authority struct res_rec *additional; Abbiamo cosi' completato la spiegazione del primo schema, quello che vi avevo detto di tener bene a mente... :) Possiamo ora costruire un pacchetto mettendoci tutto quanto dentro: struct nmb_packet { struct { int name_trn_id; int opcode; BOOL response; struct { BOOL bcast; BOOL recursion_available; BOOL recursion_desired; BOOL trunc; BOOL authoritative; } nm_flags; int rcode; int qdcount; int ancount; int nscount; int arcount; } header; struct { struct nmb_name question_name; int question_type; int question_class; } question; struct res_rec *answers; struct res_rec *nsrecs; struct res_rec *additional; }; Se date un'occhiata all'rfc1002 (questo testo non e' una sua sostituzione per chi e' troppo pigro per leggere in inglese (magari con un po' di culo trovate anche una versione italiana)) all'inizio viene detto che e' mantenuta la compatibilita' con quanto presente nell'rfc883 ed in effetti i campi delle struct dovrebbero farvi tornare alla mente un DoS scritto da FuSyS e |scacco| nel numero 6 di BFi. +---------------------+ | Header | +---------------------+ | Question | the question for the name server +---------------------+ | Answer | answering resource records (RRs) +---------------------+ | Authority | RRs pointing toward an authority +---------------------+ | Additional | RRs holding pertinent information +---------------------+ Questo sta alla base del name service e lo stesso header gode di compatibilita' attenendosi il piu' possibile al seguente header (rfc883): 1 1 1 1 1 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | ID | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ |QR| Opcode |AA|TC|RD|RA| | RCODE | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | QDCOUNT | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | ANCOUNT | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | NSCOUNT | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | ARCOUNT | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ Inserisco la spiegazione dei campi in inglese come da rfc tanto capite :) (o ci arrivate da quelli che ho presentato sopra nel NetBIOS): ID - A 16 bit identifier assigned by the program that generates any kind of query. This identifier is copied into all replies and can be used by the requestor to relate replies to outstanding questions. QR - A one bit field that specifies whether this message is a query (0), or a response (1). OPCODE - A four bit field that specifies kind of query in this message. This value is set by the originator of a query and copied into the response. The values are: 0 a standard query (QUERY) 1 an inverse query (IQUERY) 2 an completion query allowing multiple answers (CQUERYM) 2 an completion query requesting a single answer (CQUERYU) 4-15 reserved for future use AA - Authoritative Answer - this bit is valid in responses, and specifies that the responding name server is an authority for the domain name in the corresponding query. TC - TrunCation - specifies that this message was truncated due to length greater than 512 characters. This bit is valid in datagram messages but not in messages sent over virtual circuits. RD - Recursion Desired - this bit may be set in a query and is copied into the response. If RD is set, it directs the name server to pursue the query recursively. Recursive query support is optional. RA - Recursion Available - this be is set or cleared in a response, and denotes whether recursive query support is available in the name server. RCODE - Response code - this 4 bit field is set as part of responses. The values have the following interpretation: 0 No error condition 1 Format error - The name server was unable to interpret the query. 2 Server failure - The name server was unable to process this query due to a problem with the name server. 3 Name Error - Meaningful only for responses from an authoritative name server, this code signifies that the domain name referenced in the query does not exist. 4 Not Implemented - The name server does not support the requested kind of query. 5 Refused - The name server refuses to perform the specified operation for policy reasons. For example, a name server may not wish to provide the information to the particular requestor, or a name server may not wish to perform a particular operation (e.g. zone transfer) for particular data. 6-15 Reserved for future use. QDCOUNT - an unsigned 16 bit integer specifying the number of entries in the question section. ANCOUNT - an unsigned 16 bit integer specifying the number of resource records in the answer section. NSCOUNT - an unsigned 16 bit integer specifying the number of name server resource records in the authority records section. ARCOUNT - an unsigned 16 bit integer specifying the number of resource records in the additional records section. Vi riporto una parte del DoS: killer.head.id=getpid(); killer.head.rd=1; killer.head.aa=0; killer.head.opcode=QUERY; // definito in arpa/nameser.h killer.head.qr=0; killer.head.qdcount=htons(1); killer.head.ancount=htons(0); killer.head.nscount=htons(0); killer.head.arcount=htons(0); Se volessimo settare in modo identico su una struct del netbios: nmb.header.name_trn_id=getpid(); // per come settare questo val guarda // l'esempio del main() dopo... nmb.header.nm_flags.recursion_desired = True; nmb.header.nm_flags.authoritative = False; nmb.header.opcode = 0x0; // lo stesso valore di QUERY nmb.header.response = False; nmb.header.qdcount=htons(1); nmb.header.ancount=htons(0); nmb.header.nscount=htons(0); nmb.header.arcount=htons(0); Il campo RCODE nell'header del NetBIOS puo' assumere gli stessi valori definiti in arpa/nameser.h fino al quinto, poi ci sono quelli specifici per il NetBIOS: #define NOERROR 0 #define FORMERR 1 #define SERVFAIL 2 #define NXDOMAIN 3 #define NOTIMP 4 #define REFUSED 5 Corrispondono a: FMT_ERR 0x1 Format Error. Request was invalidly formatted. SRV_ERR 0x2 Server failure. Problem with NBNS, cannot process name. IMP_ERR 0x4 Unsupported request error. Allowable only for challenging NBNS when gets an Update type registration request. RFS_ERR 0x5 Refused error. For policy reasons server will not register this name from this host. In piu' (ovviamente non li trovate in nameser.h): ACT_ERR 0x6 Active error. Name is owned by another node. CFT_ERR 0x7 Name in conflict error. A UNIQUE name is owned by more than one node. Bene... siamo ora in grado di parlare al signore che vive alla porta 137 dell'indirizzo localhost :) Ora vi includo un semplice sorgente da completare/modificare a vostro piacimento (non includo dos per non farvi combinare casini... pero' vi dico subito che c'e' da divertirsi :) tra jokes e dos...). ---------- snip ---------- /* nmb_comp_decomp.c -- es. extract of nat10 ***************************************************************************** ** piccolo sorgente per i vostri programmini contro l'uomo della 137esima ** ** porta.. questo codice non e' altro che un estratto del nat10 .. con le ** ** strutture necessarie per creare pacchetti e convertire i nomi psichede- ** ** lici del NetBIOS ... bauz ** ** nota: alla fine ho aggiunto pure il supporto per l'omino della 138 ... ** *****************************************************************************/ #include <stdio.h> #include <string.h> #include <ctype.h> #include <sys/socket.h> #include <netinet/in.h> #include <netinet/ip.h> #include <netinet/udp.h> #include <arpa/inet.h> #include <errno.h> //checka se sta qui #include <unistd.h> #include <time.h> typedef unsigned short uint16; typedef unsigned int uint32; #define MAX_DGRAM_SIZE 576 #define PTR_DIFF(p1,p2) ((ptrdiff_t)(((char *)(p1)) - (char *)(p2))) #define ptrdiff_t int #define GMT_TO_LOCAL (-1) // LE SEGUENTi MACRO SONO BUONE PER PROCESS0Ri INTEL // PUOi CAMBIARLE GUARDANDO byteorder.h #define SVAL(buf,pos) (*(uint16 *)((char *)(buf) + (pos))) #define IVAL(buf,pos) (*(uint32 *)((char *)(buf) + (pos))) #define SVALS(buf,pos) (*(int16 *)((char *)(buf) + (pos))) #define IVALS(buf,pos) (*(int32 *)((char *)(buf) + (pos))) #define SSVAL(buf,pos,val) SVAL(buf,pos)=((uint16)(val)) #define SIVAL(buf,pos,val) IVAL(buf,pos)=((uint32)(val)) #define SSVALS(buf,pos,val) SVALS(buf,pos)=((int16)(val)) #define SIVALS(buf,pos,val) IVALS(buf,pos)=((int32)(val)) #define SREV(x) ((((x)&0xFF)<<8) | (((x)>>8)&0xFF)) #define IREV(x) ((SREV(x)<<16) | (SREV((x)>>16))) /*-----------------------------------------------------------*/ #define RSVAL(buf,pos) SREV(SVAL(buf,pos)) #define RIVAL(buf,pos) IREV(IVAL(buf,pos)) #define RSSVAL(buf,pos,val) SSVAL(buf,pos,SREV(val)) #define RSIVAL(buf,pos,val) SIVAL(buf,pos,IREV(val)) typedef enum BOOLEAN { False, True } BOOL; enum node_type {B_NODE=0, P_NODE=1, M_NODE=2, NBDD_NODE=3}; enum packet_type {NMB_PACKET, DGRAM_PACKET}; typedef char fstring[128]; typedef fstring string; typedef char pstring[1024]; // DATI DA MODIFICARE A SECONDA DELLE ESiGENZE pstring scope = ""; #define NMB_PORT 137 #define NAME "BAU" #define ADDRESS "192.168.1.xxx" int name_type = 0x20; // guarda i valori su rfc1002 int num_good_sends = 0; // Strutture che abbiamo incontrato nel testo struct nmb_name { char name[17]; char scope[64]; int name_type; }; struct dgram_packet { struct { int msg_type; struct { enum node_type node_type; BOOL first; BOOL more; } flags; int dgm_id; struct in_addr source_ip; int source_port; int dgm_length; int packet_offset; } header; struct nmb_name source_name; struct nmb_name dest_name; int datasize; char data[MAX_DGRAM_SIZE]; }; struct nmb_packet { struct { int name_trn_id; int opcode; BOOL response; struct { BOOL bcast; BOOL recursion_available; BOOL recursion_desired; BOOL trunc; BOOL authoritative; } nm_flags; int rcode; int qdcount; int ancount; int nscount; int arcount; } header; struct { struct nmb_name question_name; int question_type; int question_class; } question; struct res_rec *answers; struct res_rec *nsrecs; struct res_rec *additional; }; struct res_rec { struct nmb_name rr_name; int rr_type; int rr_class; int ttl; int rdlength; char rdata[MAX_DGRAM_SIZE]; }; /* Struttura utilizzata per mandare sia i pacchetti per il name server del NetBIOS che i datagrammi sulla porta 138 Notate come si addice questa struct ad una union per l'nmb e il dgram */ struct packet_struct { struct packet_struct *next; struct packet_struct *prev; struct in_addr ip; int port; int fd; time_t timestamp; enum packet_type packet_type; union { struct nmb_packet nmb; struct dgram_packet dgram; } packet; }; // PROTOTiPI DELLE FUNZIONi PIU' USATE static BOOL handle_name_ptrs(unsigned char *ubuf,int *offset,int length, BOOL *got_pointer,int *ret); static int parse_nmb_name(char *inbuf,int offset,int length, struct nmb_name *name); static int build_nmb(char *buf,struct packet_struct *p); static int put_res_rec(char *buf,int offset,struct res_rec *recs,int count); static int put_nmb_name(char *buf,int offset,struct nmb_name *name); static BOOL send_udp(int fd,char *buf,int len,struct in_addr ip,int port); static int build_dgram(char *buf,struct packet_struct *p); int name_mangle(char *In,char *Out,char name_type); char *StrnCpy(char *dest,const char *src,int n); int name_len(char *s); void strupper (char * s); void make_nmb_name(struct nmb_name *n,char *name,int type,char *this_scope); BOOL send_packet(struct packet_struct *p); void putip(void *dest,void *src); // Il vostro programma int main() { // bla bla bla return 0; } 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); } 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); bzero((char *)name,sizeof(*name)); /* the "compressed" part */ if (!got_pointer) ret += m + 2; offset++; while (m) { unsigned char c1,c2; c1 = ubuf[offset++]-'A'; c2 = ubuf[offset++]-'A'; if ((c1 & 0xF0) || (c2 & 0xF0)) 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 = name->name[15]; /* 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 ((m=ubuf[offset])) { /* we can have pointers within the domain part as well */ if (!handle_name_ptrs(ubuf,&offset,length,&got_pointer,&ret)) return(0); if (!got_pointer) ret += m+1; if (n) name->scope[n++] = '.'; if (m+2+offset>length || n+m+1>sizeof(name->scope)) return(0); offset++; while (m--) name->scope[n++] = (char)ubuf[offset++]; } name->scope[n++] = 0; return(ret); } int name_mangle(char *In,char *Out,char name_type) { fstring name; char buf[20]; char *in = (char *)&buf[0]; char *out = (char *)Out; char *p, *label; int i; if (In[0] != '*') { StrnCpy(name,In,sizeof(name)-1); sprintf(buf,"%-15.15s%c",name,name_type); } else { buf[0]='*'; memset(&buf[1],0,16); } *out++ = 32; for (i=0;i<16;i++) { char c = toupper(in[i]); out[i*2] = (c>>4) + 'A'; out[i*2+1] = (c & 0xF) + 'A'; } out[32]=0; out += 32; label = scope; while (*label) { p = strchr(label, '.'); if (p == 0) p = label + strlen(label); *out++ = p - label; memcpy(out, label, p - label); out += p - label; label += p - label + (*p == '.'); } *out = 0; return(name_len(Out)); } char *StrnCpy(char *dest,const char *src,int n) { char *d = dest; if (!dest) return(NULL); if (!src) { *dest = 0; return(dest); } while (n-- && (*d++ = *src++)) ; *d = 0; return(dest); } int name_len(char *s) { char *s0=s; unsigned char c = *(unsigned char *)s; if ((c & 0xC0) == 0xC0) return(2); while (*s) s += (*s)+1; return(PTR_DIFF(s,s0)+1); } void strupper (char * s) { register unsigned int c; while (*s) { c = (unsigned int) *s; if (islower (c)) *s = toupper (c); s++; } } /* strupper */ void make_nmb_name(struct nmb_name *n,char *name,int type,char *this_scope) { strcpy(n->name,name); strupper(n->name); n->name_type = type; strcpy(n->scope,this_scope); } BOOL send_packet(struct packet_struct *p) { char buf[1024]; int len=0; bzero(buf,sizeof(buf)); switch (p->packet_type) { case NMB_PACKET: len = build_nmb(buf,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)); } 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) 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) 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); if (nmb->header.arcount) offset += put_res_rec((char *)ubuf,offset,nmb->additional, nmb->header.arcount); return(offset); } static int put_nmb_name(char *buf,int offset,struct nmb_name *name) { int ret,m; fstring buf1; char *p; if (name->name[0] == '*') { /* special case for wildcard name */ bzero(buf1,20); buf1[0] = '*'; } else { sprintf(buf1,"%-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; strcpy(&buf[offset+1],name->scope); p = &buf[offset+1]; while ((p = strchr(p,'.'))) { buf[offset] = PTR_DIFF(p,&buf[offset]); offset += buf[offset]; p = &buf[offset+1]; } buf[offset] = strlen(&buf[offset+1]); } return(ret); } 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); } 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); } 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 */ bzero((char *)&sock_out,sizeof(sock_out)); putip((char *)&sock_out.sin_addr,(char *)&ip); sock_out.sin_port = htons( port ); sock_out.sin_family = AF_INET; ret = (sendto(fd,buf,len,0,(struct sockaddr *)&sock_out, sizeof(sock_out)) >= 0); if (ret) num_good_sends++; return(ret); } void putip(void *dest,void *src) { memcpy(dest,src,4); } ---------- snip ---------- Vediamo un esempio di costruzione ed invio di un pacchetto sulla porta 137 ( il main() nel cod sopra per intenderci) - Apertura di un socket... non ve la spiego va :) - Definizione delle strutture: struct packet_struct p; struct nmb_packet *nmb = &p.packet.nmb; (notate che la seconda struttura e' un puntatore alla struttura nmb interna alla prima) struct packet_struct { struct packet_struct *next; struct packet_struct *prev; struct in_addr ip; int port; int fd; time_t timestamp; enum packet_type packet_type; union { // ottimo esempio di union!! struct nmb_packet nmb; <--- questa :) struct dgram_packet dgram; } packet; }p; - Possiamo ora riempire i dati attraverso nmb in base a quanto stabilito nell'rfc1002 e a seconda, naturalmente, di quello che vogliamo fare. Prendo come es. una funzione del nat: if (!name_trn_id) name_trn_id = (time(NULL)%(unsigned)0x7FFF) + (getpid()%(unsigned)100); name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF; nmb->header.name_trn_id = name_trn_id; nmb->header.opcode = 0; nmb->header.response = False; nmb->header.nm_flags.bcast = False; nmb->header.nm_flags.recursion_available = CanRecurse; nmb->header.nm_flags.recursion_desired = recurse; nmb->header.nm_flags.trunc = False; nmb->header.nm_flags.authoritative = False; nmb->header.rcode = 0; nmb->header.qdcount = 1; nmb->header.ancount = 0; nmb->header.nscount = 0; nmb->header.arcount = 0; make_nmb_name(&nmb->question.question_name,name,name_type,scope); nmb->question.question_type = 0x21; nmb->question.question_class = 0x1; p.ip = to_ip; // to_ip struttura di tipo in_addr p.port = NMB_PORT; p.fd = fd; p.timestamp = time(NULL); p.packet_type = NMB_PACKET; Notate la make_nmb_name() che mette il nome in GRANDE :) se avete usato qualche volta il tcpdump per monitorare il NetBIOS non sarete sorpresi... - Inviare il pacchetto: if (!send_packet(&p)) return(False); Ok, fatto... -- WINDOWS -- In Windows, nell'implementazione che ho visto io, la parte relativa al name server e' inclusa a tutto il resto :) in una classe chiamata CNCB molto valida, ma usata piu' che altro come copertura di NCB e forse troppo poco giocherellabile: class CNCB { private: NCB m_NCB; public: // Constructor CNCB(); // Helper function void ClearNCB(); UCHAR GetLSN(); WORD GetLength(); void Fill(CNCB ncbSource); void GetCommand(); // Name management services UCHAR AddName(PSTR pName); UCHAR AddGroupName(PSTR pName); UCHAR DeleteName(PSTR pName); UCHAR FindName(); // Data transfer services UCHAR Call(PSTR pWe,PSTR pTheOther,UCHAR wSendTO,UCHAR wRecvTO); UCHAR Listen(PSTR pWe,PSTR pTheOther,UCHAR wSendTO,UCHAR wRecvTO); UCHAR Hangup(UCHAR wSessionNumber); // Connectionless data transfer UCHAR Cancel(); UCHAR Send(UCHAR wSessionNumber,LPSTR lpPacket, UINT wLength); UCHAR SendNoAck(); UCHAR SendDatagram(UCHAR wSessionNumber,LPSTR lpPacket, WORD wLength); UCHAR SendBroadcastDatagram(); UCHAR Receive(UCHAR wSessionNumber,LPSTR lpPacket, UINT wLength); UCHAR ReceiveAny(); UCHAR ReceiveDatagram(UCHAR wSessionNumber,LPSTR lpPacket, WORD wLength); UCHAR ReceiveBroadcastDatagram(); UCHAR ChainSend(); UCHAR ChainSendNoAck(); // General-purpose services UCHAR Reset(UCHAR wSessions, UCHAR wNCBs); UCHAR GetAdapterStatus(PSTR pName); UCHAR GetSessionStatus(PSTR pName); UCHAR EnumerateAdapters(); UCHAR StatusAlert(); UCHAR Action(); }; // Name management services UCHAR AddName(PSTR pName); UCHAR AddGroupName(PSTR pName); UCHAR DeleteName(PSTR pName); UCHAR FindName(); Ecco qui quello che resta del nostro povero nameserver... 4 funzioncine membro che fanno tutto loro... Rimane il punto di domanda se conviene farsi la propria struttura o usare questa classe... dipende da cosa dovete fare :) Sicuramente ci sta un po' stretta... Per i curiosi la classe NCB e' definita in NC20.h come segue: typedef struct _NCB { UCHAR ncb_command; /* command code */ UCHAR ncb_retcode; /* return code */ UCHAR ncb_lsn; /* local session number */ UCHAR ncb_num; /* number of our network name */ PUCHAR ncb_buffer; /* address of message buffer */ WORD ncb_length; /* size of message buffer */ UCHAR ncb_callname[NCBNAMSZ]; /* blank-padded name of remote */ UCHAR ncb_name[NCBNAMSZ]; /* our blank-padded netname */ UCHAR ncb_rto; /* rcv timeout/retry count */ UCHAR ncb_sto; /* send timeout/sys timeout */ void (CALLBACK *ncb_post)( struct _NCB * ); /* POST routine address */ UCHAR ncb_lana_num; /* lana (adapter) number */ UCHAR ncb_cmd_cplt; /* 0xff => commmand pending */ UCHAR ncb_reserve[10]; /* reserved, used by BIOS */ HANDLE ncb_event; /* HANDLE to Win32 event which */ /* will be set to the signalled */ /* state when an ASYNCH command */ /* completes */ } NCB, *PNCB; Ad ogni modo gran parte del codice UNiX e' portabile pure su win... con ovvie modifiche. Ok credo basti: non c'e' molto da dire sul name server e poi ormai il NetBIOS tendera' a morire... Questo e' solo un articolo in suo ricordo... Ciao netbios: sarai sempre nei nostri cuori :* ;D E' tutto baubau pIGpEN ============================================================================== ---------------------------------[ EOF 7/22 ]--------------------------------- ============================================================================== ---------------------[ previous ]---[ index ]---[ next ]----------------------