C gethostbyname Seg Fault

时间:2015-09-07 00:36:26

标签: c sockets segmentation-fault

我正在尝试修改Linux tracepath(traceroute)程序,使其处理三个不同的ip地址。三个IP地址是:

  1. “11.11.11.11”;
  2. “144.133.133.133”;
  3. “202.202.202.202”;
  4. 它应该将它们转换为套接字地址结构和无符号整数值等,并且还可以转换为字符串,但我一直都会遇到seg错误。

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/socket.h>
    #include <linux/types.h>
    #include <linux/errqueue.h>
    #include <errno.h>
    #include <string.h>
    #include <netdb.h>
    #include <netinet/in.h>
    //#include <resolv.h>
    #include <sys/time.h>
    #include <sys/uio.h>
    #include <arpa/inet.h>
    #include <getopt.h> 
    
    char target_ip_string[INET_ADDRSTRLEN] = {0}; // first address  written out string
    char alternate_ip_1[INET_ADDRSTRLEN] = {0}; // second address  written out string
    char alternate_ip_2[INET_ADDRSTRLEN] = {0}; // third address  written out string
    
    struct sockaddr_in target_host; // first address
    struct sockaddr_in target_alt1; // second address
    struct sockaddr_in target_alt2; // third address
    
    /**
     * This example should convert three distict ip addresses from three distinct 
     * strings to three distinct integer values.
     */
    int
    main(int argc, char **argv) {
        setvbuf(stdout, NULL, _IONBF, 0); // auto flushing.
    
        struct hostent *hostname_target_entry;
        struct hostent *hostname_alt1_entry;
        struct hostent *hostname_alt2_entry;
    
        target_host.sin_family = AF_INET;
        target_alt1.sin_family = AF_INET;
        target_alt2.sin_family = AF_INET;
    
        char * target_hostname = (char *) "11.11.11.11";
        char * alternate_ip_1_local = (char *) "144.133.133.133";
        char * alternate_ip_2_local = (char *) "202.202.202.202";
    
        printf("The first ip is: %s \n", target_hostname);
        printf("The second ip is: %s \n", alternate_ip_1_local);
        printf("The third ip is: %s \n\n", alternate_ip_2_local);
    
        hostname_target_entry = gethostbyname(target_hostname);
        hostname_alt1_entry = gethostbyname(alternate_ip_1_local);
        hostname_alt2_entry = gethostbyname(alternate_ip_2_local);
    
        memcpy(&target_host.sin_addr, hostname_target_entry->h_addr_list[0], 4);
        memcpy(&target_alt1.sin_addr, hostname_alt1_entry->h_addr_list[0], 4);
        memcpy(&target_alt2.sin_addr, hostname_alt2_entry->h_addr_list[0], 4);
    
        // These should be three different ip addresses
        printf("First ip as an integer: %u \n", target_host.sin_addr.s_addr); // Why are these all the same?
        printf("Second ip as an integer: %u \n", target_alt1.sin_addr.s_addr); // Why are these all the same?
        printf("Third ip as an integer: %u \n\n", target_alt2.sin_addr.s_addr); // Why are these all the same?
    
        printf("No seg fault yet. \n\n");
    
        // This conversion should yield "11.11.11.11"
        const char * conversion1 = inet_ntop(AF_INET, &(target_host.sin_addr), target_ip_string, INET_ADDRSTRLEN);
    
        printf("Result of inet_ntop: %s \n", conversion1); // Why is this "202.202.202.202" and not "11.11.11.11"?
    
        printf("Seg fault here. \n\n");
    
        // This conversion should yield "144.133.133.133".
        const char * conversion2 = inet_ntop(AF_INET, &(target_alt1.sin_addr), alternate_ip_1, INET_ADDRSTRLEN);
    
        // This conversion should yield "202.202.202.202".
        const char * conversion3 = inet_ntop(AF_INET, &(target_alt2.sin_addr), alternate_ip_2, INET_ADDRSTRLEN);
    
        return 0;
    }
    

    终端输出:

    The first ip is: 11.11.11.11 
    The second ip is: 144.133.133.133 
    The third ip is: 202.202.202.202 
    
    First ip as an integer: 3402287818 
    Second ip as an integer: 3402287818 
    Third ip as an integer: 3402287818 
    
    No seg fault yet. 
    
    Result of inet_ntop: 202.202.202.202 
    Seg fault here. 
    

    为什么我在字符串和hostent / sockaddr_in之间的转换和返回保持失败?

2 个答案:

答案 0 :(得分:2)

gethostbyname函数返回一个指向静态数据的指针,因此如果你不复制给定调用的结果,它将被下一次调用覆盖。

由于您只是转换IP地址而非主机名,因此最好使用inet_addr代替:

target_host.sin_addr.s_addr = inet_addr("11.11.11.11");
target_alt1.sin_addr.s_addr = inet_addr("144.133.133.133");
target_alt2.sin_addr.s_addr = inet_addr("202.202.202.202");

答案 1 :(得分:0)

你走了。使用gethostbyname()的行都已使用#if 0进行了更正和注释。 (编辑检查“无法发生”的缓冲区溢出。)

