|
Nozioni di programmazione di rete in C su ambienti UNIX |
|
Bertera Pietro(p.bertera@valtellinux.it )
|
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
/* Numero di Port sul quale il client richiede la connessione */
#define PORT 4000
/* Funzione per inizializzare gli indirizzi */
void addr_initialize(struct sockaddr_in *indirizzo, int port, long IPaddr)
{
indirizzo->sin_family = AF_INET;
/* htons: host to network conversion, short */
indirizzo->sin_port = htons((u_short) port);
indirizzo->sin_addr.s_addr = IPaddr;
}
/* Programma principale */
void main(int argc, char* argv[])
{
/* Descrittore del socket */
int sd;
/* Indirizzo del server */
struct sockaddr_in server_addr;
/* Indirizzo del client */
struct sockaddr_in mio_addr;
/* Dimensione dell’indirizzo client */
int mio_addr_len=sizeof(mio_addr);
/* Controllo per la connect() */
int error;
/* Inizializza l’indirizzo del server, alla funzione viene passato un puntatore alla struttura che
identifica il server addres nella quale mette il numero di Port passato come secondo parametro
l’indirizzo IP inserito da riga di comando (argv[1]) e convertito nel formato di rete con la
inet_addr() */
addr_initialize(&server_addr, PORT, inet_addr(argv[1]));
/* Crea l’identificatore del socket */
sd=socket(AF_INET,SOCK_STREAM,0);
/* crea una connessione sul socket appena creato */
error=connect(sd,(struct sockaddr*) &server_addr, sizeof(server_addr));
/* Controllo se la connect() è andata a buon fine */
if (error==0)
{
/* Se la connessione ha avuto effetto positivo stampa: Ho eseguito la connessione */
printf("Ho eseguito la connessione\n");
/* Scrive nell’indirizzo in mio_addr l’indirizzo del client tramite la getsockname() */
getsockname(sd, &mio_addr, &mio_addr_len);
/* Stampa a video il port del client dopo avero convertito dal formato di rete al formato
dell host tramite la ntohs() */
printf("il mio port e': %d\n\n",ntohs(mio_addr.sin_port));
/* chiude il socket */
close(sd);
}
else printf("%s","\nErrore di connect\n\n");
/* Se la connessione non è andata a buon fine chide il socket */
close(sd);
}
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
/* Definisce il numero di port su cui si metterà in attesa */
#define PORT 4000 >
/* Definisce il numero Massimo di connessioni da lasciare in coda */
#define MAXCONN 5
/* Funzione per inizializzare gli indirizzi */
void addr_initialize(struct sockaddr_in *indirizzo, int port, long IPaddr)
{
indirizzo->sin_family = AF_INET;
indirizzo->sin_port = htons((u_short) port);
/* htons: host to network conversion, short */
indirizzo->sin_addr.s_addr = IPaddr;
}
/* Programma principale */
void main(int argc, char * argv[])
{
/* Identificatori del canale pubblico e del canale privato */
int sd,new_sd;
/* Indirizzo del Server */
struct sockaddr_in server_addr;
/* Indirizzo del client */
struct sockaddr_in client_addr;
/* Dimensione dell’indirizzo client */
int client_len=sizeof(client_addr);
/* Inizializza l’indirizzo sever per accettare connessione sull Port 4000 e da qualunque indirizzo IP (INADDR_ANY) */
addr_initialize(&server_addr, PORT, INADDR_ANY);
/* Crea il canale pubblico */
sd=socket(AF_INET,SOCK_STREAM,0);
/* Lega al socket l’indirizzo del server */
bind(sd,(struct sockaddr*) &server_addr,sizeof(server_addr));
/* Imposta il numero Massimo di connessioni in coda */
listen(sd,MAXCONN);
printf("Mi pongo in attesa di richieste di connessione\n");
/* Preleva il proprio port dalla struttura che identifica l’indirizzo del server, lo converte da
formato di rete a formato dell’ host e lo stampa a video */
printf("sul mio port: %d\n", ntohs(server_addr.sin_port));
/* Crea il canale privato per la connessione con un client */
new_sd=accept(sd,(struct sockaddr*) &client_addr, &client_len);
/* Se la accept() si è sbloccata significa che si è connesso un client */
printf("\n\nHo accettato una connessione\n");
/* Preleva il port del client, dopo averlo trasformato da formato di rete a formato host lo stampa a video */
printf("dal client con port: %d\n\n", ntohs(client_addr.sin_port));
/* Chiude il canale privato */
close(new_sd);
/* Chiude il canale pubblico */
close(sd);
}
Struttura header TCP (/usr/include/netinet/tcp.h)
struct tcphdr
{u_int16_t source; // porta sorgente 16 bit
u_int16_t dest; // porta destinazione 16 bit
u_int32_t seq; // numero di sequenza 32 bit
u_int32_t ack_seq; // numero di ack 32 bit
#if __BYTE_ORDER == __LITTLE_ENDIAN
u_int16_t res1:4; //
u_int16_t doff:4;
u_int16_t fin:1; // flag FIN
u_int16_t syn:1; // flag SYN
u_int16_t rst:1; // flag RST
u_int16_t psh:1; // flag PSH
u_int16_t ack:1; // flag ACK
u_int16_t urg:1; // flag URG
u_int16_t res2:2;
#elif __BYTE_ORDER == __BIG_ENDIAN
u_int16_t doff:4;
u_int16_t res1:4;
u_int16_t res2:2;
u_int16_t urg:1;
u_int16_t ack:1;
u_int16_t psh:1;
u_int16_t rst:1;
u_int16_t syn:1;
u_int16_t fin:1;
#else
#error "Adjust your defines"
#endif
u_int16_t window;
u_int16_t check;
u_int16_t urg_ptr;
};
struct udphdr
{
u_int16_t source;
u_int16_t dest;
u_int16_t len;
u_int16_t check;
};
Questa struttura definisce un’intestazione di un pacchetto UDP, differentemente
dal TCP, il protocollo UDP non necessita di una connessione ma invia il pacchetto
indipendentemente dagli altri.
/*******************************************************************************************
* Questo programma tcp.c genera un pacchetto tcp con il flag fin = 1 ( chiusura connessione)
* il programma usa socket raw per la creazione del pacchetto tcp che viene infine inviato,
* con la chiamata sendto().
* n.b. Dalla linea di comando viene modificato il propio IP-number!!!
*
* Il programma deve essere lanciato in questo:
* tcp porta_sorgente indirizzo_sorgente porta_remota indirizzo_remoto
*
* Il programma viene compilato nel seguente modo:
* gcc -o tcp tcp.c
*
******************************************************************************************/
/* Dichiarazione degli header principali usati nel programma */
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
/* Dichiarazione dei prototipi delle funzioni */
void tcp_gen(char *packet,unsigned short sport,
unsigned short dport,unsigned long seq,
unsigned long ack);
void udp_gen(char *packet,unsigned short sport,
unsigned short dport,unsigned short length);
void ip_gen(char *packet,unsigned char protocol,struct in_addr saddr,
struct in_addr daddr,unsigned short length);
unsigned short trans_check( unsigned char proto, char *packet,
int length, struct in_addr source_address,
struct in_addr dest_address);
unsigned short in_cksum(unsigned short *addr,int len);
#define IPVERSION 4 /* versione del pacchetto IP */
#define DEFAULT_TTL 60 /* Definizione del tempo di vita dei pacchetti */
#define TH_OFFSET 5
#define TCP_WINDOW_SIZE 512 /* larghezza della finestra del tcp */
/* struttura per il calcolo del checksum sul pacchetto tcp*/
struct psuedohdr {
struct in_addr source_address;
struct in_addr dest_address;
unsigned char place_holder;
unsigned char protocol;
unsigned short length;
} psuedohdr;
/*********************************************************************************/
/*********************** calcolo del checksum sul tcp header *********************/
/*********************************************************************************/
unsigned short trans_check(unsigned char proto,
char *packet,
int length,
struct in_addr source_address,
struct in_addr dest_address)
{
char *psuedo_packet;
unsigned short answer;
/* compilazione della struttura pseudohdr tcp */
psuedohdr.protocol = proto;
psuedohdr.length = htons(length);
psuedohdr.place_holder = 0;
psuedohdr.source_address = source_address;
psuedohdr.dest_address = dest_address;
/* allocazione della struttura pseudohdr */
if((psuedo_packet = malloc(sizeof(psuedohdr) + length)) == NULL) {
perror("malloc");
exit(1);
}
/* copia la struttura pseudohdr nella blocco puntato da pseudo_packet */
memcpy(psuedo_packet,&psuedohdr,sizeof(psuedohdr));
/* applica l'algoritmo del checksum allo pseudo pacchetto*/
answer = (unsigned short)in_cksum((unsigned short *)psuedo_packet,
(length + sizeof(psuedohdr)));
free( psuedo_packet ) ;
return answer;
}
/*********************************************************************************/
/************************* algoritmo del checksum ********************************/
/*********************************************************************************/
unsigned short in_cksum(unsigned short *addr,int len)
{
register int sum = 0;
u_short answer = 0;
register u_short *w = addr;
register int nleft = len;
/*
* Questo ciclo somma nel registro accumulatore (sum) 32 bit le parole di
* 16 bit che vengono estratte dalla struttura addr.
*/
while (nleft > 1) {
sum += *w++;
nleft -= 2;
}
/* se la lunghezza del campo dati è numero dispari viene completato */
/* con un 0 addizionale .*/
if (nleft == 1) {
*( u_char * )( &answer ) = *( u_char * )w ;
sum += answer;
}
/* viene calcolato il complemento a 1 della somma delle word */
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
answer = ~sum;
return(answer);
}
/*********************************************************************************/
/*********************** generatore pacchetto IP *********************************/
/*********************************************************************************/
void ip_gen(char *packet,unsigned char protocol,struct in_addr saddr,
struct in_addr daddr,unsigned short length)
{
/* definisco un puntatore alla struttura */
struct iphdr *iphdr;
/* La variabile pacchetto diventa puntatore alla struttura iphdr */
iphdr = (struct iphdr *)packet;
memset((char *)iphdr,'\0',sizeof(struct iphdr));
/* compilo la struttura ip */
iphdr->ihl = 5;
iphdr->version = IPVERSION;
/* BIG ENDIAN e LIITLE ENDIAN */
#ifdef IP_LEN_HORDER
iphdr->tot_len = length;
#else
iphdr->tot_len = htons(length);
#endif /* IP_LEN_HORDER */
iphdr->id = htons(getpid());
iphdr->ttl = DEFAULT_TTL;
iphdr->protocol = protocol;
iphdr->saddr = saddr.s_addr;
iphdr->daddr = daddr.s_addr;
/* calcola il checksum del pacchetto*/
iphdr->check = (unsigned short)in_cksum((unsigned short *)iphdr,
sizeof(struct iphdr));
return;
}
/*********************************************************************************/
/*************** dichiarazione del prototipo della funzione tcp_gen **************/
/*********************************************************************************/
void tcp_gen(char *packet,unsigned short sport,
unsigned short dport,unsigned long seq,
unsigned long ack)
{
/* puntatore alla struttura tcphdr */
struct tcphdr *tcp;
/* Cast di packet da (char *) a (struct tcphdr*) */
tcp = (struct tcphdr *)packet;
memset((char *)tcp,'\0',sizeof(struct tcphdr));
/* compilazione della struttura tcp */
tcp->source = htons(sport);
tcp->dest = htons(dport);
tcp->seq = htonl(seq);
tcp->ack_seq = htonl(ack);
tcp->res1 = 0;
tcp->doff = TH_OFFSET;
tcp->window = htons(TCP_WINDOW_SIZE);
tcp->fin = 1;
return;
}
/*********************************************************************************/
/********************************** M A I N **************************************/
/*********************************************************************************/
int main(int argc,char *argv[])
{
/* vettore pacchetto di lunghezza ip header + tcp header */
unsigned char packet[ sizeof(struct iphdr) + sizeof(struct tcphdr) ];
/* sockaddr_in struttura della socket */
struct sockaddr_in mysocket;
/* porte sorgenti e destinazioni */
unsigned short sport, dport;
/* struttura per l'indirizzamento ID/RETE ID/HOST */
struct in_addr saddr, daddr;
/* puntatore alla struttura tcphdr */
struct tcphdr *tcp;
unsigned long seq, ack;
int sockd, on = 1;
/* Prelevo gli argomenti dalla riga di comando */
if(argc < 5) {
fprintf(stderr,"usare: %s porta_sorg. indirizzo_sorg. porta_dest.
indirizzo_dest\n", argv[0]);
exit(1);
}
/* Compila la struttura per le socket con porta sorgente
e indirizzo sorgente */
sport = (unsigned short)atoi(argv[1]);
saddr.s_addr = inet_addr(argv[2]);
/* Compila la struttura per le socket con porta destinazione e
indirizzo destinazione */
dport = (unsigned short)atoi(argv[3]);
daddr.s_addr = inet_addr(argv[4]);
/* Creo il socket descriptor con l'opzione socket raw */
if((sockd = socket(AF_INET,SOCK_RAW,IPPROTO_RAW)) < 0) {
perror("socket");
exit(1);
}
/* Setto alcune opzioni inerenti al livello del protocollo IP */
if(setsockopt(sockd,IPPROTO_IP,IP_HDRINCL,(char *)&on,sizeof(on)) < 0) {
perror("setsockopt");
exit(1);
}
/* Genero numero di sequenza ed ack casuali */
srand(getpid());
seq = rand()%time( NULL );
ack = rand()%time( NULL );
/* Genero pacchetto IP */
ip_gen(packet,IPPROTO_TCP,saddr,daddr,sizeof(packet));
/* Sposto il puntatore della struttura tcp header della dimensione del */
/* pacchetto + la struttura ip header */
tcp = (struct tcphdr *)(packet + sizeof(struct iphdr));
/* Genero il pacchetto TCP */
tcp_gen((char *)tcp,sport,dport,seq,ack);
/* checksum calcolato sul pacchetto IP */
tcp->check = trans_check(IPPROTO_TCP,(char *)tcp,
sizeof(struct tcphdr),
saddr,
daddr);
/*inizializza la struttura mysocket */
memset(&mysocket,'\0',sizeof(mysocket));
/*Compilo la struttura mysocket */
mysocket.sin_family = AF_INET;
mysocket.sin_port = htons(dport);
mysocket.sin_addr = daddr;
/* Spedisco il pacchetto da me creato con il flag fin a a 1
secondo i parametri immessi da linea di comando.*/
if(sendto(sockd,&packet,sizeof(packet),0x0,(struct sockaddr *)&mysocket,
sizeof(mysocket)) != sizeof(packet)) {
perror("sendto");
exit(1);
}
exit(0);
}
/*Sniffo: sniffer per sistemi UNIX by Pietro Bertera il prog crea un log chiamato sniffolog.log MOLTO grande!!!*/
#include <signal.h>
#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <linux/if_ether.h>
#define MAX_PACK 65535
char *getip (u_long in);
int
main ()
{
int sd, pid, number;
FILE *fp;
struct
{
struct iphdr ip;
struct tcphdr tcp;
char data[MAX_PACK - sizeof (struct iphdr) - sizeof (struct tcphdr)];
} Packet;
if (geteuid ())
{
fprintf (stderr, "Mi dispiace ma non sei root ...\n");
exit (-1);
}
switch (pid = fork ())
{
case 0:
break;
default:
printf ("Sniffer by PedroBert - gira in background sul processo %d\n", pid);
exit (0);
}
sd = socket (AF_INET, SOCK_RAW, IPPROTO_TCP);
number=0;
while (sd)
{
pid = read (sd, &Packet, sizeof (Packet));
if (pid > 1 && Packet.ip.protocol == IPPROTO_TCP)
{
number++;
fp = fopen ("sniffolog.log", "a");
fprintf(fp, "PACKET NUMBER: %d\n",number);
fprintf(fp, "SOURCE IP: %s\n",getip(Packet.ip.saddr));
fprintf(fp, "SOURCE PORT: %d\n",ntohs(Packet.tcp.source));
fprintf(fp, "DESTINATION IP: %s\n",getip(Packet.ip.daddr));
fprintf(fp, "DESTINATION PORT: %d\n",ntohs (Packet.tcp.dest));
fprintf(fp, "FIN: %d\n", Packet.tcp.fin);
fprintf(fp, "SYN: %d\n", Packet.tcp.syn);
fprintf(fp, "RST: %d\n", Packet.tcp.rst);
fprintf(fp, "ACK: %d\n", Packet.tcp.ack);
fprintf(fp, "URG: %d\n", Packet.tcp.urg);
fprintf(fp, "WIN: %d\n", Packet.tcp.window);
fprintf(fp, "CHECK: %d\n", Packet.tcp.check);
fprintf(fp, "DATA: %s\n", Packet.data);
fprintf(fp, "_______________________________________________________________\n");
fclose (fp);
usleep(100000);
}
}
fprintf (stderr, "Errore delle Raw Socket\n");
return 0;
}
char *getip ( u_long in)
{
struct in_addr s;
s.s_addr = in;
return inet_ntoa(s);
}