diff --git a/dap_chain_net_srv_vpn.c b/dap_chain_net_srv_vpn.c
index ace1cc0b4002789bad79245237abd17e3d0f500e..de091e0eb1945a911984320e160c0d8f2bef4d58 100755
--- a/dap_chain_net_srv_vpn.c
+++ b/dap_chain_net_srv_vpn.c
@@ -8,31 +8,1073 @@
 
  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 (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.
+ 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/>.
-*/
+ 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 "dap_common.h"
+ //#include "dap_stream_ch_vpn.h"
+ #include "dap_chain_net_srv_vpn.h"
+
+ #define LOG_TAG "chain_net_srv_vpn"
+
+ int dap_chain_net_srv_vpn_init()
+ {
+ int l_res = dap_stream_ch_vpn_init("addr", "255.255.0.0");
+ return 0;
+ }
+
+ void dap_chain_net_srv_vpn_deinit()
+ {
+ dap_stream_ch_vpn_deinit();
+ }*/
+
+#include <sys/select.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/epoll.h>
+#include <sys/un.h>
+#include <sys/ioctl.h>
+
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <arpa/inet.h>
+
+#include <pthread.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+#include <errno.h>
+#include <signal.h>
+
+#include <linux/if.h>
+#include <linux/if_tun.h>
+
+#include "uthash.h"
+#include "utlist.h"
 
 #include "dap_common.h"
+#include "dap_strfuncs.h"
+#include "dap_config.h"
+
+#include "dap_client_remote.h"
+#include "dap_http_client.h"
+
+#include "dap_stream.h"
+#include "dap_stream_ch.h"
+#include "dap_stream_ch_proc.h"
+#include "dap_stream_ch_pkt.h"
+
+#include "dap_chain_utxo.h"//datum_tx_cache.h
 #include "dap_chain_net_srv_vpn.h"
 
-#define LOG_TAG "chain_net_srv_vpn"
+#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
 
-int dap_chain_net_srv_vpn_init()
+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
 {
-    return 0;
+    pthread_mutex_t mutex;
+    ch_vpn_socket_proxy_t * socks;
+    int raw_l3_sock;
+    dap_chain_net_srv_uid_t srv_uid; // Unique ID for service.
+} dap_stream_ch_vpn_t;
+
+typedef struct dap_stream_ch_vpn_remote_single { //
+    in_addr_t addr;
+//    pthread_mutex_t mutex;
+    dap_stream_ch_t * ch;
+
+    uint64_t bytes_sent;
+    uint64_t bytes_recieved;
+
+    UT_hash_handle hh;
+} dap_stream_ch_vpn_remote_single_t;
+
+typedef struct vpn_local_network {
+    struct in_addr client_addr_last;
+    struct in_addr client_addr_mask;
+    struct in_addr client_addr_host;
+    struct in_addr client_addr;
+    int tun_ctl_fd;
+    int tun_fd;
+    struct ifreq ifr;
+    dap_stream_ch_vpn_remote_single_t * clients; // Remote clients identified by destination address
+
+    ch_vpn_pkt_t * pkt_out[400];
+    size_t pkt_out_size;
+    size_t pkt_out_rindex;
+    size_t pkt_out_windex;
+    pthread_mutex_t pkt_out_mutex;
+
+    pthread_mutex_t clients_mutex;
+} vpn_local_network_t;
+
+typedef struct list_addr_element {
+    struct in_addr addr;
+    struct list_addr_element *next;
+} list_addr_element;
+
+static list_addr_element *list_addr_head = NULL;
+
+static ch_vpn_socket_proxy_t * sf_socks = NULL;
+static ch_vpn_socket_proxy_t * sf_socks_client = NULL;
+static pthread_mutex_t sf_socks_mutex;
+static pthread_cond_t sf_socks_cond;
+static int sf_socks_epoll_fd;
+static pthread_t srv_sf_socks_pid;
+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();
+void srv_ch_sf_tun_destroy();
+
+void srv_ch_sf_new(dap_stream_ch_t* ch, void* arg);
+void srv_ch_sf_delete(dap_stream_ch_t* ch, void* arg);
+void srv_ch_sf_packet_in(dap_stream_ch_t* ch, void* arg);
+void srv_ch_sf_packet_out(dap_stream_ch_t* ch, void* arg);
+
+//static int srv_ch_sf_raw_write(uint8_t op_code, const void * data, size_t data_size);
+//void srv_stream_sf_disconnect(ch_vpn_socket_proxy_t * sf_sock);
+
+static const char *s_srv_vpn_addr, *s_srv_vpn_mask;
+
+/**
+ * @brief dap_stream_ch_vpn_init Init actions for VPN stream channel
+ * @param vpn_addr Zero if only client mode. Address if the node shares its local VPN
+ * @param vpn_mask Zero if only client mode. Mask if the node shares its local VPN
+ * @return 0 if everything is okay, lesser then zero if errors
+ */
+int dap_chain_net_srv_vpn_init(dap_config_t * g_config)
+{
+    const char *s_addr = dap_config_get_item_str(g_config, "vpn", "network_address");
+    const char *s_mask = dap_config_get_item_str(g_config, "vpn", "network_mask");
+    if(s_addr && s_mask) {
+        s_srv_vpn_addr = strdup(s_addr);
+        s_srv_vpn_mask = strdup(s_mask);
+
+        raw_server = calloc(1, sizeof(vpn_local_network_t));
+        pthread_mutex_init(&raw_server->clients_mutex, NULL);
+        pthread_mutex_init(&raw_server->pkt_out_mutex, NULL);
+        pthread_mutex_init(&sf_socks_mutex, NULL);
+        pthread_cond_init(&sf_socks_cond, NULL);
+        pthread_create(&srv_sf_socks_raw_pid, NULL, srv_ch_sf_thread_raw, NULL);
+        pthread_create(&srv_sf_socks_pid, NULL, srv_ch_sf_thread, NULL);
+        dap_stream_ch_proc_add(SERVICE_CHANNEL_ID, srv_ch_sf_new, srv_ch_sf_delete, srv_ch_sf_packet_in,
+                srv_ch_sf_packet_out);
+        return 0;
+    }
+    return -1;
 }
 
+/**
+ * @brief ch_sf_deinit
+ */
 void dap_chain_net_srv_vpn_deinit()
 {
+    pthread_mutex_destroy(&sf_socks_mutex);
+    pthread_cond_destroy(&sf_socks_cond);
+    free((char*) s_srv_vpn_addr);
+    free((char*) s_srv_vpn_mask);
+    if(raw_server)
+        free(raw_server);
+}
 
+void srv_ch_sf_tun_create()
+{
+    inet_aton(s_srv_vpn_addr, &raw_server->client_addr);
+    inet_aton(s_srv_vpn_mask, &raw_server->client_addr_mask);
+    raw_server->client_addr_host.s_addr = (raw_server->client_addr.s_addr | 0x01000000); // grow up some shit here!
+    raw_server->client_addr_last.s_addr = raw_server->client_addr_host.s_addr;
+
+    if((raw_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(&raw_server->ifr, 0, sizeof(raw_server->ifr));
+        raw_server->ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
+        if((err = ioctl(raw_server->tun_ctl_fd, TUNSETIFF, (void *) &raw_server->ifr)) < 0) {
+            log_it(L_CRITICAL, "ioctl(TUNSETIFF) error: '%s' ", strerror(errno));
+            close(raw_server->tun_ctl_fd);
+            raw_server->tun_ctl_fd = -1;
+        } else {
+            char buf[256];
+            log_it(L_NOTICE, "Bringed up %s virtual network interface (%s/%s)", raw_server->ifr.ifr_name,
+                    inet_ntoa(raw_server->client_addr_host), s_srv_vpn_mask);
+            raw_server->tun_fd = raw_server->tun_ctl_fd; // Looks yes, its so
+            snprintf(buf, sizeof(buf), "ip link set %s up", raw_server->ifr.ifr_name);
+            int res = system(buf);
+            snprintf(buf, sizeof(buf), "ip addr add %s/%s dev %s ", inet_ntoa(raw_server->client_addr_host),
+                    s_srv_vpn_mask,
+                    raw_server->ifr.ifr_name);
+            res = system(buf);
+            res = 0;
+        }
+    }
+
+}
+
+void srv_ch_sf_tun_destroy()
+{
+    close(raw_server->tun_fd);
+    raw_server->tun_fd = -1;
 }
+
+/**
+ * @brief stream_sf_new Callback to constructor of object of Ch
+ * @param ch
+ * @param arg
+ */
+void srv_ch_sf_new(dap_stream_ch_t* ch, void* arg)
+{
+    ch->internal = calloc(1, sizeof(dap_stream_ch_vpn_t));
+    dap_stream_ch_vpn_t * sf = CH_SF(ch);
+    pthread_mutex_init(&sf->mutex, NULL);
+    sf->raw_l3_sock = socket(PF_INET, SOCK_RAW, IPPROTO_RAW);
+    //
+    if(ch->stream->service_key) {
+
+        char **l_str = dap_strsplit(ch->stream->service_key, ";", -1);
+        char *l_addr_base58 = NULL;
+        char *l_sign_txt = NULL;
+        if(dap_str_countv(l_str) == 2) {
+            l_addr_base58 = l_str[0];
+            l_sign_txt = l_str[1];
+        }
+        l_addr_base58 =
+                "EXh66KVCxChbKJLxXTwipYMooUpoGvpwpkcjpmGLbubwzqR2vVsH9HEgT2LcU2hDs2BTFkaNC8itE8nuCWxskVtRJG4iaubBDcRWAt2awtCVHAULffQGrwe8ocRCzS";
+        l_sign_txt = "123";
+        uint8_t *l_sign = l_sign_txt;
+        size_t l_sign_size = 0;
+        dap_chain_net_srv_abstract_t *l_cond = NULL;
+        uint64_t l_value = dap_chain_net_srv_client_auth(l_addr_base58, l_sign, l_sign_size, &l_cond);
+
+        // add service
+        {
+            dap_chain_net_srv_t l_srv;
+            memcpy(&l_srv.srv_common, l_cond, sizeof(dap_chain_net_srv_abstract_t));
+            dap_chain_net_srv_gen_uid(&l_srv.uid);
+            dap_chain_net_srv_add(&l_srv);
+            memcpy(&sf->srv_uid.raw, &l_srv.uid, sizeof(dap_chain_net_srv_uid_t)); // Unique ID for service.
+        }
+
+    }
+}
+
+/**
+ * @brief stream_sf_delete
+ * @param ch
+ * @param arg
+ */
+void srv_ch_sf_delete(dap_stream_ch_t* ch, void* arg)
+{
+    log_it(L_DEBUG, "ch_sf_delete() for %s", ch->stream->conn->hostaddr);
+    ch_vpn_socket_proxy_t * cur, *tmp;
+    dap_stream_ch_vpn_remote_single_t * raw_client = 0;
+    // in_addr_t raw_client_addr = CH_SF(ch)->tun_client_addr.s_addr;
+    in_addr_t raw_client_addr = ch->stream->session->tun_client_addr.s_addr;
+
+    if(raw_client_addr) {
+        log_it(L_DEBUG, "ch_sf_delete() %s searching in hash table",
+                inet_ntoa(ch->stream->session->tun_client_addr));
+        list_addr_element *el = (list_addr_element*) malloc(sizeof(list_addr_element));
+        //el->addr = CH_SF(ch)->tun_client_addr;
+        el->addr = ch->stream->session->tun_client_addr;
+        LL_APPEND(list_addr_head, el);
+        //   LL_FOREACH(list_addr_head,el) log_it(L_INFO,"addr = %s", inet_ntoa(el->addr));
+
+        pthread_mutex_lock(&raw_server->clients_mutex);
+
+        HASH_FIND_INT(raw_server->clients, &raw_client_addr, raw_client);
+        if(raw_client) {
+            HASH_DEL(raw_server->clients, raw_client);
+            log_it(L_DEBUG, "ch_sf_delete() %s removed from hash table",
+                    inet_ntoa(ch->stream->session->tun_client_addr));
+            free(raw_client);
+        } else
+            log_it(L_DEBUG, "ch_sf_delete() %s is not present in raw sockets hash table",
+                    inet_ntoa(ch->stream->session->tun_client_addr));
+
+        pthread_mutex_unlock(&raw_server->clients_mutex);
+    }
+    HASH_ITER(hh, CH_SF(ch)->socks , cur, tmp)
+    {
+        log_it(L_DEBUG, "delete socket: %i", cur->sock);
+        HASH_DEL(CH_SF(ch)->socks, cur);
+        if(cur)
+            free(cur);
+    }
+    pthread_mutex_unlock(&( CH_SF(ch)->mutex));
+    if(CH_SF(ch)->raw_l3_sock)
+        close(CH_SF(ch)->raw_l3_sock);
+}
+
+static void stream_sf_socket_delete(ch_vpn_socket_proxy_t * sf)
+{
+    close(sf->sock);
+    pthread_mutex_destroy(&(sf->mutex));
+    if(sf)
+        free(sf);
+}
+
+static void stream_sf_socket_ready_to_write(dap_stream_ch_t * ch, bool is_ready)
+{
+    pthread_mutex_lock(&ch->mutex);
+    ch->ready_to_write = is_ready;
+    if(is_ready)
+        ch->stream->conn_http->state_write = DAP_HTTP_CLIENT_STATE_DATA;
+    dap_client_remote_ready_to_write(ch->stream->conn, is_ready);
+    pthread_mutex_unlock(&ch->mutex);
+
+}
+
+static ch_vpn_pkt_t* srv_ch_sf_raw_read()
+{
+    ch_vpn_pkt_t*ret = NULL;
+    pthread_mutex_lock(&raw_server->pkt_out_mutex);
+    if(raw_server->pkt_out_rindex == (sizeof(raw_server->pkt_out) / sizeof(raw_server->pkt_out[0]))) {
+        raw_server->pkt_out_rindex = 0; // ring the buffer!
+    }
+    if((raw_server->pkt_out_rindex != raw_server->pkt_out_windex) || (raw_server->pkt_out_size == 0)) {
+        ret = raw_server->pkt_out[raw_server->pkt_out_rindex];
+        raw_server->pkt_out_rindex++;
+        raw_server->pkt_out_size--;
+    } else
+        log_it(L_WARNING, "Packet drop on raw_read() operation, ring buffer is full");
+    pthread_mutex_unlock(&raw_server->pkt_out_mutex);
+    return ret;
+}
+
+/*
+ static int srv_ch_sf_raw_write(uint8_t op_code, const void * data, size_t data_size)
+ {
+ pthread_mutex_lock(&raw_server->pkt_out_mutex);
+ if(raw_server->pkt_out_windex == (sizeof(raw_server->pkt_out) / sizeof(raw_server->pkt_out[0])))
+ raw_server->pkt_out_windex = 0; // ring the buffer!
+ if((raw_server->pkt_out_windex < raw_server->pkt_out_rindex) || (raw_server->pkt_out_size == 0)) {
+ ch_vpn_pkt_t * pkt = (ch_vpn_pkt_t *) calloc(1, data_size + sizeof(pkt->header));
+ pkt->header.op_code = op_code;
+ pkt->header.sock_id = raw_server->tun_fd;
+ if(data_size > 0) {
+ pkt->header.op_data.data_size = data_size;
+ memcpy(pkt->data, data, data_size);
+ }
+
+ raw_server->pkt_out[raw_server->pkt_out_windex] = pkt;
+ raw_server->pkt_out_windex++;
+ raw_server->pkt_out_size++;
+ pthread_mutex_unlock(&raw_server->pkt_out_mutex);
+ send_select_break();
+ return raw_server->pkt_out_windex;
+ } else {
+ pthread_mutex_unlock(&raw_server->pkt_out_mutex);
+ log_it(L_WARNING, "Raw socket buffer overflow");
+ return -1;
+ }
+ }
+
+ static int srv_stream_sf_socket_write(ch_vpn_socket_proxy_t * sf, uint8_t op_code, const void * data, size_t data_size)
+ {
+ if(sf->pkt_out_size < (sizeof(sf->pkt_out) / sizeof(sf->pkt_out[0]))) {
+ ch_vpn_pkt_t * pkt = (ch_vpn_pkt_t *) calloc(1, data_size + sizeof(pkt->header));
+ pkt->header.op_code = op_code;
+ pkt->header.sock_id = sf->id;
+
+ switch (op_code) {
+ case VPN_PACKET_OP_CODE_RECV: {
+ pkt->header.op_data.data_size = data_size;
+ memcpy(pkt->data, data, data_size);
+ }
+ break;
+ default: {
+ log_it(L_ERROR, "Unprocessed opcode %u for write to sf socket", op_code);
+ free(pkt);
+ return -2;
+ }
+ }
+ sf->pkt_out[sf->pkt_out_size] = pkt;
+ sf->pkt_out_size++;
+ return sf->pkt_out_size;
+ } else
+ return -1;
+ }*/
+
+/**
+ * @brief stream_sf_packet_in
+ * @param ch
+ * @param arg
+ */
+void srv_ch_sf_packet_in(dap_stream_ch_t* ch, void* arg)
+{
+    dap_stream_ch_pkt_t * pkt = (dap_stream_ch_pkt_t *) arg;
+    // 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)
+    //        );
+
+    static bool client_connected = false;
+    ch_vpn_pkt_t * sf_pkt = (ch_vpn_pkt_t *) pkt->data;
+
+    int remote_sock_id = sf_pkt->header.sock_id;
+
+    //log_it(L_DEBUG, "Got SF packet with id %d op_code 0x%02x", remote_sock_id, sf_pkt->header.op_code);
+    if(sf_pkt->header.op_code >= 0xb0) { // Raw packets
+        switch (sf_pkt->header.op_code) {
+        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, sf_pkt->header.op_code);
+            struct in_addr n_addr = { 0 };
+
+            if(n_addr.s_addr == 0) { // If the addres still in the network
+
+                pthread_mutex_lock(&raw_server->clients_mutex);
+
+                int count_free_addr = -1;
+                list_addr_element *el;
+                LL_COUNT(list_addr_head, el, count_free_addr);
+
+                dap_stream_ch_vpn_remote_single_t * n_client = (dap_stream_ch_vpn_remote_single_t*) calloc(1,
+                        sizeof(dap_stream_ch_vpn_remote_single_t));
+                n_client->ch = ch;
+
+                if(count_free_addr > 0)
+                        {
+                    n_addr.s_addr = list_addr_head->addr.s_addr;
+                    LL_DELETE(list_addr_head, list_addr_head);
+                }
+                else
+                {
+                    n_addr.s_addr = ntohl(raw_server->client_addr_last.s_addr);
+                    n_addr.s_addr++;
+                    n_addr.s_addr = ntohl(n_addr.s_addr);
+                }
+
+                n_client->addr = n_addr.s_addr;
+                raw_server->client_addr_last.s_addr = n_addr.s_addr;
+                ch->stream->session->tun_client_addr.s_addr = n_addr.s_addr;
+                HASH_ADD_INT(raw_server->clients, addr, n_client);
+                pthread_mutex_unlock(&raw_server->clients_mutex);
+
+                log_it(L_NOTICE, "VPN client address %s leased", inet_ntoa(n_addr));
+                log_it(L_INFO, "\tgateway %s", inet_ntoa(raw_server->client_addr_host));
+                log_it(L_INFO, "\tmask %s", inet_ntoa(raw_server->client_addr_mask));
+                log_it(L_INFO, "\taddr %s", inet_ntoa(raw_server->client_addr));
+                log_it(L_INFO, "\tlast_addr %s", inet_ntoa(raw_server->client_addr_last));
+
+                ch_vpn_pkt_t *pkt_out = (ch_vpn_pkt_t*) calloc(1,
+                        sizeof(pkt_out->header) + sizeof(n_addr) + sizeof(raw_server->client_addr_host));
+                pkt_out->header.sock_id = raw_server->tun_fd;
+                pkt_out->header.op_code = VPN_PACKET_OP_CODE_VPN_ADDR_REPLY;
+                pkt_out->header.op_data.data_size = sizeof(n_addr) + sizeof(raw_server->client_addr_host);
+                memcpy(pkt_out->data, &n_addr, sizeof(n_addr));
+                memcpy(pkt_out->data + sizeof(n_addr), &raw_server->client_addr_host,
+                        sizeof(raw_server->client_addr_host));
+                dap_stream_ch_pkt_write(ch, DATA_CHANNEL_ID, pkt_out,
+                        pkt_out->header.op_data.data_size + sizeof(pkt_out->header));
+                stream_sf_socket_ready_to_write(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
+                log_it(L_WARNING, "All the network is filled with clients, can't lease a new address");
+                ch_vpn_pkt_t *pkt_out = (ch_vpn_pkt_t*) calloc(1, sizeof(pkt_out->header));
+                pkt_out->header.sock_id = raw_server->tun_fd;
+                pkt_out->header.op_code = VPN_PACKET_OP_CODE_PROBLEM;
+                pkt_out->header.op_problem.code = VPN_PROBLEM_CODE_NO_FREE_ADDR;
+                dap_stream_ch_pkt_write(ch, DATA_CHANNEL_ID, pkt_out,
+                        pkt_out->header.op_data.data_size + sizeof(pkt_out->header));
+                stream_sf_socket_ready_to_write(ch, true);
+            }
+        }
+            break;
+        case VPN_PACKET_OP_CODE_VPN_SEND: {
+            struct in_addr in_saddr, in_daddr;
+            in_saddr.s_addr = ((struct iphdr*) sf_pkt->data)->saddr;
+            in_daddr.s_addr = ((struct iphdr*) sf_pkt->data)->daddr;
+
+            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));
+            int ret;
+            //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(ch)->raw_l3_sock , sf_pkt->data,sf_pkt->header.op_data.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(L_ERROR,"raw socket ring buffer overflowed");
+                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_PROBLEM;
+                pkt_out->header.op_problem.code = VPN_PROBLEM_CODE_PACKET_LOST;
+                pkt_out->header.sock_id = raw_server->tun_fd;
+                dap_stream_ch_pkt_write(ch, DATA_CHANNEL_ID, pkt_out,
+                        pkt_out->header.op_data.data_size + sizeof(pkt_out->header));
+                stream_sf_socket_ready_to_write(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);
+            }
+            //}
+        }
+            break;
+        default:
+            log_it(L_WARNING, "Can't process SF type 0x%02x", sf_pkt->header.op_code);
+        }
+    } else { // All except CONNECT
+        ch_vpn_socket_proxy_t * sf_sock = NULL;
+        if(sf_pkt->header.op_code != VPN_PACKET_OP_CODE_CONNECT) {
+            pthread_mutex_lock(&( CH_SF(ch)->mutex));
+            //      log_it(L_DEBUG,"Looking in hash table with %d",remote_sock_id);
+            HASH_FIND_INT((CH_SF(ch)->socks), &remote_sock_id, sf_sock);
+            pthread_mutex_unlock(&( CH_SF(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 (sf_pkt->header.op_code) {
+                case VPN_PACKET_OP_CODE_SEND: {
+                    if(client_connected == false)
+                    {
+                        log_it(L_WARNING, "Drop Packet! User not connected!"); // Client need send
+                        pthread_mutex_unlock(&sf_socks_mutex);
+                        break;
+                    }
+                    int ret;
+                    if((ret = send(sf_sock->sock, sf_pkt->data, 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(ch)->mutex));
+                        HASH_DEL(CH_SF(ch)->socks, sf_sock);
+                        pthread_mutex_unlock(&( CH_SF(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);
+
+                        stream_sf_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, sf_pkt->header.op_data.data_size, 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(ch)->mutex));
+                    HASH_DEL(CH_SF(ch)->socks, sf_sock);
+                    pthread_mutex_unlock(&( CH_SF(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);
+                    stream_sf_socket_delete(sf_sock);
+                }
+                    break;
+                default: {
+                    log_it(L_WARNING, "Unprocessed op code 0x%02x", 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(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 =
+                        (sf_pkt->header.op_connect.addr_size > (sizeof(addr_str) - 1)) ?
+                                (sizeof(addr_str) - 1) :
+                                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(sf_pkt->header.op_connect.port);
+
+                memcpy(addr_str, 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, sf_pkt->header.op_connect.port,
+                        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, sf_pkt->header.op_connect.port);
+                } else {
+                    int s;
+                    if((s = socket(AF_INET, SOCK_STREAM, 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,
+                                    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 = ch;
+                            pthread_mutex_init(&sf_sock->mutex, NULL);
+
+                            pthread_mutex_lock(&sf_socks_mutex);
+                            pthread_mutex_lock(&( CH_SF(ch)->mutex));
+                            HASH_ADD_INT(CH_SF(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(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);
+                                log_it(L_NOTICE, "Send Connected packet to User");
+                                ch_vpn_pkt_t *pkt_out = (ch_vpn_pkt_t*) calloc(1, sizeof(pkt_out->header));
+                                pkt_out->header.sock_id = remote_sock_id;
+                                pkt_out->header.op_code = VPN_PACKET_OP_CODE_CONNECTED;
+                                dap_stream_ch_pkt_write(ch, SERVICE_CHANNEL_ID, pkt_out,
+                                        pkt_out->header.op_data.data_size + sizeof(pkt_out->header));
+                                free(pkt_out);
+                                client_connected = true;
+                            }
+                            stream_sf_socket_ready_to_write(ch, true);
+                        } else {
+                            log_it(L_INFO, "Can't connect to the remote server %s", addr_str);
+                            dap_stream_ch_pkt_write_f(ch, 'i', "sock_id=%d op_code=%c result=-1",
+                                    sf_pkt->header.sock_id, sf_pkt->header.op_code);
+                            stream_sf_socket_ready_to_write(ch, true);
+                        }
+                    } else {
+                        log_it(L_ERROR, "Can't create the socket");
+                    }
+                }
+            }
+        }
+    }
+}
+
+/**
+ * @brief stream_sf_disconnect
+ * @param sf
+ */
+void srv_stream_sf_disconnect(ch_vpn_socket_proxy_t * sf_sock)
+{
+    struct epoll_event ev;
+    ev.data.fd = sf_sock->sock;
+    ev.events = EPOLLIN | EPOLLERR;
+    if(epoll_ctl(sf_socks_epoll_fd, EPOLL_CTL_DEL, sf_sock->sock, &ev) == -1) {
+        log_it(L_ERROR, "Can't del sock_id %d from the epoll fd", sf_sock->id);
+        //stream_ch_pkt_write_f(sf->ch,'i',"sock_id=%d op_code=%uc result=-1",sf->id, STREAM_SF_PACKET_OP_CODE_RECV);
+    } else {
+        log_it(L_ERROR, "Removed sock_id %d from the epoll fd", sf_sock->id);
+        //stream_ch_pkt_write_f(sf->ch,'i',"sock_id=%d op_code=%uc result=0",sf->id, STREAM_SF_PACKET_OP_CODE_RECV);
+    }
+
+    // Compise signal to disconnect to another side, with special opcode STREAM_SF_PACKET_OP_CODE_DISCONNECT
+    ch_vpn_pkt_t * pkt_out;
+    pkt_out = (ch_vpn_pkt_t*) calloc(1, sizeof(pkt_out->header) + 1);
+    pkt_out->header.op_code = VPN_PACKET_OP_CODE_DISCONNECT;
+    pkt_out->header.sock_id = sf_sock->id;
+    sf_sock->pkt_out[sf_sock->pkt_out_size] = pkt_out;
+    sf_sock->pkt_out_size++;
+    sf_sock->signal_to_delete = true;
+}
+
+/**
+
+ Socket forward
+ **/
+
+void * srv_ch_sf_thread(void * arg)
+{
+    struct epoll_event ev, events[SF_MAX_EVENTS] = { 0 };
+    //pthread_mutex_lock(&sf_socks_mutex);
+    sf_socks_epoll_fd = epoll_create(SF_MAX_EVENTS);
+    sigset_t sf_sigmask;
+    sigemptyset(&sf_sigmask);
+    sigaddset(&sf_sigmask, SIGUSR2);
+
+    while(1) {
+        /*pthread_mutex_lock(&sf_socks_mutex);
+         if(sf_socks==NULL)
+         pthread_cond_wait(&sf_socks_cond,&sf_socks_mutex);
+         pthread_mutex_unlock(&sf_socks_mutex);*/
+        int nfds = epoll_pwait(sf_socks_epoll_fd, events, SF_MAX_EVENTS, 10000, &sf_sigmask);
+        if(nfds < 0) {
+            //log_it(L_CRITICAL,"Can't run epoll_wait: %s",strerror(errno));
+            continue;
+        }
+        if(nfds > 0)
+            log_it(L_DEBUG, "Epolled %d fd", nfds);
+        else
+            continue;
+        int n;
+        for(n = 0; n < nfds; ++n) {
+            int s = events[n].data.fd;
+
+            ch_vpn_socket_proxy_t * sf = NULL;
+            pthread_mutex_lock(&sf_socks_mutex);
+            HASH_FIND(hh_sock, sf_socks_client, &s, sizeof(s), sf);
+            pthread_mutex_unlock(&sf_socks_mutex);
+            if(sf) {
+                if(events[n].events & EPOLLERR) {
+                    log_it(L_NOTICE, "Socket id %d has EPOLLERR flag on", s);
+                    pthread_mutex_lock(&(sf->mutex));
+                    srv_stream_sf_disconnect(sf);
+                    pthread_mutex_unlock(&(sf->mutex));
+                } else if(events[n].events & EPOLLIN) {
+                    char buf[1000000];
+                    size_t buf_size;
+                    ssize_t ret;
+                    pthread_mutex_lock(&(sf->mutex));
+                    if(sf->pkt_out_size < ((sizeof(sf->pkt_out) / sizeof(sf->pkt_out[0])) - 1)) {
+                        ret = recv(sf->sock, buf, sizeof(buf), 0);
+                        //log_it(L_DEBUG,"recv() returned %d",ret);
+                        if(ret > 0) {
+                            buf_size = ret;
+                            ch_vpn_pkt_t * pout;
+                            pout = sf->pkt_out[sf->pkt_out_size] = (ch_vpn_pkt_t *) calloc(1,
+                                    buf_size + sizeof(pout->header));
+                            pout->header.op_code = VPN_PACKET_OP_CODE_RECV;
+                            pout->header.sock_id = sf->id;
+                            pout->header.op_data.data_size = buf_size;
+                            memcpy(pout->data, buf, buf_size);
+                            sf->pkt_out_size++;
+                            pthread_mutex_unlock(&(sf->mutex));
+                            stream_sf_socket_ready_to_write(sf->ch, true);
+                        } else {
+                            log_it(L_NOTICE,
+                                    "Socket id %d returned error on recv() function - may be host has disconnected", s);
+                            pthread_mutex_unlock(&(sf->mutex));
+                            stream_sf_socket_ready_to_write(sf->ch, true);
+                            srv_stream_sf_disconnect(sf);
+                        }
+                    } else {
+                        log_it(L_WARNING, "Can't receive data, full of stack");
+                        pthread_mutex_unlock(&(sf->mutex));
+                    }
+                } else {
+                    log_it(L_WARNING, "Unprocessed flags 0x%08X", events[n].events);
+                }
+            } else {
+                if(epoll_ctl(sf_socks_epoll_fd, EPOLL_CTL_DEL, s, &ev) < 0) {
+                    log_it(L_ERROR, "Can't remove sock_id %d to the epoll fd", s);
+                } else {
+                    log_it(L_NOTICE, "Socket id %d is removed from the list", s);
+                }
+            }
+        }
+        //pthread_mutex_unlock(&sf_socks_mutex);
+    }
+}
+
+/**
+ *
+ *
+ **/
+void* srv_ch_sf_thread_raw(void *arg)
+{
+    srv_ch_sf_tun_create();
+
+    if(raw_server->tun_fd <= 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(raw_server->tun_fd, &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 = srv_ch_sf_raw_read();
+                if(pkt) {
+                    int write_ret = write(raw_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(raw_server->tun_fd, &fds_read_active)) {
+                int read_ret = read(raw_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 {
+                    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(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);
+                    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");
+    srv_ch_sf_tun_destroy();
+    return NULL;
+}
+
+/**
+ * @brief stream_sf_packet_out Packet Out Ch callback
+ * @param ch
+ * @param arg
+ */
+void srv_ch_sf_packet_out(dap_stream_ch_t* ch, void* arg)
+{
+    ch_vpn_socket_proxy_t * cur, *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, DATA_CHANNEL_ID, pout,
+                            pout->header.op_data.data_size + sizeof(pout->header))) {
+                        isSmthOut = true;
+                        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));
+            stream_sf_socket_delete(cur);
+        } else
+            pthread_mutex_unlock(&(cur->mutex));
+    }
+    ch->ready_to_write = isSmthOut;
+    if(isSmthOut) {
+        ch->stream->conn_http->state_write = DAP_HTTP_CLIENT_STATE_DATA;
+    }
+    dap_client_remote_ready_to_write(ch->stream->conn, isSmthOut);
+
+}
+
diff --git a/dap_chain_net_srv_vpn.h b/dap_chain_net_srv_vpn.h
index c61803d30d13ae4d1ce5b0ca7598db2259c1b2d5..c8cee5fc1ca7a05b7547e258ded24299f1992795 100755
--- a/dap_chain_net_srv_vpn.h
+++ b/dap_chain_net_srv_vpn.h
@@ -22,5 +22,7 @@
     along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
 */
 #pragma once
-int dap_chain_net_srv_vpn_init();
+#include "dap_chain_net_srv.h"
+
+int dap_chain_net_srv_vpn_init(dap_config_t * g_config);
 void dap_chain_net_srv_vpn_deinit();