kuji@portfolio:~/projets$ cat portscan-v3.md
Scanneur de port, v3 : multithread
Le nombre de threads devient un paramètre de la ligne de commande, pour adapter le scan à la machine et au réseau.
Source
Lien vers le repo GitHubCe qui change
Le fonctionnement (compteur partagé, mutex, timeout de 200 ms) est celui de la version 2. Seule la gestion des threads évolue : figer le nombre de threads à 5 dans le code m'obligeait à recompiler à chaque fois, ce qui n'était pas pratique en CTF.
- Nombre de threads en argument. Le programme prend l'IP et le nombre de threads.
atoiconvertit ce second argument, qui est du texte, en entier. - Tableau de threads dynamique.
mallocréserve autant depthread_tque demandé, une boucle crée les threads et une autre les attend, puisfreelibère le tableau. Cela remplace les 5 variables copiées-collées de la v2. - Une seule structure d'arguments. Tous les threads reçoivent la même
shared_args, qui ne contient que l'adresse IP et un pointeur vers le mutex. Rien n'y est modifié, donc la partager est sans risque, alors que la v2 en créait cinq copies identiques.
Utilisation
$ gcc mapping_network_multithread.c -o mapping_network_multithread -pthread
$ ./mapping_network_multithread 127.0.0.1 20 | grep -e SCAN -e OPENED
BEGINNING IP SCAN : 127.0.0.1 with 20 threads
[+] PORT 8080 : OPENED
[+] PORT 9000 : OPENED
SCAN FINISHED.
Ici, 20 threads scannent les ports de 1 à 10 000. Le filtre grep ne garde que les ports ouverts et les lignes de début et de fin.
Limites
- Le nombre de threads n'est pas vérifié. Avec
abcou0,atoirenvoie 0 : aucun thread n'est lancé, et le programme affiche « SCAN FINISHED » sans avoir rien scanné. - Augmenter les threads n'accélère pas indéfiniment.
select()ne sait surveiller que des descripteurs inférieurs à 1024 (FD_SETSIZE), et la limite de fichiers ouverts par processus est souvent de 1024 aussi. Au-delà d'un millier de threads, il faudrait passer àpoll()ouepoll().
Code source
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <sys/types.h>
#include <pthread.h>
struct ScanArgs_Mutex{ char* ip_to_scan; pthread_mutex_t* mut;};
int last_port = 10000;
int first_port = 1;
int connect_with_timeout(int s, struct sockaddr_in* addr, int timeout_sec){
int flags = fcntl(s, F_GETFL, 0);
fcntl(s, F_SETFL, flags | O_NONBLOCK);
int res = connect(s, (struct sockaddr*)addr, sizeof(*addr));
if (res < 0 && errno != EINPROGRESS){
return -1;
}
if (res == 0){
fcntl(s, F_SETFL, flags);
return 0;
}
fd_set fdset;
FD_ZERO(&fdset);
FD_SET(s, &fdset);
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = timeout_sec;
res = select(s + 1, NULL, &fdset, NULL, &tv);
fcntl(s, F_SETFL, flags);
if (res <= 0){
return -1;
}
int so_error;
socklen_t len = sizeof(so_error);
getsockopt(s, SOL_SOCKET, SO_ERROR, &so_error, &len);
if (so_error != 0){
return -1;
}
return 0;
}
void* thread_scan(void* arg_g){
struct ScanArgs_Mutex* args = (struct ScanArgs_Mutex*) arg_g;
struct sockaddr_in configuration_serveur;
while(1){
pthread_mutex_lock(args->mut);
if (first_port > last_port){
pthread_mutex_unlock(args->mut);
break;
}
int port_to_scan = first_port;
first_port++;
pthread_mutex_unlock(args->mut);
int s = socket(AF_INET, SOCK_STREAM, 0);
if(s < 0){
printf("Error while creating socket. Port %d\n", port_to_scan);
continue;
}
memset(&configuration_serveur, 0, sizeof(configuration_serveur));
configuration_serveur.sin_addr.s_addr = inet_addr(args->ip_to_scan);
configuration_serveur.sin_family = AF_INET;
configuration_serveur.sin_port = htons(port_to_scan);
if (connect_with_timeout(s, &configuration_serveur, 200000) == 0){
printf("[+] PORT %d : OPENED\n", port_to_scan);
}
else{
printf("[+] PORT %d CLOSED\n", port_to_scan);
}
close(s);
}
return NULL;
}
int main(int argc, char* argv[]){
if (argc != 3) {
printf("Usage: %s <IP_Address> <Nb_Threads>\n", argv[0]);
return 1;
}
char* ip_cible = argv[1];
int nb_threads = atoi(argv[2]); //(texte -> int)
printf("BEGINNING IP SCAN : %s with %d threads\n", ip_cible, nb_threads);
printf("--------------------------\n");
pthread_mutex_t mut;
pthread_mutex_init(&mut, NULL);
struct ScanArgs_Mutex shared_args = {ip_cible, &mut};
pthread_t* threads = malloc(sizeof(pthread_t) * nb_threads);
for(int i = 0; i < nb_threads; i++){
pthread_create(&threads[i], NULL, thread_scan, &shared_args);
}
for (int i = 0; i < nb_threads; i++) {
pthread_join(threads[i], NULL);
}
printf("--------------------------\n");
printf("SCAN FINISHED.\n");
free(threads);
pthread_mutex_destroy(&mut);
return 0;
}