Descrizione dellinterfaccia verso il
driver "NDIS 3.0 Packet Driver"
Linterfaccia a disposizione per il programmatore è
definita dalla libreria a collegamento dinamico PacketNT.dll,
generata a partire dal listato packet32.c con il relativo
header file packet32.h. Il file header è molto importante
poiché deve essere incluso in ogni file sorgente che utilizza le
API esportate dalla libreria.
Tale interfaccia è composta da un set, estendibile a piacere,
di diciotto API che rendono facile lutilizzo del driver per
la cattura del traffico di rete locale allo scopo di analizzarlo
successivamente con un analizzatore di protollo. Si veda
lesempio di utilizzo di tale API nellapplicazione HexDump
fornita assieme ai sorgenti del driver nella directory hexdump.
Ecco il codice del file packet32.h
#ifndef __PACKET32
#define __PACKET32
#include "../inc/ntddpack.h"
#define DOSNAMEPREFIX TEXT("Packet_")
#define MAX_LINK_NAME_LENGTH 64
#define NMAX_PACKET 65535
typedef struct _ADAPTER {
HANDLE hFile;
TCHAR SymbolicLink[MAX_LINK_NAME_LENGTH];
} ADAPTER, *LPADAPTER;
typedef struct _PACKET {
// HANDLE hEvent;
OVERLAPPED OverLapped;
PVOID Buffer;
UINT Length;
PVOID Next;
UINT ulBytesReceived;
BOOLEAN bIoComplete;
} PACKET, *LPPACKET;
#ifdef __cplusplus
extern "C" {
#endif
LPADAPTER PacketOpenAdapter(LPTSTR AdapterName);
BOOLEAN PacketSendPacket(LPADAPTER AdapterObject,LPPACKET pPacket,BOOLEAN Sync);
LPPACKET PacketAllocatePacket(void);
LPPACKET PacketAllocateNPacket(UINT n);
VOID PacketInitPacket(LPPACKET lpPacket,PVOID Buffer,UINT Length);
VOID PacketFreePacket(LPPACKET lpPacket);
BOOLEAN PacketResetAdapter(LPADAPTER AdapterObject);
BOOLEAN PacketWaitPacket(LPADAPTER AdapterObject,LPPACKET lpPacket);
BOOLEAN PacketReceiveNPacket(LPADAPTER AdapterObject,LPPACKET headLPacket,UINT n,UINT length,BYTE* buffer,BOOLEAN Sync);
BOOLEAN PacketReceivePacket(LPADAPTER AdapterObject,LPPACKET lpPacket,BOOLEAN Sync);
VOID PacketCloseAdapter(LPADAPTER lpAdapter);
BOOLEAN PacketSetFilter(LPADAPTER AdapterObject,ULONG Filter);
ULONG PacketGetAdapterNames(PTSTR pStr,PULONG BufferSize);
BOOLEAN PacketRequest(LPADAPTER AdapterObject,BOOLEAN Set,PPACKET_OID_DATA OidData);
VOID PacketSetNextPacket(LPPACKET lpPacket, LPPACKET next);
VOID PacketSetLengthBuffer(LPPACKET lpPacket, UINT dim);
VOID PacketSetLengthPacket(LPPACKET lpPacket, UINT numBytes);
LPPACKET PacketGetNextPacket(LPPACKET lpPacket);
#ifdef __cplusplus
}
#endif
#endif //__PACKET32
Nel codice dellheader file si nota la dichiarazione di
due tipi di struttura e dei relativi puntatori.
ADAPTER permette di definire un identificatore che
opportunamente inizializzato mi da accesso alladattatore di
rete tramite il driver packet.sys, infatti il primo campo,
hfile, è un HANDLE al driver, il secondo, symbolicLink,
rappresenta il nome delladattore.
Il tipo PACKET permette di gestire la cattura di un pacchetto
ed è composto dai seguenti campi:
- Buffer : puntatore al buffer destinato a contenere
il pacchetto
- Length : lunghezza in byte del buffer suddetto
- Overlapped : utilizzato per gestire il
completamento delle operazioni di I/O con ladattore
- Next : puntatore utilizzato per costruire una
lista linkata di oggetti PACKET (si utilizza nelle
catture di N pacchetti)
- ulBytesReceived : intero senza segno che contiene
la dimensione in byte effettiva del pacchetto catturato o
da spedire
- bIoComplete : campo booleano che indica se
loperazione di I/O (lettura o invio pacchetto) è
stata completata con successo.
Nel file header ntddpack.h è definita la seguente
struttura
typedef struct _PACKET_OID_DATA {
ULONG Oid;
ULONG Length;
UCHAR Data[1];
} PACKET_OID_DATA, *PPACKET_OID_DATA;
da utilizzare quando si richiama la funzione PacketRequest(...).
Il campo Oid indica il tipo di operazione di query/set, i
cui possibili valori sono definiti nel file ntddndis.h. Il campo Length
indica la lunghezza del campo Data il quale contiene la
sequenza di byte da/o verso lNDIS.
Ora passiamo alla descrizione di tutte le funzioni esportate
dalla libreria il cui elenco è visibile a livello di prototipi
nel codice del file header packet32.h.
- ULONG PacketGetAdapterNames(PTSTR pStr,PULONG BufferSize)
È la prima funzione da utilizzare per poter colloquiare
con il driver. Riceve un puntatore ad un buffer in cui la
funzione stessa memorizza i nomi UNICODE di tutti gli
adattatori presenti nel sistema, separati con
"\0" e terminando lultimo con doppio
"\0" . Il secondo parametreo è la lunghezza
del buffer suddetto.
I nomi degli adattori vengono ottenuti tramite una query
sul database di registro di WinNT e quindi ritornati nel
buffer, ed è carico del programmatore scegliere poi
quale nome di adattatore utilizzare tra quelli ritornati.
- LPADAPTER PacketOpenAdapter(LPTSTR AdapterName)
Riceve come parametro un vettore stringa contenente il
nome delladattatore da aprire e restituisce un
puntatore ad un oggetto ADAPTER opportunamente
inizializzato. I nomi degli adattatori si ottengono con
la funzione PacketGetAdaptersName(
) precedentemente
descritta.
- VOID PacketCloseAdapter(LPADAPTER lpAdapter)
Dealloca la struttura di tipo ADAPTER di cui riceve il
puntatore, chiudendo quindi ladattatore.
- LPPACKET PacketAllocatePacket(void)
Alloca una struttura PACKET e ne ritorna il puntatore.
Tale struttura deve essere inizializzata correttamente
con la funzione PacketInitPacket(
).
- VOID PacketInitPacket(LPPACKET lpPacket,PVOID Buffer,UINT
Length)
Inizializza una struttura PACKET. Riceve tre parametri:
- il puntatore alla struttura da inizializzare
- il puntatore al buffer per contenere il pacchetto
- la lunghezza del buffer stesso (Notare che questa
è la lunghezza massima di un pacchetto).
- PACKET PacketAllocateNPacket(UINT n)
Alloca N strutture di tipo PACKET tra loro concatenate
tramite il campo Next a formare una lista. Di tale
lista viene ritornato il puntatore di testa.
NB. Non si deve utilizzare successivamente la
PacketInitPacket(
) la quale agisce solo su un
oggetto PACKET allocato con PacketAllocatePacket(
),
ma si deve utilizzare subito la
PacketReceiveNPacket(
)(vedi oltre).
- ID PacketFreePacket(LPPACKET lpPacket)
Dealloca una struttura di tipo PACKET di cui riceve il
puntatore. NB. Non dealloca il buffer a cui punta
la struttura, quindi questo deve essere deallocato dal
progrmmatore.
- BOOLEAN PacketReceivePacket(LPADAPTER
AdapterObject,LPPACKET lpPacket,BOOLEAN Sync)
Effettua la cattura di un pacchetto.
Effettuare loperazione in modalità sincrona
significa che la funzione non ritorna finchè
loperazione non è stata completata. Se si utilizza
la modalità asincrona si deve successivamente verificare
il completamento delloperazione con la
PacketWaitPacket(...)
La modalità asincrona permette di programmare un certo
numero di catture senza bloccarsi inutilmente.
Riceve i seguenti parametri:
- puntatore ad una struttura di tipo ADAPTER che
identifica ladattatore da cui catturare il
pacchetto.
- puntatore ad una struttura PACKET in cui mettere
il pacchetto
- un flag che indica se loperazione deve
avvenire in modalità sincrona o asincrona
(rispettivamente TRUE o FALSE).
- BOOLEAN PacketWaitPacket(LPADAPTER AdapterObject,LPPACKET
lpPacket)
Si utilizza per verificare il completamento di una
operazione di I/O. È bloccante se loperazione di
I/O non è ancora stata completata da parte del driver,
ritorna TRUE se non si sono verificati errori, altrimenti
FALSE e per sapere quale errore si è verificato si deve
utilizzare lAPI GetLastError(...) dellSDK.
- BOOLEAN PacketReceiveNPacket(LPADAPTER
AdapterObject,LPPACKET headLPacket,UINT n, UINT
length,BYTE* buffer,BOOLEAN Sync) (**)
Effettua la cattura di N paccketti (massimo 2^16 -1).
Tale API permette di evitare un gran numero di chiamate
di funzione (la PacketReceivePacket(...)) aumentando
così la probabilità di catturare tutti i pacchetti in
transito sulla rete. Come per la PacketReceivePacket(...)
è bloccante se la modalita operativa richiesta è
sincrona.
I parametri in ingresso sono i seguenti:
- puntatore ad una struttura di tipo ADAPTER per
identificare ladattatore da cui effettuare
la cattura
- puntatore di testa alla lista di strutture PACKET
in cui mettere i pacchetti
- numero di pacchetti da catturare
- lunghezza massima del singolo pacchetto
- puntatore ad una grossa area di memoria destinata
a memorizzare tutti gli N pacchetti (quindi con
dimensione uguale a N x lunghezza max
pacchetto
- un flag per indicare se loperazione deve
essere sincrona o asincrona (rispettivamente TRUE
o FALSE).
- BOOLEAN PacketSendPacket(LPADAPTER AdapterObject,LPPACKET
pPacket,BOOLEAN Sync) (*)
Permette linvio di un pacchetto tramite
ladattatore di rete specificato con il primo
parametro. Valgono le stesse osservazioni fatte per la
PacketReceivePacket(...).
Nella versione per Win95 per indicare la dimensione
effettiva del pacchetto viene utilizzato il campo Length
(max dimensione del buffer) ciò risulta poco corretto,
è meglio utilizzare il campo ulByteReceived.
- BOOLEAN PacketResetAdapter(LPADAPTER AdapterObject)
Reinizializza ladattatore passato come parametro
ritornando TRUE se loperazione è andata a buon
fine.
- BOOLEAN PacketSetFilter(LPADAPTER AdapterObject,ULONG
Filter)
Permette di impostare a livello MAC un filtro sul
traffico da catturare. I filtri sono definiti da delle
apposite costanti dichiarate nel file ntddndis.h.
I parametri sono ladattatore su cui definire il
filtro e lidentificatore del filtro. Tirtorna TRUE
se loperazione termina con successo.
I filtri più comuni sono cinque:
- NDIS_PACKET_TYPE_PROMISCUOUS : qualsiasi
pacchetto anche non destinato alladattatore
in questione
- NDIS_PACKET_TYPE_DIRECTED : solo i pacchetti che
sono destinati alladattatore in questione
- NDIS_PACKET_TYPE_BROADCAST : tutti i pacchetti di
broadcast che transitano sulla rete locale
- NDIS_PACKET_TYPE_MULTICAST : i pacchetti di
multicast dei gruppi di multicast a cui è
iscritto ladattatore
- NDIS_PACKET_TYPE_ALL_MULTICAST : tutti i
pacchetti di multicast
- BOOLEAN PacketRequest(LPADAPTER AdapterObject,BOOLEAN
Set,PPACKET_OID_DATA OidData)
Permette di effettuare delle query oppure delle
operazioni di setting sulladattatore passato come
primo parametro. Il secondo parametro definisce il tipo
di operazione da effettuare (query se set = 1, set
se set = 0). Il terzo parametro è un puntatore ad
una struttura per i dati da/o verso ladattatore
(vedi struttura PPACKET_OID_DATA).
La funzione ritorna un valore TRUE se loperazione
va a buon fine altrimenti FALSE. Si possono effettuare
vari tipi di query/set utilizzando le costanti definite
nel file ntddndis. Un esempio può essere quello
di voler ottenere lindirizzo MAC della scheda di
rete (costante OID_802_3_PERMANENT_ADDRESS). Altre
operazioni possono essere la lettura dei contatori di
errore gestiti dallNDIS, lista dei gruppi di
multicast programmati sulla scheda, ecc... Ogni
operazione diversa coinvolge dati di dimensione diversa,
si rende perciò necessario consultare la documentazione
del DDK riguardante le specifiche NDIS.
Seguono ora un set di API che permettono di maneggiare in modo
indiretto alcuni campi della struttura PACKET.
- LPPACKET PacketGetNextPacket(LPPACKET lpPacket) (**)
Dato un puntatore di tipo LPPACKET ritorna il successivo
nella lista a cui appartiene quello dato; NULL se era
lultimo oppure non faceva parte di una lista.
- VOID PacketSetNextPacket(LPPACKET lpPacket, LPPACKET
next) (**)
Permette di settare il nampo Next al fine di
costruire manualmente una lista di PACKET.
- VOID PacketSetLengthBuffer(LPPACKET lpPacket, UINT dim)
(**)
Permette di impostare la dimesione del buffer nella
struttura PACKET.
- VOID PacketSetLengthPacket(LPPACKET lpPacket, UINT
numBytes) (**)
Permette di impostare la dimensione effettiva del
paccketto presente nel buffer.
Nota : quando è presente il simbolo (*)
indica che ci sono delle differenze rispetto al driver sviluppato
per Win95. Il simbolo (**) indica lassenza di tale
feature nella versione per Win95.