recvfrom()不起作用

时间:2015-05-07 16:15:48

标签: linux sockets

我尝试使用tracert(echo)等原始套接字在linux(ubuntu)中实现ICMP。我想我几乎实现了功能。但是当我执行它时,它不起作用。

我通过测试发现的是程序在recvfrom()'停止。

我使用wireshark,我可以看到它正在发送和接收数据包。但是recvfrom()不起作用。它只是在等待一个packaet包。

我从wireshark上传了截图。

http://blogfiles.naver.net/20150508_188/hong015700_1431014683356CJkRQ_JPEG/wireshark.jpg

以下是我的代码。

/*  Copyright (C) 2011-2015  P.D. Buchan (pdbuchan@yahoo.com)

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

// Send an IPv4 ICMP packet via raw socket.
// Stack fills out layer 2 (data link) information (MAC addresses) for us.
// Values set for echo request packet, includes some ICMP data.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>           // close()
#include <string.h>           // strcpy, memset(), and memcpy()

#include <netdb.h>            // struct addrinfo
#include <sys/types.h>        // needed for socket(), uint8_t, uint16_t, uint32_t
#include <sys/socket.h>       // needed for socket()
#include <netinet/in.h>       // IPPROTO_RAW, IPPROTO_IP, IPPROTO_ICMP, INET_ADDRSTRLEN
#include <netinet/ip.h>       // struct ip and IP_MAXPACKET (which is 65535)
#include <netinet/ip_icmp.h>  // struct icmp, ICMP_ECHO
#include <arpa/inet.h>        // inet_pton() and inet_ntop()
#include <sys/ioctl.h>        // macro ioctl is defined
//#include <bits/ioctls.h>      // defines values for argument "request" of ioctl.
#include <net/if.h>           // struct ifreq

#include <errno.h>            // errno, perror()

// Define some constants.
#define IP4_HDRLEN 20         // IPv4 header length
#define ICMP_HDRLEN 8         // ICMP header length for echo request, excludes data

// Function prototypes
uint16_t checksum (uint16_t *, int);
char *allocate_strmem (int);
uint8_t *allocate_ustrmem (int);
int *allocate_intmem (int);

int
main (int argc, char **argv)
{
  int status, sd, *ip_flags; // status? ip_flags?
  const int on = 1; // ?
  //char *interface, *target, *src_ip, *dst_ip; // ????
  struct ip iphdr;
  struct icmp icmphdr;
  uint8_t data[1000];
  uint8_t packet[1000];
  struct addrinfo hints, *res; // hints? res?
  struct sockaddr_in *ipv4, serverAddr, routerAddr, clientAddr; // ipv4?
  struct ifreq ifr; // ifr?
  void *tmp; // tmp?
  memset (&ifr, 0, sizeof (ifr));


  // IP header
  iphdr.ip_hl = 5;
  iphdr.ip_v = 4;
  iphdr.ip_tos = 0;
  iphdr.ip_len = htons (IP4_HDRLEN + ICMP_HDRLEN);
  iphdr.ip_id = htons (0);
  iphdr.ip_off = 0;
  iphdr.ip_ttl = 1;
  iphdr.ip_p = IPPROTO_ICMP;
  iphdr.ip_src.s_addr=inet_addr("192.168.81.128");
  iphdr.ip_dst.s_addr=inet_addr(argv[1]);
  iphdr.ip_sum = 0;
  iphdr.ip_sum = checksum ((uint16_t *) &iphdr, IP4_HDRLEN);

  // ICMP header
  icmphdr.icmp_type = ICMP_ECHO;
  icmphdr.icmp_code = 0;
  icmphdr.icmp_id = htons (1000);
  icmphdr.icmp_seq = htons (0);
  icmphdr.icmp_cksum = 0;
  icmphdr.icmp_cksum = checksum ((uint16_t *) &icmphdr, ICMP_HDRLEN);

  // set IP packet(IP Header, ICMP Header, ICMP Data)
  memcpy (packet, &iphdr, IP4_HDRLEN);
  memcpy ((packet + IP4_HDRLEN), &icmphdr, ICMP_HDRLEN);

  // set Destination address
  memset (&serverAddr, 0, sizeof (struct sockaddr_in)); // about destination(server). use for bind
  serverAddr.sin_family = AF_INET;
  serverAddr.sin_addr.s_addr = iphdr.ip_dst.s_addr;



  // Submit request for a raw socket descriptor.
  if ((sd = socket (AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
    perror ("socket() failed ");
    exit (EXIT_FAILURE);
  }

  // Set flag so socket expects us to provide IPv4 header.
  if (setsockopt (sd, IPPROTO_IP, IP_HDRINCL, &on, sizeof (on)) < 0) {
    perror ("setsockopt() failed to set IP_HDRINCL ");
    exit (EXIT_FAILURE);
  }

  // Bind socket to interface index.



  // send and receive
  printf("send with ttl 1\n");
  if (sendto (sd, packet, IP4_HDRLEN + ICMP_HDRLEN, 0, (struct sockaddr *) &serverAddr, sizeof (struct sockaddr)) < 0)  {
      perror ("sendto() failed ");
      exit (EXIT_FAILURE);
  }
  printf("after send\n");

  int addrSize = sizeof(routerAddr);
  char buff[1000];
  printf("before receive\n");
  recvfrom(sd, buff, 1000, 0, (struct sockaddr*)&routerAddr, &addrSize);
  printf("after receive\n");


  printf("close(sd)!\n");

  close (sd);

  // Free allocated memory.

  return (EXIT_SUCCESS);
}

uint16_t checksum (uint16_t *hdr, int hdrlen)
{
    uint32_t sum = 0;
    int n;
    for(n=0; n<hdrlen/2; n++)
        sum += hdr[n];

    sum = (sum&0xFFFF) + (sum>>16);
    sum = ~sum;

    return sum;
}

我想像其他人一样上传我的代码(有些代码是彩色的),但我找不到它......抱歉。

以下是节目结果。

send with ttl 1
after send
before receive

谢谢。

PS。我使用vmware来使用ubuntu。我正在使用NAT。

0 个答案:

没有答案