zoukankan      html  css  js  c++  java
  • DNS解析

    //****************************************************************************************/
    //获取DNS
     
    #include "DNS.h"
    
    
    
    //全局变量
    PDNSADDRANDURL global_pwsadata;
    
    NTSTATUS
    DriverEntry(
        PDRIVER_OBJECT pDriverObj,
        PUNICODE_STRING pRegistryString
    )
    {
        NTSTATUS status = STATUS_SUCCESS;
        UNICODE_STRING ustrLinkName;
        UNICODE_STRING ustrDevName;
        PDEVICE_OBJECT pDevObj;
    
        int s_dns = 0;
    
        unsigned char hostname[100] = { "www.debugman.com" };
    
        //if (DBG)
        {
            //    __asm int 3 
        }
    
    
    
        dprintf("[hello] DriverEntry
    ");
    
        pDriverObj->MajorFunction[IRP_MJ_CREATE] = DispatchCreate;
        pDriverObj->MajorFunction[IRP_MJ_CLOSE] = DispatchClose;
        pDriverObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchIoctl;
        pDriverObj->DriverUnload = DriverUnload;
    
    
        RtlInitUnicodeString(&ustrDevName, DEVICE_NAME);
        status = IoCreateDevice(pDriverObj,
            0,
            &ustrDevName,
            FILE_DEVICE_UNKNOWN,
            0,
            FALSE,
            &pDevObj);
    
        if (!NT_SUCCESS(status)) {
            dprintf("[hello] IoCreateDevice = 0x%x
    ", status);
            return status;
        }
    
        RtlInitUnicodeString(&ustrLinkName, LINK_NAME);
         
        if (!NT_SUCCESS(status)) {
            dprintf("[hello] IoCreateSymbolicLink = 0x%x
    ", status);
            IoDeleteDevice(pDevObj);
            return status;
        }
    
        global_pwsadata = (PDNSADDRANDURL)ExAllocatePool(0, sizeof(DNSADDRANDURL));
    
        s_dns = ReadDnsServerFromRegistry();  //返回网络字节顺序
        global_pwsadata->serveur_dns = s_dns;
        gethostbyname(hostname);
        dprintf(" remote ip address is %x
    ", global_pwsadata->urladdr);
    
        return STATUS_SUCCESS;
    }
    
    
    VOID
    DriverUnload(
        PDRIVER_OBJECT pDriverObj
    )
    {
        UNICODE_STRING strLink;
        RtlInitUnicodeString(&strLink, LINK_NAME);
    
        //
        // 添加卸载代码
        //
    
    
    
        IoDeleteSymbolicLink(&strLink);
        IoDeleteDevice(pDriverObj->DeviceObject);
        dprintf("[hello] Unloaded
    ");
    }
    
    
    NTSTATUS
    DispatchCreate(
        PDEVICE_OBJECT pDevObj,
        PIRP pIrp
    )
    {
        pIrp->IoStatus.Status = STATUS_SUCCESS;
        pIrp->IoStatus.Information = 0;
    
        dprintf("[hello] IRP_MJ_CREATE
    ");
    
        IoCompleteRequest(pIrp, IO_NO_INCREMENT);
        return STATUS_SUCCESS;
    }
    
    
    NTSTATUS
    DispatchClose(
        PDEVICE_OBJECT pDevObj,
        PIRP pIrp
    )
    {
        pIrp->IoStatus.Status = STATUS_SUCCESS;
        pIrp->IoStatus.Information = 0;
    
        dprintf("[hello] IRP_MJ_CLOSE
    ");
    
        IoCompleteRequest(pIrp, IO_NO_INCREMENT);
        return STATUS_SUCCESS;
    }
    
    
    NTSTATUS
    DispatchIoctl(
        PDEVICE_OBJECT pDevObj,
        PIRP pIrp
    )
    {
        NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;
        PIO_STACK_LOCATION pIrpStack;
        ULONG uIoControlCode;
        PVOID pIoBuffer;
        ULONG uInSize;
        ULONG uOutSize;
    
        pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
        uIoControlCode = pIrpStack->Parameters.DeviceIoControl.IoControlCode;
        pIoBuffer = pIrp->AssociatedIrp.SystemBuffer;
        uInSize = pIrpStack->Parameters.DeviceIoControl.InputBufferLength;
        uOutSize = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
    
        switch (uIoControlCode) {
    
        case IOCTL_HELLO: {
    
            dprintf("[hello] Hello
    ");
            status = STATUS_SUCCESS;
        }
                          break;
        }
    
        if (status == STATUS_SUCCESS)
            pIrp->IoStatus.Information = uOutSize;
        else
            pIrp->IoStatus.Information = 0;
    
        /////////////////////////////////////
        pIrp->IoStatus.Status = status;
        IoCompleteRequest(pIrp, IO_NO_INCREMENT);
    
        return status;
    }
    
    /*
    返回网络字节顺序
    */
    int ReadDnsServerFromRegistry()
    {
        //Variables locales
        NTSTATUS       status = STATUS_UNSUCCESSFUL;
    
        WCHAR       ChaineRegistre[] = L"\REGISTRY\MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces";
        UNICODE_STRING     usRegistryKey = { 0 };
        OBJECT_ATTRIBUTES     obNomClefRegistre = { 0 };
        HANDLE        RegHandle = 0;
    
        UNICODE_STRING     usRegistryKeySub = { 0 };
        OBJECT_ATTRIBUTES     obNomClefRegistreSub = { 0 };
        HANDLE        RegHandleSub = 0;
    
        WCHAR       ChaineEnableDHCP[] = L"EnableDHCP";
        WCHAR       ChaineNameServer[] = L"NameServer";
        WCHAR       ChaineDhcpNameServer[] = L"DhcpNameServer";    //有问题这个,注册表里好像没有   Win10下DhcpServer
                                                                //DhcpServer
        char        informations_lues[256];
        ULONG       size_lue = 0;
    
        KEY_VALUE_FULL_INFORMATION *KeyValue = NULL;
        char        adresses_ips_dns[40];
    
        int         compteur_subkey = 0;
        unsigned int       adresse = 0;
    
        ANSI_STRING AnsiString;
        UNICODE_STRING CurrentName;
    
    
        RtlInitUnicodeString(&usRegistryKey, ChaineRegistre);
    
        InitializeObjectAttributes(&obNomClefRegistre,
            &usRegistryKey,
            OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
            NULL,
            NULL);
    
        status = ZwOpenKey(&RegHandle, KEY_READ, &obNomClefRegistre);    
        //打开 L"\REGISTRY\MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces"
    
        if (status != STATUS_SUCCESS)
        {
            return -1;
        }
    
        compteur_subkey = 0;
        status = STATUS_SUCCESS;
        while (TRUE)
        {
            memset(informations_lues, 0, 256);
            status = ZwEnumerateKey(RegHandle,
                compteur_subkey,
                KeyBasicInformation,
                &informations_lues,
                256,
                &size_lue);
    
    
            if (status != STATUS_SUCCESS)
                break;
    
    
            RtlInitUnicodeString(&usRegistryKeySub,
                ((*(KEY_BASIC_INFORMATION*)&informations_lues).Name));
    
            InitializeObjectAttributes(&obNomClefRegistreSub,
                &usRegistryKeySub,
                OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
                NULL, NULL);
    
    
            obNomClefRegistreSub.RootDirectory = RegHandle;
    
    
            status = ZwOpenKey(&RegHandleSub,
                KEY_READ,
                &obNomClefRegistreSub);
    
    
            if (status != STATUS_SUCCESS)
            {
                compteur_subkey++;
    
                continue;
            }
    
    
            memset(informations_lues, 0, 256);
    
            RtlInitUnicodeString(&usRegistryKey,
                ChaineEnableDHCP);
    
            status = ZwQueryValueKey(RegHandleSub,
                &usRegistryKey,
                KeyValueFullInformation,
                &informations_lues,
                256,
                &size_lue);
    
    
            if (status != STATUS_SUCCESS)
            {
                compteur_subkey++;
                ZwClose(RegHandleSub);
                continue;
            }
    
    
            KeyValue = (KEY_VALUE_FULL_INFORMATION *)informations_lues;
            if (*(int*)(informations_lues + KeyValue->DataOffset))
            {
    
                RtlInitUnicodeString(&usRegistryKey,
                    ChaineDhcpNameServer);
            }
            else
            {
    
                RtlInitUnicodeString(&usRegistryKey,
                    ChaineNameServer);
            }
    
    
            memset(informations_lues, 0, 256);
            status = ZwQueryValueKey(RegHandleSub,
                &usRegistryKey,
                KeyValueFullInformation,
                &informations_lues,
                256,
                &size_lue);
    
    
            if (status != STATUS_SUCCESS)
            {
                compteur_subkey++;
    
                ZwClose(RegHandleSub);
                continue;
            }
    
    
            RtlZeroMemory(adresses_ips_dns, 40);
    
            RtlInitUnicodeString(&CurrentName, informations_lues + KeyValue->DataOffset);
            RtlUnicodeStringToAnsiString(&AnsiString, &CurrentName, TRUE);
            RtlCopyMemory(adresses_ips_dns, AnsiString.Buffer, 40);
    
            dprintf("DNS SERVICE IP %s
    ", adresses_ips_dns);
    
            ZwClose(RegHandleSub);
    
            adresse = inet_addr(adresses_ips_dns);
            if (adresse == 0)
            {
                compteur_subkey++;
                continue;
            }
    
            ZwClose(RegHandle);
            return adresse;
    
            compteur_subkey++;
        }
        ZwClose(RegHandle);
        return -1;
    }
    
    
    
    //获取了DNS的ip后问题就容易处理,剩下构造dns请求包和udp的相关东西~~
    //因为dns请求的协议要求获得本机地址,要去取本机地址,代码如下
    
    /*
    返回网络字节顺序
    */
    int ReadHostIPsFromRegistry()
    {
        NTSTATUS        status = STATUS_UNSUCCESSFUL;
        int*            pHostentArray = NULL;
        char*            pHostentData = NULL;
    
        WCHAR            ChaineRegistre[] = L"\REGISTRY\MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces";
    
        UNICODE_STRING  usRegistryKey = { 0 };
        OBJECT_ATTRIBUTES        obNomClefRegistre = { 0 };
        HANDLE            RegHandle = 0;
    
        UNICODE_STRING     usRegistryKeySub = { 0 };
        OBJECT_ATTRIBUTES  obNomClefRegistreSub = { 0 };
        HANDLE               RegHandleSub = 0;
    
        WCHAR       ChaineEnableDHCP[] = L"EnableDHCP";
        WCHAR       ChaineIPAddress[] = L"IPAddress";
        WCHAR       ChaineDhcpIPAddress[] = L"DhcpIPAddress";
    
        char        informations_lues[256];
        ULONG       size_lue = 0;
    
        KEY_VALUE_FULL_INFORMATION *KeyValue = NULL;
        char        adresse_ip[20];
    
        int          compteur_subkey = 0;
        unsigned int adresse = 0;
    
        ANSI_STRING AnsiString;
        UNICODE_STRING CurrentName;
    
        RtlInitUnicodeString(&usRegistryKey,
            ChaineRegistre);
    
        InitializeObjectAttributes(&obNomClefRegistre,
            &usRegistryKey,
            OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
            NULL, NULL);
    
        status = ZwOpenKey(&RegHandle,//打开主键
            KEY_READ,
            &obNomClefRegistre);
        if (status != STATUS_SUCCESS)
        {
            return -1;
        }
    
        compteur_subkey = 0;//子键的个数
        status = STATUS_SUCCESS;
        while (TRUE)
        {
            memset(informations_lues, 0, 256);
            status = ZwEnumerateKey(RegHandle,
                compteur_subkey,
                KeyBasicInformation,
                &informations_lues,
                256,
                &size_lue);
    
            if (status != STATUS_SUCCESS)
                break;
    
            RtlInitUnicodeString(&usRegistryKeySub,
                ((*(KEY_BASIC_INFORMATION*)&informations_lues).Name));
            DbgPrint("subkey is  %ws", usRegistryKeySub.Buffer);
    
            InitializeObjectAttributes(&obNomClefRegistreSub,
                &usRegistryKeySub,
                OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
                NULL,
                NULL);
    
            obNomClefRegistreSub.RootDirectory = RegHandle;
    
            status = ZwOpenKey(&RegHandleSub,
                KEY_READ,
                &obNomClefRegistreSub);
            if (status != STATUS_SUCCESS)
            {
                compteur_subkey++;
                dprintf("[niveau socket] !! ReadHostIPsFromRegistry : Echec d'ouverture du registre sur sous-clef
    ");
                continue;
            }
    
            memset(informations_lues, 0, 256);
            RtlInitUnicodeString(&usRegistryKey, ChaineEnableDHCP);
    
            status = ZwQueryValueKey(RegHandleSub,
                &usRegistryKey,
                KeyValueFullInformation,
                &informations_lues,
                256,
                &size_lue);
    
            if (status != STATUS_SUCCESS)
            {
                compteur_subkey++;
                dprintf("[niveau socket] !! ReadHostIPsFromRegistry : Echec lecture valeur EnableDHCP
    ");
                ZwClose(RegHandleSub);
                continue;
            }
    
            KeyValue = (KEY_VALUE_FULL_INFORMATION *)informations_lues;
            if (*(int*)(informations_lues + KeyValue->DataOffset))
            {
                RtlInitUnicodeString(&usRegistryKey, ChaineDhcpIPAddress);
            }
            else
            {
                RtlInitUnicodeString(&usRegistryKey, ChaineIPAddress);
            }
    
            memset(informations_lues, 0, 256);
            status = ZwQueryValueKey(RegHandleSub,
                &usRegistryKey,
                KeyValueFullInformation,
                &informations_lues,
                256,
                &size_lue);
            if (status != STATUS_SUCCESS)
            {
                compteur_subkey++;
                ZwClose(RegHandleSub);
                continue;
            }
    
            RtlZeroMemory(adresse_ip, 20);
            RtlInitUnicodeString(&CurrentName, informations_lues + KeyValue->DataOffset);
            RtlUnicodeStringToAnsiString(&AnsiString, &CurrentName, TRUE);
            RtlCopyMemory(adresse_ip, AnsiString.Buffer, 20);
    
            dprintf("HOST IP %s", adresse_ip);
    
            ZwClose(RegHandleSub);
    
            adresse = inet_addr(adresse_ip);
            if (adresse == 0)
            {
                compteur_subkey++;
                continue;
            }
            else
            {
                return adresse;
            }
        }
        ZwClose(RegHandle);
    
        return adresse;
    }
    
    //下面开始贴具体DNS请求过程的代码了
    //已经获取得到网络字节顺序
    PHOSTENT gethostbyname(IN char *name)
    {
        struct sockaddr_in  sockaddr_dns = { 0 };
        unsigned char* phostent_buf = NULL;
    
        if (global_pwsadata->serveur_dns == 0)
        {
            return NULL;
        }
    
        phostent_buf = ExAllocatePoolWithTag(0, 2048, 'doki');
        if (phostent_buf == NULL)
        {
            return NULL;
        }
        RtlZeroMemory(phostent_buf, 2048);
    
        sockaddr_dns.sin_family = AF_INET;
        sockaddr_dns.sin_addr.s_addr = global_pwsadata->serveur_dns;//DNS的主机地址
        sockaddr_dns.sin_port = HTONS(53);//dns 服务器固定端口
    
        if (query_dns(sockaddr_dns, name, phostent_buf, FALSE) != -1)
        {
            return (PHOSTENT)phostent_buf;
        }
        else
        {
            ExFreePool(phostent_buf);
            return NULL;
        }
    }
    
    int query_dns(IN  struct sockaddr_in sockaddr_dns,    
        IN  char* URL,    //www.DebugMan.com
        OUT char *hostent_buf,//返回的值
        IN  int rdns)//rdns 是否反向查询
    {
        struct sockaddr_in    sockaddr_bind = { 0 }; //干什么用的?
        int            com_socket = 0;
        NTSTATUS    status = STATUS_UNSUCCESSFUL;
    
        int size_string_requete_format_dns = 0;
        int size_string_requete = 0;
    
        unsigned char * buf = NULL;//需要构造的缓冲区
        unsigned char * reader;  //读取的位置指针
        DNS_HEADER      *    dns = NULL;
        int                size_buffer_dns = 0;// sendto must be know length of databuf
    
        char *                res_record_crawler = NULL;
        CUSTOM_RES_RECORD * res_record = NULL;
        unsigned int *        adresse_ip = NULL;
        int                    compteur_reponses = 0;
    
        PHOSTENT    hostent = NULL;
        char*        hostent_content = NULL;
        char**        hostent_array = NULL;//指向指针的指针
    
        unsigned char * qname = NULL;
        QUESTION *   qinfo = NULL;
    
        int lock = 0, i, j, k;
        int stop, lenthqname;
    
        struct sockaddr_in a;//便于记录读取的IP 
        struct RES_RECORD answers[20], auth[20], addit[20];  //the replies from the DNS server
    
        PUCHAR returnaddr;//指针
    
        int lenth = sizeof(DNS_HEADER);
    
        buf = ExAllocatePoolWithTag(0, 2048, 'doki');
        if (buf == NULL)
        {
            return NULL;
        }
        RtlZeroMemory(buf, 2048);
    
        /*
        +---------------------+
        | Header              |
        +---------------------+
        | Question            | the question for the name server
        +---------------------+
        | Answer              | RRs answering the question
        +---------------------+
        | Authority           | RRs pointing toward an authority
        +---------------------+
        | Additional          | RRs holding additional information
        +---------------------+
    
    
        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
        | ID                                            |
        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
        |QR| Opcode    |AA|TC|RD|RA| Z      |  RCODE    |
        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
        |                   QDCOUNT                     |
        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
        |                   ANCOUNT                     |
        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
        |                   NSCOUNT                     |
        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
        |                   ARCOUNT                     |
        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    
        */
        //1 Construction du message DNS 
        //buffer : DNS_HEADER | nom modifi?| QUESTION
        dns = (DNS_HEADER*)buf;
    
        dns->id = 1234;
    
        //Flags DNS
        dns->qr = 0; //This is a query
        dns->opcode = 0; //This is a standard query
        dns->aa = 0; //Not Authoritative
        dns->tc = 0; //This message is not truncated
        dns->rd = 1; //Recursion Desired
        dns->ra = 0; //Recursion not available! hey we dont have it (lol)
        dns->z = 0;
        dns->ad = 0;
        dns->cd = 0;
        dns->rcode = 0;
    
        dns->q_count = HTONS(1); //we have only 1 question
        dns->ans_count = 0;
        dns->auth_count = 0;
        dns->add_count = 0;
    
        //point to the query portion
        qname = (unsigned char*)&buf[sizeof(DNS_HEADER)];
        //www.google.com ==>> 3www6google3com  
        ChangetoDnsNameFormat(qname, URL);
    
        qinfo = (struct QUESTION*)&buf[sizeof(DNS_HEADER) + (strlen((const char*)qname) + 1)]; //fill it
    
        qinfo->qtype = HTONS(1);  //we are requesting the ipv4 address
        qinfo->qclass = HTONS(1); //its internet always is 1 
    
        size_buffer_dns = sizeof(DNS_HEADER) + strlen(qname) + 1 + sizeof(QUESTION);//33
    
        //com_socket = socket(AF_INET, SOCK_DGRAM ,IPPROTO_UDP);
        //udp 数据报查询
        com_socket = socket(2, 2, 17);
        if (com_socket == -1)
        {
            ExFreePool(buf);
            return -1;
        }
    
        status = sendto(com_socket, buf, size_buffer_dns, 0, &sockaddr_dns, sizeof(sockaddr_dns));
        if (status == -1)
        {
    
            ExFreePool(buf);
            status = close(com_socket);
            if (status == -1)
            {
                ;
            }
            return -1;
        }
    
        k = sizeof(sockaddr_dns);
    
        status = recvfrom(com_socket, buf, 1024 * 2, 0, &sockaddr_dns, &k);
        if (status == -1)
        {
            ExFreePool(buf);
            status = close(com_socket);
            if (status == -1)
            {
                ;
            }
            return -1;
        }
        dprintf("received ok 
     ");
    
        status = close(com_socket);
        if (status == -1)
        {
            return -1;
        }
    
    
        dns = (struct DNS_HEADER*)buf;
    
        if (dns->ans_count == 0)
        {
            ExFreePool(buf);
            return -1;
        }
        else
        {
            //http://www.codeproject.com/KB/IP/dns_query.aspx  如果你还不知道返回数据格式,可以参考这篇文章
            //move ahead of the dns header and the query field
            //从返回的数据开始读取,也就是去除自己的构造部分
            reader = &buf[sizeof(DNS_HEADER) + (strlen((const char*)qname) + 1) + sizeof(QUESTION)];
            dprintf("The response contains : 
    ");
            dprintf("%d Questions.
    ", ntohs(dns->q_count));
            dprintf("%d Answers.
    ", ntohs(dns->ans_count));
            dprintf("%d Authoritative Servers.
    ", ntohs(dns->auth_count));
            dprintf("%d Additional records.
    ", ntohs(dns->add_count));
    
            //reading answers
            stop = 0;
    
            for (i = 0;i<ntohs(dns->ans_count);i++)
            {
                answers[i].name = ReadName(reader, buf, &stop);
                reader = reader + stop;
                answers[i].resource = (struct R_DATA*)(reader);
                reader = reader + sizeof(struct R_DATA);
                if (ntohs(answers[i].resource->type) == 1) //if its an ipv4 address
                {
                    answers[i].rdata = (unsigned char*)malloc(ntohs(answers[i].resource->data_len));
                    for (j = 0; j<ntohs(answers[i].resource->data_len); j++)
                        answers[i].rdata[j] = reader[j];
                    answers[i].rdata[ntohs(answers[i].resource->data_len)] = '';
                    reader = reader + ntohs(answers[i].resource->data_len);
                }
                else
                {
                    answers[i].rdata = ReadName(reader, buf, &stop);
                    reader = reader + stop;
                }
            }
    
            //read authorities
            for (i = 0;i<ntohs(dns->auth_count);i++)
            {
                auth[i].name = ReadName(reader, buf, &stop);
                reader += stop;
    
                auth[i].resource = (struct R_DATA*)(reader);
                reader += sizeof(struct R_DATA);
    
                auth[i].rdata = ReadName(reader, buf, &stop);
                reader += stop;
            }
    
            //read additional
            for (i = 0;i<ntohs(dns->add_count);i++)
            {
                addit[i].name = ReadName(reader, buf, &stop);
                reader += stop;
    
                addit[i].resource = (struct R_DATA*)(reader);
                reader += sizeof(struct R_DATA);
    
                if (ntohs(addit[i].resource->type) == 1)
                {
                    addit[i].rdata = (unsigned char*)malloc(ntohs(addit[i].resource->data_len));
                    for (j = 0;j<ntohs(addit[i].resource->data_len);j++)
                        addit[i].rdata[j] = reader[j];
    
                    addit[i].rdata[ntohs(addit[i].resource->data_len)] = '';
                    reader += ntohs(addit[i].resource->data_len);
    
                }
                else
                {
                    addit[i].rdata = ReadName(reader, buf, &stop);
                    reader += stop;
                }
            }
    
    
            //print answers
            for (i = 0;i<ntohs(dns->ans_count);i++)
            {
                //printf("
    Answer : %d",i+1);
                dprintf("Name  :  %s ", answers[i].name);
    
                if (ntohs(answers[i].resource->type) == 1)   //IPv4 address
                {
                    long *p;
                    p = (long*)answers[i].rdata;
                    a.sin_addr.s_addr = (*p);    //working without ntohl
                    dprintf("has IPv4 address :  %x
    ", *p);
    
                    RtlCopyMemory(&(global_pwsadata->urladdr), p, 4); //保存在全局变量中
    
                    returnaddr = ExAllocatePoolWithTag(0, 16, 'doki');
                    if (returnaddr == NULL)
                    {
                        return NULL;
                    }
    
                    RtlZeroMemory(returnaddr, 16);
                    RtlCopyMemory(returnaddr, inet_ntoa(a.sin_addr), 16);
                    dprintf("has IPv4 address :  %s
    ", returnaddr[i]);
    
                    ExFreePool(returnaddr);
                }
                if (ntohs(answers[i].resource->type) == 5)   //Canonical name for an alias
                    dprintf("has alias name : %s
    ", answers[i].rdata);
                dprintf("
    ");
            }
    
            //print authorities
            for (i = 0;i<ntohs(dns->auth_count);i++)
            {
                //printf("
    Authorities : %d",i+1);
                dprintf("Name  :  %s ", auth[i].name);
                if (ntohs(auth[i].resource->type) == 2)
                    dprintf("has authoritative nameserver : %s", auth[i].rdata);
                dprintf("
    ");
            }
    
            //print additional resource records
            for (i = 0;i<ntohs(dns->add_count);i++)
            {
                //printf("
    Additional : %d",i+1);
                dprintf("Name  :  %s ", addit[i].name);
                if (ntohs(addit[i].resource->type) == 1)
                {
                    long *p;
                    p = (long*)addit[i].rdata;
                    a.sin_addr.s_addr = (*p);    //working without ntohl
                    dprintf("has IPv4 address :  %s", inet_ntoa(a.sin_addr));
                }
                dprintf("
    ");
            }
    
    
        }
    
        ExFreePool(buf);
    
        return 0;
    }
    
    
    unsigned char* ReadName(unsigned char* reader, unsigned char* buffer, int* count)
    {
        unsigned char *name;
        unsigned int p = 0, jumped = 0, offset;
        int i, j;
    
        *count = 1;
        name = (unsigned char*)malloc(256);
    
        name[0] = '';
    
        //read the names in 3www6google3com format
        while (*reader != 0)
        {
            if (*reader >= 192)
            {
                offset = (*reader) * 256 + *(reader + 1) - 49152; //49152 = 11000000 00000000  ;)
                reader = buffer + offset - 1;
                jumped = 1;  //we have jumped to another location so counting wont go up!
            }
            else
                name[p++] = *reader;
    
            reader = reader + 1;
    
            if (jumped == 0) *count = *count + 1; //if we havent jumped to another location then we can count up
        }
    
        name[p] = '';    //string complete
        if (jumped == 1) *count = *count + 1;  //number of steps we actually moved forward in the packet
    
        ChangefromDnsNameFormat(name);
    
        return name;
    }
    PVOID malloc(int size)
    {
        return ExAllocatePoolWithTag(0, size, 'doki');//分配内部缓冲区
    }
    
    //this will convert www.google.com to 3www6google3com ;got it :)
    void ChangetoDnsNameFormat(unsigned char* dns, unsigned char* host)
    {
        int lock = 0, i;
    
        strcat((char*)host, ".");
    
        for (i = 0;i<(int)strlen((char*)host);i++)
        {
            if (host[i] == '.')
            {
                *dns++ = i - lock;
                for (;lock<i;lock++)
                {
                    *dns++ = host[lock];
                }
                lock++; //or lock=i+1;
            }
        }
        *dns++ = '';
    }
    //this will convert 3www6google3com to www.google.com ;got it :)
    void ChangefromDnsNameFormat(unsigned char* name)
    {
        int i, j;
        char p;
    
        //now convert 3www6google3com0 to www.google.com
        for (i = 0;i<(int)strlen((const char*)name);i++)
        {
            p = name[i];
            for (j = 0;j<(int)p;j++)
            {
                name[i] = name[i + 1];
                i = i + 1;
            }
            name[i] = '.';
        }
        name[i - 1] = '';      //remove the last dot
    }
    
    int __cdecl bind(int socket, const struct sockaddr *addr, int addrlen)
    {
        PSOCKET s = (PSOCKET)-socket;
        const struct sockaddr_in* localAddr = (const struct sockaddr_in*) addr;
        UNICODE_STRING devName;
        NTSTATUS status;
    
        if (s->isBound || addr == NULL || addrlen < sizeof(struct sockaddr_in))
        {
            return -1;
        }
    
        if (s->type == SOCK_DGRAM)
        {
            RtlInitUnicodeString(&devName, L"\Device\Udp");
        }
        else if (s->type == SOCK_STREAM)
        {
            RtlInitUnicodeString(&devName, L"\Device\Tcp");
        }
        else
        {
            return -1;
        }
    
        status = tdi_open_transport_address(
            &devName,
            localAddr->sin_addr.s_addr,
            localAddr->sin_port,
            s->isShared,
            &s->addressHandle,
            &s->addressFileObject
        );  
    
        if (!NT_SUCCESS(status))
        {
            s->addressFileObject = NULL;
            s->addressHandle = (HANDLE)-1;
            return status;
        }
    
        if (s->type == SOCK_STREAM)
        {
            tdi_set_event_handler(s->addressFileObject, TDI_EVENT_DISCONNECT, event_disconnect, s);
        }
    
        s->isBound = TRUE;
    
        return 0;
    }
    NTSTATUS event_disconnect(PVOID TdiEventContext, CONNECTION_CONTEXT ConnectionContext, LONG DisconnectDataLength,
        PVOID DisconnectData, LONG DisconnectInformationLength, PVOID DisconnectInformation,
        ULONG DisconnectFlags)
    {
        PSOCKET s = (PSOCKET)TdiEventContext;
        PSTREAM_SOCKET streamSocket = (PSTREAM_SOCKET)ConnectionContext;
        KeSetEvent(&streamSocket->disconnectEvent, 0, FALSE);
        return STATUS_SUCCESS;
    }
    
    NTSTATUS tdi_set_event_handler(PFILE_OBJECT addressFileObject, LONG eventType, PVOID eventHandler, PVOID eventContext)
    {
        PDEVICE_OBJECT  devObj;
        KEVENT          event;
        PIRP            irp;
        IO_STATUS_BLOCK iosb;
        NTSTATUS        status;
    
        devObj = IoGetRelatedDeviceObject(addressFileObject);
    
        KeInitializeEvent(&event, NotificationEvent, FALSE);
    
        irp = TdiBuildInternalDeviceControlIrp(TDI_SET_EVENT_HANDLER, devObj, addressFileObject, &event, &iosb);
    
        if (irp == NULL)
        {
            return STATUS_INSUFFICIENT_RESOURCES;
        }
    
        TdiBuildSetEventHandler(irp, devObj, addressFileObject, NULL, NULL, eventType, eventHandler, eventContext);
    
        status = IoCallDriver(devObj, irp);
    
        if (status == STATUS_PENDING)
        {
            KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
            status = iosb.Status;
        }
    
        return status;
    }
    
    
    int __cdecl close(int socket)
    {
        PSOCKET s = (PSOCKET)-socket;
    
        if (s->isBound)
        {
            if (s->type == SOCK_STREAM && s->streamSocket)
            {
                if (s->isConnected)
                {
                    if (!s->isShuttingdown)
                    {
                        tdi_disconnect(s->streamSocket->connectionFileObject, TDI_DISCONNECT_RELEASE);
                    }
                    KeWaitForSingleObject(&s->streamSocket->disconnectEvent, Executive, KernelMode, FALSE, NULL);
                }
                if (s->streamSocket->connectionFileObject)
                {
                    tdi_disassociate_address(s->streamSocket->connectionFileObject);
                    ObDereferenceObject(s->streamSocket->connectionFileObject);
                }
                if (s->streamSocket->connectionHandle != (HANDLE)-1)
                {
                    ZwClose(s->streamSocket->connectionHandle);
                }
                ExFreePool(s->streamSocket);
            }
    
            if (s->type == SOCK_DGRAM || s->type == SOCK_STREAM)
            {
                ObDereferenceObject(s->addressFileObject);
                if (s->addressHandle != (HANDLE)-1)
                {
                    ZwClose(s->addressHandle);
                }
            }
        }
    
        ExFreePool(s);
    
        return 0;
    }
    
    NTSTATUS tdi_disconnect(PFILE_OBJECT connectionFileObject, ULONG flags)
    {
        PDEVICE_OBJECT  devObj;
        KEVENT          event;
        PIRP            irp;
        IO_STATUS_BLOCK iosb;
        NTSTATUS        status;
    
        devObj = IoGetRelatedDeviceObject(connectionFileObject);
    
        KeInitializeEvent(&event, NotificationEvent, FALSE);
    
        irp = TdiBuildInternalDeviceControlIrp(TDI_DISCONNECT, devObj, connectionFileObject, &event, &iosb);
    
        if (irp == NULL)
        {
            return STATUS_INSUFFICIENT_RESOURCES;
        }
    
        TdiBuildDisconnect(irp, devObj, connectionFileObject, NULL, NULL, NULL, flags, NULL, NULL);
    
        status = IoCallDriver(devObj, irp);
    
        if (status == STATUS_PENDING)
        {
            KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
            status = iosb.Status;
        }
    
        return status;
    }
    NTSTATUS tdi_disassociate_address(PFILE_OBJECT connectionFileObject)
    {
        PDEVICE_OBJECT  devObj;
        KEVENT          event;
        PIRP            irp;
        IO_STATUS_BLOCK iosb;
        NTSTATUS        status;
    
        devObj = IoGetRelatedDeviceObject(connectionFileObject);
    
        KeInitializeEvent(&event, NotificationEvent, FALSE);
    
        irp = TdiBuildInternalDeviceControlIrp(TDI_DISASSOCIATE_ADDRESS, devObj, connectionFileObject, &event, &iosb);
    
        if (irp == NULL)
        {
            return STATUS_INSUFFICIENT_RESOURCES;
        }
    
        TdiBuildDisassociateAddress(irp, devObj, connectionFileObject, NULL, NULL);
    
        status = IoCallDriver(devObj, irp);
    
        if (status == STATUS_PENDING)
        {
            KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
            status = iosb.Status;
        }
    
        return status;
    }
    
    NTSTATUS tdi_open_transport_address(PUNICODE_STRING devName, ULONG addr, USHORT port, int shared, PHANDLE addressHandle, PFILE_OBJECT *addressFileObject)
    {
        OBJECT_ATTRIBUTES           attr;
        PFILE_FULL_EA_INFORMATION   eaBuffer;
        ULONG                       eaSize;
        PTA_IP_ADDRESS              localAddr;
        IO_STATUS_BLOCK             iosb;
        NTSTATUS                    status;
    
    #if (VER_PRODUCTBUILD >= 2195)
        InitializeObjectAttributes(&attr, devName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
    #else
        InitializeObjectAttributes(&attr, devName, OBJ_CASE_INSENSITIVE, NULL, NULL);
    #endif
    
        eaSize = FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]) +
            TDI_TRANSPORT_ADDRESS_LENGTH +
            1 +
            sizeof(TA_IP_ADDRESS);
    
        eaBuffer = (PFILE_FULL_EA_INFORMATION)ExAllocatePool(PagedPool, eaSize);
    
        if (eaBuffer == NULL)
        {
            return STATUS_INSUFFICIENT_RESOURCES;
        }
    
        eaBuffer->NextEntryOffset = 0;
        eaBuffer->Flags = 0;
        eaBuffer->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
        eaBuffer->EaValueLength = sizeof(TA_IP_ADDRESS);
    
        RtlCopyMemory(eaBuffer->EaName, TdiTransportAddress, eaBuffer->EaNameLength + 1);
    
        localAddr = (PTA_IP_ADDRESS)(eaBuffer->EaName + eaBuffer->EaNameLength + 1);
    
        localAddr->TAAddressCount = 1;
        localAddr->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
        localAddr->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
        localAddr->Address[0].Address[0].sin_port = port;
        localAddr->Address[0].Address[0].in_addr = addr;
    
        RtlZeroMemory(localAddr->Address[0].Address[0].sin_zero, sizeof(localAddr->Address[0].Address[0].sin_zero));
    
        status = ZwCreateFile(
            addressHandle,
            GENERIC_READ | GENERIC_WRITE,
            &attr,
            &iosb,
            NULL,
            FILE_ATTRIBUTE_NORMAL,
            shared ? FILE_SHARE_READ | FILE_SHARE_WRITE : 0,
            FILE_OPEN,
            0,
            eaBuffer,
            eaSize
        );
    
        ExFreePool(eaBuffer);
    
        if (!NT_SUCCESS(status))
        {
            return status;
        }
    
        status = ObReferenceObjectByHandle(*addressHandle, FILE_ALL_ACCESS, NULL, KernelMode, addressFileObject, NULL);
    
        if (!NT_SUCCESS(status))
        {
            ZwClose(*addressHandle);
            return status;
        }
    
        return STATUS_SUCCESS;
    }
    NTSTATUS tdi_send_dgram(PFILE_OBJECT addressFileObject, ULONG addr, USHORT port, const char *buf, int len)
    {
        PDEVICE_OBJECT              devObj;
        KEVENT                      event;
        PTDI_CONNECTION_INFORMATION remoteInfo;
        PTA_IP_ADDRESS              remoteAddr;
        PIRP                        irp;
        PMDL                        mdl;
        IO_STATUS_BLOCK             iosb;
        NTSTATUS                    status;
    
        devObj = IoGetRelatedDeviceObject(addressFileObject);
    
        KeInitializeEvent(&event, NotificationEvent, FALSE);
    
        remoteInfo = (PTDI_CONNECTION_INFORMATION)ExAllocatePool(NonPagedPool, sizeof(TDI_CONNECTION_INFORMATION) + sizeof(TA_IP_ADDRESS));
    
        if (remoteInfo == NULL)
        {
            return STATUS_INSUFFICIENT_RESOURCES;
        }
    
        RtlZeroMemory(remoteInfo, sizeof(TDI_CONNECTION_INFORMATION) + sizeof(TA_IP_ADDRESS));
    
        remoteInfo->RemoteAddressLength = sizeof(TA_IP_ADDRESS);
        remoteInfo->RemoteAddress = (PUCHAR)remoteInfo + sizeof(TDI_CONNECTION_INFORMATION);
    
        remoteAddr = (PTA_IP_ADDRESS)remoteInfo->RemoteAddress;
    
        remoteAddr->TAAddressCount = 1;
        remoteAddr->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
        remoteAddr->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
        remoteAddr->Address[0].Address[0].sin_port = port;
        remoteAddr->Address[0].Address[0].in_addr = addr;
    
        irp = TdiBuildInternalDeviceControlIrp(TDI_SEND_DATAGRAM, devObj, addressFileObject, &event, &iosb);
    
        if (irp == NULL)
        {
            ExFreePool(remoteInfo);
            return STATUS_INSUFFICIENT_RESOURCES;
        }
    
        if (len)
        {
            mdl = IoAllocateMdl((void*)buf, len, FALSE, FALSE, NULL);
    
            if (mdl == NULL)
            {
                IoFreeIrp(irp);
                ExFreePool(remoteInfo);
                return STATUS_INSUFFICIENT_RESOURCES;
            }
    
            __try
            {
                MmProbeAndLockPages(mdl, KernelMode, IoReadAccess);
                status = STATUS_SUCCESS;
            }
            __except (EXCEPTION_EXECUTE_HANDLER)
            {
                IoFreeMdl(mdl);
                IoFreeIrp(irp);
                ExFreePool(remoteInfo);
                status = STATUS_INVALID_USER_BUFFER;
            }
    
            if (!NT_SUCCESS(status))
            {
                return status;
            }
        }
    
        TdiBuildSendDatagram(irp, devObj, addressFileObject, NULL, NULL, len ? mdl : 0, len, remoteInfo);
    
        status = IoCallDriver(devObj, irp);
    
        if (status == STATUS_PENDING)
        {
            KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
            status = iosb.Status;
        }
    
        ExFreePool(remoteInfo);
    
        return NT_SUCCESS(status) ? iosb.Information : status;
    }
    int __cdecl sendto(int socket, const char *buf, int len, int flags, const struct sockaddr *addr, int addrlen)
    {
        {
            PSOCKET s = (PSOCKET)-socket;
            const struct sockaddr_in* remoteAddr = (const struct sockaddr_in*) addr;
            struct  sockaddr_in localAddr;
            NTSTATUS status;
    
            /*
            if (s->type == SOCK_STREAM)
            {
            return send(socket, buf, len, flags);
            }
            */
            // else 
            if (s->type == SOCK_DGRAM)
            {
                if (addr == NULL || addrlen < sizeof(struct sockaddr_in))
                {
                    return -1;
                }
    
                if (!s->isBound)
                {
                    struct sockaddr_in localAddr;
                    NTSTATUS status;  //定义在前面
    
                    localAddr.sin_family = AF_INET;//2
                    localAddr.sin_port = 0;
                    localAddr.sin_addr.s_addr = ReadHostIPsFromRegistry();
    
                    status = bind(socket, (struct sockaddr*) &localAddr, sizeof(localAddr));
    
                    if (!NT_SUCCESS(status))
                    {
                        return status;
                    }
                }
    
                return tdi_send_dgram(
                    s->addressFileObject,
                    remoteAddr->sin_addr.s_addr,
                    remoteAddr->sin_port,
                    buf,
                    len);
            }
            else
            {
                return -1;
            }
        }
    
    }
    
    
        char * inet_ntoa(IN  struct in_addr  in)
        {
            PUCHAR p;
            UCHAR buffer[20];
            PUCHAR b;
    
            //
            // A number of applications apparently depend on calling inet_ntoa()
            // without first calling WSAStartup(). Because of this, we must perform
            // our own explicit thread initialization check here.
            //
    
            b = buffer;
    
            //
            // In an unrolled loop, calculate the string value for each of the four
            // bytes in an IP address.  Note that for values less than 100 we will
            // do one or two extra assignments, but we save a test/jump with this
            // algorithm.
            //
    
            p = (PUCHAR)&in;
    
            *b = NToACharStrings[*p][0];
            *(b + 1) = NToACharStrings[*p][1];
            *(b + 2) = NToACharStrings[*p][2];
            b += NToACharStrings[*p][3];
            *b++ = '.';
    
            p++;
            *b = NToACharStrings[*p][0];
            *(b + 1) = NToACharStrings[*p][1];
            *(b + 2) = NToACharStrings[*p][2];
            b += NToACharStrings[*p][3];
            *b++ = '.';
    
            p++;
            *b = NToACharStrings[*p][0];
            *(b + 1) = NToACharStrings[*p][1];
            *(b + 2) = NToACharStrings[*p][2];
            b += NToACharStrings[*p][3];
            *b++ = '.';
    
            p++;
            *b = NToACharStrings[*p][0];
            *(b + 1) = NToACharStrings[*p][1];
            *(b + 2) = NToACharStrings[*p][2];
            b += NToACharStrings[*p][3];
            *b = '';
            dprintf("buffer %s 
    ", buffer);//注意打印buffer
            return(buffer);
        }
    
        /*
        * Internet address interpretation routine.
        * All the network library routines call this
        * routine to interpret entries in the data bases
        * which are expected to be an address.
        * The value returned is in network order.
        */
        unsigned long
            inet_addr(
                IN const char *cp
            )
        {
            register unsigned long val, base, n;
            register char c;
            unsigned long parts[4], *pp = parts;
    
            // WS_ENTER( "inet_addr", (PVOID)cp, NULL, NULL, NULL );
        again:
            /*
            * Collect number up to ``.''.
            * Values are specified as for C:
            * 0x=hex, 0=octal, other=decimal.
            */
            val = 0; base = 10;
            if (*cp == '0') {
                base = 8, cp++;
                if (*cp == 'x' || *cp == 'X')
                    base = 16, cp++;
            }
    
            while (c = *cp) {
                if (isdigit(c)) {
                    val = (val * base) + (c - '0');
                    cp++;
                    continue;
                }
                if (base == 16 && isxdigit(c)) {
                    val = (val << 4) + (c + 10 - (islower(c) ? 'a' : 'A'));
                    cp++;
                    continue;
                }
                break;
            }
            if (*cp == '.') {
                /*
                * Internet format:
                *      a.b.c.d
                *      a.b.c   (with c treated as 16-bits)
                *      a.b     (with b treated as 24 bits)
                */
                /* GSS - next line was corrected on 8/5/89, was 'parts + 4' */
                if (pp >= parts + 3) {
                    //WS_EXIT( "inet_addr", -1, TRUE );
                    return ((unsigned long)-1);
                }
                *pp++ = val, cp++;
                goto again;
            }
            /*
            * Check for trailing characters.
            */
            if (*cp && !isspace(*cp)) {
                // WS_EXIT( "inet_addr", -1, TRUE );
                return (INADDR_NONE);
            }
            *pp++ = val;
            /*
            * Concoct the address according to
            * the number of parts specified.
            */
            n = (unsigned long)(pp - parts);
            switch ((int)n) {
    
            case 1:                         /* a -- 32 bits */
                val = parts[0];
                break;
    
            case 2:                         /* a.b -- 8.24 bits */
                if ((parts[0] > 0xff) || (parts[1] > 0xffffff)) {
                    //WS_EXIT( "inet_addr", -1, TRUE );
                    return(INADDR_NONE);
                }
                val = (parts[0] << 24) | (parts[1] & 0xffffff);
                break;
    
            case 3:                         /* a.b.c -- 8.8.16 bits */
                if ((parts[0] > 0xff) || (parts[1] > 0xff) ||
                    (parts[2] > 0xffff)) {
                    //WS_EXIT( "inet_addr", -1, TRUE );
                    return(INADDR_NONE);
                }
                val = (parts[0] << 24) | ((parts[1] & 0xff) << 16) |
                    (parts[2] & 0xffff);
                break;
    
            case 4:                         /* a.b.c.d -- 8.8.8.8 bits */
                if ((parts[0] > 0xff) || (parts[1] > 0xff) ||
                    (parts[2] > 0xff) || (parts[3] > 0xff)) {
                    // WS_EXIT( "inet_addr", -1, TRUE );
                    return(INADDR_NONE);
                }
                val = (parts[0] << 24) | ((parts[1] & 0xff) << 16) |
                    ((parts[2] & 0xff) << 8) | (parts[3] & 0xff);
                break;
    
            default:
                //WS_EXIT( "inet_addr", -1, TRUE );
                return (INADDR_NONE);
            }
            val = htonl(val);
            // WS_EXIT( "inet_addr", val, FALSE );
            return (val);
        }
    
    
        //com_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);//udp 数据报查询
        int __cdecl socket(int af, int type, int protocol)
        {
            PSOCKET s;
    
            if (af != AF_INET ||
                (type != SOCK_DGRAM && type != SOCK_STREAM) ||
                (type == SOCK_DGRAM && protocol != IPPROTO_UDP && protocol != 0) ||
                (type == SOCK_STREAM && protocol != IPPROTO_TCP && protocol != 0)
                )
            {
                return STATUS_INVALID_PARAMETER;
            }
    
            s = (PSOCKET)ExAllocatePool(NonPagedPool, sizeof(SOCKET));
    
            if (!s)
            {
                return STATUS_INSUFFICIENT_RESOURCES;
            }
    
            RtlZeroMemory(s, sizeof(SOCKET));
    
            s->type = type;
            s->addressHandle = (HANDLE)-1;
            //自己添加一行
            s->isBound = FALSE;
            return -(int)s;
        }
    
    
    
        int __cdecl recvfrom(int socket, char *buf, int len, int flags, struct sockaddr *addr, int *addrlen)
        {
            PSOCKET s = (PSOCKET)-socket;
            struct sockaddr_in* returnAddr = (struct sockaddr_in*) addr;
            /*
            if (s->type == SOCK_STREAM)
            {
            return recv(socket, buf, len, flags);
            }
            */
            //    else
            if (s->type == SOCK_DGRAM)
            {
                u_long* sin_addr = 0;
                u_short* sin_port = 0;
    
                if (!s->isBound)
                {
                    return -1;
                }
    
                if (addr != NULL && addrlen != NULL && *addrlen >= sizeof(struct sockaddr_in))
                {
                    sin_addr = &returnAddr->sin_addr.s_addr;
                    sin_port = &returnAddr->sin_port;
                    *addrlen = sizeof(struct sockaddr_in);
                }
    
                return tdi_recv_dgram(
                    s->addressFileObject,
                    sin_addr,
                    sin_port,
                    buf,
                    len,
                    TDI_RECEIVE_NORMAL
                );
            }
            else
            {
                return -1;
            }
        }
    
        NTSTATUS tdi_recv_dgram(PFILE_OBJECT addressFileObject, PULONG addr, PUSHORT port, char *buf, int len, ULONG flags)
        {
            PDEVICE_OBJECT              devObj;
            KEVENT                      event;
            PTDI_CONNECTION_INFORMATION remoteInfo;
            PTDI_CONNECTION_INFORMATION returnInfo;
            PTA_IP_ADDRESS              returnAddr;
            PIRP                        irp;
            PMDL                        mdl;
            IO_STATUS_BLOCK             iosb;
            NTSTATUS                    status;
    
            devObj = IoGetRelatedDeviceObject(addressFileObject);
    
            KeInitializeEvent(&event, NotificationEvent, FALSE);
    
            remoteInfo = (PTDI_CONNECTION_INFORMATION)ExAllocatePool(NonPagedPool, 2 * sizeof(TDI_CONNECTION_INFORMATION) + sizeof(TA_IP_ADDRESS));
    
            if (remoteInfo == NULL)
            {
                return STATUS_INSUFFICIENT_RESOURCES;
            }
    
            RtlZeroMemory(remoteInfo, 2 * sizeof(TDI_CONNECTION_INFORMATION) + sizeof(TA_IP_ADDRESS));
    
            remoteInfo->RemoteAddressLength = 0;
            remoteInfo->RemoteAddress = NULL;
    
            returnInfo = (PTDI_CONNECTION_INFORMATION)((PUCHAR)remoteInfo + sizeof(TDI_CONNECTION_INFORMATION));
    
            returnInfo->RemoteAddressLength = sizeof(TA_IP_ADDRESS);
            returnInfo->RemoteAddress = (PUCHAR)returnInfo + sizeof(TDI_CONNECTION_INFORMATION);
    
            returnAddr = (PTA_IP_ADDRESS)returnInfo->RemoteAddress;
    
            returnAddr->TAAddressCount = 1;
            returnAddr->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
            returnAddr->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
    
            irp = TdiBuildInternalDeviceControlIrp(TDI_RECEIVE_DATAGRAM, devObj, addressFileObject, &event, &iosb);
    
            if (irp == NULL)
            {
                ExFreePool(remoteInfo);
                return STATUS_INSUFFICIENT_RESOURCES;
            }
    
            if (len)
            {
                mdl = IoAllocateMdl((void*)buf, len, FALSE, FALSE, NULL);
    
                if (mdl == NULL)
                {
                    IoFreeIrp(irp);
                    ExFreePool(remoteInfo);
                    return STATUS_INSUFFICIENT_RESOURCES;
                }
    
                __try
                {
                    MmProbeAndLockPages(mdl, KernelMode, IoWriteAccess);
                    status = STATUS_SUCCESS;
                }
                __except (EXCEPTION_EXECUTE_HANDLER)
                {
                    IoFreeMdl(mdl);
                    IoFreeIrp(irp);
                    ExFreePool(remoteInfo);
                    status = STATUS_INVALID_USER_BUFFER;
                }
    
                if (!NT_SUCCESS(status))
                {
                    return status;
                }
            }
    
            TdiBuildReceiveDatagram(irp, devObj, addressFileObject, NULL, NULL, len ? mdl : 0, len, remoteInfo, returnInfo, flags);
    
            status = IoCallDriver(devObj, irp);
    
            if (status == STATUS_PENDING)
            {
                KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
                status = iosb.Status;
            }
    
            if (addr)
            {
                *addr = returnAddr->Address[0].Address[0].in_addr;
            }
    
            if (port)
            {
                *port = returnAddr->Address[0].Address[0].sin_port;
            }
    
            ExFreePool(remoteInfo);
    
            return NT_SUCCESS(status) ? iosb.Information : status;
        }
    
        ///////////////////////////////   END OF FILE   ///////////////////////////////
    
    
    
    
    
    
    
    
    
    
    #pragma once
    
    
    
    #ifndef _HELLO_H
    #define _HELLO_H 1
    
    
    #include <ntifs.h>
    
    #include <ntddk.h>
    #include <tdikrnl.h>
    //#define PF_INET   TDI_ADDRESS_TYPE_IP
    #define AF_INET   2
    
    #define SOCK_STREAM 1 //TCP
    #define SOCK_DGRAM  2 //UDP
    #define SOCK_RAW   3 //RAW  是winsock.h中定义的
    
    #define IPPROTO_ICMP        1
    #define IPPROTO_TCP         6
    #define IPPROTO_UDP         17
    
    
    #define TDI_MAX_SOCKET   256
    #define TDI_MAX_BACKLOG 20
    
    #define TDI_TCP_DEVICE_NAME_W   L"\Device\Tcp"
    #define TDI_UDP_DEVICE_NAME_W L"\Device\Udp"
    #define TDI_RAW_DEVICE_NAME_W L"\Device\RawIp"
    
    #define TDI_TIMEOUT_CONNECT_SEC   60
    #define TDI_TIMEOUT_DISCONNECT_SEC 60
    #define TDI_TIMEOUT_COMMUNICATION 60
    
    
    #define SOCKET_STATUS_CLEAR     0
    #define SOCKET_STATUS_ALLOCATED    1
    #define SOCKET_STATUS_TRANSPORT    2
    #define SOCKET_STATUS_CONNECTION    3
    #define SOCKET_STATUS_CON_AND_TRANS   4
    #define SOCKET_STATUS_ASSOCIATED    5
    #define SOCKET_STATUS_LISTEN     6
    #define SOCKET_STATUS_WAITING_INBOUND 7 
    #define SOCKET_STATUS_DISCONNECTED   8
    #define SOCKET_STATUS_CONNECTED    9
    #define SOCKET_STATUS_CHANGING    10
    
    
    #define WSA_NOT_ENOUGH_MEMORY     8
    #define WSAEMFILE        10024 
    #define WSAEPROTOTYPE       10041 
    #define WSAEPROTONOSUPPORT     10043 
    #define WSAESHUTDOWN       10058
    #define WSANO_DATA        11004
    
    unsigned char NToACharStrings[][4] = {
        '0', 'x', 'x', 1,
        '1', 'x', 'x', 1,
        '2', 'x', 'x', 1,
        '3', 'x', 'x', 1,
        '4', 'x', 'x', 1,
        '5', 'x', 'x', 1,
        '6', 'x', 'x', 1,
        '7', 'x', 'x', 1,
        '8', 'x', 'x', 1,
        '9', 'x', 'x', 1,
        '1', '0', 'x', 2,
        '1', '1', 'x', 2,
        '1', '2', 'x', 2,
        '1', '3', 'x', 2,
        '1', '4', 'x', 2,
        '1', '5', 'x', 2,
        '1', '6', 'x', 2,
        '1', '7', 'x', 2,
        '1', '8', 'x', 2,
        '1', '9', 'x', 2,
        '2', '0', 'x', 2,
        '2', '1', 'x', 2,
        '2', '2', 'x', 2,
        '2', '3', 'x', 2,
        '2', '4', 'x', 2,
        '2', '5', 'x', 2,
        '2', '6', 'x', 2,
        '2', '7', 'x', 2,
        '2', '8', 'x', 2,
        '2', '9', 'x', 2,
        '3', '0', 'x', 2,
        '3', '1', 'x', 2,
        '3', '2', 'x', 2,
        '3', '3', 'x', 2,
        '3', '4', 'x', 2,
        '3', '5', 'x', 2,
        '3', '6', 'x', 2,
        '3', '7', 'x', 2,
        '3', '8', 'x', 2,
        '3', '9', 'x', 2,
        '4', '0', 'x', 2,
        '4', '1', 'x', 2,
        '4', '2', 'x', 2,
        '4', '3', 'x', 2,
        '4', '4', 'x', 2,
        '4', '5', 'x', 2,
        '4', '6', 'x', 2,
        '4', '7', 'x', 2,
        '4', '8', 'x', 2,
        '4', '9', 'x', 2,
        '5', '0', 'x', 2,
        '5', '1', 'x', 2,
        '5', '2', 'x', 2,
        '5', '3', 'x', 2,
        '5', '4', 'x', 2,
        '5', '5', 'x', 2,
        '5', '6', 'x', 2,
        '5', '7', 'x', 2,
        '5', '8', 'x', 2,
        '5', '9', 'x', 2,
        '6', '0', 'x', 2,
        '6', '1', 'x', 2,
        '6', '2', 'x', 2,
        '6', '3', 'x', 2,
        '6', '4', 'x', 2,
        '6', '5', 'x', 2,
        '6', '6', 'x', 2,
        '6', '7', 'x', 2,
        '6', '8', 'x', 2,
        '6', '9', 'x', 2,
        '7', '0', 'x', 2,
        '7', '1', 'x', 2,
        '7', '2', 'x', 2,
        '7', '3', 'x', 2,
        '7', '4', 'x', 2,
        '7', '5', 'x', 2,
        '7', '6', 'x', 2,
        '7', '7', 'x', 2,
        '7', '8', 'x', 2,
        '7', '9', 'x', 2,
        '8', '0', 'x', 2,
        '8', '1', 'x', 2,
        '8', '2', 'x', 2,
        '8', '3', 'x', 2,
        '8', '4', 'x', 2,
        '8', '5', 'x', 2,
        '8', '6', 'x', 2,
        '8', '7', 'x', 2,
        '8', '8', 'x', 2,
        '8', '9', 'x', 2,
        '9', '0', 'x', 2,
        '9', '1', 'x', 2,
        '9', '2', 'x', 2,
        '9', '3', 'x', 2,
        '9', '4', 'x', 2,
        '9', '5', 'x', 2,
        '9', '6', 'x', 2,
        '9', '7', 'x', 2,
        '9', '8', 'x', 2,
        '9', '9', 'x', 2,
        '1', '0', '0', 3,
        '1', '0', '1', 3,
        '1', '0', '2', 3,
        '1', '0', '3', 3,
        '1', '0', '4', 3,
        '1', '0', '5', 3,
        '1', '0', '6', 3,
        '1', '0', '7', 3,
        '1', '0', '8', 3,
        '1', '0', '9', 3,
        '1', '1', '0', 3,
        '1', '1', '1', 3,
        '1', '1', '2', 3,
        '1', '1', '3', 3,
        '1', '1', '4', 3,
        '1', '1', '5', 3,
        '1', '1', '6', 3,
        '1', '1', '7', 3,
        '1', '1', '8', 3,
        '1', '1', '9', 3,
        '1', '2', '0', 3,
        '1', '2', '1', 3,
        '1', '2', '2', 3,
        '1', '2', '3', 3,
        '1', '2', '4', 3,
        '1', '2', '5', 3,
        '1', '2', '6', 3,
        '1', '2', '7', 3,
        '1', '2', '8', 3,
        '1', '2', '9', 3,
        '1', '3', '0', 3,
        '1', '3', '1', 3,
        '1', '3', '2', 3,
        '1', '3', '3', 3,
        '1', '3', '4', 3,
        '1', '3', '5', 3,
        '1', '3', '6', 3,
        '1', '3', '7', 3,
        '1', '3', '8', 3,
        '1', '3', '9', 3,
        '1', '4', '0', 3,
        '1', '4', '1', 3,
        '1', '4', '2', 3,
        '1', '4', '3', 3,
        '1', '4', '4', 3,
        '1', '4', '5', 3,
        '1', '4', '6', 3,
        '1', '4', '7', 3,
        '1', '4', '8', 3,
        '1', '4', '9', 3,
        '1', '5', '0', 3,
        '1', '5', '1', 3,
        '1', '5', '2', 3,
        '1', '5', '3', 3,
        '1', '5', '4', 3,
        '1', '5', '5', 3,
        '1', '5', '6', 3,
        '1', '5', '7', 3,
        '1', '5', '8', 3,
        '1', '5', '9', 3,
        '1', '6', '0', 3,
        '1', '6', '1', 3,
        '1', '6', '2', 3,
        '1', '6', '3', 3,
        '1', '6', '4', 3,
        '1', '6', '5', 3,
        '1', '6', '6', 3,
        '1', '6', '7', 3,
        '1', '6', '8', 3,
        '1', '6', '9', 3,
        '1', '7', '0', 3,
        '1', '7', '1', 3,
        '1', '7', '2', 3,
        '1', '7', '3', 3,
        '1', '7', '4', 3,
        '1', '7', '5', 3,
        '1', '7', '6', 3,
        '1', '7', '7', 3,
        '1', '7', '8', 3,
        '1', '7', '9', 3,
        '1', '8', '0', 3,
        '1', '8', '1', 3,
        '1', '8', '2', 3,
        '1', '8', '3', 3,
        '1', '8', '4', 3,
        '1', '8', '5', 3,
        '1', '8', '6', 3,
        '1', '8', '7', 3,
        '1', '8', '8', 3,
        '1', '8', '9', 3,
        '1', '9', '0', 3,
        '1', '9', '1', 3,
        '1', '9', '2', 3,
        '1', '9', '3', 3,
        '1', '9', '4', 3,
        '1', '9', '5', 3,
        '1', '9', '6', 3,
        '1', '9', '7', 3,
        '1', '9', '8', 3,
        '1', '9', '9', 3,
        '2', '0', '0', 3,
        '2', '0', '1', 3,
        '2', '0', '2', 3,
        '2', '0', '3', 3,
        '2', '0', '4', 3,
        '2', '0', '5', 3,
        '2', '0', '6', 3,
        '2', '0', '7', 3,
        '2', '0', '8', 3,
        '2', '0', '9', 3,
        '2', '1', '0', 3,
        '2', '1', '1', 3,
        '2', '1', '2', 3,
        '2', '1', '3', 3,
        '2', '1', '4', 3,
        '2', '1', '5', 3,
        '2', '1', '6', 3,
        '2', '1', '7', 3,
        '2', '1', '8', 3,
        '2', '1', '9', 3,
        '2', '2', '0', 3,
        '2', '2', '1', 3,
        '2', '2', '2', 3,
        '2', '2', '3', 3,
        '2', '2', '4', 3,
        '2', '2', '5', 3,
        '2', '2', '6', 3,
        '2', '2', '7', 3,
        '2', '2', '8', 3,
        '2', '2', '9', 3,
        '2', '3', '0', 3,
        '2', '3', '1', 3,
        '2', '3', '2', 3,
        '2', '3', '3', 3,
        '2', '3', '4', 3,
        '2', '3', '5', 3,
        '2', '3', '6', 3,
        '2', '3', '7', 3,
        '2', '3', '8', 3,
        '2', '3', '9', 3,
        '2', '4', '0', 3,
        '2', '4', '1', 3,
        '2', '4', '2', 3,
        '2', '4', '3', 3,
        '2', '4', '4', 3,
        '2', '4', '5', 3,
        '2', '4', '6', 3,
        '2', '4', '7', 3,
        '2', '4', '8', 3,
        '2', '4', '9', 3,
        '2', '5', '0', 3,
        '2', '5', '1', 3,
        '2', '5', '2', 3,
        '2', '5', '3', 3,
        '2', '5', '4', 3,
        '2', '5', '5', 3
    };
    
    typedef unsigned char   u_char;
    typedef unsigned short  u_short;
    typedef unsigned int    u_int;
    typedef unsigned long   u_long;
    
    struct in_addr {
        union {
            struct { u_char s_b1, s_b2, s_b3, s_b4; }   S_un_b;
            struct { u_short s_w1, s_w2; }              S_un_w;
            u_long                                      S_addr;
        } S_un;
    };
    #define s_addr S_un.S_addr
    
    struct sockaddr_in {
        short           sin_family;
        unsigned short  sin_port;
        struct in_addr  sin_addr;
        char            sin_zero[8];
    }sockaddr;
    #define h_addr h_addr_list[0]
    
    //Constant sized fields of the resource record structure
    #pragma pack(push, 1)
    struct  R_DATA
    {
        unsigned short type;
        unsigned short _class;
        unsigned int   ttl;
        unsigned short data_len;
    };
    #pragma pack(pop)
    
    //Pointers to resource record contents
    struct RES_RECORD
    {
        unsigned char  *name;
        struct R_DATA  *resource;
        unsigned char  *rdata;
    };
    
    typedef struct {
        char * h_name;
        char ** h_aliases;
        short h_addrtype;
        short h_length;
        unsigned int ** h_addr_list;
    } HOSTENT, *PHOSTENT;  //定义一样的
    
    typedef struct _DNSADDRANDURL
    {
        int serveur_dns;//
        int urladdr;//已解析的
    } DNSADDRANDURL, *PDNSADDRANDURL;
    
    typedef struct
    {
        unsigned short id;       // identification number 
        unsigned char rd : 1;     // recursion desired 
        unsigned char tc : 1;     // truncated message 
        unsigned char aa : 1;     // authoritive answer 
        unsigned char opcode : 4; // purpose of message 
        unsigned char qr : 1;     // query/response flag 
        unsigned char rcode : 4; // response code 
        unsigned char cd : 1;     // checking disabled 
        unsigned char ad : 1;     // authenticated data 
        unsigned char z : 1;      // its z! reserved 
        unsigned char ra : 1;     // recursion available 
        unsigned short q_count; // number of question entries
        unsigned short ans_count; // number of answer entries 
        unsigned short auth_count; // number of authority entries 
        unsigned short add_count; // number of resource entries
    } DNS_HEADER;
    
    //DNS Question
    typedef struct
    {
        unsigned short qtype;
        unsigned short qclass;
    } QUESTION;
    
    
    typedef struct {
        unsigned short name;
        unsigned short type;
        unsigned short _class;
        unsigned short ttl_hi;
        unsigned short ttl_low;
        unsigned short data_len;
        unsigned char rdata[1];
    }CUSTOM_RES_RECORD;
    
    typedef struct _STREAM_SOCKET {
        HANDLE              connectionHandle;
        PFILE_OBJECT        connectionFileObject;
        KEVENT              disconnectEvent;
    } STREAM_SOCKET, *PSTREAM_SOCKET;
    
    typedef struct _SOCKET {
        int                 type;
        BOOLEAN             isBound;
        BOOLEAN             isConnected;
        BOOLEAN             isListening;
        BOOLEAN             isShuttingdown;
        BOOLEAN             isShared;
        HANDLE              addressHandle;
        PFILE_OBJECT        addressFileObject;
        PSTREAM_SOCKET      streamSocket;
        struct sockaddr_in     peer;
    } SOCKET, *PSOCKET;
    
    #define INADDR_NONE             0xffffffff
    
    #define htonl(l)                                
        ( ( ((l) >> 24) & 0x000000FFL ) |       
        ( ((l) >>  8) & 0x0000FF00L ) |       
        ( ((l) <<  8) & 0x00FF0000L ) |       
                  ( ((l) << 24) & 0xFF000000L ) )
    
    #define ntohs(s)                            
        ( ( ((s) >> 8) & 0x00FF ) |             
                  ( ((s) << 8) & 0xFF00 ) )
    
    
    #define HTONS(a) (((0xFF&a)<<8) + ((0xFF00&a)>>8))
    #define NTOHS(s) ((((s)>> 8) & 0x00FF)|(((s)<<8)&0xFF00)) //找了好久哦,其实也很简单
    
    #define dprintf if (DBG) DbgPrint
    #define nprintf DbgPrint
    
    #define DEVICE_NAME L"\Device\devhello" // Driver Name
    #define LINK_NAME L"\DosDevices\hello"  // Link Name
    
    //
    // The device driver IOCTLs
    //
    
    #define IOCTL_BASE    0x800
    #define MY_CTL_CODE(i) 
        CTL_CODE(FILE_DEVICE_UNKNOWN, IOCTL_BASE+i, METHOD_BUFFERED, FILE_ANY_ACCESS)
    
    
    #define IOCTL_HELLO    MY_CTL_CODE(0)
    
    
    /////////////////////////////////////////////////////////////////////
    
    NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pRegistryString);
    NTSTATUS DispatchCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp);
    NTSTATUS DispatchClose(PDEVICE_OBJECT pDevObj, PIRP pIrp);
    VOID     DriverUnload(PDRIVER_OBJECT pDriverObj);
    NTSTATUS DispatchIoctl(PDEVICE_OBJECT pDevObj, PIRP pIrp);
    
    /////////////////////////////////////////////////////////////////////
    //函数声明
    char*            inet_ntoa(struct in_addr  in);
    unsigned long    inet_addr(const char *cp);
    PVOID            malloc(int size);
    int                ReadDnsServerFromRegistry();
    int                ReadHostIPsFromRegistry();
    PHOSTENT        gethostbyname(char *name);
    int                query_dns(struct sockaddr_in sockaddr_dns,
        char* nom_a_resoudre,
        char *hostent_buf,
        int rdns);
    int                build_dns_query(char* URL, int* taille_buffer_dns, int rdns);
    void            ChangetoDnsNameFormat(unsigned char* dns, unsigned char* host);
    void            ChangefromDnsNameFormat(unsigned char* name);
    int __cdecl        bind(int socket, const struct sockaddr *addr, int addrlen);
    NTSTATUS        tdi_open_transport_address(PUNICODE_STRING devName,
        ULONG addr,
        USHORT port,
        int shared,
        PHANDLE addressHandle,
        PFILE_OBJECT *addressFileObject);
    NTSTATUS        tdi_set_event_handler(PFILE_OBJECT addressFileObject,
        LONG eventType,
        PVOID eventHandler,
        PVOID eventContext);
    int __cdecl        sendto(int socket, const char *buf, int len, int flags, const struct sockaddr *addr, int addrlen);
    int __cdecl        send(int socket, const char *buf, int len, int flags);
    NTSTATUS        tdi_send_dgram(PFILE_OBJECT addressFileObject,
        ULONG addr,
        USHORT port,
        const char *buf,
        int len);
    int __cdecl        socket(int af, int type, int protocol);
    NTSTATUS        tdi_disconnect(PFILE_OBJECT connectionFileObject, ULONG flags);
    NTSTATUS        tdi_disassociate_address(PFILE_OBJECT connectionFileObject);
    int __cdecl        close(int socket);
    int __cdecl        recvfrom(int socket, char *buf, int len, int flags, struct sockaddr *addr, int *addrlen);
    unsigned char*    ReadName(unsigned char* reader, unsigned char* buffer, int* count);
    NTSTATUS        tdi_recv_dgram(PFILE_OBJECT addressFileObject, PULONG addr, PUSHORT port, char *buf, int len, ULONG flags);
    NTSTATUS        event_disconnect(PVOID TdiEventContext, CONNECTION_CONTEXT ConnectionContext, LONG DisconnectDataLength,
        PVOID DisconnectData, LONG DisconnectInformationLength, PVOID DisconnectInformation,
        ULONG DisconnectFlags);
    int __cdecl        recv(int socket, char *buf, int len, int flags);
    NTSTATUS        tdi_recv_stream(PFILE_OBJECT connectionFileObject, char *buf, int len, ULONG flags);
    int __cdecl        socket(int af, int type, int protocol);
    NTSTATUS        tdi_set_event_handler(PFILE_OBJECT addressFileObject, LONG eventType, PVOID eventHandler, PVOID eventContext);
    NTSTATUS        tdi_send_dgram(PFILE_OBJECT addressFileObject, ULONG addr, USHORT port, const char *buf, int len);
    NTSTATUS        tdi_send_stream(PFILE_OBJECT connectionFileObject, const char *buf, int len, ULONG flags);
    NTSTATUS        tdi_open_transport_address(PUNICODE_STRING devName, ULONG addr, USHORT port, int shared, PHANDLE addressHandle, PFILE_OBJECT *addressFileObject);
    
    
    #endif
    
    ///////////////////////////////   END OF FILE   ///////////////////////////////
  • 相关阅读:
    PHP实现无限极分类
    html2canvas生成并下载图片
    一次线上问题引发的过程回顾和思考,以更换两台服务器结束
    Intellij IDEA启动项目报Command line is too long. Shorten command line for XXXApplication or also for
    mq 消费消息 与发送消息传参问题
    idea 创建不了 java 文件
    Java switch 中如何使用枚举?
    Collections排序
    在idea 设置 git 的用户名
    mongodb添加字段和创建自增主键
  • 原文地址:https://www.cnblogs.com/yifi/p/6527916.html
Copyright © 2011-2022 走看看