2015-09-07 21 views
0

Я пытаюсь изменить программу tracepath (traceroute) для Linux, чтобы обрабатывать три разных IP-адреса. Три IP-адреса:C gethostbyname Seg Fault

  1. "11.11.11.11";
  2. "144.133.133.133";
  3. "202.202.202.202";

Предполагается преобразовать их в структуры адресов сокетов и целые значения без знака и т. П., А также обратно в строки, но я продолжаю получать seg fault.

#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 и обратно держать неудачу?

+0

Почему вы выбрали 'char *'? Кроме того, почему вы пытаетесь разрешить ip-адреса как имена хостов? – Jason

+0

Вы не копируете структуры, возвращаемые 'gethostbyname()', поэтому каждый последующий вызов перезаписывает их. Вот почему функция устарела. – Davislor

+0

О, дерьмо. Я не хотел заменить «11.11.11.11» на «202.202.202.202». Я хотел, чтобы у каждого были свои собственные данные. Как вы это исправите? –

ответ

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"); 
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; 
}