来自云龙湖轮廓分明的月亮 发表于 2024-11-28 03:50:52

鸿蒙开发进阶(HarmonyOS)VPN虚拟专网管理(仅对体系应用开放)

 鸿蒙NEXT开发实战往期必看文章:
一分钟相识”纯血版!鸿蒙HarmonyOS Next应用开发!
“非常详细的” 鸿蒙HarmonyOS Next应用开发学习蹊径!(从零基础入门到精通)
HarmonyOS NEXT应用开发案例实践总联合(持续更新......)
HarmonyOS NEXT应用开发性能优化实践总结(持续更新......)
简介

VPN 即虚拟专网(VPN-Virtual Private Network)在公用网络上建立专用网络的技术。整个 VPN 网络的任意两个节点之间的毗连并没有传统专网所需的端到端的物理链路,而是架构在公用网络服务商所提供的网络平台(如 Internet)之上的逻辑网络,用户数据在逻辑链路中传输。
   说明: 为了包管应用的运行效率,大部分 API 调用都是异步的,对于异步调用的 API 均提供了 callback 和 Promise 两种方式,以下示例均接纳 promise 函数,更多方式可以查阅API 参考。
以下分别先容具体开发方式。
接口说明

完整的 JS API 说明以及实例代码请参考:VPN API 参考。
接口名描述setUp(config: VpnConfig, callback: AsyncCallback<number>): void建立一个 VPN 网络,利用 callback 方式作为异步方法。protect(socketFd: number, callback: AsyncCallback<void>): void掩护 VPN 的隧道,利用 callback 方式作为异步方法。destroy(callback: AsyncCallback<void>): void烧毁一个 VPN 网络,利用 callback 方式作为异步方法。 启动 VPN 的流程


[*]建立一个 VPN 的网络隧道,下面以 UDP 隧道为例。
[*]掩护前一步建立的 UDP 隧道。
[*]建立一个 VPN 网络。
[*]处置处罚虚拟网卡的数据,如:读写操纵。
[*]烧毁 VPN 网络。
本示例通过 Native C++ 的方式开发应用程序,Native C++ 可参考: 简易 Native C++ 示例(ArkTS)(API9)
示例程序主要包含两个部分:js 功能代码和 C++功能代码
VPN 示例源码(js 部分)

主要功能:实现业务逻辑,如:创建隧道、建立 VPN 网络、掩护 VPN 网络、烧毁 VPN 网络
import { vpn } from '@kit.NetworkKit';
import { common } from '@kit.AbilityKit';
import vpn_client from "libvpn_client.so";
import { BusinessError } from '@kit.BasicServicesKit';

let TunnelFd: number = -1;

@Entry
@Component
struct Index {
@State message: string = 'Test VPN';

private context = getContext(this) as common.UIAbilityContext;
private VpnConnection: vpn.VpnConnection = vpn.createVpnConnection(this.context);

//1. 建立一个VPN的网络隧道,下面以UDP隧道为例。
CreateTunnel() {
    TunnelFd = vpn_client.udpConnect("192.168.43.208", 8888);
}

//2. 保护前一步建立的UDP隧道。
Protect() {
    this.VpnConnection.protect(TunnelFd).then(() => {
      console.info("vpn Protect Success.");
    }).catch((err: BusinessError) => {
      console.info("vpn Protect Failed " + JSON.stringify(err));
    })
}

SetupVpn() {
    let tunAddr : vpn.LinkAddress = {} as vpn.LinkAddress;
    tunAddr.address.address = "10.0.0.5";
    tunAddr.address.family = 1;

    let config : vpn.VpnConfig = {} as vpn.VpnConfig;
    config.addresses.push(tunAddr);
    config.mtu = 1400;
    config.dnsAddresses = ["114.114.114.114"];

    //3. 建立一个VPN网络。
    this.VpnConnection.setUp(config).then((data: number) => {
      console.info("tunfd: " + JSON.stringify(data));
      //4. 处理虚拟网卡的数据,如:读写操作。
      vpn_client.startVpn(data, TunnelFd)
    }).catch((err: BusinessError) => {
      console.info("setUp fail" + JSON.stringify(err));
    });
}

//5.销毁VPN网络。
Destroy() {
    vpn_client.stopVpn(TunnelFd);
    this.VpnConnection.destroy().then(() => {
      console.info("vpn Destroy Success.");
    }).catch((err: BusinessError) => {
      console.info("vpn Destroy Failed " + JSON.stringify(err));
    })
}

build() {
    Row() {
      Column() {
      Text(this.message)
          .fontSize(50)
          .fontWeight(FontWeight.Bold)
          .onClick(() => {
            console.info("vpn Client")
          })
      Button('CreateTunnel').onClick(() => {
          this.CreateTunnel()
      }).fontSize(50)
      Button('Protect').onClick(() => {
          this.Protect()
      }).fontSize(50)
      Button('SetupVpn').onClick(() => {
          this.SetupVpn()
      }).fontSize(50)
      Button('Destroy').onClick(() => {
          this.Destroy()
      }).fontSize(50)
      }
      .width('100%')
    }
    .height('100%')
}
}
<strong>js</strong> VPN 示例源码(c++部分)

