From: Mazet Laurent Date: Fri, 23 May 2025 15:16:44 +0000 (+0200) Subject: manage tun connection X-Git-Tag: v1.0~32 X-Git-Url: https://secure.softndesign.org/git/?a=commitdiff_plain;h=e44e9cee2661b9b7f4639538e82ea3395ce93b72;p=ulvpn.git manage tun connection --- diff --git a/makefile b/makefile index 84a07fc..6e11254 100644 --- a/makefile +++ b/makefile @@ -6,6 +6,7 @@ CC ?= gcc RANLIB ?= ranlib #INCLUDES = -I../debug -D__MEMORY_ALLOCATION__ +INCLUDES = -D_DEFAULT_SOURCE=1 INCLUDES += -DVERBOSE_COLOR=1 #INCLUDES += -DVERBOSE_LOCATION=1 OFLAGS = -O4 -Os diff --git a/mapec.c b/mapec.c index 8f1a420..3aec8a2 100644 --- a/mapec.c +++ b/mapec.c @@ -12,14 +12,20 @@ - initial version */ +#include #include #include #include +#include +#include +#include #include #include #include +#include #include #include +#include #include #include #include @@ -37,7 +43,8 @@ DECLARE_VERBOSE_LEVEL (mapec, INFO); */ typedef enum { MAPEC_error_e = 0, - MAPEC_udp_e + MAPEC_udp_e, + MAPEC_tun_e } MAPEC_type_t; /** @@ -83,20 +90,23 @@ void __attribute__ ((constructor)) _init_morep_ (void) atexit (free_all_mapecs); } -int parse_protocol (MAPEC_addr_t *addr, char *url) +int parse_protocol (MAPEC_type_t *type, char *url) { VERBOSE (mapec, TRACE, PRINTF ("parse_protocol\n")); int rc = -1; - MAPEC_type_t type = MAPEC_error_e; + MAPEC_type_t newtype = MAPEC_error_e; if (strncmp (url, "udp://", 6) == 0) { - type = MAPEC_udp_e; + newtype = MAPEC_udp_e; + rc = 6; + } else if (strncmp (url, "tun://", 6) == 0) { + newtype = MAPEC_tun_e; rc = 6; } - if (addr->type == MAPEC_error_e) { - addr->type = type; - } else if (addr->type != type) { + if (*type == MAPEC_error_e) { + *type = newtype; + } else if (*type != newtype) { rc = -1; } @@ -126,7 +136,7 @@ int parse_address (struct sockaddr_in *addr, char *url) addr->sin_family = AF_INET; addr->sin_port = htons (atoi (port)); - + VERBOSE (mapec, INFO, PRINTF ("parse URL -> %s %s\n", hostname, port)); if (hostname[0] != '*') { @@ -146,33 +156,28 @@ int parse_address (struct sockaddr_in *addr, char *url) return 0; } -int MAPEC_Connect (char *local_address, char * remote_address) +int connect_udp (MAPEC_addr_t *mapec, char *local_address, char *remote_address) { - VERBOSE (mapec, TRACE, PRINTF ("MAPEC_Connect\n")); - - MAPEC_addr_t mapec = { 0 }; - int rc; + VERBOSE (mapec, TRACE, PRINTF ("connect_udp\n")); /* parse local url */ VERBOSE (mapec, DEBUG, PRINTF ("MAPEC local addr %s\n", local_address)); - rc = parse_protocol (&mapec, local_address); - if ((rc <= 0) || (parse_address (&mapec.addrin, local_address + rc) < 0)) { + if (parse_address (&mapec->addrin, local_address) < 0) { VERBOSE (mapec, ERROR, PRINTF ("can't parse local url\n")); errno = EINVAL; return -1; } - VERBOSE (mapec, DEBUG, PRINTF ("local port -> %d\n", ntohs (mapec.addrin.sin_port))); + VERBOSE (mapec, DEBUG, PRINTF ("local port -> %d\n", ntohs (mapec->addrin.sin_port))); /* parse remote url */ VERBOSE (mapec, DEBUG, PRINTF ("MAPEC remote addr %s\n", remote_address)); - rc = parse_protocol (&mapec, remote_address); - if ((rc <= 0) || (parse_address (&mapec.addrout, remote_address + rc) < 0)) { + if (parse_address (&mapec->addrout, remote_address) < 0) { VERBOSE (mapec, ERROR, PRINTF ("can't parse remote url\n")); errno = EINVAL; return -1; } - VERBOSE (mapec, DEBUG, PRINTF ("remote port -> %d\n", ntohs (mapec.addrout.sin_port))); + VERBOSE (mapec, DEBUG, PRINTF ("remote port -> %d\n", ntohs (mapec->addrout.sin_port))); /* create socket */ int fid = socket (PF_INET, SOCK_DGRAM, 0); @@ -185,18 +190,110 @@ int MAPEC_Connect (char *local_address, char * remote_address) /* bind on local */ int val = 1; setsockopt (fid, SOL_SOCKET, SO_REUSEADDR, (int *)&val, sizeof (val)); - if (bind (fid, (struct sockaddr *)&mapec.addrin, sizeof (mapec.addrin)) < 0) { + if (bind (fid, (struct sockaddr *)&mapec->addrin, sizeof (mapec->addrin)) < 0) { VERBOSE (mapec, ERROR, PRINTF ("can't bind socket %d\n", fid)); return -1; } /* connect on remote */ - if (connect (fid, (struct sockaddr *)&mapec.addrout, sizeof (mapec.addrout)) < 0) { + if (connect (fid, (struct sockaddr *)&mapec->addrout, sizeof (mapec->addrout)) < 0) { VERBOSE (mapec, ERROR, PRINTF ("can't connect socket %d\n", fid)); return -1; } - - MAPEC_list[fid] = mapecdup (&mapec); + + return fid; +} + +#define ifreq_offsetof(x) offsetof(struct ifreq, x) + +int connect_tun (MAPEC_addr_t *mapec, char *device_name, char *ip_address) +{ + + VERBOSE (mapec, TRACE, PRINTF ("connect_tun\n")); + + /* request a TUN device */ + int fid = open ("/dev/net/tun", O_RDWR); + if (fid < 0) { + VERBOSE (mapec, ERROR, PRINTF ("can't open a tun device '%s'\n", device_name)); + return -1; + } + + /* link to named device */ + struct ifreq ifr = { 0 }; + ifr.ifr_flags = IFF_TUN | IFF_NO_PI; + if (ioctl (fid, TUNSETIFF, &ifr) < 0) { + VERBOSE (mapec, ERROR, PRINTF ("can't link to named device '%s'\n", device_name)); + return -1; + } + + /* Create a channel to the NET kernel. */ + int sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock < 0) { + VERBOSE (mapec, ERROR, PRINTF ("can't accept socket %d\n", sock)); + errno = ENOMEM; + return -1; + } + + /* get interface name */ + ifr.ifr_flags = 0; + strncpy(ifr.ifr_name, device_name, IFNAMSIZ); + + /* set ip address */ + mapec->addrin.sin_family = AF_INET; + mapec->addrin.sin_port = 0; + mapec->addrin.sin_addr.s_addr = inet_addr (ip_address); + memcpy (&ifr.ifr_addr, &mapec->addrin, sizeof (struct sockaddr)); + + if ((ioctl (sock, SIOCSIFADDR, &ifr) < 0) || (ioctl (sock, SIOCGIFFLAGS, &ifr) < 0)) { + VERBOSE (mapec, ERROR, PRINTF ("can't set ip address '%s' on tun device '%s'\n", ip_address, device_name)); + return -1; + } + + ifr.ifr_flags |= IFF_UP | IFF_RUNNING; + if (ioctl (sock, SIOCSIFFLAGS, &ifr) < 0) { + VERBOSE (mapec, ERROR, PRINTF ("can't activate tun interface '%s'\n", device_name)); + return -1; + } + close (sock); + + return fid; +} + +int MAPEC_Connect (char *arg1, char *arg2) +{ + + VERBOSE (mapec, TRACE, PRINTF ("MAPEC_Connect\n")); + + MAPEC_addr_t mapec = { 0 }; + + /* check type */ + int rc = parse_protocol (&mapec.type, arg1); + if (arg2) { + rc = parse_protocol (&mapec.type, arg2); + } + if (rc < 0) { + VERBOSE (mapec, ERROR, PRINTF ("non coherent protocol '%s' <> '%s'\n", arg1, (arg2) ? arg2 : "")); + errno = EINVAL; + return -1; + } + + int fid; + switch (mapec.type) { + case MAPEC_udp_e: + fid = connect_udp (&mapec, arg1 + rc, arg2 + rc); + break; + + case MAPEC_tun_e: + fid = connect_tun (&mapec, arg1 + rc, arg2 + rc); + break; + + default: + fid = -1; + } + + if (fid >= 0) { + MAPEC_list[fid] = mapecdup (&mapec); + } return fid; } diff --git a/mapec.h b/mapec.h index b2fc202..af38283 100644 --- a/mapec.h +++ b/mapec.h @@ -35,10 +35,13 @@ __BEGIN_DECLS Establish a connection between a local URL and a remote URL. Block until connection is established or refused. - @param local_address local address of the MAPEC with the following - syntax: 'udp://hostname:port' or 'tun://device'. - @param remote_address same format as for local_address. For TUN, - remote address is not usesfull. + @param arg1 first argument + @param arg2 second argrument + + For UDP connection, arguements are local and remote addresses. The + syntax is 'udp://hostname:port' + For TUN connection, first argument is an url, second argument is the + IP address of the tun device. The syntax is tun://device and tun://ip @return a new file descriptor associated with this connection @@ -46,7 +49,7 @@ __BEGIN_DECLS @see MAPEC_Send() @see MAPEC_Receive() */ -int MAPEC_Connect (char *local_address, char *remote_address); +int MAPEC_Connect (char *arg1, char *arg2); /** @ingroup MAPEC diff --git a/mapec_test.c b/mapec_test.c index b197573..1848e6d 100644 --- a/mapec_test.c +++ b/mapec_test.c @@ -28,24 +28,30 @@ #include "mapec.h" -int MAPEC_Send_UDP_OK = 0; -int MAPEC_Echo_UDP_OK = 0; +char *progname = NULL; +char *client_local_url = "udp://localhost:13501"; +char *client_remote_url = "udp://localhost:12501"; +char *server_local_url = "udp://localhost:12501"; +char *server_remote_url = "udp://localhost:13501"; + +int MAPEC_Send_OK = 0; +int MAPEC_Echo_OK = 0; #define UNUSED __attribute__ ((unused)) -void *udp_client (UNUSED void *dummy) +void *client (UNUSED void *dummy) { - VERBOSE (mapec, TRACE, PRINTF ("test_client\n")); + VERBOSE (mapec, TRACE, PRINTF ("client\n")); int count; unsigned char tx_data[10][1500]; int tx_len[10]; - int fid = MAPEC_Connect ("udp://localhost:13501", "udp://localhost:12501"); + int fid = MAPEC_Connect (client_local_url, client_remote_url); if (fid < 0) { VERBOSE (mapec, WARNING, PRINTF ("client MAPEC_Connect error\n")); - MAPEC_Echo_UDP_OK = 0; + MAPEC_Echo_OK = 0; return NULL; } @@ -53,7 +59,7 @@ void *udp_client (UNUSED void *dummy) VERBOSE (mapec, INFO, PRINTF ("client connected to server, trying to exchange %d messages\n", nb_messages)); for (count = 0; count < nb_messages; count++) { - + tx_len[count] = rand () % sizeof (tx_data[count]); for (int i = 0; i < tx_len[count]; i++) tx_data[count][i] = rand () % 256; @@ -61,13 +67,13 @@ void *udp_client (UNUSED void *dummy) int rc = MAPEC_Send (fid, tx_data[count], tx_len[count]); if (rc < 0) { VERBOSE (mapec, WARNING, PRINTF ("client MAPEC_Send tx error (%d/%d-%d)\n", rc, tx_len[count], errno)); - MAPEC_Echo_UDP_OK = 0; + MAPEC_Echo_OK = 0; return NULL; } if (tx_len[count] != rc) { VERBOSE (mapec, WARNING, PRINTF ("client MAPEC_Send tx len error tx=%d rc=%d\n", tx_len[count], rc)); - MAPEC_Echo_UDP_OK = 0; + MAPEC_Echo_OK = 0; return NULL; } VERBOSE (mapec, DEBUG, PRINTF ("client MAPEC_Send ok (%d)\n", tx_len[count])); @@ -89,36 +95,36 @@ void *udp_client (UNUSED void *dummy) if (tx_len[count] != rx_len) { VERBOSE (mapec, WARNING, PRINTF ("client MAPEC_Receive rx len error : tx=%d / rx=%d\n", tx_len[count], rx_len)); - MAPEC_Echo_UDP_OK = 0; + MAPEC_Echo_OK = 0; return NULL; } if (memcmp (rx_data, tx_data[count], tx_len[count]) != 0 ) { VERBOSE (mapec, WARNING, PRINTF ("client MAPEC_Receive rx corrupted data\n")); - MAPEC_Echo_UDP_OK = 0; + MAPEC_Echo_OK = 0; return NULL; } } MAPEC_Close (fid); VERBOSE (mapec, INFO, PRINTF ("client end of test, %d echo processed\n", count)); - MAPEC_Echo_UDP_OK = 1; + MAPEC_Echo_OK = 1; return NULL; } -void *udp_server (UNUSED void *dummy) +void *server (UNUSED void *dummy) { - VERBOSE (mapec, TRACE, PRINTF ("udp_server\n")); + VERBOSE (mapec, TRACE, PRINTF ("server\n")); - int fid = MAPEC_Connect ("udp://localhost:12501", "udp://localhost:13501"); + int fid = MAPEC_Connect (server_local_url, server_remote_url); if (fid < 0) { - VERBOSE (mapec, ERROR, PRINTF ("MAPEC_Connect (%d)", fid)); + VERBOSE (mapec, ERROR, PRINTF ("MAPEC_Connect (%d)\n", fid)); exit (1); } - VERBOSE (mapec, INFO, PRINTF ("udp_server waiting for data\n")); + VERBOSE (mapec, INFO, PRINTF ("server waiting for data\n")); while (1) { unsigned char data[8192]; @@ -135,12 +141,12 @@ void *udp_server (UNUSED void *dummy) break; } - VERBOSE (mapec, INFO, PRINTF ("udp_server receive data len=%d, sending echo\n", rx_len)); + VERBOSE (mapec, INFO, PRINTF ("server receive data len=%d, sending echo\n", rx_len)); usleep (1e4); int tx_len = MAPEC_Send (fid, data, rx_len); if (tx_len == rx_len) { - MAPEC_Send_UDP_OK = 1; + MAPEC_Send_OK = 1; } } @@ -160,43 +166,86 @@ void *udp_server (UNUSED void *dummy) int main (int argc, char **argv) { - /* process arguments */ - if (argc > 1) { - CHANGE_VERBOSE_LEVEL (mapec, atoi (argv[1])); - argc--; + /* get basename */ + char *pt = progname = argv[0]; + while (*pt) { + if ((*pt == '/') || (*pt == '\\')) { + progname = pt + 1; + } + pt++; } - if (argc > 1) { - printf ("usage: %s [verbose level]\n", argv[0]); - exit (1); + + /* process argument */ + while (argc-- > 1) { + char *arg = *(++argv); + if (arg[0] != '-') { + VERBOSE (mapec, ERROR, PRINTF ("%s: unknown command '%s'\n", progname, arg)); + return 1; + } + char c = arg[1]; + switch (c) { + case 'c': + arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL; + if (arg == NULL) { + VERBOSE (mapec, ERROR, PRINTF ("%s: client url not specified\n", progname)); + return 1; + } + client_local_url = arg; + client_remote_url = ((argc > 1) && (**(argv + 1) != '-') && (argc--)) ? *(++argv) : NULL; + break; + case 's': + arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL; + if (arg == NULL) { + VERBOSE (mapec, ERROR, PRINTF ("%s: server url not specified\n", progname)); + return 1; + } + server_local_url = arg; + server_remote_url = ((argc > 1) && (**(argv + 1) != '-') && (argc--)) ? *(++argv) : NULL; + break; + case 'v': + arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL; + if (arg == NULL) { + VERBOSE (mapec, ERROR, PRINTF ("%s: verbose level not specified\n", progname)); + return 1; + } + CHANGE_VERBOSE_LEVEL (mapec, atoi (arg)); + break; + case 'h': + default: + printf ("usage: %s [-c url [url]] [-h] [-s url [url]] [-v int]\n", progname); + return (c != 'h'); + } } printf ("*** STARTING SERVERS ***\n"); - pthread_t udp_thread; + pthread_t server_thread; - pthread_create (&udp_thread, NULL, udp_server, NULL); + pthread_create (&server_thread, NULL, server, NULL); /* Give some delay to server to setup there MAPEC */ usleep (1e6); - + printf ("*** STARTING TEST SEQUENCE ***\n"); - pthread_t udp_client_thread; + pthread_t client_thread; + + pthread_create (&client_thread, NULL, client, NULL); - pthread_create (&udp_client_thread, NULL, udp_client, NULL); + pthread_join (client_thread, NULL); - pthread_join (udp_client_thread, NULL); - printf ("*** END OF TEST SEQUENCE ***\n"); int failed = 0; - DUMP_STATUS (MAPEC_Send_UDP_OK); - DUMP_STATUS (MAPEC_Echo_UDP_OK); + DUMP_STATUS (MAPEC_Send_OK); + DUMP_STATUS (MAPEC_Echo_OK); return failed ? EXIT_FAILURE : EXIT_SUCCESS; } +/* test: mapec_test.exe -h */ /* test: mapec_test.exe */ -/* test: mapec_test.exe 4 */ +/* test: mapec_test.exe -v 4 */ +/* test: mapec_test.exe -v 3 -c udp://localhost:1234 udp://localhost:1235 -s udp://localhost:1235 udp://localhost:1234 */ /* vim: set ts=4 sw=4 si et: */