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

238 lines
5.8 KiB
C
Raw Normal View History

2019-11-13 11:10:05 +01:00
#include "extremite.h"
2019-10-25 23:53:43 +02:00
#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>
2019-11-13 17:33:17 +01:00
#include <sys/select.h>
2019-10-25 23:53:43 +02:00
#include <sys/socket.h>
#include <sys/stat.h>
2019-11-13 17:33:17 +01:00
#include <sys/time.h>
2019-10-25 23:53:43 +02:00
#include <sys/types.h>
2019-11-06 07:36:00 +01:00
#include <sys/wait.h>
2019-11-13 17:33:17 +01:00
#include <unistd.h>
2019-11-06 07:36:00 +01:00
#define BUFSIZE 1024
2019-10-25 23:53:43 +02:00
2019-11-13 17:33:17 +01:00
static int setup_out(int port) {
/* Create the socket. */
2019-10-25 23:53:43 +02:00
int server = socket(AF_INET6, SOCK_STREAM, 0);
if (server == -1) {
perror("socket");
exit(1);
}
2019-11-13 17:33:17 +01:00
/* Enable socket re-use, makes debugging easier. */
2019-11-06 07:36:00 +01:00
setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &(int) {1}, sizeof (int));
2019-11-13 17:33:17 +01:00
/* Bind to any local IPv6 address on port PORT. */
2019-10-25 23:53:43 +02:00
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);
}
2019-11-13 17:33:17 +01:00
/* Pretty print the matched address. */
2019-10-25 23:53:43 +02:00
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);
2019-11-13 11:10:05 +01:00
if (listen(server, 1) == -1) {
2019-10-25 23:53:43 +02:00
perror("listen");
exit(1);
}
2019-11-13 17:33:17 +01:00
return server;
}
static int accept_client(int server) {
/* Wait for a connection attempt. */
2019-10-25 23:53:43 +02:00
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);
2019-11-13 11:10:05 +01:00
2019-11-13 17:33:17 +01:00
/* We only serve one peer, no need to keep the server socket
* open. */
2019-11-13 11:10:05 +01:00
close(server);
2019-11-13 17:33:17 +01:00
/* Pretty print the peers address */
2019-10-25 23:53:43 +02:00
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);
2019-11-13 11:10:05 +01:00
return client;
2019-11-13 17:33:17 +01:00
}
2019-11-13 11:10:05 +01:00
2019-11-13 17:33:17 +01:00
int ext_out(int port) {
int server = setup_out(port);
return accept_client(server);
2019-10-25 23:53:43 +02:00
}
2019-11-13 17:33:17 +01:00
2019-10-25 23:53:43 +02:00
2019-11-13 17:33:17 +01:00
static int setup_in() {
2019-10-25 23:53:43 +02:00
int s = socket(AF_INET6, SOCK_STREAM, 0);
if (s == -1) {
perror("socket");
exit(1);
}
2019-11-13 17:33:17 +01:00
return s;
}
static int try_connect(int s, const char addr[], int port) {
2019-10-25 23:53:43 +02:00
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.");
2019-11-13 17:33:17 +01:00
if (connect(s, (struct sockaddr *) &sa, sizeof sa) == -1) {
2019-10-25 23:53:43 +02:00
perror("connect");
2019-11-13 17:33:17 +01:00
return 0;
2019-10-25 23:53:43 +02:00
}
2019-11-13 17:33:17 +01:00
2019-10-25 23:53:43 +02:00
char addr_pretty[INET6_ADDRSTRLEN] = "";
inet_ntop(AF_INET6, &(sa.sin6_addr), addr_pretty, sizeof addr_pretty);
printf("Connecté à : %s\n", addr_pretty);
2019-11-13 17:33:17 +01:00
return 1;
2019-10-25 23:53:43 +02:00
}
2019-11-06 07:36:00 +01:00
2019-11-13 17:33:17 +01:00
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;
}
}
2019-11-06 07:36:00 +01:00
}
2019-11-13 17:33:17 +01:00
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);
}
}
2019-11-06 07:36:00 +01:00
}
}