主要功能:具体业务的底层实现,如:UDP 隧道 Client 端的实现、虚拟网卡读写数据的实现
#include "napi/native_api.h"
#include "hilog/log.h"

#include <cstring>
#include <thread>
#include <js_native_api.h>
#include <js_native_api_types.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <thread>
#include <sys/time.h>

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define BUFFER_SIZE 2048

#define VPN_LOG_TAG "NetMgrVpn"
#define VPN_LOG_DOMAIN 0x15b0
#define MAKE_FILE_NAME (strrchr(__FILE__, '/') + 1)

#define NETMANAGER_VPN_LOGE(fmt, ...)                                                                                  \
    OH_LOG_Print(LOG_APP, LOG_ERROR, VPN_LOG_DOMAIN, VPN_LOG_TAG, "vpn [%{public}s %{public}d] " fmt, MAKE_FILE_NAME,\
               __LINE__, ##__VA_ARGS__)

#define NETMANAGER_VPN_LOGI(fmt, ...)                                                                                  \
    OH_LOG_Print(LOG_APP, LOG_INFO, VPN_LOG_DOMAIN, VPN_LOG_TAG, "vpn [%{public}s %{public}d] " fmt, MAKE_FILE_NAME,   \
               __LINE__, ##__VA_ARGS__)

#define NETMANAGER_VPN_LOGD(fmt, ...)                                                                                  \
    OH_LOG_Print(LOG_APP, LOG_DEBUG, VPN_LOG_DOMAIN, VPN_LOG_TAG, "vpn [%{public}s %{public}d] " fmt, MAKE_FILE_NAME,   \
               __LINE__, ##__VA_ARGS__)

struct FdInfo {
    int32_t tunFd = 0;
    int32_t tunnelFd = 0;
    struct sockaddr_in serverAddr;
};

static FdInfo fdInfo;
static bool threadRunF = false;
static std::thread threadt1;
static std::thread threadt2;

//获取对应字符串数据, 用于获取udp server 的IP地址
static constexpr const int MAX_STRING_LENGTH = 1024;
std::string GetStringFromValueUtf8(napi_env env, napi_value value) {
    std::string result;
    char str = {0};
    size_t length = 0;
    napi_get_value_string_utf8(env, value, str, MAX_STRING_LENGTH, &length);
    if (length > 0) {
      return result.append(str, length);
    }
    return result;
}

void HandleReadTunfd(FdInfo fdInfo) {
    uint8_t buffer = {0};
    while (threadRunF) {
      int ret = read(fdInfo.tunFd, buffer, sizeof(buffer));
      if (ret <= 0) {
            if (errno != 11) {
                NETMANAGER_VPN_LOGE("read tun device error: %{public}d, tunfd: %{public}d", errno, fdInfo.tunFd);
            }
            continue;
      }

      // 读取到虚拟网卡的数据,通过udp隧道,发送给服务器
      NETMANAGER_VPN_LOGD("buffer: %{public}s, len: %{public}d", buffer, ret);
      ret = sendto(fdInfo.tunnelFd, buffer, ret, 0, (struct sockaddr *)&fdInfo.serverAddr, sizeof(fdInfo.serverAddr));
      if (ret <= 0) {
            NETMANAGER_VPN_LOGE("send to server[%{public}s:%{public}d] failed, ret: %{public}d, error: %{public}s",
                              inet_ntoa(fdInfo.serverAddr.sin_addr), ntohs(fdInfo.serverAddr.sin_port), ret,
                              strerror(errno));
            continue;
      }
    }
}

void HandleTcpReceived(FdInfo fdInfo) {
    int addrlen = sizeof(struct sockaddr_in);
    uint8_t buffer = {0};
    while (threadRunF) {
      int length = recvfrom(fdInfo.tunnelFd, buffer, sizeof(buffer), 0, (struct sockaddr *)&fdInfo.serverAddr,
                              (socklen_t *)&addrlen);
      if (length < 0) {
            if (errno != 11) {
                NETMANAGER_VPN_LOGE("read tun device error: %{public}d,tunnelfd: %{public}d", errno, fdInfo.tunnelFd);
            }
            continue;
      }

      // 接收到udp server的数据,写入到虚拟网卡中
      NETMANAGER_VPN_LOGD("from [%{public}s:%{public}d] data: %{public}s, len: %{public}d",
                            inet_ntoa(fdInfo.serverAddr.sin_addr), ntohs(fdInfo.serverAddr.sin_port), buffer, length);
      int ret = write(fdInfo.tunFd, buffer, length);
      if (ret <= 0) {
            NETMANAGER_VPN_LOGE("error Write To Tunfd, errno: %{public}d", errno);
      }
    }
}

static napi_value UdpConnect(napi_env env, napi_callback_info info) {
    size_t argc = 2;
    napi_value args = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    int32_t port = 0;
    napi_get_value_int32(env, args, &port);
    std::string ipAddr = GetStringFromValueUtf8(env, args);

    NETMANAGER_VPN_LOGI("ip: %{public}s port: %{public}d", ipAddr.c_str(), port);

    // 建立udp隧道
    int32_t sockFd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockFd == -1) {
      NETMANAGER_VPN_LOGE("socket() error");
      return 0;
    }

    struct timeval timeout = {1, 0};
    setsockopt(sockFd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(struct timeval));

    memset(&fdInfo.serverAddr, 0, sizeof(fdInfo.serverAddr));
    fdInfo.serverAddr.sin_family = AF_INET;
    fdInfo.serverAddr.sin_addr.s_addr = inet_addr(ipAddr.c_str()); // server's IP addr
    fdInfo.serverAddr.sin_port = htons(port);                      // port

    NETMANAGER_VPN_LOGI("Connection successful");

    napi_value tunnelFd;
    napi_create_int32(env, sockFd, &tunnelFd);
    return tunnelFd;
}

static napi_value StartVpn(napi_env env, napi_callback_info info) {
    size_t argc = 2;
    napi_value args = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    napi_get_value_int32(env, args, &fdInfo.tunFd);
    napi_get_value_int32(env, args, &fdInfo.tunnelFd);

    if (threadRunF) {
      threadRunF = false;
      threadt1.join();
      threadt2.join();
    }

    // 启动两个线程, 一个处理读取虚拟网卡的数据,另一个接收服务端的数据
    threadRunF = true;
    std::thread tt1(HandleReadTunfd, fdInfo);
    std::thread tt2(HandleTcpReceived, fdInfo);

    threadt1 = std::move(tt1);
    threadt2 = std::move(tt2);

    NETMANAGER_VPN_LOGI("StartVpn successful");

    napi_value retValue;
    napi_create_int32(env, 0, &retValue);
    return retValue;
}

static napi_value StopVpn(napi_env env, napi_callback_info info) {
    size_t argc = 1;
    napi_value args = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    int32_t tunnelFd;
    napi_get_value_int32(env, args, &tunnelFd);
    if (tunnelFd) {
      close(tunnelFd);
      tunnelFd = 0;
    }

    // 停止两个线程
    if (threadRunF) {
      threadRunF = false;
      threadt1.join();
      threadt2.join();
    }

    NETMANAGER_VPN_LOGI("StopVpn successful");

    napi_value retValue;
    napi_create_int32(env, 0, &retValue);
    return retValue;
}

EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports) {
    napi_property_descriptor desc[] = {
      {"udpConnect", nullptr, UdpConnect, nullptr, nullptr, nullptr, napi_default, nullptr},
      {"startVpn", nullptr, StartVpn, nullptr, nullptr, nullptr, napi_default, nullptr},
      {"stopVpn", nullptr, StopVpn, nullptr, nullptr, nullptr, napi_default, nullptr},
    };
    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc), desc);
    return exports;
}
EXTERN_C_END

static napi_module demoModule = {
    .nm_version = 1,
    .nm_flags = 0,
    .nm_filename = nullptr,
    .nm_register_func = Init,
    .nm_modname = "entry",
    .nm_priv = ((void *)0),
    .reserved = {0},
};

extern "C" __attribute__((constructor)) void RegisterEntryModule(void) {
    napi_module_register(&demoModule);
}  
https://i-blog.csdnimg.cn/direct/0ba5f2e092624ec6bff056276d3d9fe1.png

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 鸿蒙开发进阶(HarmonyOS)VPN虚拟专网管理(仅对体系应用开放)