⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tracert.cpp

📁 这个是网络编程
💻 CPP
📖 第 1 页 / 共 2 页
字号:
            );
    if (rc == SOCKET_ERROR)
    {
        if (WSAGetLastError() != WSA_IO_PENDING)
        {
            fprintf(stderr, "WSARecvFrom failed: %d\n", WSAGetLastError());
            return SOCKET_ERROR;
        }
    }
    return NO_ERROR;
}

//
// Function: AnalyzePacket
// 
// Description:
//    This routines finds the ICMP packet within the encapsulated header and
//    verifies that the ICMP packet is a TTL expired or echo reply message.
//    If not then an error is returned.
//
int AnalyzePacket(char *buf, int bytes)
{
    int     hdrlen=0,
            routes=0,
            rc;

    rc = NO_ERROR;
    if (gAddressFamily == AF_INET)
    {
        IPV4_HDR        *v4hdr=NULL;
        ICMP_HDR        *icmphdr=NULL;

        v4hdr = (IPV4_HDR *)buf;
        hdrlen = (v4hdr->ip_verlen & 0x0F) * 4;

        if (v4hdr->ip_protocol == IPPROTO_ICMP)
        {
            icmphdr = (ICMP_HDR *)&buf[hdrlen];

            if ((icmphdr->icmp_type != ICMPV4_TIMEOUT) &&
                    (icmphdr->icmp_type != ICMPV4_ECHO_REPLY_TYPE) &&
                    (icmphdr->icmp_code != ICMPV4_ECHO_REPLY_CODE) )
            {
                printf("Received ICMP message type %d instead of TTL expired!\n", icmphdr->icmp_type);
                rc = SOCKET_ERROR;
            }
        }
    }
    else if (gAddressFamily == AF_INET6)
    {
        IPV6_HDR        *v6hdr=NULL;
        ICMPV6_HDR      *icmp6=NULL;

        v6hdr = (IPV6_HDR *)buf;

        if (v6hdr->ipv6_nexthdr == IPPROTO_ICMP6)
        {
            icmp6 = (ICMPV6_HDR *)&buf[sizeof(IPV6_HDR)];

            if ((icmp6->icmp6_type != ICMPV6_TIME_EXCEEDED_TYPE) &&
                (icmp6->icmp6_code != ICMPV6_TIME_EXCEEDED_CODE) &&
                (icmp6->icmp6_type != ICMPV6_ECHO_REPLY_TYPE) &&
                (icmp6->icmp6_code != ICMPV6_ECHO_REPLY_CODE) )
            {
                printf("Received ICMP6 message type %d instead of TTL expired!\n",
                        icmp6->icmp6_type);
                rc = SOCKET_ERROR;
            }
        }
    }
    return rc;
}

//
// Function: SetTtl
//
// Description:
//    Sets the TTL on the socket.
//
int SetTtl(SOCKET s, int ttl)
{
    int     optlevel,
            option,
            rc;

    rc = NO_ERROR;
    if (gAddressFamily == AF_INET)
    {
        optlevel = IPPROTO_IP;
        option   = IP_TTL;
    }
    else if (gAddressFamily == AF_INET6)
    {
        optlevel = IPPROTO_IPV6;
        option   = IPV6_UNICAST_HOPS;
    }
    else
    {
        rc = SOCKET_ERROR;
    }
    if (rc == NO_ERROR)
    {
        rc = setsockopt(
                s,
                optlevel,
                option,
                (char *)&ttl,
                sizeof(ttl)
                );
    }
    if (rc == SOCKET_ERROR)
    {
        fprintf(stderr, "SetTtl: setsockopt failed: %d\n", WSAGetLastError());
    }
    return rc;
}

//
// Function: IsSockaddrEqual
//
// Description:
//    This routines compares two SOCKADDR structure to determine
//    whether the address portion of them are equal. Zero is returned
//    for equal; non-zero for not equal.
//
int IsSockaddrEqual(SOCKADDR *sa1, SOCKADDR *sa2)
{
    int rc;

    rc = 1;
    if (sa1->sa_family == sa2->sa_family)
    {
        if (sa1->sa_family == AF_INET)
        {
            rc = memcmp(
                    &((SOCKADDR_IN *)sa1)->sin_addr,
                    &((SOCKADDR_IN *)sa2)->sin_addr,
                    sizeof(struct in_addr)
                    );
            rc = rc;
        }
        else if (sa1->sa_family == AF_INET6)
        {
            rc = memcmp(
                    &((SOCKADDR_IN6 *)sa1)->sin6_addr,
                    &((SOCKADDR_IN6 *)sa2)->sin6_addr,
                    sizeof(struct in6_addr)
                    );
            rc = rc;
        }
    }

    return rc; 
}
        
