This repository has been archived on 2019-11-14. You can view files and clone it, but cannot push or open issues or pull requests.
rip-vm2/partage/src/extremite.c
2019-11-13 17:33:17 +01:00

238 lines
5.8 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "extremite.h"
#include <arpa/inet.h>
#include <fcntl.h>
#include <linux/if.h>
#include <linux/if_tun.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#define BUFSIZE 1024
static int setup_out(int port) {
/* Create the socket. */
int server = socket(AF_INET6, SOCK_STREAM, 0);
if (server == -1) {
perror("socket");
exit(1);
}
/* Enable socket re-use, makes debugging easier. */
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};
server_addr.sin6_family = AF_INET6;
server_addr.sin6_port = htons(port);
server_addr.sin6_addr = in6addr_any;
if (bind(server, (struct sockaddr *) &server_addr, sizeof server_addr) == -1) {
perror("bind");
exit(1);
}
/* Pretty print the matched address. */
char server_addr_pretty[INET6_ADDRSTRLEN] = "";
inet_ntop(AF_INET6, &(server_addr.sin6_addr), server_addr_pretty, sizeof server_addr_pretty);
printf("Écoute sur : %s\n", server_addr_pretty);
if (listen(server, 1) == -1) {
perror("listen");
exit(1);
}
return server;
}
static int accept_client(int server) {
/* Wait for a connection attempt. */
struct sockaddr_in6 client_addr;
socklen_t client_addr_len;
puts("Attente dun client.");
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);
/* Pretty print the peers address */
char client_addr_pretty[INET6_ADDRSTRLEN] = "";
inet_ntop(AF_INET6, &(client_addr.sin6_addr), client_addr_pretty, sizeof client_addr_pretty);
printf("Client connecté : %s\n", client_addr_pretty);
return client;
}
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);
if (s == -1) {
perror("socket");
exit(1);
}
return s;
}
static int try_connect(int s, const char addr[], int port) {
struct sockaddr_in6 sa = {0};
sa.sin6_family = AF_INET6;
sa.sin6_port = htons(port);
inet_pton(AF_INET6, addr, &sa.sin6_addr);
puts("Connexion.");
if (connect(s, (struct sockaddr *) &sa, sizeof sa) == -1) {
perror("connect");
return 0;
}
char addr_pretty[INET6_ADDRSTRLEN] = "";
inet_ntop(AF_INET6, &(sa.sin6_addr), addr_pretty, sizeof addr_pretty);
printf("Connecté à : %s\n", addr_pretty);
return 1;
}
int ext_in(const char addr[], int port) {
int s = setup_in();
/* 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 dun client. Cela nous donne donc deux connexions
* matérialisées par deux socket, lune qui est utilisée en lecture et
* lautre en écriture.
*
* Il pourrait suffir davoir une extremité qui écoute, et lautre qui
* se connecte, établissant ainsi une seule connexion quon
* 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
* daccepter une connexion (mais de ne pas attendre que les deux
* conditions soient vraies, et dutiliser 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, lets 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 {
/* Attempt to connect every second. */
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);
}
}
}
}