sendto function setting "network is unreachable" errno
Asked Answered
M

0

1

I'll apologise for any lack of clarity, and I'll do my best to update with any missed info, but I'm struggling to understand what I need to do to figure out why the network is unreachable.

I'm getting the output "sendto failed Network is unreachable" from the function

int send_dhcp_packet(void * buffer, int buffer_size, int sock, struct sockaddr_in* dest)
{
    int result;

    result = sendto(sock, (char*) buffer, buffer_size, 0, (struct sockaddr*)dest, sizeof(*dest));

    if(result < 0)
    {
        printf("sendto failed %s\n", strerror(errno));
        return -1;
    }

    return 0;
}

Where buffer is a struct of type dhcp_packet

typedef struct dhcp_packet_struct
{
    uint8_t op; //Packet type
    uint8_t htype; //Type of hardware address for this machine
    uint8_t hlen; //Length of hardware address for this machine
    uint8_t hops; //Number of hops to the gateway
    uint32_t xid; //Random transaction ID to match this boot request with responses
    uint16_t secs; //Seconds since booted
    uint16_t flags; //Flags for the packet 

    struct in_addr ciaddr; //IP of this machine if it has one
    struct in_addr yiaddr; //IP of this machine offered by the DHCP server
    struct in_addr siaddr; //IP of the DHCP server
    struct in_addr giaddr; //IP of the DHCP relay

    unsigned char chaddr[MAX_DHCP_CHADDR_LENGTH]; //Hardware address of this machine
    char sname[MAX_DHCP_SNAME_LENGTH]; //Name of DHCP server
    char file[MAX_DHCP_FILE_LENGTH]; //Boot file name (full path qualified, null terminated string. Used by later sessions)
    char options[MAX_DHCP_OPTIONS_LENGTH]; //DHCP options. Variable length octet strings
}dhcp_packet;

And I'm setting it up in the following function

int send_dhcp_discover(int sock)
{
    dhcp_packet discover_packet;
    struct sockaddr_in sockaddr_bcast;

    //We're setting up the discover packet
    bzero(&discover_packet, sizeof(discover_packet));

    discover_packet.op = BOOTREQUEST;

    discover_packet.htype = ETHERNET_HARDWARE_ADDRESS;

    discover_packet.hlen = ETHERNET_HARDWARE_ADDRESS_LENGTH;

    discover_packet.hops = 0;

    srand(time(NULL));
    packet_xid = random();
    discover_packet.xid = htonl(packet_xid);
    ntohl(packet_xid);

    discover_packet.secs = DHCP_PACKET_SECS;

    //Tell the server to broadcast it's response
    discover_packet.flags = htons(DHCP_BROADCAST_FLAG);

    memcpy(discover_packet.chaddr, client_hardware_address, ETHERNET_HARDWARE_ADDRESS_LENGTH); //Our hw address

    //First 4 bytes is a magic cookie
    discover_packet.options[0] = '\x63';
    discover_packet.options[1] = '\x82';
    discover_packet.options[2] = '\x53';
    discover_packet.options[3] = '\x63';

    discover_packet.options[4] = DHCP_OPTION_MESSAGE_TYPE;
    discover_packet.options[5] = '\x01'; //Message option length (bytes)
    discover_packet.options[6] = DHCPDISCOVER;

    if(request_specific_address)
    {
        discover_packet.options[7] = DHCP_OPTION_REQUESTED_ADDRESS;
        discover_packet.options[8] = '\x04'; //Length (bytes)
        memcpy(&discover_packet.options[9], &requested_address, sizeof(requested_address));
    }

    //Send the discover packet to the broadcast address
    //Set up the struct
    sockaddr_bcast.sin_family = AF_INET;
    sockaddr_bcast.sin_port = htons(DHCP_SERVER_PORT);
    sockaddr_bcast.sin_addr.s_addr = INADDR_BROADCAST;
    bzero(&sockaddr_bcast.sin_zero, sizeof(sockaddr_bcast.sin_zero));

    //Send the damn packet already
    send_dhcp_packet(&discover_packet, sizeof(discover_packet), sock, &sockaddr_bcast);

    return 0;
}

How the socket is set up

int create_dhcp_socket()
{
    struct sockaddr_in name;
    struct ifreq interface;
    int sock;
    int flag = 1;

    //Set up the address that we're going to use
    bzero(&name, sizeof(name));
    name.sin_family = AF_INET;
    name.sin_port = htons(DHCP_CLIENT_PORT); //Converts from host byte order to network byte order
    name.sin_addr.s_addr = INADDR_ANY; //Listen on any address

    //Create a socket
    sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); //Creates endpoint using ipv4, supporting datagrams over UDP
    if(sock < 0)
    {
        printf("Error: couldn't create socket\n");
        return -1;
    }

    flag = 1;

    //Set the reuse option so there aren't errors on restarting
    if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&flag, sizeof(flag)) < 0)
    {
        printf("Error: couldn't set reuse option on DHCP socket\n");
        return -1;
    }

    //Set the broadcast option
    if(setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char*)&flag, sizeof(flag)) < 0)
    {
        printf("Error: couldn't set broadcast option on DHCP socket\n");
        return -1;
    }

    strncpy(interface.ifr_ifrn.ifrn_name, network_interface_name, IFNAMSIZ);

    if(bind(sock, (struct sockaddr*)&name, sizeof(name)) < 0)
    {
        printf("Error: couldn't bind DHCP socket (port %d). Check yo privilage\n", DHCP_CLIENT_PORT);
        return -1;
    }

    return sock;
}

I guess the question is; why is the network unreachable and how do I fix it so that it's reachable?

Mis answered 25/3, 2015 at 11:28 Comment(11)
How do you create your socket?Oscitancy
And what is inside dest. Are you sending it to the broadcast address? What is the content of your routing tables?Fokker
@Fokker dest is a pointer to sockaddr_bcast which is filled out toward the end of send_dhcp_discover. And as far as routing tables, not a clue, I'll look them up.Mis
@Oscitancy I updated the question to include the socket creation functionMis
Try running your program with strace and check return code from every system call you use for sending your packetFokker
@Fokker The box I'm running on doesn't have strace, irritatingly enough. Any alternatives that you know of, or just printf?Mis
Note: you should be using htonl for INADDR_BROADCAST and INADDR_ANY: #6082392Savil
strace doesn't seem to need special priviledges (it hasn't its S-UID set). Maybe you can compile it from sourcesFokker
@juhist, the various answers to the question you linked point out that you do not technically need to use htonl() with INADDR_BROADCAST and INADDR_ANY, and they demonstrate that opinions are divided over whether you should.Tuppence
Since the code seems to be part of a DHCP client, I presume it runs when the client machine doesn't know any of its (correct) network parameters. It seems plausible that this would lead to routing failures (which appears to be what the error is indicating), even for a broadcast. Perhaps it would help if you set socket option SO_DONTROUTE.Tuppence
@Mis i have similar problem on a similar board... my program works on full stack linux machines but when moved to this embedded linux board it sends no broadcast packets at all... i testes it with tcpdump and there is no packets. I checked the errorno and the problem is network unreachable... I tested what proposed in comments and nothing worked do you find a working solution?Retinol

© 2022 - 2024 — McMap. All rights reserved.