//
// Function: main
//
// Description:
//    Setup the ICMP raw socket and create the ICMP header. Add
//    the appropriate IP option header and start sending ICMP
//    echo requests to the endpoint. For each send and receive we
//    set a timeout value so that we don't wait forever for a 
//    response in case the endpoint is not responding. When we
//    receive a packet decode it.
//
int __cdecl main(int argc, char **argv)
{

    WSADATA            wsd;
    WSAOVERLAPPED      recvol;
    SOCKET             s=INVALID_SOCKET;
    char              *icmpbuf=NULL,
                       recvbuf[0xFFFF],
                       hopname[512];
    struct addrinfo   *dest=NULL,
                      *local=NULL;
    SOCKADDR_STORAGE   from;
    DWORD              bytes,
                       flags;
    int                packetlen=0,
                       recvbuflen=0xFFFF,
                       hopbuflen=512,
                       fromlen,
                       notdone,
                       time=0,
                       ttl,
                       rc;

    // Load Winsock
    if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)
    {
        printf("WSAStartup() failed: %d\n", GetLastError());
        return -1;
    }

    // Parse the command line
    ValidateArgs(argc, argv);

    // Resolve the destination address
    dest = ResolveAddress(
            gDestination,
            "0",
            gAddressFamily,
            0,
            0
            );
    if (dest == NULL)
    {
        printf("bad name %s\n", gDestination);
        return -1;
    }
    gAddressFamily = dest->ai_family;

    if (gAddressFamily == AF_INET)
        gProtocol = IPPROTO_ICMP;
    else if (gAddressFamily == AF_INET6)
        gProtocol = IPPROTO_ICMP6;

    // Get the bind address
    local = ResolveAddress(
            NULL,
            "0",
            gAddressFamily,
            0,
            0
            );
    if (local == NULL)
    {
        printf("Unable to obtain the bind address!\n");
        return -1;
    }

    // Create the raw socket
    s = socket(gAddressFamily, SOCK_RAW, gProtocol);
    if (s == INVALID_SOCKET) 
    {
        printf("socket failed: %d\n", WSAGetLastError());
        return -1;
    }

    // Figure out the size of the ICMP header and payload
    if (gAddressFamily == AF_INET)
        packetlen += sizeof(ICMP_HDR);
    else if (gAddressFamily == AF_INET6)
        packetlen += sizeof(ICMPV6_HDR) + sizeof(ICMPV6_ECHO_REQUEST);

    // Add in the data size
    packetlen += DEFAULT_DATA_SIZE;

    // Allocate the buffer that will contain the ICMP request
    icmpbuf = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, packetlen);
    if (icmpbuf == NULL)
    {
        fprintf(stderr, "HeapAlloc failed: %d\n", GetLastError());
        return -1;
    }

    // Initialize the ICMP headers
    if (gAddressFamily == AF_INET)
    {
        InitIcmpHeader(icmpbuf, DEFAULT_DATA_SIZE);
    }
    else if (gAddressFamily == AF_INET6)
    {
        InitIcmp6Header(icmpbuf, DEFAULT_DATA_SIZE);
    }

    // Bind the socket -- need to do this since we post a receive first
    rc = bind(s, local->ai_addr, local->ai_addrlen);
    if (rc == SOCKET_ERROR)
    {
        fprintf(stderr, "bind failed: %d\n", WSAGetLastError());
        return -1;
    }

    // Setup the receive operation
    memset(&recvol, 0, sizeof(recvol));
    recvol.hEvent = WSACreateEvent();

    // Post the first overlapped receive
    fromlen = sizeof(from);
    PostRecvfrom(s, recvbuf, recvbuflen, (SOCKADDR *)&from, &fromlen, &recvol);

    printf("\nTraceroute to %s [", gDestination);
    PrintAddress(dest->ai_addr, dest->ai_addrlen);
    printf("]\nover a maximum of %d hops\n\n", gTtl);

    ttl = 1;

    // Start sending the ICMP requests
    do
    {
        notdone = 1;

        SetTtl(s, ttl);

        // Set the sequence number and compute the checksum
        SetIcmpSequence(icmpbuf);
        ComputeIcmpChecksum(s, icmpbuf, packetlen, dest);

        // Send the ICMP echo request
        time = GetTickCount();
        rc = sendto(
                s,
                icmpbuf,
                packetlen,
                0,
                dest->ai_addr,
                dest->ai_addrlen
                );
        if (rc == SOCKET_ERROR)
        {
            fprintf(stderr, "sendto failed: %d\n", WSAGetLastError());
            return -1;
        }

        // Wait for a response
        rc = WaitForSingleObject((HANDLE)recvol.hEvent, gTimeout);
        if (rc == WAIT_FAILED)
        {
            fprintf(stderr, "WaitForSingleObject failed: %d\n", GetLastError());
            return -1;
        }
        else if (rc == WAIT_TIMEOUT)
        {
            printf("Request timed out.\n");
        }
        else
        {
            // Check for an error
            rc = WSAGetOverlappedResult(
                    s,
                   &recvol,
                   &bytes,
                    FALSE,
                   &flags
                    );
            if (rc == FALSE)
            {
                fprintf(stderr, "WSAGetOverlappedResult failed: %d\n", WSAGetLastError());
            }
            time = time - GetTickCount();

            WSAResetEvent(recvol.hEvent);

            // See if we got an ICMP ttl expired or echo reply, if not ignore and
            //    receive again.
            if (AnalyzePacket(recvbuf, bytes) == NO_ERROR)
            {
                if (bResolve)
                {
                    ReverseLookup((SOCKADDR *)&from, fromlen, hopname, hopbuflen);

                    printf("%d   %d ms   %s [", ttl, time, hopname);
                    PrintAddress((SOCKADDR *)&from, fromlen);
                    printf("]\n");
                }
                else
                {
                    printf("%d   %d ms   ", ttl, time);
                    PrintAddress((SOCKADDR *)&from, fromlen);
                    printf("\n");
                }

                // See if the response is from the desired destination
                notdone = IsSockaddrEqual(dest->ai_addr, (SOCKADDR *)&from);

                // Increment the TTL
                ttl++;
            }

            // Post another receive
            if (notdone)
            {
                fromlen = sizeof(from);
                PostRecvfrom(s, recvbuf, recvbuflen, (SOCKADDR *)&from, &fromlen, &recvol);
            }
        }

        Sleep(1000);
    } while ((notdone) && (ttl < gTtl));

    //
    // Cleanup
    //
    freeaddrinfo(dest);
    freeaddrinfo(local);

    if (s != INVALID_SOCKET) 
        closesocket(s);

    HeapFree(GetProcessHeap(), 0, icmpbuf);

    WSACleanup();
    return 0;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -