maintenant à deux voies!
This commit is contained in:
parent
8b350efed2
commit
0c97dac0d1
@ -1,4 +1,4 @@
|
|||||||
CC := gcc -Wall -Wextra -Wpedantic -Wshadow=local -Iinclude -Isrc -g -std=c11
|
CC := gcc -Wall -Wextra -Wpedantic -Iinclude -Isrc -g -std=c11
|
||||||
|
|
||||||
# pkg-config
|
# pkg-config
|
||||||
# LIBS :=
|
# LIBS :=
|
||||||
|
@ -11,25 +11,30 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/select.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <sys/time.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
|
||||||
#define BUFSIZE 1024
|
#define BUFSIZE 1024
|
||||||
|
|
||||||
|
|
||||||
int ext_out(int port) {
|
static int setup_out(int port) {
|
||||||
|
/* Create the socket. */
|
||||||
int server = socket(AF_INET6, SOCK_STREAM, 0);
|
int server = socket(AF_INET6, SOCK_STREAM, 0);
|
||||||
if (server == -1) {
|
if (server == -1) {
|
||||||
perror("socket");
|
perror("socket");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Enable socket re-use, makes debugging easier. */
|
||||||
setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &(int) {1}, sizeof (int));
|
setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &(int) {1}, sizeof (int));
|
||||||
|
|
||||||
|
/* Bind to any local IPv6 address on port PORT. */
|
||||||
struct sockaddr_in6 server_addr = {0};
|
struct sockaddr_in6 server_addr = {0};
|
||||||
server_addr.sin6_family = AF_INET6;
|
server_addr.sin6_family = AF_INET6;
|
||||||
server_addr.sin6_port = htons(port);
|
server_addr.sin6_port = htons(port);
|
||||||
@ -38,6 +43,8 @@ int ext_out(int port) {
|
|||||||
perror("bind");
|
perror("bind");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Pretty print the matched address. */
|
||||||
char server_addr_pretty[INET6_ADDRSTRLEN] = "";
|
char server_addr_pretty[INET6_ADDRSTRLEN] = "";
|
||||||
inet_ntop(AF_INET6, &(server_addr.sin6_addr), server_addr_pretty, sizeof server_addr_pretty);
|
inet_ntop(AF_INET6, &(server_addr.sin6_addr), server_addr_pretty, sizeof server_addr_pretty);
|
||||||
printf("Écoute sur : %s\n", server_addr_pretty);
|
printf("Écoute sur : %s\n", server_addr_pretty);
|
||||||
@ -47,87 +54,184 @@ int ext_out(int port) {
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int accept_client(int server) {
|
||||||
|
/* Wait for a connection attempt. */
|
||||||
struct sockaddr_in6 client_addr;
|
struct sockaddr_in6 client_addr;
|
||||||
socklen_t client_addr_len;
|
socklen_t client_addr_len;
|
||||||
puts("Attente d’un client.");
|
puts("Attente d’un client.");
|
||||||
int client = accept(server, (struct sockaddr *) &client_addr, &client_addr_len);
|
int client = accept(server, (struct sockaddr *) &client_addr, &client_addr_len);
|
||||||
|
|
||||||
|
/* We only serve one peer, no need to keep the server socket
|
||||||
|
* open. */
|
||||||
close(server);
|
close(server);
|
||||||
|
|
||||||
|
/* Pretty print the peer’s address */
|
||||||
char client_addr_pretty[INET6_ADDRSTRLEN] = "";
|
char client_addr_pretty[INET6_ADDRSTRLEN] = "";
|
||||||
inet_ntop(AF_INET6, &(client_addr.sin6_addr), client_addr_pretty, sizeof client_addr_pretty);
|
inet_ntop(AF_INET6, &(client_addr.sin6_addr), client_addr_pretty, sizeof client_addr_pretty);
|
||||||
printf("Client connecté : %s\n", client_addr_pretty);
|
printf("Client connecté : %s\n", client_addr_pretty);
|
||||||
|
|
||||||
return client;
|
return client;
|
||||||
|
|
||||||
/* char buf[BUFSIZE]; */
|
|
||||||
/* ssize_t n; */
|
|
||||||
/* while (1) { */
|
|
||||||
/* n = read(client, buf, sizeof buf); */
|
|
||||||
/* if (n == -1) { */
|
|
||||||
/* perror("read"); */
|
|
||||||
/* exit(1); */
|
|
||||||
/* } */
|
|
||||||
/* n = write(out, buf, n); */
|
|
||||||
/* if (n == -1) { */
|
|
||||||
/* perror("write"); */
|
|
||||||
/* exit(1); */
|
|
||||||
/* } */
|
|
||||||
/* } */
|
|
||||||
|
|
||||||
/* close(client); */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int ext_in(const char addr[], int port) {
|
int ext_out(int port) {
|
||||||
|
int server = setup_out(port);
|
||||||
|
return accept_client(server);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int setup_in() {
|
||||||
int s = socket(AF_INET6, SOCK_STREAM, 0);
|
int s = socket(AF_INET6, SOCK_STREAM, 0);
|
||||||
if (s == -1) {
|
if (s == -1) {
|
||||||
perror("socket");
|
perror("socket");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int try_connect(int s, const char addr[], int port) {
|
||||||
struct sockaddr_in6 sa = {0};
|
struct sockaddr_in6 sa = {0};
|
||||||
sa.sin6_family = AF_INET6;
|
sa.sin6_family = AF_INET6;
|
||||||
sa.sin6_port = htons(port);
|
sa.sin6_port = htons(port);
|
||||||
inet_pton(AF_INET6, addr, &sa.sin6_addr);
|
inet_pton(AF_INET6, addr, &sa.sin6_addr);
|
||||||
|
|
||||||
puts("Connexion.");
|
puts("Connexion.");
|
||||||
while (connect(s, (struct sockaddr *) &sa, sizeof sa) == -1) {
|
if (connect(s, (struct sockaddr *) &sa, sizeof sa) == -1) {
|
||||||
perror("connect");
|
perror("connect");
|
||||||
sleep(1);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
char addr_pretty[INET6_ADDRSTRLEN] = "";
|
char addr_pretty[INET6_ADDRSTRLEN] = "";
|
||||||
inet_ntop(AF_INET6, &(sa.sin6_addr), addr_pretty, sizeof addr_pretty);
|
inet_ntop(AF_INET6, &(sa.sin6_addr), addr_pretty, sizeof addr_pretty);
|
||||||
printf("Connecté à : %s\n", addr_pretty);
|
printf("Connecté à : %s\n", addr_pretty);
|
||||||
|
|
||||||
return s;
|
return 1;
|
||||||
|
|
||||||
/* char buf[BUFSIZE]; */
|
|
||||||
/* ssize_t n; */
|
|
||||||
/* while (1) { */
|
|
||||||
/* n = read(in, buf, sizeof buf); */
|
|
||||||
/* if (n == -1) { */
|
|
||||||
/* perror("read"); */
|
|
||||||
/* exit(1); */
|
|
||||||
/* } */
|
|
||||||
/* n = write(s, buf, n); */
|
|
||||||
/* if (n == -1) { */
|
|
||||||
/* perror("write"); */
|
|
||||||
/* exit(1); */
|
|
||||||
/* } */
|
|
||||||
/* } */
|
|
||||||
|
|
||||||
/* close(s); */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ext_bidir(const char addr[], int port, int in, int out) {
|
int ext_in(const char addr[], int port) {
|
||||||
pid_t pid = fork();
|
int s = setup_in();
|
||||||
if (pid == 0) {
|
|
||||||
ext_in(addr, port);
|
/* Attempt a connection every second (waiting for the server to
|
||||||
|
* start). */
|
||||||
|
while (!try_connect(s, addr, port)) {
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* On établie ici une connexion bidirectionelle en se connectant à un
|
||||||
|
* serveur distant ET en écoutant nous-même sur un port local en
|
||||||
|
* attente d’un client. Cela nous donne donc deux connexions
|
||||||
|
* matérialisées par deux socket, l’une qui est utilisée en lecture et
|
||||||
|
* l’autre en écriture.
|
||||||
|
*
|
||||||
|
* Il pourrait suffir d’avoir une extremité qui écoute, et l’autre qui
|
||||||
|
* se connecte, établissant ainsi une seule connexion qu’on
|
||||||
|
* utiliserait en lecture/écriture, mais cela pose le problème de
|
||||||
|
* savoir qui écoute et qui se connecte.
|
||||||
|
*
|
||||||
|
* De plus, si les deux tentent en parallèle de se connecter OU
|
||||||
|
* d’accepter une connexion (mais de ne pas attendre que les deux
|
||||||
|
* conditions soient vraies, et d’utiliser une seule socket en
|
||||||
|
* lecture/écriture, la première disponible), se posent tout un tas de
|
||||||
|
* problèmes de synchronisation si les deux extrémités du tunnel
|
||||||
|
* essaient de se connecter en même temps par exemple.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void ext_bidir(const char addr[], int port, int local_port, int local_r, int local_w) {
|
||||||
|
/* First, let’s establish a full-duplex connection. */
|
||||||
|
int server = setup_out(local_port);
|
||||||
|
int peer_r; /* Future remote client socket to read from. */
|
||||||
|
int peer_w = setup_in(addr, port);
|
||||||
|
|
||||||
|
int client_connected = 0;
|
||||||
|
int server_connected = 0;
|
||||||
|
|
||||||
|
struct timeval one_sec = {.tv_sec=1, .tv_usec=0};
|
||||||
|
struct timeval *timeout = &one_sec;
|
||||||
|
|
||||||
|
fd_set set;
|
||||||
|
while (!(client_connected && server_connected)) {
|
||||||
|
if (!client_connected) {
|
||||||
|
FD_ZERO(&set);
|
||||||
|
FD_SET(server, &set);
|
||||||
|
}
|
||||||
|
|
||||||
|
select(server + 1, &set, NULL, NULL, timeout);
|
||||||
|
|
||||||
|
if (FD_ISSET(server, &set)) {
|
||||||
|
/* The server socket is readable, a peer is trying to
|
||||||
|
* connect. */
|
||||||
|
fputs("acceptation\n", stderr);
|
||||||
|
peer_r = accept_client(server);
|
||||||
|
FD_CLR(server, &set);
|
||||||
|
client_connected = 1;
|
||||||
|
fputs("Client connecté.\n", stderr);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ext_out(port);
|
/* Attempt to connect every second. */
|
||||||
waitpid(pid, NULL, 0);
|
if (try_connect(peer_w, addr, port)) {
|
||||||
|
timeout = NULL;
|
||||||
|
server_connected = 1;
|
||||||
|
fputs("Connecté au serveur.\n", stderr);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
timeout->tv_sec = 1;
|
||||||
|
timeout->tv_usec = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fputs("Connexion bidirectionelle établie.\n", stderr);
|
||||||
|
|
||||||
|
fd_set rfd;
|
||||||
|
|
||||||
|
int nfds = peer_r > local_r ? peer_r : local_r;
|
||||||
|
nfds++;
|
||||||
|
|
||||||
|
char in_buf[1024];
|
||||||
|
char out_buf[1024];
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
FD_ZERO(&rfd);
|
||||||
|
FD_SET(peer_r, &rfd);
|
||||||
|
FD_SET(local_r, &rfd);
|
||||||
|
|
||||||
|
select(nfds, &rfd, NULL, NULL, NULL);
|
||||||
|
|
||||||
|
if (FD_ISSET(peer_r, &rfd)) {
|
||||||
|
/* Ready to read from client. */
|
||||||
|
ssize_t n = read(peer_r, in_buf, sizeof in_buf);
|
||||||
|
if (n < 0) {
|
||||||
|
perror("read (from out)");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (write(local_w, in_buf, n) < 0) {
|
||||||
|
perror("write (to local_out)");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (FD_ISSET(local_r, &rfd)) {
|
||||||
|
/* Ready to read from tun dev. */
|
||||||
|
ssize_t n = read(local_r, out_buf, sizeof out_buf);
|
||||||
|
if (n < 0) {
|
||||||
|
perror("read (from local_in)");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (write(peer_w, out_buf, n) < 0) {
|
||||||
|
perror("write (to in)");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,18 @@
|
|||||||
#define EXTREMITE_H
|
#define EXTREMITE_H
|
||||||
|
|
||||||
|
|
||||||
|
/* Sets up a tunnel exit on the specified PORT, returns a readable fd
|
||||||
|
* representing it. */
|
||||||
int ext_out(int port);
|
int ext_out(int port);
|
||||||
|
|
||||||
|
/* Sets up a tunnel entrance connected to the exit at ADDR and PORT,
|
||||||
|
* returns a writable fd representing it. */
|
||||||
int ext_in(const char addr[], int port);
|
int ext_in(const char addr[], int port);
|
||||||
void ext_bidir(const char addr[], int port, int in, int out);
|
|
||||||
|
/* Establishes a full-duplex tunnel listening on LOCAL_PORT and
|
||||||
|
* connected to ADDR and PORT. Copies data from local_r to the tunnel,
|
||||||
|
* and data from the tunnel to local_w. */
|
||||||
|
void ext_bidir(const char addr[], int port, int local_port, int local_r, int local_w);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -34,6 +34,7 @@ int tun_alloc(const char *dev) {
|
|||||||
|
|
||||||
int err = ioctl(fd, TUNSETIFF, (void *) &ifr);
|
int err = ioctl(fd, TUNSETIFF, (void *) &ifr);
|
||||||
if(err < 0){
|
if(err < 0){
|
||||||
|
perror("ioctl");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,7 +47,15 @@ int copy(int src, int dest) {
|
|||||||
int n = 0;
|
int n = 0;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
n = read(src, buf, 1024);
|
n = read(src, buf, sizeof buf);
|
||||||
write(dest, buf, n);
|
if (n < 0) {
|
||||||
|
perror("copy");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
n = write(dest, buf, n);
|
||||||
|
if (n < 0) {
|
||||||
|
perror("copy");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,7 @@ int main(int argc, char *argv[argc]) {
|
|||||||
fprintf(stderr, "Erreur lors de l’exécution du script de configuration de l’interface.\n");
|
fprintf(stderr, "Erreur lors de l’exécution du script de configuration de l’interface.\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
ext_bidir(outip, outport, tun, tun);
|
ext_bidir(outip, outport, inport, tun, tun);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "iftun.h"
|
#include "iftun.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char *argv[argc]) {
|
int main(int argc, char *argv[argc]) {
|
||||||
@ -8,6 +9,12 @@ int main(int argc, char *argv[argc]) {
|
|||||||
fprintf(stderr, "Utilisation : %s interface\n", argv[0]);
|
fprintf(stderr, "Utilisation : %s interface\n", argv[0]);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (getuid() != 0) {
|
||||||
|
fprintf(stderr, "%s doit être lancé en tant que superutilisateur.\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
int tun = tun_alloc(argv[1]);
|
int tun = tun_alloc(argv[1]);
|
||||||
fprintf(stderr, "Configurez l’interface puis appuyez sur <Entrée>... ");
|
fprintf(stderr, "Configurez l’interface puis appuyez sur <Entrée>... ");
|
||||||
fflush(stderr);
|
fflush(stderr);
|
||||||
|
Reference in New Issue
Block a user