精华内容
下载资源
问答
  • windows 创建虚拟网卡 修改MAC地址

    千次阅读 2020-10-30 22:16:02
    高云FPGA软件与 MAC地址绑定了,想要在另一个电脑上运行就得重新申请很麻烦,使用虚拟网卡 设置同一个MAC地址,就可以通过认证。 1、下载tap-windows 2、设备管理器->网络适配器->找到tap-windows 双击 ...

    高云FPGA 软件 与 MAC地址绑定了,想要在另一个电脑上运行就得重新申请很麻烦,使用虚拟的网卡 设置同一个MAC地址,就可以通过认证。

     

    1、下载 tap-windows

    2、设备管理器->网络适配器->找到tap-windows  双击 高级 ->MACAddr  设定成你想要的地址就可以了。

     

    展开全文
  • Windows 2000/XP/VISTA如何创建虚拟网卡
  • windows添加虚拟网卡

    千次阅读 2013-12-18 01:58:00
    转载于:https://www.cnblogs.com/zzmiot/p/3479594.html

    转载于:https://www.cnblogs.com/zzmiot/p/3479594.html

    展开全文
  • windows虚拟网卡驱动开发

    千次阅读 热门讨论 2017-04-06 19:05:24
    by fanxiushu 2017-04-06 转载或...很早前的文章介绍过windows和linux平台的虚拟网卡技术, 详见 http://blog.csdn.net/fanxiushu/article/details/8526708 http://blog.csdn.net/fanxiushu/article/details/8526
     
                                                                                                                              by fanxiushu   2017-04-06 转载或引用请注明原始作者。

    很早前的文章介绍过windows和linux平台的虚拟网卡技术,
    详见
         http://blog.csdn.net/fanxiushu/article/details/8526708
         http://blog.csdn.net/fanxiushu/article/details/8526719
         http://blog.csdn.net/fanxiushu/article/details/8525749
         http://blog.csdn.net/fanxiushu/article/details/8507638
    前两个是讲述如何组成一个虚拟局域网,后边的是如何在linux平台下开发一个虚拟网卡
    (当时提供的代码比较老,需要修改才能在新版本linux下使用,
    或者懒得自己开发,直接使用linux自带的tun驱动,linux底层这些驱动总比windows平台方便得多)。
    这些文章介绍过如何利用虚拟网卡组建局域网的原理:获取应用层程序发给虚拟网卡的数据包,
    然后通过真实的网络发给服务端, 服务端再转发给另外一台机器,这台机器再把从网络获取的数据包传递给虚拟网卡。
    通过这样的方式,就把处于不同真实网络环境中的机器连接到同一个虚拟局域网中。
    只是当时没介绍如何开发windows虚拟网卡驱动,这篇文章填补这个空白。

    win7系统有最新的NDIS6.2框架,win8 的NDIS提高到6.3以上,win10 达到ndis6.4 。
    最大变化是从NDIS5.x 到 NDIS6.x, 连最基本的包的定义等数据结构都发生了巨大变化。
    但是windows有个最大优点,就是兼容,在win7,win8,win10,等平台可以运行ndis5.x框架的驱动,
    (不过ndis5.x的中间驱动无法在win10上运行,这个估计是最大不方便了)
    就跟TDI驱动能在各种windows平台通吃一样,NDIS5.x也能通吃各种windows平台。
    这里采用 NDIS5.1框架,不是要抱着老的框架不放,而是许多用户抱着WinXP 不放,
    同时要兼容 WinXP和WIN7,而且也不用开发两套代码的最好选择就是NDIS5.1 了。
    如果你的程序只运行在WIN7系统以上,可以只使用NDIS6以上的版本的框架,
    NDIS6虽然基本结构尤其是包结构改变了,但是我们开发的总体方式差不多。

    首先在DriverEntry中声明 NDIS_MINIPORT_CHARACTERISTICS 变量,它是一个包含多个回调函数的数据结构,
    在此结构中填写好我们需要的各种回调函数之后,调用 NdisMRegisterMiniport 函数注册。

    NdisMRegisterMiniport虽然没开放源代码,但是基本工作流程应该能想到,因为虚拟网卡驱动也是即插即用驱动模型,
    因此在DriverEntry 函数中一样需要实现 AddDevice,以及各种派遣函数,
    只是 NdisMRegisterMiniport  使用它内部的某个函数 设置到AddDevice 回调中,同时设置各种IRP_MJ_XXX派遣函数,
    并且做一些其他初始化操作,当有设备(也就是网卡)插上来,DriverObject->DriverExtension->AddDevice 函数被调用,
    这时会进入到NdisMRegisterMiniport注册的 某个内部函数中,
    在这个函数中会调用 NDIS_MINIPORT_CHARACTERISTICS  导出的 InitializeHandler 函数,
    这样就进入到我们注册的网卡初始化函数。

    在虚拟网卡驱动中,主要实现以下几个回调函数,基本上就能完成一个虚拟网卡的功能:

      InitializeHandler , 初始化网卡。也就是当我们安装一块网卡实例驱动的时候,这个函数被调用,
                                      在这个函数中,初始化各种资源,这个函数等同于普通的即插即用驱动的AddDevice函数,
                                      只是被NDIS框架封装成 InitializeHandler 回调函数了。
     HaltHandler , 卸载网卡,当我们卸载某个网卡驱动时候,这个函数被调用,
                             相当于普通即插即用驱动程序收到 IRP_MN_REMOVE_DEVICE等消息之后触发的回调。

    QueryInformationHandler, 查询网卡 OID。其实就是查询网卡的各种信息,网卡包含的信息很多,基本上有几十个。
    SetInformationHandler,      设置网卡OID。 设置我们感兴趣的OID信息。
    ResetHandler, 是否重启网卡,虚拟网卡驱动中,基本用不上。
    CheckForHangHandler, 检测网卡是否处于hang状态,是的话,调用ResetHandler, 虚拟网卡基本上也用不着。

    SendPacketsHandler, 处理网络数据包的核心函数之一,这个回调函数表示网卡从应用层程序接收到以太网数据包,
                                          比如在应用层调用套接字函数send 或sendto发送数据,数据进入到内核的传输层,
                                          经过分析剥离,进入到NDIS协议驱动层,协议驱动层找到这个数据是朝哪个网卡发送的,
                                          于是找到这个网卡注册的  SendPacketsHandler 回调函数地址,
                                          最后调用这个回调函数实现数据包的真正发送。                             
                                          在SendPacketsHandler  函数中处理的数据包是准备发给底层的物理链路的,
                                          虚拟网卡没有物理链路,因此我们把这些数据包入队,
                                          然后直接在驱动层通过WSK(TDI)方式(或者其他各种方式,如USB, 串口等)发给远端设备或电脑,
                                          或者把数据包传递到应用层, 让我们的应用层程序做各种处理,为了开发的方便和简洁,
                                          我们采用的是传递到应用层来处理。

    ReturnPacketHandler, 这个函数与上边的刚好相反,当物理链路有数据包到达(或者通过其他方式有数据包,如USB等),
                                          调用NDIS函数NdisMIndicateReceivePacket,通知上层有个数据包达到,
                                          等上层(这个上层就是处理TCP/IP等各种协议的协议层)处理完这个数据包之后,
                                          ReturnPacketHandler 就被调用。
                                          接着这个数据被上传到传输层进一步分析处理,
                                          再进入到应用层,这时候调用 recv或者recvfrom等套接字函数的程序就接收到了数据。
                                          我们的虚拟网卡驱动在应用层程序通过某个IOCTL控制命令传递一个数据包到驱动,
                                          在驱动中直接调用NdisMIndicateReceivePacket通知上层有数据包到达。

    CancelSendPacketsHandler, 这个是NDIS5.1框架中,提供的取消某些数据包发送的回调函数,也就是上层调用SendPacketsHandler,
                                         发送数据包,但是我们的驱动还没来得及处理,只是入队等待处理,这个时候上层决定取消某些数据包的发送,
                                         于是调用 CancelSendPacketsHandler 让我们取消某些数据包的发送。
    PnPEventNotifyHandler, NDIS5.1框架的PnP通知事件,其实就是对应普通的即插即用驱动中的IRP_MJ_PNP请求的封装。
    AdapterShutdownHandler, NDIS5.1框架的网卡关闭事件。

    因为我们的虚拟网卡驱动是把数据包传递到应用层来处理,也就是应用层相当于是“物理连线”,
    必须创建一个控制设备才能跟应用层交换数据,NDIS5.1框架提供了NdisMRegisterDevice 函数来创建一个控制设备,
    在 InitializeHandler 网卡实例初始化函数中可以调用这个函数创建控制设备,
    在 HaltHandler 网卡卸载函数中可以调用NdisMDeregisterDevice删除这个设备。
    创建这个控制设备时候,传递一些参数,包括派遣函数,我们感兴趣的主要是IRP_MJ_DEVICE_CONTROL,以及CREATE /CLOSE 。
    可以定义两个IOCTL命令,一个用于数据包读取,一个用于向驱动写数据包,比如命名为 READ IOCTL 和WRITE IOCTL。
    网卡处理的数据包是非常多的,
    以100M以太网来计算,以太网数据包大小 1514,当全速传输时候, 100M*1024*1024/8/1514 =  大约 8千多个数据包, 
    全速传输,每秒传输8千多个数据包甚至更多, 这个量是很大的,千兆网达到8万多个包每秒,甚至更多。
    为了尽量提高IO吞吐率,在应用层可以采用完成端口方式接收数据包,下边会讲到。
    (开发虚拟网卡驱动相对而言不算太难,难得是如何调优,让他的IO性能提升到更好的效果)

    如此之多的数据包要在应用层和驱动层进行交换,驱动里边该采用什么结构来处理,才能尽可能的提高IO效率呢?
    这里顺带提一下我测试IO效率的方式,
    一个服务端程序,负责多个虚拟网卡数据包转发,它让多个虚拟网卡组成一个虚拟局域网,
    虚拟网卡的客户端程序采用TCP连接到服务端,转发的虚拟网卡数据包也是通过TCP方式转发。
    服务端程序放到一台性能还可以的WIN7的机器上(四代 i7 的 8核CPU,16G内存),
    它的千兆网卡接到千兆交换机上,完全保证它达到千兆网卡的速度。
    一台装有XP系统的古老机器,以前的ATOM的CPU,1G内存,它的网卡接到百兆交换机上。
    一台装WIN10系统的古老CPU是Core2的机器,2G内存,它的网卡接到百兆交换机上。
    测试以TCP传输为主,UDP基本不考虑,
    测试时候使用FTP,HTTP,windows文件夹共享三种方式上传或者下载一个超过1G大小的大文件。
    在100M网络环境下,以上的测试,XP和WIN10之间通过虚拟网络传输文件,
    基本达到5M-6MB的速度,也就是达到50-%60%的真实网卡利用率,
    也许使用更好的机器效果会更高,在装服务端程序的机器上也装上虚拟网卡,让他与WIN10传输文件,
    这个速度就比较高了,维持在7-11M的速度,基本上达到 70-95%的真实网卡利用率,峰值时候基本能达到饱和。
    这种测试还跟客户端服务端程序,机器配置等多种因素有关,因此不能保证换个环境就一定准确。
    整体来看,WIN7以上的系统性能的表现比WINXP系统好,这应该是WIN7上的内核,微软把整个网络层重构了一遍,跟WINXP完全不同。

    我是基于以上测试来评定开发的虚拟网卡的IO性能。
    为此想了许多办法,也做了多种尝试,往往写好了一种方式的代码发现效果不太理想,之后想到另外一种处理方式可能会更好,
    因此废弃先前的代码,重新再实现新想到的处理方式,来来回回的折腾了多种处理方式,采用了如下的处理结构:
    (不过任然是采用单帧接收和发送的方式)
    数据包传递以IRP 请求为主,一个IRP传递一个数据包。也就是上边所说的定义两个IOCTL命令,read ioctl和write ioctl,
    每次都发送和接收一个数据包,都会产生一个IOCTL调用。

    以read ioctl为例,
    应用层投递read ioctl请求到驱动,这个请求的 Irp 都被驱动挂载到某个 IRP队列 比如 tx_irps_head,
    上层数据包发到虚拟网卡驱动 ,也就是 SendPacketsHandler 函数被调用时候,
    把这些数据包挂载到 某个Packet队列,比如 tx_pkts_head 。
    两者每次处理完后,都调用 KeInsertQueueDpc触发DPC调用 ,在DPC执行函数中,检查两个队列是否都不为空,
    都不为空的话,分别取出一个IRP和一个Packet,把Packet数据copy到IRP,完成这个IRP和Packet,如此循环,直到某个队列为空。

    可能有人会问,这里为何要多次一举使用DPC调用,而不是直接执行这种检查处理!?
    一般是在硬件的中断函数中,为了尽快让出中断函数,让稍微耗时的处理交给次一级的函数处理,
    但是也是要求尽快处理完成而不被其他软中断打断,DPC就处于这种地位。
    对软件来说,是很高的运行级别,在DISPACH_LEVEL,运行的时候是不会被调度到其他CPU或者被软中断打断的运行级别。
    对于网络数据包的处理就是需要在这种DPC环境中运行,才能让他达到更好的IO效率。

     大致伪代码如下,
    在IRP_MJ_DEVICE_CONTROL请求中,响应 IOCTL_NCARD_READ_DATA(也就是read IOCTL宏)

    case IOCTL_NCARD_READ_DATA:
             // PENDING
             status = STATUS_PENDING;
             IoMarkIrpPending(Irp);

              InitializeListHead(&Irp->Tail.Overlay.ListEntry);
              Irp->Tail.Overlay.DriverContext[0] = a;
               IoSetCancelRoutine(Irp, ioctl_cacnel_routine); ///
             if (Irp->Cancel) {
                if (IoSetCancelRoutine(Irp, NULL) != NULL) { //取消例程还没被执行,自己取消
                   status = STATUS_CANCELLED;
                   complete_irp(Irp, status, 0);
                }
               
             }
            else {
                ///加入到队列 , 等待 上层有数据包发送 SendPacketsHandler 被调用,再从 tx_irps_head队列取出IRP进行处理。  
                NdisInterlockedInsertTailList(&a->tx_irps_head, &Irp->Tail.Overlay.ListEntry, &a->tx_spinlock);
            }
           
            // 触发DPC调用,这里采用DPC。
            KeInsertQueueDpc(&(a)->tx_dpc, NULL, NULL); /
           .......
         上边的DPC的初始化操作,
            KeInitializeDpc(&a->tx_dpc, adapter_complete_send_packets_dpc, a);
     
          在 adapter_complete_send_packets_dpc 这个DPC执行函数中完成类似如下的操作:
       
    ///--------------------------------------------------------------------------------------------------
        adapter_t* a = (adapter_t*)context;
        adapter_inc(a);
        PLIST_ENTRY entry;
       
        while (TRUE) {
           
            tx_lock(a);

            if (IsListEmpty(&a->tx_irps_head) || IsListEmpty(&a->tx_pkts_head)) {
                tx_unlock(a);
                break;
            }
            entry = RemoveHeadList(&a->tx_irps_head);
            PIRP Irp = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry );

            if (IoSetCancelRoutine(Irp, NULL) == NULL) { /// 应该检查返回值,若为空,说明取消例程已经被调用了
                NdisInitializeListHead(&Irp->Tail.Overlay.ListEntry); //初始化,防止在取消例程出问题
                tx_unlock(a);
                continue;
            }
           
            entry = RemoveHeadList(&a->tx_pkts_head);
            PNDIS_PACKET packet = CONTAINING_RECORD(entry, NDIS_PACKET, MiniportReserved);

            tx_unlock(a);
            /
            NTSTATUS status = adapter_send_packet_to_irp(a, packet, Irp); 复制 Packet 数据到 Irp

            ///
        }

        adapter_dec(a);
         /------------------------------------------------------------------------------------------------------------

        在网卡 SendPacketsHandler 函数中做类似如下处理:
         
            for (index = 0; index < NumberOfPackets; ++index) {
                  PNDIS_PACKET packet = PacketArray[index];  ///
                 
                  status = NDIS_STATUS_PENDING;
                  NDIS_SET_PACKET_STATUS(packet, status);

                   tx_inc(a);  //增加send包计数
                   NdisInterlockedInsertTailList(&a->tx_pkts_head, (PLIST_ENTRY)packet->MiniportReserved, &a->tx_spinlock); ///挂载到队列

                  ///
             }
             .........
            触发 DPC调用        
            KeInsertQueueDpc(&(a)->tx_dpc, NULL, NULL);
            -------.........................................................

         如上就完成一个数据包的交换。
         write ioctl也做类似的处理。

         回到应用层来,在应用层,一般做法都是阻塞调用 DeviceIoControl ,这样没什么问题。
         但是可以这样考虑,我们在调用DeviceIoControl返回后,处理数据包,然后再接着调用DeviceIoControl,
         在再次调用DeviceIocontrol之前这中间有空隙,如果一次多投递读请求,这样数据包一来就被接收,中间就不存在空隙了。
         最容易想到的就是多线程调用 DeviceIoControl ,但是这种密集型的IO,多线程反而会降低效率,
         而且多线程还容易造成接收到的数据包乱序,这对TCP这种君子协议来说不是好事。
         在一个线程里,同时投递多个请求,异步方式处理,这才是解决这个问题的办法。
         完成端口就可以完成这件事,
         大家所熟悉的完成端口,多用到网络编程上,其实网络套接字只是它的一个应用而已,
         凡是具备异步读写的OVERLAPPED重叠请求的,都可以关联到完成端口。
         这里也就不具体描述如何使用完成端口来异步投递read ioctl请求了,因为相信大家已经很熟悉。
        
         以上开发的虚拟网卡测试的都是在100M网络环境下进行的,但是在千兆网络环境下的测试是很糟糕的。
         我按照上边的环境测试,1000Mbps 的环境下,最快只能达到 20 MBytes 每秒的速度,也就是相当于 千兆网的 五分之一的速度。
         这个测试数据非常让人气馁。
        
         归根结底还是因为每个数据包长度不超过 1514,千兆网每秒需要处理 8多万甚至更多数据包,这么多数据包,
         按照每个包的取,而且取出来之后,再把每个包在应用层封装一下再发到服务端,再服务端再转发出去,
         达到对方虚拟网卡,再传递到网卡驱动层接收,再等待ACK回应,
         这中间的延时比真正的物理硬件环境要高得多了,
         解决这个问题也不是没办法,既然包太多了,那就减少包数量。如果在纯粹的虚拟网络中,可以设置虚拟网卡的MTU值,
         让他更大,比如设置4M这么大的MTU值,这样每个包就可以达到 4M,传递的包个数大大减少,这种情况下疯狂传输文件的话,
         立马就能把千兆网络跑满。
         但是如果把虚拟网卡和真实的网卡混合桥接,1514的包大小的限制是无法改变的,任然要面对大量的包造成的效率问题。
         
          在写这篇文章时候,想到另外一个把数据包传递到应用层的办法,不采用IRP传递。
          就是在应用层开辟一块很大的内存,比如2M的内存,这块内存映射到驱动,这个内存块按照 1514 拆分成起码1000多个小块。
          这些小块组成循环队列, 驱动不停的朝这个循环队列写数据包,应用层不停的从这个循环队列读数据包。
          这样就减少IRP调用的开销,应该能提高效率,但在千兆网环境中能否得到质的提升,因为没实现,所以不能下定论。
          不过即使提升了驱动和应用层的IO效率,但是应用层还得发数据包到网络去转发,这个无论如何也得不到实质的提升。
          总体下来估计不会有质的提升。
         
                                                                                                                                 范秀树 2017-04-06  晚
     

    展开全文
  • 如何设置TAP-Windows虚拟网卡的上网优先级? ![图片说明](https://img-ask.csdn.net/upload/202003/21/1584790913_585408.png) 本来的目的是想通过TAP-Windows构建VLAN但是不通过其网关进行上网 <br>...
  • 前一段时间,一直在找寻windows操作系统上的虚拟网卡接口,为了搭建隧道使用。但是windows操作系统不像Linux操作系统,它的代码不开源,导致这方面的资料很少,因此也找寻了很长时间,最终找到了两款开源项目的虚拟...

    前一段时间,一直在找寻windows操作系统上的虚拟网卡接口,主要是为了搭建隧道使用。但是windows操作系统不像Linux操作系统,它的代码不开源,导致这方面的资料很少,因此花费了较长时间来寻找相关实现框架,最终找到了两款开源项目的虚拟接口驱动:

    这两个项目都是非常出名的搭建隧道的开源V.P.N项目。由于目前对openVPN项目不太了解,也没有适配Tap接口,因此这里重点介绍下WinTun接口。此接口实现我是非常非常的喜欢,喜欢到简直不要不要的。

    1.简介

    说到Wintun项目,就不得不说到它的父亲:WireGuard项目(以下简称WG)。Github传送门

    WG项目作为开源V.P.N项目,不同于OpenVPN, Openswan, Strongswan等,它的实现非常简介,Linux内核代码实现不到4000行。相对于上述的三个“按行收费”的项目(代码10万行起步),它简直是太简洁了。故而得到了众多好评,其中就包括Linux鼻祖:Linus Torvalds。他的评价如下:

    Btw, on an unrelated issue: I see that Jason actually made the pull request to have wireguard included in the kernel.

    Can I just once again state my love for it and hope it gets merged soon? Maybe the code isn’t perfect, but I’ve skimmed it, and compared to the horrors that are OpenVPN and IPSec, it’s a work of art.

    Linus

     简而言之就是:劳资稀罕你,要把你合入我的Linux项目中。因此Linux内核自5.6之后便自带WG隧道功能,配置非常的简单。通过几行代码便可以完成一个WG隧道:

    ip link add dev wg0 type wireguard
    ip address add dev wg0 10.0.0.1/24
    wg set wg0 listen-port 51820 private-key ./private.key peer NIk5TyDpRDoU9tfIckTTXCsz1eht2aEmdN7l0Q31ow0= allowed-ips 10.0.0.2/32 endpoint 192.168.1.5:51820
    ip link set dev wg0 up

    官网上的配置如下:

    配置非常简单。除此之外,还提供了Windows客户端,这也是此项目为何包含Wintun虚拟网络接口的原因。

    客户端页面也是非常简洁,没有多余的东西(客户端链接):

    客户端上隧道协商成功之后,会根据隧道名称建立一个虚拟网卡,隧道拆除后接口自动删除。由于我的隧道名称为Tun-1,因此在“控制版面”的“网络连接”中出现了一个Tun-1的网络接口:

    好了,下面开始介绍此虚拟网络接口。

     

    2.WinTun虚拟网络接口

    Github传送门

    wintun官网传送门

    常见的windwos的接口驱动开发、安装比较复杂。常见的驱动安装包有:.inf文件、.sys文件、.cat文件; 除此之外还涉及驱动程序签名,否则无法安装成功。尤其在开发调试阶段,每次都得签名,太磨叽了。

    但是WinTun接口用法非常简单高效非常简单高效非常简单高效

    1. 引入头文件:wintun.h

    2. 加载动态库,解析动态库中的函数指针

    它通过动态库中方式来提供接口,我们可以加载此动态库,然后调用动态库中的函数指针来完成虚拟接口的创建、销毁、收发数据包等工作。此外它提供了一个示例供大家学习,我便是通过参考开源代码中的示例(example.c),将Wintun接口移植到我的工程之中。非常简单,我太喜欢它了

    实例代码就400行,其中大部分为log信息,供大家查看程序运行状态和报文收发信息。

    2.1加载动态库中的函数指针

    此函数的作用:

    • 加载动态库,获取到动态库中的函数指针,后面通过函数指针来操作虚拟网卡接口。
    static HMODULE
    InitializeWintun(void)
    {
        HMODULE Wintun =
            LoadLibraryExW(L"wintun.dll", NULL, LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32);
        if (!Wintun)
            return NULL;
    #define X(Name, Type) ((Name = (Type)GetProcAddress(Wintun, #Name)) == NULL)
        if (X(WintunCreateAdapter, WINTUN_CREATE_ADAPTER_FUNC) || X(WintunDeleteAdapter, WINTUN_DELETE_ADAPTER_FUNC) ||
            X(WintunDeletePoolDriver, WINTUN_DELETE_POOL_DRIVER_FUNC) || X(WintunEnumAdapters, WINTUN_ENUM_ADAPTERS_FUNC) ||
            X(WintunFreeAdapter, WINTUN_FREE_ADAPTER_FUNC) || X(WintunOpenAdapter, WINTUN_OPEN_ADAPTER_FUNC) ||
            X(WintunGetAdapterLUID, WINTUN_GET_ADAPTER_LUID_FUNC) ||
            X(WintunGetAdapterName, WINTUN_GET_ADAPTER_NAME_FUNC) ||
            X(WintunSetAdapterName, WINTUN_SET_ADAPTER_NAME_FUNC) ||
            X(WintunGetRunningDriverVersion, WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC) ||
            X(WintunSetLogger, WINTUN_SET_LOGGER_FUNC) || X(WintunStartSession, WINTUN_START_SESSION_FUNC) ||
            X(WintunEndSession, WINTUN_END_SESSION_FUNC) || X(WintunGetReadWaitEvent, WINTUN_GET_READ_WAIT_EVENT_FUNC) ||
            X(WintunReceivePacket, WINTUN_RECEIVE_PACKET_FUNC) ||
            X(WintunReleaseReceivePacket, WINTUN_RELEASE_RECEIVE_PACKET_FUNC) ||
            X(WintunAllocateSendPacket, WINTUN_ALLOCATE_SEND_PACKET_FUNC) || X(WintunSendPacket, WINTUN_SEND_PACKET_FUNC))
    #undef X
        {
            DWORD LastError = GetLastError();
            FreeLibrary(Wintun);
            SetLastError(LastError);
            return NULL;
        }
        return Wintun;
    }

    2.2 main()函数

    作用:

    • 通过函数指针创建虚拟网卡
    • 创建虚拟网卡的收发线程
    int
    main(void)
    {
        HMODULE Wintun = InitializeWintun();
        if (!Wintun)
            return LogError(L"Failed to initialize Wintun", GetLastError());
        WintunSetLogger(ConsoleLogger);
        Log(WINTUN_LOG_INFO, L"Wintun library loaded");
        WintunEnumAdapters(L"Example", PrintAdapter, 0);
    
        DWORD LastError;
        HaveQuit = FALSE;
        QuitEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
        if (!QuitEvent)
        {
            LastError = LogError(L"Failed to create event", GetLastError());
            goto cleanupWintun;
        }
        if (!SetConsoleCtrlHandler(CtrlHandler, TRUE))
        {
            LastError = LogError(L"Failed to set console handler", GetLastError());
            goto cleanupQuit;
        }
    
        GUID ExampleGuid = { 0xdeadbabe, 0xcafe, 0xbeef, { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef } };
        WINTUN_ADAPTER_HANDLE Adapter = WintunOpenAdapter(L"Example", L"Demo");
        if (!Adapter)
        {
            Adapter = WintunCreateAdapter(L"Example", L"Demo", &ExampleGuid, NULL);
            if (!Adapter)
            {
                LastError = GetLastError();
                LogError(L"Failed to create adapter", LastError);
                goto cleanupQuit;
            }
        }
    
        DWORD Version = WintunGetRunningDriverVersion();
        Log(WINTUN_LOG_INFO, L"Wintun v%u.%u loaded", (Version >> 16) & 0xff, (Version >> 0) & 0xff);
    
        MIB_UNICASTIPADDRESS_ROW AddressRow;
        InitializeUnicastIpAddressEntry(&AddressRow);
        WintunGetAdapterLUID(Adapter, &AddressRow.InterfaceLuid);
        AddressRow.Address.Ipv4.sin_family = AF_INET;
        AddressRow.Address.Ipv4.sin_addr.S_un.S_addr = htonl((10 << 24) | (6 << 16) | (7 << 8) | (7 << 0)); /* 10.6.7.7 */
        AddressRow.OnLinkPrefixLength = 24; /* This is a /24 network */
        LastError = CreateUnicastIpAddressEntry(&AddressRow);
        if (LastError != ERROR_SUCCESS && LastError != ERROR_OBJECT_ALREADY_EXISTS)
        {
            LogError(L"Failed to set IP address", LastError);
            goto cleanupAdapter;
        }
    
        WINTUN_SESSION_HANDLE Session = WintunStartSession(Adapter, 0x400000);
        if (!Session)
        {
            LastError = LogLastError(L"Failed to create adapter");
            goto cleanupAdapter;
        }
    
        Log(WINTUN_LOG_INFO, L"Launching threads and mangling packets...");
    
        HANDLE Workers[] = { CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ReceivePackets, (LPVOID)Session, 0, NULL),
                             CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)SendPackets, (LPVOID)Session, 0, NULL) };
        if (!Workers[0] || !Workers[1])
        {
            LastError = LogError(L"Failed to create threads", GetLastError());
            goto cleanupWorkers;
        }
        WaitForMultipleObjectsEx(_countof(Workers), Workers, TRUE, INFINITE, TRUE);
        LastError = ERROR_SUCCESS;
    
    cleanupWorkers:
        HaveQuit = TRUE;
        SetEvent(QuitEvent);
        for (size_t i = 0; i < _countof(Workers); ++i)
        {
            if (Workers[i])
            {
                WaitForSingleObject(Workers[i], INFINITE);
                CloseHandle(Workers[i]);
            }
        }
        WintunEndSession(Session);
    cleanupAdapter:
        WintunDeleteAdapter(Adapter, FALSE, NULL);
        WintunFreeAdapter(Adapter);
    cleanupQuit:
        SetConsoleCtrlHandler(CtrlHandler, FALSE);
        CloseHandle(QuitEvent);
    cleanupWintun:
        FreeLibrary(Wintun);
        return LastError;
    }

    收发报文的接口操作也非常简单,但是与windows网络协议栈之间的关系仍需要继续摸索。

     

    2.3 特别说明

    Wintun接口是严格意义上的3层逻辑接口。原文如下:

    Wintun is a very simple and minimal TUN driver for the Windows kernel, which provides userspace programs with a simple network adapter for reading and writing packets. It is akin to Linux's /dev/net/tun and BSD's /dev/tun. Originally designed for use in WireGuard, Wintun is meant to be generally useful for a wide variety of layer 3 networking protocols and experiments. The driver is open source, so anybody can inspect and build it. Due to Microsoft's driver signing requirements, we provide precompiled and signed versions that may be distributed with your software. The goal of the project is to be as simple as possible, opting to do things in the most pure and straight-forward way provided by NDIS.

     

     

    这里出现了一个小小的问题:Wireshark上无法抓取此接口报文。如果想看封装后的报文信息,则需要单独记录日志而非抓包来完成。

    导致这个问题原因没有找到,我认为是:wireshark抓取的报文是二层报文(一个完整的以太网帧),而3层逻辑接口上的报文尚未封装以太网帧,故无法抓取此接口。这只是个人猜测,根本原因不得而知。


    好了,基本介绍完毕,重新表达下我对WireGuard和WinTun的态度: 劳资稀罕你,very喜欢

     
     
     
     
    展开全文
  • 为何要用虚拟网卡,当无以太网的情况下,即无路由器,我们可以使用创建虚拟网卡来实现共享,将Windows和虚拟机进行共享网络,实现映射方式,类似samba。 主要做如下步骤: 1.PC创建虚拟网卡; 2.虚拟机网络配设置...
  • 前一段时间,一直在找寻windows操作系统上的虚拟网卡接口,主要是为了搭建隧道使用。但是windows操作系统不像Linux操作系统,它的代码不开源,导致这方面的资料很少,因此花费了较长时间来寻找相关实现框架,最终...
  • Linux下创建虚拟网卡

    万次阅读 2016-03-07 17:04:23
    创建虚拟网卡:Sudo ifconfig eth0:0 192.168.1.5 up 删除虚拟网卡:Sudo ifconfig eth0:0 down 重启电脑或网络后,虚拟网卡消失,且创建的虚拟网卡mac地址和eth0相同。   方法二: 在ubuntu下,修改...
  • TAP-Windows Adapter V9虚拟网卡的源代码tap-windows6-master-9.23.3.601.zip,可参考我写的教程用VS2019+WDK10编译。
  • win10系统创建虚拟网卡

    千次阅读 2019-11-12 15:47:55
    由于工作原因,下午需要重新在物理机上创建块虚拟网卡...下面把具体步骤写下,希望可以帮助向我一样不懂如何创建虚拟网卡的小白。 在win10系统中按下快捷键 win+x 打开设备管理器,如下图 在win10里,“Mic...
  • 由于网络虚拟化会在物理机上新增许多虚拟网络设备 (包括虚拟网卡),情况会变得复杂,因而首先我们需要分清他们。当然如果没有进行网络虚拟化,那么就可以跳过这部分。网络虚拟化环境中,通过设备管理器应该可见:以...
  • 虚拟网卡

    2019-11-30 18:10:07
    虚拟网卡(又称虚拟网络适配器),即用软件模拟网络环境,模拟网络适配器,windows系统自带此软件。 虚拟网卡作用 在使用VMware Workstation创建虚拟机时,可以根据需要选择使用哪种虚拟网卡,哪种连接方式。...
  • win8如何创建虚拟网卡

    2018-05-03 09:58:20
    下面演示win8如何创建虚拟网卡:百度经验:jingyan.baidu.com方法/步骤按快捷键【WIN+X】然后点击【设备管理器】步骤阅读进入【设备管理器】依次点击【操作】----【添加过时硬件】步骤阅读在添加硬件对话框中【下一步...
  • 【已解决】Vmware无法创建虚拟网卡的问题
  • Docker 创建虚拟网卡

    2020-12-18 16:12:19
    docker network create -d bridge <name> docker network inspect <name>
  • Win7虚拟网卡创建

    2012-02-08 15:40:10
    用于windows7创建一个虚拟的无线网卡,能分享自己的无线网络或者其他用途
  • 虚拟网卡创建

    千次阅读 2017-10-24 14:18:43
    安装uml-utilities。 Sudo apt-get install uml-utilities 安装完成后,执行命令tunctl -b即可...附脚本批量创建删除虚拟网卡创建: #!/bin/bash clear for((i=0;i tunctl -b ip link set tap$i up Done
  • 虚拟TAP设备,虚拟网卡 ,TAP-windows V9.21.2.exe 由于原网址非常难下载,故放这里备用
  • windows10 设置虚拟网卡/ip

    千次阅读 2019-04-11 13:25:00
    windows+x —— 设备管理器 —— 网络适配器 点左上角的 操作——添加过时硬件 点Microsoft——点右侧Microsoft KM-TEST环回适配器——点下一步就可以了 备注:windows 7 选的是Microsoft Loopback ...
  • 在其他windows操作系统,如 winxp, win7,win8等系统上安装都没有问题,但在一些windows10 64版本系统上安装时有问题,具体是:安装完后可以从设备管理器上找到 虚拟网卡,但查看属性时只有最上面的链接按钮可...
  • windows 上面虚拟网卡(vNIC)安装时会自动配置 “SYSTEM\\CurrentControlSet\\Control\\Class\\{4d36e972-e325-11ce-bfc1-08002be10318}” 注册类,但具体安装在这个注册类哪一项没有明确的值(不是一个固定值,每次...
  • win8重新添加虚拟网卡即用软件模拟网络环境:Microsoft Loopback Adapter (微软回环网卡)类似一个虚拟网卡,能够被安装在一个没有网卡或者要用于测试多个宿主环境的 Windows 上。
  • win + r打开运行,输入hdwwiz ...查看虚拟网卡 安装完成后,返回”网络和共享中心“,可以看到虚拟环回适配器添加成功,根据自己需要配置IP即可使用。 拟环回适配器添加成功,根据自己需要配置IP即可使用。 ...
  • Windows server 2003增加虚拟网卡虚拟网卡主要是建立远程计算机间的局域网,虚拟网卡链接技术就是×××,比如说你可以和别的地方的几台机子通过建立虚拟HUB 实现××× client的链接这样就算是在这几台远程...
  • 添加虚拟网卡

    千次阅读 2016-09-14 17:19:21
    Linux添加虚拟网卡的多种方法 有时候,一台服务器需要设置多个ip,但又不想添加多块网卡,...第一种方法:快递创建\删除虚拟网卡 sudo ifconfig eth0:0 192.168.10.10 up 以上的命令就可以在eth0网卡上创建一个叫eth0:0
  • 实现虚拟网卡代码

    2014-10-08 23:58:53
    linux下实现虚拟网卡技术,该代码使用c语言实现,已经测试可以使用。
  • 在win7下创建虚拟网卡

    2013-05-27 21:51:00
    1.在windows下远程访问虚拟机当中的Linux系统,如果在电脑没有连接网线的情况下,可以通过建“虚拟网卡”来处理,win7系统的具体操作如下:    打开“设备管理器”,右击根目录,选择“添加过时硬件”    在...
  • 有一天去朋友那里玩,看见朋友电脑上的cmd窗口有一条命令:netsh wlan start ...果真如此,虽然现在网上有好多软件可以实现电脑共享无线wifi上网,例如wifi共享精灵等,但是我在这里还是想在强调一下这个虚拟连接的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 39,912
精华内容 15,964
关键字:

windows建立虚拟网卡