#define _POSIX_C_SOURCE     200809L
#define _XOPEN_SOURCE       700
#define _ISOC99_SOURCE
#define _ISOC11_SOURCE

#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <string.h>
#include <netdb.h>
#include <netinet/in.h>
//#include <resolv.h>
#include <sys/time.h>
#include <sys/uio.h>
#include <arpa/inet.h>
#include <getopt.h> 

char target_ip_string[INET_ADDRSTRLEN] = {0}; // first address  written out string
char alternate_ip_1[INET_ADDRSTRLEN] = {0}; // second address  written out string
char alternate_ip_2[INET_ADDRSTRLEN] = {0}; // third address  written out string

struct sockaddr_storage target_host; // first address
struct sockaddr_storage target_alt1; // second address
struct sockaddr_storage target_alt2; // third address

/**
 * This example should convert three distict ip addresses from three distinct 
 * strings to three distinct integer values.
 */
int
main(void) {
    setvbuf(stdout, NULL, _IONBF, 0); // auto flushing.

#if 0
    struct hostent hostname_target_entry;
    struct hostent hostname_alt1_entry;
    struct hostent hostname_alt2_entry;
    const struct hostent* p;
#endif

    struct addrinfo *hostaddr_temp = NULL;

    char * target_hostname = (char *) "11.11.11.11";
    char * alternate_ip_1_local = (char *) "144.133.133.133";
    char * alternate_ip_2_local = (char *) "202.202.202.202";

    printf("The first ip is: %s \n", target_hostname);
    printf("The second ip is: %s \n", alternate_ip_1_local);
    printf("The third ip is: %s \n\n", alternate_ip_2_local);

#if 0 /* Simple fix, but not thread-safe. */
    p = gethostbyname(target_hostname);
    memcpy( &hostname_target_entry, p, sizeof(struct hostent) );
    p = gethostbyname(alternate_ip_1_local);
    memcpy( &hostname_alt1_entry, p, sizeof(struct hostent) );
    p = gethostbyname(alternate_ip_2_local);
    memcpy( &hostname_alt2_entry, p, sizeof(struct hostent) );
#endif


/* The correct fix.
 */
/* Change AF_INET to AF_UNSPECIFIED to support IPv6: */
    static const struct addrinfo hints = { .ai_flags = AI_NUMERICHOST, .ai_family = AF_INET };

    if ( 0 == getaddrinfo( target_hostname, NULL, &hints, &hostaddr_temp ) ) {
/* The POSIX standard "guarantees" that a sockaddr_storage will always
 * be big enough to hold any socket address, so this should never cause a
 * buffer overflow, but ....
 */
      assert( sizeof(target_host) >= hostaddr_temp[0].ai_addrlen );
      memcpy ( &target_host, hostaddr_temp[0].ai_addr, hostaddr_temp[0].ai_addrlen );
      freeaddrinfo(hostaddr_temp);
      assert( AF_INET == target_host.ss_family );
    }
    else
      perror("getaddrinfo");

    if ( 0 == getaddrinfo( alternate_ip_1_local, NULL, &hints, &hostaddr_temp ) ) {
      assert( sizeof(target_alt1) >= hostaddr_temp[0].ai_addrlen );
      memcpy ( &target_alt1, hostaddr_temp[0].ai_addr, hostaddr_temp[0].ai_addrlen );
      freeaddrinfo(hostaddr_temp);
      assert( AF_INET == target_alt1.ss_family );
    }
    else
      perror("getaddrinfo");

    if ( 0 == getaddrinfo( alternate_ip_2_local, NULL, &hints, &hostaddr_temp ) ) {
      assert( sizeof(target_alt2) >= hostaddr_temp[0].ai_addrlen );
      memcpy ( &target_alt2, hostaddr_temp[0].ai_addr, hostaddr_temp[0].ai_addrlen );
      freeaddrinfo(hostaddr_temp);
      assert( AF_INET == target_alt2.ss_family );
    }
    else
      perror("getaddrinfo");

    hostaddr_temp = NULL;

    // These should be three different ip addresses
    const in_addr_t* const host_ipv4 = &((struct sockaddr_in*)(&target_host))->sin_addr.s_addr;
    const in_addr_t* const alt1_ipv4 = &((struct sockaddr_in*)(&target_alt1))->sin_addr.s_addr;
    const in_addr_t* const alt2_ipv4 = &((struct sockaddr_in*)(&target_alt2))->sin_addr.s_addr;

//    printf("No seg fault yet. \n\n");

    // This conversion should yield "11.11.11.11"
    const char * conversion1 = inet_ntop(AF_INET, host_ipv4, target_ip_string, INET_ADDRSTRLEN);
    printf("Result of inet_ntop: %s \n", conversion1);

//    printf("Seg fault here. \n\n");

    // This conversion should yield "144.133.133.133".
    const char * conversion2 = inet_ntop(AF_INET, alt1_ipv4, alternate_ip_1, INET_ADDRSTRLEN);
    printf("Result of inet_ntop: %s \n", conversion2);

    // This conversion should yield "202.202.202.202".
    const char * conversion3 = inet_ntop(AF_INET, alt2_ipv4, alternate_ip_2, INET_ADDRSTRLEN);
    printf("Result of inet_ntop: %s \n", conversion3);


    return 0;
}