---------------------[ 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 ]----------------------