From ae64871deee33799f99fa1ecb985fb044ae2b726 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Al=D0=B5x=D0=B0nder=20Lysik=D0=BEv?= <alexander.lysikov@demlabs.net> Date: Tue, 8 Oct 2019 15:25:35 +0500 Subject: [PATCH] added vpn-client --- CMakeLists.txt | 8 +- dap_chain_net_srv_vpn.c | 102 +-- dap_chain_net_srv_vpn.h | 95 +++ dap_chain_net_vpn_client.c | 542 ++++++++++++++ dap_chain_net_vpn_client.h | 32 + dap_chain_net_vpn_client_tun.c | 1230 ++++++++++++++++++++++++++++++++ dap_chain_net_vpn_client_tun.h | 28 + 7 files changed, 1946 insertions(+), 91 deletions(-) create mode 100644 dap_chain_net_vpn_client.c create mode 100644 dap_chain_net_vpn_client.h create mode 100644 dap_chain_net_vpn_client_tun.c create mode 100644 dap_chain_net_vpn_client_tun.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 23f6ef4..fc2f166 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,11 +2,15 @@ cmake_minimum_required(VERSION 2.8) project (dap_chain_net_srv_vpn) set(DAP_CHAIN_NET_SRV_VPN_SRCS - dap_chain_net_srv_vpn.c + dap_chain_net_srv_vpn.c + dap_chain_net_vpn_client.c + dap_chain_net_vpn_client_tun.c ) set(DAP_CHAIN_NET_SRV_VPN_HEADERS - dap_chain_net_srv_vpn.h + dap_chain_net_srv_vpn.h + dap_chain_net_vpn_client.h + dap_chain_net_vpn_client_tun.h ) if(WIN32) diff --git a/dap_chain_net_srv_vpn.c b/dap_chain_net_srv_vpn.c index fda6f8d..8a89556 100755 --- a/dap_chain_net_srv_vpn.c +++ b/dap_chain_net_srv_vpn.c @@ -83,96 +83,9 @@ #define LOG_TAG "srv_vpn" -#define VPN_PACKET_OP_CODE_CONNECTED 0x000000a9 -#define VPN_PACKET_OP_CODE_CONNECT 0x000000aa -#define VPN_PACKET_OP_CODE_DISCONNECT 0x000000ab -#define VPN_PACKET_OP_CODE_SEND 0x000000ac -#define VPN_PACKET_OP_CODE_RECV 0x000000ad -#define VPN_PACKET_OP_CODE_PROBLEM 0x000000ae - -#define VPN_PROBLEM_CODE_NO_FREE_ADDR 0x00000001 -#define VPN_PROBLEM_CODE_TUNNEL_DOWN 0x00000002 -#define VPN_PROBLEM_CODE_PACKET_LOST 0x00000003 - -#define VPN_PACKET_OP_CODE_VPN_METADATA 0x000000b0 -#define VPN_PACKET_OP_CODE_VPN_RESERVED 0x000000b1 -#define VPN_PACKET_OP_CODE_VPN_ADDR_REQUEST 0x000000b2 -#define VPN_PACKET_OP_CODE_VPN_ADDR_REPLY 0x000000b3 - -#define VPN_PACKET_OP_CODE_VPN_SEND 0x000000bc -#define VPN_PACKET_OP_CODE_VPN_RECV 0x000000bd - #define SF_MAX_EVENTS 256 -typedef struct ch_vpn_pkt { - struct { - int sock_id; // Client's socket id - uint32_t op_code; // Operation code - union { - struct { // L4 connect operation - uint32_t addr_size; - uint16_t port; - uint16_t padding; - } op_connect; - struct { // For data transmission, usualy for I/O functions - uint32_t data_size; - uint32_t padding; - } op_data; - struct { // We have a problem and we know that! - uint32_t code; // I hope we'll have no more than 4B+ problems, not I?? - uint32_t padding_padding_padding_damned_padding_nobody_nowhere_uses_this_fild_but_if_wil_change_me_pls_with_an_auto_rename; - } op_problem; - struct { - uint32_t padding1; - uint32_t padding2; - } raw; // Raw access to OP bytes - }; - }__attribute__((packed)) header; - uint8_t data[]; // Binary data nested by packet -}__attribute__((packed)) ch_vpn_pkt_t; - -/** - * @struct ch_vpn_socket_proxy - * @brief Internal data storage for single socket proxy functions. Usualy helpfull for\ - * port forwarding or for protecting single application's connection - * - **/ -typedef struct ch_vpn_socket_proxy { - int id; - int sock; - struct in_addr client_addr; // Used in raw L3 connections - pthread_mutex_t mutex; - dap_stream_ch_t * ch; - - bool signal_to_delete; - ch_vpn_pkt_t * pkt_out[100]; - size_t pkt_out_size; - - uint64_t bytes_sent; - uint64_t bytes_recieved; - - time_t time_created; - time_t time_lastused; - - UT_hash_handle hh; - UT_hash_handle hh2; - UT_hash_handle hh_sock; -} ch_vpn_socket_proxy_t; -/** - * @struct dap_stream_ch_vpn - * @brief Object that creates for every remote channel client - * - * - **/ -typedef struct dap_stream_ch_vpn -{ - dap_chain_net_srv_t net_srv; - //dap_chain_net_srv_uid_t srv_uid; // Unique ID for service. - pthread_mutex_t mutex; - ch_vpn_socket_proxy_t * socks; - int raw_l3_sock; -} dap_stream_ch_vpn_t; typedef struct dap_stream_ch_vpn_remote_single { // in_addr_t addr; @@ -221,8 +134,6 @@ static pthread_t srv_sf_socks_raw_pid; vpn_local_network_t *raw_server; -#define CH_SF(a) ((dap_stream_ch_vpn_t *) ((a)->internal) ) - void *srv_ch_sf_thread(void * arg); void *srv_ch_sf_thread_raw(void *arg); void srv_ch_sf_tun_create(); @@ -347,6 +258,19 @@ static void callback_trafic(dap_client_remote_t *a_client, dap_stream_ch_t* a_ch } +/** + * @brief ch_sf_socket_delete + * @param sf + */ +static void ch_sf_socket_delete(ch_vpn_socket_proxy_t * sf) +{ + close(sf->sock); + pthread_mutex_destroy(& (sf->mutex) ); + if (sf) + free(sf); +} + + /** * @brief stream_sf_new Callback to constructor of object of Ch * @param ch diff --git a/dap_chain_net_srv_vpn.h b/dap_chain_net_srv_vpn.h index c8cee5f..78cbb04 100755 --- a/dap_chain_net_srv_vpn.h +++ b/dap_chain_net_srv_vpn.h @@ -24,5 +24,100 @@ #pragma once #include "dap_chain_net_srv.h" +#define VPN_PACKET_OP_CODE_CONNECTED 0x000000a9 +#define VPN_PACKET_OP_CODE_CONNECT 0x000000aa +#define VPN_PACKET_OP_CODE_DISCONNECT 0x000000ab +#define VPN_PACKET_OP_CODE_SEND 0x000000ac +#define VPN_PACKET_OP_CODE_RECV 0x000000ad +#define VPN_PACKET_OP_CODE_PROBLEM 0x000000ae + +#define VPN_PROBLEM_CODE_NO_FREE_ADDR 0x00000001 +#define VPN_PROBLEM_CODE_TUNNEL_DOWN 0x00000002 +#define VPN_PROBLEM_CODE_PACKET_LOST 0x00000003 + +#define VPN_PACKET_OP_CODE_VPN_METADATA 0x000000b0 +#define VPN_PACKET_OP_CODE_VPN_RESERVED 0x000000b1 +#define VPN_PACKET_OP_CODE_VPN_ADDR_REQUEST 0x000000b2 +#define VPN_PACKET_OP_CODE_VPN_ADDR_REPLY 0x000000b3 + +#define VPN_PACKET_OP_CODE_VPN_SEND 0x000000bc +#define VPN_PACKET_OP_CODE_VPN_RECV 0x000000bd + +#define VPN_PACKET_OP_CODE_PING 0xc0 +#define VPN_PACKET_OP_CODE_PONG 0xc1 + +typedef struct ch_vpn_pkt { + struct { + int sock_id; // Client's socket id + uint32_t op_code; // Operation code + union { + struct { // L4 connect operation + uint32_t addr_size; + uint16_t port; + uint16_t padding; + } op_connect; + struct { // For data transmission, usualy for I/O functions + uint32_t data_size; + uint32_t padding; + } op_data; + struct { // We have a problem and we know that! + uint32_t code; // I hope we'll have no more than 4B+ problems, not I?? + uint32_t padding_padding_padding_damned_padding_nobody_nowhere_uses_this_fild_but_if_wil_change_me_pls_with_an_auto_rename; + } op_problem; + struct { + uint32_t padding1; + uint32_t padding2; + } raw; // Raw access to OP bytes + }; + }__attribute__((packed)) header; + uint8_t data[]; // Binary data nested by packet +}__attribute__((packed)) ch_vpn_pkt_t; + +/** + * @struct ch_vpn_socket_proxy + * @brief Internal data storage for single socket proxy functions. Usualy helpfull for\ + * port forwarding or for protecting single application's connection + * + **/ +typedef struct ch_vpn_socket_proxy { + int id; + int sock; + struct in_addr client_addr; // Used in raw L3 connections + pthread_mutex_t mutex; + dap_stream_ch_t * ch; + + bool signal_to_delete; + ch_vpn_pkt_t * pkt_out[100]; + size_t pkt_out_size; + + uint64_t bytes_sent; + uint64_t bytes_recieved; + + time_t time_created; + time_t time_lastused; + + UT_hash_handle hh; + UT_hash_handle hh2; + UT_hash_handle hh_sock; +} ch_vpn_socket_proxy_t; + + +/** + * @struct dap_stream_ch_vpn + * @brief Object that creates for every remote channel client + * + * + **/ +typedef struct dap_stream_ch_vpn +{ + dap_chain_net_srv_t net_srv; + //dap_chain_net_srv_uid_t srv_uid; // Unique ID for service. + pthread_mutex_t mutex; + ch_vpn_socket_proxy_t * socks; + int raw_l3_sock; +} dap_stream_ch_vpn_t; + +#define CH_SF(a) ((dap_stream_ch_vpn_t *) ((a)->internal) ) + int dap_chain_net_srv_vpn_init(dap_config_t * g_config); void dap_chain_net_srv_vpn_deinit(); diff --git a/dap_chain_net_vpn_client.c b/dap_chain_net_vpn_client.c new file mode 100644 index 0000000..10c58d0 --- /dev/null +++ b/dap_chain_net_vpn_client.c @@ -0,0 +1,542 @@ +/* + * Authors: + * Alexander Lysikov <alexander.lysikov@demlabs.net> + * DeM Labs Inc. https://demlabs.net + * Kelvin Project https://gitlab.demlabs.net/cellframe + * Copyright (c) 2019 + * All rights reserved. + + This file is part of DAP (Deus Applications Prototypes) the open source project + + DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + DAP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with any DAP based project. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <pthread.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/select.h> +#include <sys/ioctl.h> +#include <sys/time.h> +#include <sys/epoll.h> +#include "dap_common.h" +#include "dap_config.h" +#include "dap_strfuncs.h" + +#include "dap_client.h" +#include "dap_chain_node_client.h" + +#include "dap_stream_ch_proc.h" + +#include "dap_chain_net.h" +#include "dap_chain_net_srv_vpn.h" +#include "dap_chain_net_vpn_client.h" +#include "dap_client.h" + +#include "dap_stream_ch_pkt.h" +#include "dap_chain_net_vpn_client_tun.h" + +typedef enum dap_http_client_state { + DAP_HTTP_CLIENT_STATE_NONE = 0, + DAP_HTTP_CLIENT_STATE_START = 1, + DAP_HTTP_CLIENT_STATE_HEADERS = 2, + DAP_HTTP_CLIENT_STATE_DATA = 3 +} dap_http_client_state_t; + +#define LOG_TAG "vpn_client" + +EPOLL_HANDLE sf_socks_epoll_fd; + +ch_vpn_socket_proxy_t *sf_socks = NULL; +ch_vpn_socket_proxy_t *sf_socks_client = NULL; + +static pthread_mutex_t sf_socks_mutex; + +dap_chain_node_info_t *s_node_info = NULL; +dap_chain_node_client_t *s_vpn_client = NULL; +/** + * Start VPN client + * + * return: 0 Ok, 1 Already started, <0 Error + */ +int dap_chain_net_vpn_client_start(dap_chain_net_t *a_net, const char *a_ipv4_str, const char *a_ipv6_str, int a_port) +{ + int l_ret = 0; + if(!a_ipv4_str) // && !a_ipv6_str) + return -1; + /* + dap_client_t *l_client = DAP_NEW_Z(dap_client_t); + dap_events_t *l_events = NULL; //dap_events_new(); + l_client = dap_client_new(l_events, s_stage_status_callback, s_stage_status_error_callback); + char l_channels[2] = { SERVICE_CHANNEL_ID, 0 }; + dap_client_set_active_channels(l_client, l_channels); + dap_client_set_uplink(l_client, strdup(a_ip_v4), a_port); + dap_client_go_stage(l_client, STAGE_STREAM_STREAMING, s_stage_connected_callback); + */ + + if(!s_node_info) + s_node_info = DAP_NEW_Z(dap_chain_node_info_t); + s_node_info->hdr.ext_port = a_port; + + dap_client_stage_t l_stage_target = STAGE_STREAM_STREAMING; + const char l_active_channels[] = { SERVICE_CHANNEL_ID, 0 }; + if(a_ipv4_str) + inet_pton(AF_INET, a_ipv4_str, &(s_node_info->hdr.ext_addr_v4)); + if(a_ipv6_str) + inet_pton(AF_INET6, a_ipv6_str, &(s_node_info->hdr.ext_addr_v6)); + s_vpn_client = dap_chain_client_connect(s_node_info, l_stage_target, l_active_channels); + if(!s_vpn_client) { + log_it(L_ERROR, "Can't connect to VPN server=%s:%d", a_ipv4_str, a_port); + // clean client struct + dap_chain_node_client_close(s_vpn_client); + DAP_DELETE(s_node_info); + s_node_info = NULL; + return -2; + } + // wait connected + int timeout_ms = 500000; //5 sec = 5000 ms + int res = dap_chain_node_client_wait(s_vpn_client, NODE_CLIENT_STATE_CONNECTED, timeout_ms); + if(res) { + log_it(L_ERROR, "No response from VPN server=%s:%d", a_ipv4_str, a_port); + // clean client struct + dap_chain_node_client_close(s_vpn_client); + DAP_DELETE(s_node_info); + s_node_info = NULL; + return -3; + } + + /* dap_stream_ch_t *l_stream = dap_client_get_stream_ch(s_vpn_client->client, SERVICE_CHANNEL_ID);//dap_stream_ch_chain_get_id()); + size_t l_res = dap_stream_ch_chain_pkt_write(l_stream, + VPN_PACKET_OP_CODE_CONNECT, a_net->pub.id, (dap_chain_id_t ) { { 0 } }, + a_net->pub.cell_id, NULL, 0);*/ + + return l_ret; + + l_ret = dap_chain_net_vpn_client_tun_init(a_ipv4_str); + + return l_ret; +} + +int dap_chain_net_vpn_client_stop(void) +{ + // delete connection with VPN server + if(!s_vpn_client) { + dap_chain_node_client_close(s_vpn_client); + s_vpn_client = NULL; + } + DAP_DELETE(s_node_info); + s_node_info = NULL; + int l_ret = dap_chain_net_vpn_client_tun_delete(); + + return l_ret; +} + +int dap_chain_net_vpn_client_status(void) +{ + if(!dap_chain_net_vpn_client_tun_status()) + // VPN client started + return 1; + return 0; +} + +static void vpn_socket_delete(ch_vpn_socket_proxy_t * sf) +{ + close(sf->sock); + pthread_mutex_destroy(&(sf->mutex)); + if(sf) + free(sf); +} + +static void send_pong_pkt(dap_stream_ch_t* a_ch) +{ +// log_it(L_DEBUG,"---------------------------------- PONG!"); + ch_vpn_pkt_t *pkt_out = (ch_vpn_pkt_t*) calloc(1, sizeof(pkt_out->header)); + pkt_out->header.op_code = VPN_PACKET_OP_CODE_PONG; + + dap_stream_ch_pkt_write(a_ch, 'd', pkt_out, + pkt_out->header.op_data.data_size + sizeof(pkt_out->header)); + dap_stream_ch_set_ready_to_write(a_ch, true); + free(pkt_out); +} + +/** + * @brief ch_sf_new Callback to constructor of object of Ch + * @param ch + * @param arg + */ +static void ch_sf_new(dap_stream_ch_t* a_ch, void* arg) +{ + log_it(L_INFO, "SF channel created"); + + a_ch->internal = DAP_NEW_Z(dap_stream_ch_vpn_t); + dap_stream_ch_vpn_t * l_sf = CH_SF(a_ch); + //l_sf->ch=a_ch; + pthread_mutex_init(&l_sf->mutex, NULL); + l_sf->raw_l3_sock = socket(PF_INET, SOCK_RAW, IPPROTO_RAW); + a_ch->stream->events_socket->is_pingable = true; //set up connection to be pingable by main loop + +} + +/** + * @brief ch_sf_delete + * @param ch + * @param arg + */ +static void ch_sf_delete(dap_stream_ch_t* a_ch, void* arg) +{ + + log_it(L_DEBUG, "ch_sf_delete() for %s", a_ch->stream->events_socket->hostaddr); + /* ch_vpn_socket_proxy_t * cur, *tmp; + ch_sf_tun_delete(CH_SF(a_ch)); + HASH_ITER(hh, CH_SF(a_ch)->socks , cur, tmp) { + log_it(L_DEBUG,"delete socket: %i", cur->sock); + HASH_DEL(CH_SF(a_ch)->socks,cur); + if (cur) + free(cur); + }*/ + pthread_mutex_unlock(&( CH_SF(a_ch)->mutex)); + if(CH_SF(a_ch)->raw_l3_sock) + close(CH_SF(a_ch)->raw_l3_sock); +} + +/** + * @brief ch_sf_packet_in + * @param ch + * @param arg + */ +static void ch_sf_packet_in(dap_stream_ch_t* a_ch, void* a_arg) +{ + dap_stream_ch_pkt_t * l_pkt = (dap_stream_ch_pkt_t *) a_arg; + +// log_it(L_DEBUG,"******************************************************************************************************"); +// log_it(L_DEBUG,"stream_sf_packet_in: channel packet hdr size %lu ( last bytes 0x%02x 0x%02x 0x%02x 0x%02x ) ", pkt->hdr.size, +// *((uint8_t *)pkt->data + pkt->hdr.size-4),*((uint8_t *)pkt->data + pkt->hdr.size-3) +// ,*((uint8_t *)pkt->data + pkt->hdr.size-2),*((uint8_t *)pkt->data + pkt->hdr.size-1) +// ); + /**/ + ch_vpn_pkt_t * l_sf_pkt = (ch_vpn_pkt_t *) l_pkt->data; + size_t l_sf_pkt_data_size = l_pkt->hdr.size - sizeof(l_sf_pkt->header); + + int remote_sock_id = l_sf_pkt->header.sock_id; + +// log_it(L_DEBUG,"Got SF packet: remote_sock_id:%d op_code:0x%02x data_size:%lu" +// ,remote_sock_id, l_sf_pkt->header.op_code, l_sf_pkt_data_size ); + if(l_sf_pkt->header.op_code >= 0xb0) { // Raw packets + switch (l_sf_pkt->header.op_code) { + case VPN_PACKET_OP_CODE_VPN_ADDR_REPLY: { // Assigned address for peer + ch_sf_tun_addr_leased(CH_SF(a_ch), l_sf_pkt, l_sf_pkt_data_size); + } + break; + case VPN_PACKET_OP_CODE_VPN_ADDR_REQUEST: { // Client request after L3 connection the new IP address +// log_it(L_DEBUG,"Got SF packet with id %d op_code 0x%02x",remote_sock_id, l_sf_pkt->header.op_code ); + ch_sf_tun_addr_request(CH_SF(a_ch), l_sf_pkt, l_sf_pkt_data_size); +//here!! + + } + break; + case VPN_PACKET_OP_CODE_VPN_SEND: + log_it(L_WARNING, "Got L3_SEND packet with id %d, it's very strange' ", remote_sock_id, + l_sf_pkt->header.op_code); + case VPN_PACKET_OP_CODE_VPN_RECV: + // log_it(L_DEBUG,"feature-2498: Got L3_RECV packet with id %d ",remote_sock_id, l_sf_pkt->header.op_code ); + a_ch->stream->events_socket->last_ping_request = time(NULL); // not ping, but better ;-) + ch_sf_tun_send(CH_SF(a_ch), l_sf_pkt->data, l_sf_pkt->header.op_data.data_size); + break; + //case STREAM_SF_PACKET_OP_CODE_L3_SEND: + // log_it(L_WARNING,"Got L3_SEND packet with id %d, it's very strange' ",remote_sock_id, l_sf_pkt->header.op_code ); + // a_ch->stream->events_socket->last_ping_request = time(NULL); // not ping, but better ;-) + // ch_sf_tun_send(CH_SF(a_ch),l_sf_pkt->data,l_sf_pkt->header.op_data.data_size ); + //break; + case VPN_PACKET_OP_CODE_PING: + a_ch->stream->events_socket->last_ping_request = time(NULL); + send_pong_pkt(a_ch); + break; + case VPN_PACKET_OP_CODE_PONG: + a_ch->stream->events_socket->last_ping_request = time(NULL); + break; + default: + log_it(L_WARNING, "Can't process SF type 0x%02x", l_sf_pkt->header.op_code); + } + } else { // All except CONNECT + ch_vpn_socket_proxy_t * sf_sock = NULL; + if((l_sf_pkt->header.op_code != VPN_PACKET_OP_CODE_CONNECT) // tcp + && (l_sf_pkt->header.op_code != VPN_PACKET_OP_CODE_CONNECTED)) { //udp + pthread_mutex_lock(&( CH_SF(a_ch)->mutex)); + log_it(L_DEBUG, "Looking in hash table with %d", remote_sock_id); + HASH_FIND_INT((CH_SF(a_ch)->socks), &remote_sock_id, sf_sock); + pthread_mutex_unlock(&( CH_SF(a_ch)->mutex)); + if(sf_sock != NULL) { + pthread_mutex_lock(&sf_sock->mutex); // Unlock it in your case as soon as possible to reduce lock time + sf_sock->time_lastused = time(NULL); + switch (l_sf_pkt->header.op_code) { + case VPN_PACKET_OP_CODE_SEND: { + int ret; + if((ret = send(sf_sock->sock, l_sf_pkt->data, l_sf_pkt->header.op_data.data_size, 0)) < 0) { + log_it(L_INFO, "Disconnected from the remote host"); + pthread_mutex_unlock(&sf_sock->mutex); + pthread_mutex_lock(&( CH_SF(a_ch)->mutex)); + HASH_DEL(CH_SF(a_ch)->socks, sf_sock); + pthread_mutex_unlock(&( CH_SF(a_ch)->mutex)); + + pthread_mutex_lock(&sf_socks_mutex); + HASH_DELETE(hh2, sf_socks, sf_sock); + HASH_DELETE(hh_sock, sf_socks_client, sf_sock); + + struct epoll_event ev; + ev.data.fd = sf_sock->sock; + ev.events = EPOLLIN; + if(epoll_ctl(sf_socks_epoll_fd, EPOLL_CTL_DEL, sf_sock->sock, &ev) < 0) { + log_it(L_ERROR, "Can't remove sock_id %d from the epoll fd", remote_sock_id); + //stream_ch_pkt_write_f(ch,'i',"sock_id=%d op_code=0x%02x result=-2",sf_pkt->sock_id, sf_pkt->op_code); + } else { + log_it(L_NOTICE, "Removed sock_id %d from the the epoll fd", remote_sock_id); + //stream_ch_pkt_write_f(ch,'i',"sock_id=%d op_code=0x%02x result=0",sf_pkt->sock_id, sf_pkt->op_code); + } + pthread_mutex_unlock(&sf_socks_mutex); + + vpn_socket_delete(sf_sock); + } else { + sf_sock->bytes_sent += ret; + pthread_mutex_unlock(&sf_sock->mutex); + } + log_it(L_INFO, "Send action from %d sock_id (sf_packet size %lu, ch packet size %lu, have sent %d)" + , sf_sock->id, l_sf_pkt->header.op_data.data_size, l_pkt->hdr.size, ret); + } + break; + case VPN_PACKET_OP_CODE_DISCONNECT: { + log_it(L_INFO, "Disconnect action from %d sock_id", sf_sock->id); + + pthread_mutex_lock(&( CH_SF(a_ch)->mutex)); + HASH_DEL(CH_SF(a_ch)->socks, sf_sock); + pthread_mutex_unlock(&( CH_SF(a_ch)->mutex)); + + pthread_mutex_lock(&sf_socks_mutex); + + HASH_DELETE(hh2, sf_socks, sf_sock); + HASH_DELETE(hh_sock, sf_socks_client, sf_sock); + + struct epoll_event ev; + ev.data.fd = sf_sock->sock; + ev.events = EPOLLIN; + if(epoll_ctl(sf_socks_epoll_fd, EPOLL_CTL_DEL, sf_sock->sock, &ev) < 0) { + log_it(L_ERROR, "Can't remove sock_id %d to the epoll fd", remote_sock_id); + //stream_ch_pkt_write_f(ch,'i',"sock_id=%d op_code=%uc result=-2",sf_pkt->sock_id, sf_pkt->op_code); + } else { + log_it(L_NOTICE, "Removed sock_id %d from the epoll fd", remote_sock_id); + //stream_ch_pkt_write_f(ch,'i',"sock_id=%d op_code=%uc result=0",sf_pkt->sock_id, sf_pkt->op_code); + } + pthread_mutex_unlock(&sf_socks_mutex); + + pthread_mutex_unlock(&sf_sock->mutex); + vpn_socket_delete(sf_sock); + } + break; + default: { + log_it(L_WARNING, "Unprocessed op code 0x%02x", l_sf_pkt->header.op_code); + pthread_mutex_unlock(&sf_sock->mutex); + } + } + } else + log_it(L_WARNING, "Packet input: packet with sock_id %d thats not present in current stream channel", + remote_sock_id); + } else { + HASH_FIND_INT(CH_SF(a_ch)->socks, &remote_sock_id, sf_sock); + if(sf_sock) { + log_it(L_WARNING, "Socket id %d is already used, take another number for socket id", remote_sock_id); + } else { // Connect action + struct sockaddr_in remote_addr; + char addr_str[1024]; + size_t addr_str_size = + (l_sf_pkt->header.op_connect.addr_size > (sizeof(addr_str) - 1)) ? + (sizeof(addr_str) - 1) : + l_sf_pkt->header.op_connect.addr_size; + memset(&remote_addr, 0, sizeof(remote_addr)); + remote_addr.sin_family = AF_INET; + remote_addr.sin_port = htons(l_sf_pkt->header.op_connect.port); + + memcpy(addr_str, l_sf_pkt->data, addr_str_size); + addr_str[addr_str_size] = 0; + + log_it(L_DEBUG, "Connect action to %s:%u (addr_size %lu)", addr_str, l_sf_pkt->header.op_connect.port, + l_sf_pkt->header.op_connect.addr_size); + if(inet_pton(AF_INET, addr_str, &(remote_addr.sin_addr)) < 0) { + log_it(L_ERROR, "Wrong remote address '%s:%u'", addr_str, l_sf_pkt->header.op_connect.port); + + ch_vpn_pkt_t *l_pkt_out = DAP_NEW_Z(ch_vpn_pkt_t); + l_pkt_out->header.op_code = VPN_PACKET_OP_CODE_PROBLEM; + + dap_stream_ch_pkt_write(a_ch, 'd', l_pkt_out, + l_pkt_out->header.op_data.data_size + sizeof(l_pkt_out->header)); + dap_stream_ch_set_ready_to_write(a_ch, true); + + free(l_pkt_out); + + } else { + int s; + if((s = socket(AF_INET, + (l_sf_pkt->header.op_code == VPN_PACKET_OP_CODE_CONNECT) ? + SOCK_STREAM : + SOCK_DGRAM, 0)) >= 0) { + log_it(L_DEBUG, "Socket is created (%d)", s); + if(connect(s, (struct sockaddr *) &remote_addr, sizeof(remote_addr)) >= 0) { + fcntl(s, F_SETFL, O_NONBLOCK); + log_it(L_INFO, "Remote address connected (%s:%u) with sock_id %d", addr_str, + l_sf_pkt->header.op_connect.port, remote_sock_id); + ch_vpn_socket_proxy_t * sf_sock = NULL; + sf_sock = DAP_NEW_Z(ch_vpn_socket_proxy_t); + sf_sock->id = remote_sock_id; + sf_sock->sock = s; + sf_sock->ch = a_ch; + pthread_mutex_init(&sf_sock->mutex, NULL); + + pthread_mutex_lock(&sf_socks_mutex); + pthread_mutex_lock(&( CH_SF(a_ch)->mutex)); + HASH_ADD_INT(CH_SF(a_ch)->socks, id, sf_sock); + log_it(L_DEBUG, "Added %d sock_id with sock %d to the hash table", sf_sock->id, + sf_sock->sock); + HASH_ADD(hh2, sf_socks, id, sizeof(sf_sock->id), sf_sock); + log_it(L_DEBUG, "Added %d sock_id with sock %d to the hash table", sf_sock->id, + sf_sock->sock); + HASH_ADD(hh_sock, sf_socks_client, sock, sizeof(int), sf_sock); + // log_it(L_DEBUG,"Added %d sock_id with sock %d to the socks hash table",sf->id,sf->sock); + pthread_mutex_unlock(&sf_socks_mutex); + pthread_mutex_unlock(&( CH_SF(a_ch)->mutex)); + + struct epoll_event ev; + ev.data.fd = s; + ev.events = EPOLLIN | EPOLLERR; + + if(epoll_ctl(sf_socks_epoll_fd, EPOLL_CTL_ADD, s, &ev) == -1) { + log_it(L_ERROR, "Can't add sock_id %d to the epoll fd", remote_sock_id); + //stream_ch_pkt_write_f(ch,'i',"sock_id=%d op_code=%uc result=-2",sf_pkt->sock_id, sf_pkt->op_code); + } else { + log_it(L_NOTICE, "Added sock_id %d with sock %d to the epoll fd", remote_sock_id, s); + //stream_ch_pkt_write_f(ch,'i',"sock_id=%d op_code=%uc result=0",sf_pkt->sock_id, sf_pkt->op_code); + } + dap_stream_ch_set_ready_to_write(a_ch, true); + } else { + ch_vpn_pkt_t *l_pkt_out = (ch_vpn_pkt_t*) calloc(1, sizeof(l_pkt_out->header)); + l_pkt_out->header.op_code = VPN_PACKET_OP_CODE_PROBLEM; + + dap_stream_ch_pkt_write(a_ch, 'd', l_pkt_out, + l_pkt_out->header.op_data.data_size + sizeof(l_pkt_out->header)); + dap_stream_ch_set_ready_to_write(a_ch, true); + + free(l_pkt_out); + + log_it(L_INFO, "Can't connect to the remote server %s", addr_str); + dap_stream_ch_pkt_write_f(a_ch, 'i', "sock_id=%d op_code=%c result=-1", + l_sf_pkt->header.sock_id, l_sf_pkt->header.op_code); + dap_stream_ch_set_ready_to_write(a_ch, true); + + } + } else { + log_it(L_ERROR, "Can't create the socket"); + ch_vpn_pkt_t *l_pkt_out = (ch_vpn_pkt_t*) calloc(1, sizeof(l_pkt_out->header)); + l_pkt_out->header.op_code = VPN_PACKET_OP_CODE_PROBLEM; + + dap_stream_ch_pkt_write(a_ch, 'd', l_pkt_out, + l_pkt_out->header.op_data.data_size + sizeof(l_pkt_out->header)); + dap_stream_ch_set_ready_to_write(a_ch, true); + + free(l_pkt_out); + + } + } + } + } + } +} + +/** + * @brief stream_sf_packet_out Packet Out Ch callback + * @param ch + * @param arg + */ +static void ch_sf_packet_out(dap_stream_ch_t* ch, void* arg) +{ + ch_vpn_socket_proxy_t * cur = NULL, *tmp; + bool isSmthOut = false; +// log_it(L_DEBUG,"Socket forwarding packet out callback: %u sockets in hashtable", HASH_COUNT(CH_SF(ch)->socks) ); + HASH_ITER(hh, CH_SF(ch)->socks , cur, tmp) + { + bool signalToBreak = false; + pthread_mutex_lock(&(cur->mutex)); + int i; +// log_it(L_DEBUG,"Socket with id %d has %u packets in output buffer", cur->id, cur->pkt_out_size ); + if(cur->pkt_out_size) { + for(i = 0; i < cur->pkt_out_size; i++) { + ch_vpn_pkt_t * pout = cur->pkt_out[i]; + if(pout) { + if(dap_stream_ch_pkt_write(ch, 'd', pout, pout->header.op_data.data_size + sizeof(pout->header))) { + isSmthOut = true; + if(pout) + free(pout); + cur->pkt_out[i] = NULL; + } else { + log_it(L_WARNING, + "Buffer is overflowed, breaking cycle to let the upper level cycle drop data to the output socket"); + isSmthOut = true; + signalToBreak = true; + break; + } + } + } + } + + if(signalToBreak) { + pthread_mutex_unlock(&(cur->mutex)); + break; + } + cur->pkt_out_size = 0; + if(cur->signal_to_delete) { + log_it(L_NOTICE, "Socket id %d got signal to be deleted", cur->id); + pthread_mutex_lock(&( CH_SF(ch)->mutex)); + HASH_DEL(CH_SF(ch)->socks, cur); + pthread_mutex_unlock(&( CH_SF(ch)->mutex)); + + pthread_mutex_lock(&(sf_socks_mutex)); + HASH_DELETE(hh2, sf_socks, cur); + HASH_DELETE(hh_sock, sf_socks_client, cur); + pthread_mutex_unlock(&(sf_socks_mutex)); + + pthread_mutex_unlock(&(cur->mutex)); + vpn_socket_delete(cur); + } else + pthread_mutex_unlock(&(cur->mutex)); + } + /* ch->writable = isSmthOut; + if(isSmthOut) { + if(ch->stream->conn_http) + ch->stream->conn_http->state_write = DAP_HTTP_CLIENT_STATE_DATA; //SAP_HTTP_CONN_STATE_DATA; + }*/ +} + +int dap_chain_net_vpn_client_init(dap_config_t * g_config) +{ + pthread_mutex_init(&sf_socks_mutex, NULL); + + dap_stream_ch_proc_add(SERVICE_CHANNEL_ID, ch_sf_new, ch_sf_delete, ch_sf_packet_in, + ch_sf_packet_out); + return 0; +} + +void dap_chain_net_vpn_client_deinit() +{ + pthread_mutex_destroy(&sf_socks_mutex); +} diff --git a/dap_chain_net_vpn_client.h b/dap_chain_net_vpn_client.h new file mode 100644 index 0000000..4d3cf11 --- /dev/null +++ b/dap_chain_net_vpn_client.h @@ -0,0 +1,32 @@ +/* + * Authors: + * Alexander Lysikov <alexander.lysikov@demlabs.net> + * DeM Labs Inc. https://demlabs.net + * Kelvin Project https://gitlab.demlabs.net/cellframe + * Copyright (c) 2019 + * All rights reserved. + + This file is part of DAP (Deus Applications Prototypes) the open source project + + + DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + DAP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with any DAP based project. If not, see <http://www.gnu.org/licenses/>. + */ +#pragma once + +int dap_chain_net_vpn_client_start(dap_chain_net_t *a_net, const char *a_ipv4_str, const char *a_ipv6_str, int a_port); +int dap_chain_net_vpn_client_stop(void); +int dap_chain_net_vpn_client_status(void); + +int dap_chain_net_vpn_client_init(dap_config_t * g_config); +void dap_chain_net_vpn_client_deinit(); diff --git a/dap_chain_net_vpn_client_tun.c b/dap_chain_net_vpn_client_tun.c new file mode 100644 index 0000000..4b019c3 --- /dev/null +++ b/dap_chain_net_vpn_client_tun.c @@ -0,0 +1,1230 @@ +/* + * Authors: + * Alexander Lysikov <alexander.lysikov@demlabs.net> + * DeM Labs Inc. https://demlabs.net + * Kelvin Project https://gitlab.demlabs.net/cellframe + * Copyright (c) 2019 + * All rights reserved. + + This file is part of DAP (Deus Applications Prototypes) the open source project + + DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + DAP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with any DAP based project. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <sys/epoll.h> +#include <sys/un.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/socket.h> + +#include <arpa/inet.h> +#include <net/ethernet.h> +#include <netpacket/packet.h> +#include <netinet/in.h> + +#include <time.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <stdio.h> +#include <stdarg.h> +#include "utlist.h" + +#include "dap_common.h" +#include "dap_config.h" +#include "dap_strfuncs.h" +#include "dap_stream_ch_pkt.h" + +#include <arpa/inet.h> +#include <fcntl.h> +#include <linux/if_tun.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/ip.h> + +#include "dap_chain_net_srv_vpn.h" +#include "dap_chain_net_vpn_client_tun.h" + +#define LOG_TAG "vpn_client_tun" + +//list_addr_element * list_addr_head = NULL; +//ch_sf_tun_server_t * m_tun_server = NULL; +//pthread_t sf_socks_tun_pid; + +int tun_device_create(char *dev) +{ + struct ifreq ifr; + int fd, err; + char clonedev[] = "/dev/net/tun"; + // open the clone device + if((fd = open(clonedev, O_RDWR)) < 0) { + log_it(L_ERROR, "Can't open %s device!", clonedev); + return -1; + } + memset(&ifr, 0, sizeof(ifr)); + + /* Flags: IFF_TUN - TUN device (no Ethernet headers) + * IFF_TAP - TAP device + * + * IFF_NO_PI - Do not provide packet information + */ + ifr.ifr_flags = IFF_TUN | IFF_NO_PI; + if(dev && *dev) + strncpy(ifr.ifr_name, dev, IFNAMSIZ); + + // try to create the device + if((err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0) { + close(fd); + log_it(L_ERROR, "Can't create tun network interface!"); + //qCritical() << "Can't create tun network interface!"; + return err; + } + if(dev) + strcpy(dev, ifr.ifr_name); + log_it(L_INFO, "Created %s network interface", ifr.ifr_name); + return fd; +} + +static char* run_bash_cmd(const char *a_cmd) +{ + char* l_ret_str = NULL; + FILE* fp = popen(a_cmd, "r"); + char line[256] = { 0x0 }; + if(fgets(line, sizeof(line), fp) != NULL) + l_ret_str = dap_strdup(dap_strstrip(line)); + pclose(fp); + return l_ret_str; +} + +static void exe_bash_cmd(const char *a_cmd) +{ +// char* l_ret_str = NULL; + FILE* fp = popen(a_cmd, "r"); + pclose(fp); +} + +/** + * Get default gateway (only for Unix-like) + * + * return: gateway or NULL if error + */ +static char* get_def_gateway(void) +{ + char* l_gateway = run_bash_cmd("netstat -rn | grep 'UG[ \t]' | awk '{print $2}'"); //netstat -rn = route -n(for root only) + return l_gateway; +} + +/** + * Get connection + * + * return: connection name or NULL + */ +static char* get_connection(const char *a_conn_name) +{ + if(!a_conn_name) + return NULL; + char *l_cmd = dap_strdup_printf("nmcli connection show | grep %s | awk '{print $1}'", a_conn_name); + char* l_connection_name = run_bash_cmd(l_cmd); + DAP_DELETE(l_cmd); + return l_connection_name; +} + +void save_current_connection_interface_data(char **a_last_used_connection_name, char **a_last_used_connection_device) +{ + // nmcli -t -f NAME,TIMESTAMP con show | sort -t: -nk2 | tail -n1 | cut -d: -f1 + char* l_res_str = run_bash_cmd("nmcli -terse --fields NAME,DEVICE con show | head -n1"); + + char **l_res_str_arr = dap_strsplit(l_res_str, ":", 2); + + if(dap_str_countv(l_res_str_arr) != 2) { + log_it(L_ERROR, "Can't get current connection interface name!"); + dap_strfreev(l_res_str_arr); + return; + } + if(a_last_used_connection_name) + *a_last_used_connection_name = l_res_str_arr[0]; + if(a_last_used_connection_device) + *a_last_used_connection_device = l_res_str_arr[1]; + DAP_DELETE(l_res_str_arr); +} + +void disableIPV6(const char *l_device_name) +{ + if(!l_device_name) { + log_it(L_ERROR, "Can't disable IPV6 device name is empty"); + return; + } + char *l_disable_cmd = dap_strdup_printf("echo 1 > /proc/sys/net/ipv6/conf/%s/disable_ipv6", l_device_name); + char* l_ret = run_bash_cmd(l_disable_cmd); + DAP_DELETE(l_disable_cmd); + DAP_DELETE(l_ret); +} + +void enableIPV6(const char *l_device_name) +{ + if(!l_device_name) { + log_it(L_ERROR, "Can't enable IPV6 device name is empty"); + return; + } + char *l_enable_cmd = dap_strdup_printf("echo 0 > /proc/sys/net/ipv6/conf/%s/disable_ipv6", l_device_name); + char* l_ret = run_bash_cmd(l_enable_cmd); + DAP_DELETE(l_enable_cmd); + DAP_DELETE(l_ret); +} + +static bool is_local_address(const char *a_address) +{ + //In accordance with the IANA standard + char **l_octets = dap_strsplit(a_address, ".", -1); + + if(dap_str_countv(l_octets) < 4) { + dap_strfreev(l_octets); + return false; + } + int first_octet = strtol(l_octets[0], NULL, 10); + int second_octet = strtol(l_octets[1], NULL, 10); + if(first_octet == 10) + return true; + else if(first_octet == 172 && second_octet >= 16 && second_octet < 32) + return true; + else if(first_octet == 192 && second_octet == 168) + return true; + return false; + +} + +static int s_fd_tun; // tun0 file descriptor + +static char s_dev[IFNAMSIZ]; +static char *s_cur_gw = NULL; +static const char *s_conn_name = "nodeVPNClient"; +static char *s_last_used_connection_name = NULL, *s_last_used_connection_device = NULL; + +static pthread_t s_thread_read_tun_id; + +/** + * Thread for read from /dev/net/tun + */ +static void* thread_read_tun(void *arg) +{ + //srv_ch_sf_tun_create(); + + if(s_fd_tun <= 0) { + log_it(L_CRITICAL, "Tun/tap file descriptor is not initialized"); + return NULL; + } + /* if (fcntl(raw_server->tun_fd, F_SETFL, O_NONBLOCK) < 0){ ; + log_it(L_CRITICAL,"Can't switch tun/tap socket into the non-block mode"); + return NULL; + } + if (fcntl(raw_server->tun_fd, F_SETFD, FD_CLOEXEC) < 0){; + log_it(L_CRITICAL,"Can't switch tun/tap socket to not be passed across execs"); + return NULL; + } + */ + uint8_t *tmp_buf; +// ssize_t tmp_buf_size; + static int tun_MTU = 100000; /// TODO Replace with detection of MTU size + + tmp_buf = (uint8_t *) calloc(1, tun_MTU); +// tmp_buf_size = 0; + log_it(L_INFO, "Tun/tap thread starts with MTU = %d", tun_MTU); + + fd_set fds_read, fds_read_active; + + FD_ZERO(&fds_read); + FD_SET(s_fd_tun, &fds_read); + FD_SET(get_select_breaker(), &fds_read); + /// Main cycle + do { + fds_read_active = fds_read; + int ret = select(FD_SETSIZE, &fds_read_active, NULL, NULL, NULL); + // + if(ret > 0) { + if(FD_ISSET(get_select_breaker(), &fds_read_active)) { // Smth to send + ch_vpn_pkt_t* pkt = NULL; //TODO srv_ch_sf_raw_read(); + if(pkt) { + int write_ret = write(s_fd_tun, pkt->data, pkt->header.op_data.data_size); + if(write_ret > 0) { + log_it(L_DEBUG, "Wrote out %d bytes to the tun/tap interface", write_ret); + } else { + log_it(L_ERROR, "Tun/tap write %u bytes returned '%s' error, code (%d)", + pkt->header.op_data.data_size, strerror(errno), write_ret); + } + } + } + if(FD_ISSET(s_fd_tun, &fds_read_active)) { + int read_ret = read(s_fd_tun, tmp_buf, tun_MTU); + if(read_ret < 0) { + log_it(L_CRITICAL, "Tun/tap read returned '%s' error, code (%d)", strerror(errno), read_ret); + break; + } else { + struct iphdr *iph = (struct iphdr*) tmp_buf; + struct in_addr in_daddr, in_saddr; + // destination address + in_daddr.s_addr = iph->daddr; + // source address + in_saddr.s_addr = iph->saddr; + char str_daddr[42], str_saddr[42]; + strncpy(str_saddr, inet_ntoa(in_saddr), sizeof(str_saddr)); + strncpy(str_daddr, inet_ntoa(in_daddr), sizeof(str_daddr)); + + if(iph->tot_len > (uint16_t) read_ret) { + log_it(L_INFO, "Tun/Tap interface returned only the fragment (tot_len =%u read_ret=%d) ", + iph->tot_len, read_ret); + } + if(iph->tot_len < (uint16_t) read_ret) { + log_it(L_WARNING, "Tun/Tap interface returned more then one packet (tot_len =%u read_ret=%d) ", + iph->tot_len, read_ret); + } + + log_it(L_DEBUG, "Read IP packet from tun/tap interface daddr=%s saddr=%s total_size = %d " + , str_daddr, str_saddr, read_ret); + // form packet to vpn-server + ch_vpn_pkt_t *pkt_out = (ch_vpn_pkt_t*) calloc(1, sizeof(pkt_out->header) + read_ret); + pkt_out->header.op_code = VPN_PACKET_OP_CODE_VPN_SEND; //VPN_PACKET_OP_CODE_VPN_RECV + pkt_out->header.sock_id = s_fd_tun; + pkt_out->header.op_data.data_size = read_ret; + memcpy(pkt_out->data, tmp_buf, read_ret); + // sent packet to vpn-server + // TODO + + /* dap_stream_ch_vpn_remote_single_t * raw_client = NULL; + pthread_mutex_lock(&raw_server->clients_mutex); + HASH_FIND_INT(raw_server->clients, &in_daddr.s_addr, raw_client); + // HASH_ADD_INT(CH_SF(ch)->socks, id, sf_sock ); + // HASH_DEL(CH_SF(ch)->socks,sf_sock); + if(raw_client) { // Is present in hash table such destination address + ch_vpn_pkt_t *pkt_out = (ch_vpn_pkt_t*) calloc(1, sizeof(pkt_out->header) + read_ret); + pkt_out->header.op_code = VPN_PACKET_OP_CODE_VPN_RECV; + pkt_out->header.sock_id = raw_server->tun_fd; + pkt_out->header.op_data.data_size = read_ret; + memcpy(pkt_out->data, tmp_buf, read_ret); + dap_stream_ch_pkt_write(raw_client->ch, DATA_CHANNEL_ID, pkt_out, + pkt_out->header.op_data.data_size + sizeof(pkt_out->header)); + stream_sf_socket_ready_to_write(raw_client->ch, true); + } else { + log_it(L_DEBUG, "No remote client for income IP packet with addr %s", inet_ntoa(in_daddr)); + } + pthread_mutex_unlock(&raw_server->clients_mutex);*/ + } + }/*else { + log_it(L_CRITICAL,"select() has no tun handler in the returned set"); + break; + + }*/ + } else { + log_it(L_CRITICAL, "Select returned %d", ret); + break; + } + } while(1); + log_it(L_NOTICE, "Raw sockets listen thread is stopped"); + // close tun + if(s_fd_tun > 0) { + int l_fd_tun = s_fd_tun; + s_fd_tun = 0; + close(l_fd_tun); + } + + return NULL; +} + +/* void DapTunWorkerAbstract::procDataFromTun(void * a_buf,size_t a_bufSize) + { + // struct ip *iph = (struct ip* ) tmpBuf; + // qDebug() << "[DapChSockForw] saddr = " << ::inet_ntoa(iph->ip_src)<< " dadrr = " << inet_ntoa( iph->ip_dst) << " size = "<<tmpBufSize ; + DapSockForwPacket * pktOut = + (DapSockForwPacket *)::calloc(1,sizeof(pktOut->header)+a_bufSize ); + pktOut->header.op_code = STREAM_SF_PACKET_OP_CODE_RAW_SEND; + pktOut->header.socket_id = m_tunSocket; + pktOut->header.op_data.data_size = a_bufSize; + memcpy(pktOut->data, a_buf, pktOut->header.op_data.data_size); + + emit packetOut(pktOut); + emit readPackets(); + }*/ + +int dap_chain_net_vpn_client_tun_init(const char *a_ipv4_str) +{ + // char dev[IFNAMSIZ] = { 0 }; + memset(s_dev, 0, IFNAMSIZ); + if((s_fd_tun = tun_device_create(s_dev)) < 0) { + return -1; + } + // get current gateway + DAP_DELETE(s_cur_gw); + s_cur_gw = get_def_gateway(); + if(!s_cur_gw) { + log_it(L_ERROR, "Can't get default gateway"); + return -2; + } + + // delete default gateway + char *l_cmd_del_gw = dap_strdup_printf("ip route del default via %s", s_cur_gw); + char *l_cmd_ret = run_bash_cmd(l_cmd_del_gw); + DAP_DELETE(l_cmd_del_gw); + if(!l_cmd_del_gw) { + log_it(L_ERROR, "Can't delete dafault gateway %s)", s_cur_gw); + DAP_DELETE(s_cur_gw); + return -3; + } + DAP_DELETE(l_cmd_ret); + + DAP_DELETE(s_last_used_connection_name); + DAP_DELETE(s_last_used_connection_device); + s_last_used_connection_name = NULL; + s_last_used_connection_device = NULL; + save_current_connection_interface_data(&s_last_used_connection_name, &s_last_used_connection_device); + disableIPV6(s_last_used_connection_device); + + // add new default gateway for vpn-server address + if(!is_local_address(a_ipv4_str)) { + // This route don't need if address is local + char *l_str_cmd = dap_strdup_printf("route add -host %s gw %s metric 10", a_ipv4_str, s_cur_gw); + char *l_cmd_ret = run_bash_cmd(l_str_cmd); + DAP_DELETE(l_str_cmd); + DAP_DELETE(l_cmd_ret); + } + + // check and delete present connection + char *l_conn_present = get_connection(s_conn_name); + if(!dap_strcmp(l_conn_present, s_conn_name)) { + char *l_str_cmd = dap_strdup_printf("nmcli c delete %s", s_conn_name); + exe_bash_cmd(l_str_cmd); + DAP_DELETE(l_str_cmd); + } + DAP_DELETE(l_conn_present); + int l_ret = 0; + // create new connection + { + // nmcli connection show + char *l_cmd_add_con = dap_strdup_printf( + "nmcli connection add type tun con-name %s autoconnect false ifname %s mode tun ip4 %s gw4 %s", + s_conn_name, s_dev, a_ipv4_str, s_cur_gw); + char *l_cmd_ret = run_bash_cmd(l_cmd_add_con); + l_conn_present = get_connection(s_conn_name); + if(dap_strcmp(l_conn_present, s_conn_name)) + l_ret = -1; + DAP_DELETE(l_cmd_ret); + DAP_DELETE(l_cmd_add_con); + DAP_DELETE(l_conn_present); + } + if(l_ret < 0) { + log_it(L_ERROR, "Can't create network configuration (connection=%s)", s_conn_name); + DAP_DELETE(s_cur_gw); + return l_ret; + } + // modify new connection and up + { + char *l_str_cmd = dap_strdup_printf("nmcli connection modify %s +ipv4.ignore-auto-routes true", s_conn_name); + exe_bash_cmd(l_str_cmd); + DAP_DELETE(l_str_cmd); + l_str_cmd = dap_strdup_printf("nmcli connection modify %s +ipv4.ignore-auto-dns true", s_conn_name); + exe_bash_cmd(l_str_cmd); + DAP_DELETE(l_str_cmd); + l_str_cmd = dap_strdup_printf("nmcli connection modify %s +ipv4.dns-search %s", s_conn_name, s_conn_name); + exe_bash_cmd(l_str_cmd); + DAP_DELETE(l_str_cmd); + l_str_cmd = dap_strdup_printf("nmcli connection modify %s ipv4.dns-priority 10", s_conn_name); + exe_bash_cmd(l_str_cmd); + DAP_DELETE(l_str_cmd); + l_str_cmd = dap_strdup_printf("nmcli connection modify %s +ipv4.method manual", s_conn_name); + exe_bash_cmd(l_str_cmd); + DAP_DELETE(l_str_cmd); + l_str_cmd = dap_strdup_printf("nmcli connection modify %s +ipv4.dns %s", s_conn_name, s_cur_gw); + exe_bash_cmd(l_str_cmd); + DAP_DELETE(l_str_cmd); + l_str_cmd = dap_strdup_printf("nmcli connection modify %s +ipv4.route-metric 10", s_conn_name); + exe_bash_cmd(l_str_cmd); + DAP_DELETE(l_str_cmd); + l_str_cmd = dap_strdup_printf("nmcli connection up %s", s_conn_name); + exe_bash_cmd(l_str_cmd); + DAP_DELETE(l_str_cmd); + } + + pthread_create(&s_thread_read_tun_id, NULL, thread_read_tun, NULL); + //m_tunDeviceName = dev; + //m_tunSocket = fd; + return l_ret; +} + +int dap_chain_net_vpn_client_tun_delete(void) +{ + // restore previous routing + if(!s_conn_name || !s_last_used_connection_name) + return -1; + if(s_fd_tun > 0) { + int l_fd_tun = s_fd_tun; + s_fd_tun = 0; + close(l_fd_tun); + } + char *l_str_cmd = dap_strdup_printf("ifconfig %s down", s_dev); + exe_bash_cmd(l_str_cmd); + DAP_DELETE(l_str_cmd); + + l_str_cmd = dap_strdup_printf("nmcli connection down %s", s_conn_name); + exe_bash_cmd(l_str_cmd); + DAP_DELETE(l_str_cmd); + + l_str_cmd = dap_strdup_printf("nmcli connection delete %s", s_conn_name); + exe_bash_cmd(l_str_cmd); + DAP_DELETE(l_str_cmd); + + // ip route add default via 192.168.100.1 + if(s_cur_gw) { + l_str_cmd = dap_strdup_printf("ip route add default via %s", s_cur_gw); + exe_bash_cmd(l_str_cmd); + DAP_DELETE(l_str_cmd); + } + + enableIPV6(s_last_used_connection_device); + + l_str_cmd = dap_strdup_printf("nmcli connection up \"%s\"", s_last_used_connection_name); + exe_bash_cmd(l_str_cmd); + DAP_DELETE(l_str_cmd); + + DAP_DELETE(s_last_used_connection_name); + DAP_DELETE(s_last_used_connection_device); + s_last_used_connection_name = NULL; + s_last_used_connection_device = NULL; + return 0; +} + + +int dap_chain_net_vpn_client_tun_status(void) +{ + char *l_str_cmd = get_connection(s_conn_name); + if(!l_str_cmd) + return 0; + // connection must be present + if(dap_strcmp(l_str_cmd, s_conn_name)) { + DAP_DELETE(l_str_cmd); + return 0; + } + DAP_DELETE(l_str_cmd); + + char *l_used_connection_name = NULL; + char *l_used_connection_device = NULL; + save_current_connection_interface_data(&l_used_connection_name, &l_used_connection_device); + // connection must be upped + if(dap_strcmp(l_used_connection_name, s_conn_name) || dap_strcmp(l_used_connection_device, s_dev)) { + DAP_DELETE(l_used_connection_name); + DAP_DELETE(l_used_connection_device); + return -1; + } + DAP_DELETE(l_used_connection_name); + DAP_DELETE(l_used_connection_device); + + // VPN client started + return 0; +} + + + + + + + +dap_stream_ch_pkt_t* ch_sf_tun_read(); +void ch_sf_tun_destroy(); + +/** + * @brief ch_sf_thread_tun + * @param arg + * @return + */ +void* ch_sf_thread_tun(void *arg) +{ + ch_sf_tun_create(); + + if(m_tun_server->tun_fd <= 0) { + log_it(L_CRITICAL, "Tun/tap file descriptor is not initialized"); + pthread_cond_signal(&m_tun_server->tun_started_cond); + return NULL; + } + + m_tun_server->tun_tx = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); + struct sockaddr_ll my_addr = { 0 }; + struct ifreq s_ifr; + + strncpy(s_ifr.ifr_name, m_tun_server->ifr.ifr_name, sizeof(s_ifr.ifr_name)); + + /* get interface index of tun0 */ + ioctl(m_tun_server->tun_tx, SIOCGIFINDEX, &s_ifr); + + /* fill sockaddr_ll struct to prepare binding */ + my_addr.sll_family = AF_PACKET; + my_addr.sll_protocol = htons(ETH_P_ALL); + my_addr.sll_ifindex = s_ifr.ifr_ifindex; + +// tun_server->tun_tx = socket(); + + uint8_t *tmp_buf; + ssize_t tmp_buf_size; + static int tun_MTU = 100000; /// TODO Replace with detection of MTU size + + tmp_buf = (uint8_t *) calloc(1, tun_MTU); + tmp_buf_size = 0; + log_it(L_INFO, "Tun/tap thread starts with MTU = %d", tun_MTU); + + fd_set fds_read, fds_read_active; + + FD_ZERO(&fds_read); + FD_SET(m_tun_server->tun_fd, &fds_read); + FD_SET(get_select_breaker(), &fds_read); + /// Main cycle + pthread_cond_signal(&m_tun_server->tun_started_cond); + do { + fds_read_active = fds_read; + int ret = select(FD_SETSIZE, &fds_read_active, NULL, NULL, NULL); + // + if(ret > 0) { + if(FD_ISSET(get_select_breaker(), &fds_read_active)) { // Smth to send +// log_it(L_DEBUG,"--------------------------- something to sent"); + dap_stream_ch_pkt_t* pkt = ch_sf_tun_read(); + if(pkt) { + int write_ret = write(m_tun_server->tun_fd, pkt->data, pkt->header.op_data.data_size); + if(write_ret > 0) { + log_it(L_DEBUG, "Wrote out %d bytes to the tun/tap interface", write_ret); + } else { + log_it(L_ERROR,"Tun/tap write %u bytes returned '%s' error, code (%d)",pkt->header.op_data.data_size,strerror(errno),write_ret); + } + } + } + if(FD_ISSET(m_tun_server->tun_fd, &fds_read_active)) { + int read_ret = read(m_tun_server->tun_fd, tmp_buf, tun_MTU); + if(read_ret < 0) { + log_it(L_CRITICAL,"Tun/tap read returned '%s' error, code (%d)",strerror(errno),read_ret); + break; + } else { + bool passPacket = true; + //log_it(L_DEBUG,"read %d from tun_fd",read_ret); + //switch(ch_sf_snort_pkt(tmp_buf,read_ret)){ + // case SNORT_ALERT: passPacket=false; break; + // default: passPacket=true; + //} + if(passPacket) { + struct iphdr *iph = (struct iphdr*) tmp_buf; + struct in_addr in_daddr, in_saddr; + in_daddr.s_addr = iph->daddr; + in_saddr.s_addr = iph->saddr; + char str_daddr[42], str_saddr[42]; + strncpy(str_saddr, inet_ntoa(in_saddr), sizeof(str_saddr)); + strncpy(str_daddr, inet_ntoa(in_daddr), sizeof(str_daddr)); + /*if(iph->tot_len > (uint16_t) read_ret ){ + log_it(INFO,"Tun/Tap interface returned only the fragment (tot_len =%u read_ret=%d) ", + iph->tot_len,read_ret); + }*/ + /*if(iph->tot_len < (uint16_t) read_ret ){ + log_it(WARNING,"Tun/Tap interface returned more then one packet (tot_len =%u read_ret=%d) ", + iph->tot_len,read_ret); + }*/ + + //log_it(L_DEBUG,"Read IP packet from tun/tap interface daddr=%s saddr=%s total_size = %d " + // ,str_daddr,str_saddr,read_ret); + ch_sf_tun_client_t * raw_client = NULL; + pthread_mutex_lock(&m_tun_server->clients_mutex); + HASH_FIND_INT(m_tun_server->clients, &in_daddr.s_addr, raw_client); + // HASH_ADD_INT(CH_SF(ch)->socks, id, sf_sock ); + // HASH_DEL(CH_SF(ch)->socks,sf_sock); + if(raw_client) { // Is present in hash table such destination address + dap_stream_ch_pkt_t *pkt_out = (dap_stream_ch_pkt_t*) calloc(1, + sizeof(pkt_out->header) + read_ret); + if(pkt_out) { + pkt_out->header.op_code = STREAM_SF_PACKET_OP_CODE_L3_RECV; + pkt_out->header.sock_id = m_tun_server->tun_fd; + pkt_out->header.op_data.data_size = read_ret; + memcpy(pkt_out->data, tmp_buf, read_ret); + stream_ch_pkt_write(raw_client->ch, 'd', pkt_out, + pkt_out->header.op_data.data_size + sizeof(pkt_out->header)); + stream_sf_socket_ready_to_write(raw_client->ch, true); + } else + log_it(L_CRITICAL, "Can't allocate memory for the new packet: %s", strerror(errno)); + } else { + ch_sf_peer_info_t * l_peer = NULL; + size_t i; + for(i = 0; i < m_tun_server->peers_count; i++) { + if(!(m_tun_server->peers[i].in_use)) + continue; + /* + struct in_addr in_daddr_net; + in_daddr_net.s_addr = m_tun_server->peers[i].netmask & in_daddr.s_addr; + + log_it(L_DEBUG,"Check peer #%u of %u @%p",i,m_tun_server->peers_count,&m_tun_server->peers[i]); + log_it(L_DEBUG,"--- dst net: %s",inet_ntoa(in_daddr_net)); + log_it(L_DEBUG,"--- peer net: %s",inet_ntoa(inet_makeaddr(htonl(m_tun_server->peers[i].netaddr),0))); + log_it(L_DEBUG,"--- peer mask: %s",inet_ntoa(inet_makeaddr(htonl(m_tun_server->peers[i].netmask),0))); + */ + if((m_tun_server->peers[i].netmask & in_daddr.s_addr) + == (m_tun_server->peers[i].netmask & m_tun_server->peers[i].netaddr)) { // Address in peer + l_peer = m_tun_server->peers + i; +// log_it(L_DEBUG,"*** Mutch!!"); + break; + } + } + if(l_peer) { // Peer is found + ch_sf_pkt_send(l_peer->ch, tmp_buf, read_ret); + } else { + log_it(L_DEBUG, "No remote client for income IP packet with addr %s ", + inet_ntoa(in_daddr)); + } + } + pthread_mutex_unlock(&m_tun_server->clients_mutex); + } + } + }/*else { + log_it(CRITICAL,"select() has no tun handler in the returned set"); + break; + + }*/ + } else { + log_it(L_CRITICAL, "Select returned %d", ret); + break; + } + } while(1); + ch_sf_tun_destroy(); + log_it(L_NOTICE, "Raw sockets listen thread is stopped"); + return NULL; +} + +/** + * @brief ms2ts + * @param ts + * @param ms + */ +static void ms2ts(struct timespec *ts, unsigned long ms) +{ + ts->tv_sec = ms / 1000; + ts->tv_nsec = (ms % 1000) * 1000000; +} +/** + * @brief ch_sf_tun_init + * @return + */ +int ch_sf_tun_init() +{ + struct timespec l_time_wait; + clock_gettime(CLOCK_REALTIME, &l_time_wait); + l_time_wait.tv_sec += 10; + + m_tun_server = SAP_NEW_Z(ch_sf_tun_server_t); + m_tun_server->peers_max = CH_SF_PEER_MAX; + m_tun_server->peers = SAP_NEW_Z_SIZE(ch_sf_peer_info_t, m_tun_server->peers_max); + pthread_mutex_init(&m_tun_server->clients_mutex, NULL); + pthread_mutex_init(&m_tun_server->pkt_out_mutex, NULL); + pthread_mutex_init(&m_tun_server->tun_started_mutex, NULL); + pthread_cond_init(&m_tun_server->tun_started_cond, NULL); + + pthread_mutex_lock(&m_tun_server->tun_started_mutex); + log_it(L_DEBUG, "Initializing TUN driver..."); + pthread_create(&sf_socks_tun_pid, NULL, ch_sf_thread_tun, NULL); + pthread_cond_timedwait(&m_tun_server->tun_started_cond, &m_tun_server->tun_started_mutex, &l_time_wait); + pthread_mutex_unlock(&m_tun_server->tun_started_mutex); + log_it(L_INFO, "TUN driver configured successfuly"); + + return 0; +} + +/** + * @brief ch_sf_tun_deinit + */ +void ch_sf_tun_deinit() +{ + if(m_tun_server) { + ch_sf_tun_destroy(); + SAP_DELETE(m_tun_server->peers); + free(m_tun_server); + } +} + +void ch_sf_tun_destroy() +{ + if(m_tun_server->tun_fd) { + close(m_tun_server->tun_fd); + m_tun_server->tun_fd = -1; + } + +} + +/** + * @brief ch_sf_tun_create + */ +void ch_sf_tun_create() +{ + inet_aton(my_config.vpn_addr, &m_tun_server->int_network); + inet_aton(my_config.vpn_mask, &m_tun_server->int_network_mask); + m_tun_server->int_network_addr.s_addr = (m_tun_server->int_network.s_addr | 0x01000000); // grow up some shit here! + m_tun_server->client_addr_last.s_addr = m_tun_server->int_network_addr.s_addr; + + if((m_tun_server->tun_ctl_fd = open("/dev/net/tun", O_RDWR)) < 0) { + log_it(L_ERROR, "Opening /dev/net/tun error: '%s'", strerror(errno)); + } else { + int err; + memset(&m_tun_server->ifr, 0, sizeof(m_tun_server->ifr)); + m_tun_server->ifr.ifr_flags = IFF_TUN | IFF_NO_PI; + if((err = ioctl(m_tun_server->tun_ctl_fd, TUNSETIFF, (void *) &m_tun_server->ifr)) < 0) { + log_it(L_CRITICAL, "ioctl(TUNSETIFF) error: '%s' ", strerror(errno)); + close(m_tun_server->tun_ctl_fd); + m_tun_server->tun_ctl_fd = -1; + } else { + char buf[256]; + log_it(L_NOTICE, "Bringed up %s virtual network interface (%s/%s)", m_tun_server->ifr.ifr_name, + inet_ntoa(m_tun_server->int_network_addr), my_config.vpn_mask); + m_tun_server->tun_fd = m_tun_server->tun_ctl_fd; // Looks yes, its so +// snprintf(buf,sizeof(buf),"ip_sapnet link set %s up",m_tun_server->ifr.ifr_name); + snprintf(buf, sizeof(buf), "ip link set %s up", m_tun_server->ifr.ifr_name); + system(buf); +// snprintf(buf,sizeof(buf),"ip_sapnet addr add %s/%s dev %s ",inet_ntoa(m_tun_server->int_network_addr),my_config.vpn_mask, m_tun_server->ifr.ifr_name ); + snprintf(buf, sizeof(buf), "ip addr add %s/%s dev %s ", inet_ntoa(m_tun_server->int_network_addr), + my_config.vpn_mask, m_tun_server->ifr.ifr_name); + system(buf); + } + } + +} + +void ch_sf_tun_delete(ch_sf_t * ch_sf) +{ + ch_sf_tun_client_t * tun_client = 0; + + in_addr_t tun_client_addr = ch_sf->ch->stream->session + ? ch_sf->ch->stream->session->tun_client_addr.s_addr + : + 0; + char* l_tun_cliend_addr_str = strdup(inet_ntoa(ch_sf->ch->stream->session->tun_client_addr)); + char* l_tun_cliend_mask_str = strdup(inet_ntoa(ch_sf->ch->stream->session->tun_client_mask)); + + bool need_remove_addr = false; + + struct in_addr l_tun_cliend_mask = ch_sf->ch->stream->session->tun_client_mask; + +// log_it(L_DEBUG,"b_1773 %x %x %x ",tun_client_addr,ch_sf->ch->stream->session,ch_sf->ch->stream->session->tun_client_addr.s_addr); +// log_it(L_DEBUG, "b_1773 btw: %p %x %x",m_tun_server->peers,ch_sf->peer_id,sizeof(ch_sf_peer_info_t)); + if(tun_client_addr) { + log_it(L_DEBUG, "ch_sf_tun_delete() %s searching in hash table", l_tun_cliend_addr_str); + if((uint32_t) (m_tun_server->int_network.s_addr & m_tun_server->int_network_mask.s_addr) + == (uint32_t) (tun_client_addr & m_tun_server->int_network_mask.s_addr)) { + list_addr_element *el = (list_addr_element*) malloc(sizeof(list_addr_element)); + el->addr.s_addr = tun_client_addr; + LL_APPEND(list_addr_head, el); + } else + need_remove_addr = true; + pthread_mutex_lock(&m_tun_server->clients_mutex); + size_t i; + if(ch_sf->is_peer && m_tun_server->peers_count) { + if(ch_sf->peer_id < m_tun_server->peers_count) { + log_it(L_DEBUG, "Reorganize peer table"); +// log_it(L_DEBUG, "b_1773 memzero: %p %x",m_tun_server->peers+ch_sf->peer_id,sizeof(ch_sf_peer_info_t)); + memzero(m_tun_server->peers + ch_sf->peer_id, sizeof(ch_sf_peer_info_t)); + (m_tun_server->peers + ch_sf->peer_id)->netmask = 0xffffffff; + } + } + HASH_FIND_INT(m_tun_server->clients, &tun_client_addr, tun_client); + if(tun_client) { + HASH_DEL(m_tun_server->clients, tun_client); + log_it(L_DEBUG, "ch_sf_tun_delete() %s removed from hash table", l_tun_cliend_addr_str); + free(tun_client); + } else + log_it(L_DEBUG, "ch_sf_tun_delete() %s is not present in raw sockets hash table", l_tun_cliend_addr_str); + pthread_mutex_unlock(&m_tun_server->clients_mutex); + + if(need_remove_addr) { + if(exec_with_ret_f(NULL, "ip addr del %s/%s dev %s", l_tun_cliend_addr_str, l_tun_cliend_mask_str, + m_tun_server->ifr.ifr_name)) + log_it(L_ERROR, "can't execute 'addr del %s/%s dev %s'", l_tun_cliend_addr_str, l_tun_cliend_mask_str, + m_tun_server->ifr.ifr_name); + + } + } + free(l_tun_cliend_addr_str); + free(l_tun_cliend_mask_str); +} + +/** + * @brief ch_sf_tun_read + * @return + */ +dap_stream_ch_pkt_t* ch_sf_tun_read() +{ +// log_it(L_DEBUG,"ch_sf_tun_read()"); + dap_stream_ch_pkt_t*ret = NULL; + pthread_mutex_lock(&m_tun_server->pkt_out_mutex); + if(m_tun_server->pkt_out_rindex == (sizeof(m_tun_server->pkt_out) / sizeof(m_tun_server->pkt_out[0]))) { + m_tun_server->pkt_out_rindex = 0; // ring the buffer! + } + if((m_tun_server->pkt_out_rindex != m_tun_server->pkt_out_windex) || (m_tun_server->pkt_out_size == 0)) { + ret = m_tun_server->pkt_out[m_tun_server->pkt_out_rindex]; + m_tun_server->pkt_out_rindex++; + m_tun_server->pkt_out_size--; + } //else log_it(L_WARNING,"Packet drop on raw_read() operation, ring buffer is full"); + pthread_mutex_unlock(&m_tun_server->pkt_out_mutex); + return ret; +} + +/** + * @brief ch_sf_raw_write + * @param op_code + * @param data + * @param data_size + * @return + */ +int ch_sf_tun_write(uint8_t op_code, const void * data, size_t data_size) +{ +// log_it(L_DEBUG,"ch_sf_tun_write()"); + pthread_mutex_lock(&m_tun_server->pkt_out_mutex); + if(m_tun_server->pkt_out_windex == (sizeof(m_tun_server->pkt_out) / sizeof(m_tun_server->pkt_out[0]))) + m_tun_server->pkt_out_windex = 0; // ring the buffer! + if((m_tun_server->pkt_out_windex < m_tun_server->pkt_out_rindex) || (m_tun_server->pkt_out_size == 0)) { + dap_stream_ch_pkt_t * pkt = (dap_stream_ch_pkt_t *) calloc(1, data_size + sizeof(pkt->header)); + pkt->header.op_code = op_code; + pkt->header.sock_id = m_tun_server->tun_fd; + if(data_size > 0) { + pkt->header.op_data.data_size = data_size; + memcpy(pkt->data, data, data_size); + } + + m_tun_server->pkt_out[m_tun_server->pkt_out_windex] = pkt; + m_tun_server->pkt_out_windex++; + m_tun_server->pkt_out_size++; + pthread_mutex_unlock(&m_tun_server->pkt_out_mutex); + send_select_break(); + return m_tun_server->pkt_out_windex; + } else { + pthread_mutex_unlock(&m_tun_server->pkt_out_mutex); + log_it(L_WARNING, "Raw socket buffer overflow"); + return -1; + } +} + +void ch_sf_tun_send(ch_sf_t * ch_sf, void * pkt_data, size_t pkt_data_size) { + bool passPacket = true; + /*switch(ch_sf_snort_pkt(pkt_data,pkt_data_size)){ + case SNORT_ALERT: passPacket=false; break; + default: passPacket=true; + }*/ +// log_it(L_DEBUG,"==== ch_sf_tun_send()"); + if(passPacket) { +// log_it(L_DEBUG,"==== ch_sf_tun_send() ++"); + struct in_addr in_saddr, in_daddr, in_daddr_net; + in_saddr.s_addr = ((struct iphdr*) pkt_data)->saddr; + in_daddr.s_addr = ((struct iphdr*) pkt_data)->daddr; + in_daddr_net.s_addr = in_daddr.s_addr & m_tun_server->int_network_mask.s_addr; + char * in_daddr_str = strdup(inet_ntoa(in_daddr)); + char * in_saddr_str = strdup(inet_ntoa(in_saddr)); + + sap_stream_ch_t * l_route_ch = ch_sf_peer_ch_find(ch_sf->ch->stream->session, pkt_data, pkt_data_size); + + if(l_route_ch) { +// log_it(L_DEBUG, "Route packet %s=>%s to %d socket", in_saddr_str,in_daddr_str,l_route_ch->stream->events_socket->socket); + ch_sf_pkt_send(l_route_ch, pkt_data, pkt_data_size); +// }else /*if(m_tun_server->int_network.s_addr != in_daddr_net.s_addr )*/{ // No ways to route so write it out to the OS network stack +// }else if(ch_sf_peer_ch_find(NULL, pkt_data,pkt_data_size)){ // No ways to route so write it out to the OS network stack + } else { // if(!ch_sf_peer_ch_check(pkt_data,pkt_data_size)){ // No ways to route so write it out to the OS network stack + int ret; +// log_it(L_DEBUG, "Route packet %s=>%s size %u to the OS network stack",in_saddr_str, +// in_daddr_str,pkt_data_size); + //if( ch_sf_raw_write(STREAM_SF_PACKET_OP_CODE_RAW_SEND, sf_pkt->data, sf_pkt->op_data.data_size)<0){ + struct sockaddr_in sin = { 0 }; + sin.sin_family = AF_INET; + sin.sin_port = 0; + sin.sin_addr.s_addr = in_daddr.s_addr; + if((ret = sendto(ch_sf->raw_l3_sock, pkt_data, pkt_data_size, 0, (struct sockaddr *) &sin, sizeof(sin))) + < 0) { + // if((ret = write(raw_server->tun_fd, sf_pkt->data, sf_pkt->header.op_data.data_size))<0){ + log_it(L_ERROR, "write() returned error %d : '%s'", ret, strerror(errno)); + //log_it(ERROR,"raw socket ring buffer overflowed"); + dap_stream_ch_pkt_t *pkt_out = (dap_stream_ch_pkt_t*) calloc(1, sizeof(pkt_out->header)); + pkt_out->header.op_code = STREAM_SF_PACKET_OP_CODE_PROBLEM; + pkt_out->header.op_problem.code = STREAM_SF_PROBLEM_CODE_PACKET_LOST; + pkt_out->header.sock_id = m_tun_server->tun_fd; + stream_ch_pkt_write(ch_sf->ch, 'd', pkt_out, + pkt_out->header.op_data.data_size + sizeof(pkt_out->header)); + stream_sf_socket_ready_to_write(ch_sf->ch, true); + } else { + //log_it(L_DEBUG, "Raw IP packet daddr:%s saddr:%s %u from %d bytes sent to tun/tap interface", + // str_saddr,str_daddr, sf_pkt->header.op_data.data_size,ret); +// log_it(L_DEBUG,"Raw IP sent %u bytes ",ret); + } + }/*else log_it(L_ERROR,"I don't know what to do with packet");*/ + + if(in_daddr_str) + free(in_daddr_str); + if(in_saddr_str) + free(in_saddr_str); + } +} + +/** + * @brief ch_sf_tun_addr_leased + * @param a_sf + * @param a_pkt + * @param a_pkt_data_size + */ +void ch_sf_tun_addr_leased(ch_sf_t * a_sf, dap_stream_ch_pkt_t * a_pkt, size_t a_pkt_data_size) +{ +// ------------------------------------------- we'd receive address assigment from server + log_it(L_WARNING, "feature-2498 ======== We'd receive address assigment"); + a_sf->is_peer = false; // paranoja ? + struct in_addr l_addr = { 0 }; + struct in_addr l_netmask = { 0 }; + struct in_addr l_netaddr = { 0 }; + struct in_addr l_gw = { 0 }; + + size_t l_route_net_count = 0; + + if(a_pkt_data_size < (sizeof(l_addr) + sizeof(l_gw))) { + log_it(L_ERROR, "Too small ADDR_REPLY packet (%u bytes, need at least %u" + , a_pkt_data_size, sizeof(l_addr)); + return; + } + + l_route_net_count = (a_pkt_data_size - 3 * sizeof(struct in_addr)) / (2 * sizeof(struct in_addr)); + + pthread_mutex_lock(&m_tun_server->clients_mutex); + ch_sf_tun_client_t * n_client = SAP_NEW_Z(ch_sf_tun_client_t); + n_client->ch = a_sf->ch; + + memcpy(&l_addr, a_pkt->data, sizeof(l_addr)); + memcpy(&l_gw, a_pkt->data + sizeof(l_addr), sizeof(l_gw)); + memcpy(&l_netmask, a_pkt->data + sizeof(l_addr) + sizeof(l_gw), sizeof(l_netmask)); + l_netaddr.s_addr = l_addr.s_addr & l_netmask.s_addr; + n_client->addr = l_addr.s_addr; + if(a_sf->ch->stream->session) { + a_sf->ch->stream->session->tun_client_addr.s_addr = l_addr.s_addr; + a_sf->ch->stream->session->tun_client_gw.s_addr = l_gw.s_addr; + a_sf->ch->stream->session->tun_client_mask.s_addr = l_netmask.s_addr; + } + HASH_ADD_INT(m_tun_server->clients, addr, n_client); + char l_addr_buf[INET_ADDRSTRLEN]; + char l_netmask_buf[INET_ADDRSTRLEN]; + char l_netaddr_buf[INET_ADDRSTRLEN]; + char l_gw_buf[INET_ADDRSTRLEN]; + char* err; + pthread_mutex_unlock(&m_tun_server->clients_mutex); + inet_ntop(AF_INET, &l_addr, l_addr_buf, sizeof(l_addr_buf)); + inet_ntop(AF_INET, &l_gw, l_gw_buf, sizeof(l_gw_buf)); + inet_ntop(AF_INET, &l_netmask, l_netmask_buf, sizeof(l_netmask_buf)); + inet_ntop(AF_INET, &l_netaddr, l_netaddr_buf, sizeof(l_netaddr_buf)); + log_it(L_NOTICE, "Registred tunnel %s=>%s to %s/%s via remote socket %d", l_addr_buf, l_gw_buf, l_netaddr_buf, + l_netmask_buf, + a_sf->ch->stream->events_socket->socket); + if(a_sf->ch->stream->is_client_to_uplink) { + log_it(L_NOTICE, "Assign address %s to the network device %s", l_addr_buf, m_tun_server->ifr.ifr_name); + if(exec_with_ret_f(&err, "ip address add %s/%s dev %s", l_addr_buf, l_netmask_buf, m_tun_server->ifr.ifr_name)) + { + log_it(L_ERROR, + "Can't assign ip address, leased from remote server. Routing to the remote network will not work"); + log_it(L_ERROR, "exec returns: '%s'", err); + } + ch_sf_tun_peer_add(a_sf, l_addr.s_addr, l_gw.s_addr, l_netmask.s_addr & l_gw.s_addr, l_netmask.s_addr); + + size_t i; + log_it(L_DEBUG, "Found %u networks in reply", l_route_net_count); + for(i = 0; i < l_route_net_count; i++) { + in_addr_t l_r_netaddr; + in_addr_t l_r_netmask; + + memcpy(&l_r_netaddr, a_pkt->data + (3 + i * 2) * sizeof(in_addr_t), sizeof(in_addr_t)); + memcpy(&l_r_netmask, a_pkt->data + (4 + i * 2) * sizeof(in_addr_t), sizeof(in_addr_t)); + + if(!l_r_netaddr && !l_r_netmask) { + log_it(L_DEBUG, "Ignores default route from upstream"); + continue; + } + +// ch_sf_tun_peer_add(a_sf, 0,0,l_r_netaddr,l_r_netmask); + ch_sf_tun_peer_add(a_sf, l_r_netaddr, l_r_netmask, l_r_netaddr, l_r_netmask); + inet_ntop(AF_INET, &l_r_netmask, l_netmask_buf, sizeof(l_netmask_buf)); + inet_ntop(AF_INET, &l_r_netaddr, l_netaddr_buf, sizeof(l_netaddr_buf)); + +// if(!l_r_netaddr && !l_r_netmask){ +// log_it(L_DEBUG,"Ignores default route from upstream"); +// log_it(L_DEBUG," %s/%s ",l_netaddr_buf, l_netmask_buf); +// continue; +// } + + exec_with_ret_f(NULL, "route add -net %s netmask %s dev %s metric 2", + l_netaddr_buf, l_netmask_buf, m_tun_server->ifr.ifr_ifrn.ifrn_name); + } + + } +} + +/** + * @brief ch_sf_tun_addr_request + * @param a_ch_sf + * @param a_pkt_requet + * @param a_pkt_data_size + */ +void ch_sf_tun_addr_request(ch_sf_t * a_ch_sf, dap_stream_ch_pkt_t * a_pkt_request, size_t a_pkt_data_size) +{ +// ------------------------------------------- we'd receive address request with client routing info + log_it(L_WARNING, "feature-2498 ======== We'd receive address request and try to serve it"); +// a_ch_sf->is_peer=false; // paranoja ? + struct in_addr n_addr = { 0 }; +// if(n_addr.s_addr==0 ){ // If the addres still in the network + pthread_mutex_lock(&m_tun_server->clients_mutex); + + int count_free_addr = -1; + list_addr_element *el; + LL_COUNT(list_addr_head, el, count_free_addr); + + ch_sf_tun_client_t * n_client = (ch_sf_tun_client_t*) calloc(1, sizeof(ch_sf_tun_client_t)); + n_client->ch = a_ch_sf->ch; + + if(count_free_addr > 0) { +// log_it(L_WARNING,"############################################################################ >0"); + n_addr.s_addr = list_addr_head->addr.s_addr; + LL_DELETE(list_addr_head, list_addr_head); + } else { +// log_it(L_WARNING,"############################################################################ <=0"); + n_addr.s_addr = ntohl(m_tun_server->client_addr_last.s_addr); + n_addr.s_addr++; + +// log_it(L_DEBUG,"net address: %x",ntohl(m_tun_server->int_network.s_addr)); +// log_it(L_DEBUG,"net mask: %x",ntohl(m_tun_server->int_network_mask.s_addr)); +// log_it(L_DEBUG,"net top: %x",ntohl(m_tun_server->int_network.s_addr)|~ntohl(m_tun_server->int_network_mask.s_addr)); +// log_it(L_DEBUG,"suggested addr: %x",n_addr.s_addr); + + if((uint32_t) n_addr.s_addr + >= (uint32_t) (ntohl(m_tun_server->int_network.s_addr) | ~(ntohl(m_tun_server->int_network_mask.s_addr)))) { // no free addresses, abort request + log_it(L_WARNING, "All the network is filled with clients, can't lease a new address"); + dap_stream_ch_pkt_t *pkt_out = (dap_stream_ch_pkt_t*) calloc(1, sizeof(pkt_out->header)); + pkt_out->header.sock_id = m_tun_server->tun_fd; + pkt_out->header.op_code = STREAM_SF_PACKET_OP_CODE_PROBLEM; + pkt_out->header.op_problem.code = STREAM_SF_PROBLEM_CODE_NO_FREE_ADDR; + stream_ch_pkt_write(a_ch_sf->ch, 'd', pkt_out, pkt_out->header.op_data.data_size + sizeof(pkt_out->header)); + stream_sf_socket_ready_to_write(a_ch_sf->ch, true); + return; + } + + n_addr.s_addr = ntohl(n_addr.s_addr); + m_tun_server->client_addr_last.s_addr = n_addr.s_addr; + + } + + n_client->addr = n_addr.s_addr; +// m_tun_server->client_addr_last.s_addr = n_addr.s_addr; + if(a_ch_sf->ch->stream->session) + a_ch_sf->ch->stream->session->tun_client_addr.s_addr = n_addr.s_addr; + + HASH_ADD_INT(m_tun_server->clients, addr, n_client); + log_it(L_NOTICE, "VPN client address %s leased", inet_ntoa(n_addr)); + log_it(L_INFO, " gateway %s", inet_ntoa(m_tun_server->int_network_addr)); + log_it(L_INFO, " mask %s", inet_ntoa(m_tun_server->int_network_mask)); + log_it(L_INFO, " addr %s", inet_ntoa(m_tun_server->int_network)); + log_it(L_INFO, " last_addr %s", inet_ntoa(m_tun_server->client_addr_last)); + + dap_stream_ch_pkt_t *l_pkt_out; + size_t l_pkt_out_size = sizeof(l_pkt_out->header) + sizeof(n_addr) + + sizeof(m_tun_server->int_network_addr) + + sizeof(m_tun_server->int_network_mask) + + 2 * sizeof(in_addr_t) * (m_tun_server->peers_count); + + l_pkt_out = SAP_NEW_Z_SIZE(dap_stream_ch_pkt_t, l_pkt_out_size); + l_pkt_out->header.sock_id = m_tun_server->tun_fd; + l_pkt_out->header.op_code = STREAM_SF_PACKET_OP_CODE_L3_ADDR_REPLY; + l_pkt_out->header.op_data.data_size = l_pkt_out_size - sizeof(l_pkt_out->header); + + size_t l_offset = 0, i; + memcpy(l_pkt_out->data + l_offset, &n_addr, sizeof(n_addr)); + l_offset += sizeof(n_addr); + memcpy(l_pkt_out->data + l_offset, &m_tun_server->int_network_addr, sizeof(m_tun_server->int_network_addr)); + l_offset += sizeof(m_tun_server->int_network_addr); + memcpy(l_pkt_out->data + l_offset, &m_tun_server->int_network_mask, sizeof(m_tun_server->int_network_mask)); + l_offset += sizeof(m_tun_server->int_network_mask); + log_it(L_DEBUG, "Additional %u networks in response", m_tun_server->peers_count); + + db_auth_info_t *ai = db_auth_info_by_cookie(a_ch_sf->ch->stream->conn_http->in_cookie); + // log_it(L_WARNING, "IN TUN SF Login: %s", ai->user); + sap_stream_session_t * ss = a_ch_sf->ch->stream->session; + for(i = 0; i < m_tun_server->peers_count; i++) { + if(!(m_tun_server->peers[i].in_use)) + continue; + if(m_tun_server->peers[i].ch) { + char *host = m_tun_server->peers[i].ch->stream->events_socket->hostaddr; + log_it(L_DEBUG, "Add netaddr to reply: %s ", host); + log_it(L_DEBUG, "*** is_client_to_uplink *** %d", m_tun_server->peers[i].ch->stream->is_client_to_uplink); + log_it(L_DEBUG, "*** I am peer: %d ***", a_ch_sf->is_peer); +// if(ai)log_it(L_DEBUG, "*** ai *** %d",a_ch_sf->is_peer); +// else log_it(L_DEBUG, "*** ai *** NULL"); +// if (my_config.scan_peers_conf || mod_sf_peer_list_is_have_access(host, ai->user, ai->groups)) { + char net_addr[INET_ADDRSTRLEN] = { 0 }; + char mask[INET_ADDRSTRLEN] = { 0 }; + inet_ntop(AF_INET, &m_tun_server->peers[i].netaddr, net_addr, sizeof(net_addr)); + inet_ntop(AF_INET, &m_tun_server->peers[i].netmask, mask, sizeof(mask)); + + log_it(L_DEBUG, "User %s have access to peer (host) %s\n" + "addr: %s mask: %s", ai->user, host, net_addr, mask); + + sap_stream_session_add_peer(ss, &m_tun_server->peers[i]); + + memcpy(l_pkt_out->data + l_offset, &m_tun_server->peers[i].netaddr, sizeof(m_tun_server->peers[i].netaddr)); + l_offset += sizeof(m_tun_server->peers[i].netaddr); + memcpy(l_pkt_out->data + l_offset, &m_tun_server->peers[i].netmask, sizeof(m_tun_server->peers[i].netmask)); + l_offset += sizeof(m_tun_server->peers[i].netmask); +// } + } else + log_it(L_WARNING, "Strange -- channel is NULL"); + } + pthread_mutex_unlock(&m_tun_server->clients_mutex); + log_it(L_DEBUG, "hotfix-2151: btw 'data '%p'' offset: '%x'' size: '%x'", l_pkt_out->data, l_offset, + l_pkt_out_size); + + // Add peer to the downlink networks (if present) + if(a_pkt_data_size > 0) { +// log_it(L_DEBUG, "hotfix-2151: disable 'Add peer to the downlink networks'"); +// if( false){ + size_t l_downlinks_nets = a_pkt_data_size / (2 * sizeof(struct in_addr)); + size_t i; + in_addr_t l_netaddr, l_netmask; + char l_netaddr_buf[INET_ADDRSTRLEN], l_netmask_buf[INET_ADDRSTRLEN]; + log_it(L_DEBUG, "Additional %u networks in address request", l_downlinks_nets); + for(i = 0; i < l_downlinks_nets; i++) { + memcpy(&l_netaddr, a_pkt_request->data + i * 2 * sizeof(in_addr_t), sizeof(in_addr_t)); + memcpy(&l_netmask, a_pkt_request->data + (1 + i * 2) * sizeof(in_addr_t), sizeof(in_addr_t)); + if(!l_netaddr && !l_netmask) { + log_it(L_DEBUG, "Ignores default route from downstream"); + continue; + } + inet_ntop(AF_INET, &l_netmask, l_netmask_buf, sizeof(l_netmask_buf)); + inet_ntop(AF_INET, &l_netaddr, l_netaddr_buf, sizeof(l_netaddr_buf)); + log_it(L_NOTICE, "Add in peer table the network %s/%s", l_netaddr_buf, l_netmask_buf); + + int ret = exec_with_ret_f(NULL, "route add -net %s netmask %s dev %s metric 5", + l_netaddr_buf, l_netmask_buf, m_tun_server->ifr.ifr_ifrn.ifrn_name); + switch (ret) { + case 0: + case 7: + case 0x700: // strange, but sometimes we obtain 7 in high byte. +// ch_sf_tun_peer_add(a_ch_sf,0,0,l_netaddr,l_netmask); + ch_sf_tun_peer_add(a_ch_sf, l_netaddr, l_netmask, l_netaddr, l_netmask); + break; + default: + log_it(L_WARNING, "Bad route for %s/%s ignored, cause %d", l_netaddr_buf, l_netmask_buf, ret); + } + + } + } else + log_it(L_DEBUG, "Additional 0 networks in address request"); + +// pthread_mutex_unlock(& m_tun_server->clients_mutex ); + + stream_ch_pkt_write(a_ch_sf->ch, 'd', l_pkt_out, l_pkt_out_size); + stream_sf_socket_ready_to_write(a_ch_sf->ch, true); + + //ch_sf_raw_write(n_addr.s_addr,STREAM_SF_PACKET_OP_CODE_RAW_L3_ADDR_REPLY,&n_addr,sizeof(n_addr)); +// }else{ // All the network is filled with clients, can't lease a new address +// } +} diff --git a/dap_chain_net_vpn_client_tun.h b/dap_chain_net_vpn_client_tun.h new file mode 100644 index 0000000..53c8b03 --- /dev/null +++ b/dap_chain_net_vpn_client_tun.h @@ -0,0 +1,28 @@ +/* + * Authors: + * Alexander Lysikov <alexander.lysikov@demlabs.net> + * DeM Labs Inc. https://demlabs.net + * Kelvin Project https://gitlab.demlabs.net/cellframe + * Copyright (c) 2019 + * All rights reserved. + + This file is part of DAP (Deus Applications Prototypes) the open source project + + DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + DAP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with any DAP based project. If not, see <http://www.gnu.org/licenses/>. + */ + + +int dap_chain_net_vpn_client_tun_init(const char *a_ipv4_str); +int dap_chain_net_vpn_client_tun_delete(void); +int dap_chain_net_vpn_client_tun_status(void); -- GitLab