Linux sendto implementation possibly adding extra padding to UDP message

1.2k views Asked by At

I have recently written a C program using Windows/Winsock2, in which a string is to be transmitted via UDP. The following code produces expected and correct results:

static const char *network_config_init = "HF-A11ASSISTHREAD";

void send_broadcast_message(){
    struct sockaddr_in remote;
    memset((char *)&remote, 0,sizeof(remote));
    remote.sin_family = AF_INET;
    remote.sin_port = htons(PLUG_PORT);
    remote.sin_addr.s_addr = INADDR_BROADCAST;//htonl(INADDR_BROADCAST);


    sendto(m_send_socket, network_config_init,strlen(network_config_init),0,(struct sockaddr *)&remote,sizeof(struct sockaddr_in));
}

Running this code produces the following wireshark output for this call to sendto:

    Frame 81421: 59 bytes on wire (472 bits), 59 bytes captured (472 bits) on interface 0
81421   20451.695078000 EWGECO028.local 255.255.255.255 UDP 59  Source port: 51488  Destination port: 48899
Ethernet II, Src: 70:18:8b:c6:5b:f8 (70:18:8b:c6:5b:f8), Dst: ff:ff:ff:ff:ff:ff (ff:ff:ff:ff:ff:ff)
Internet Protocol Version 4, Src: EWGECO028.local (10.10.100.150), Dst: 255.255.255.255 (255.255.255.255)
User Datagram Protocol, Src Port: 51488 (51488), Dst Port: 48899 (48899)
HF-A11ASSISTHREAD <---THIS IS THE TEXT TO BE TRANSMITTED

I have now ported this same code to Ubuntu being run on VM VirtualBox, and the same code now outputs the following via wireshark:

Frame 76620: 60 bytes on wire (480 bits), 60 bytes captured (480 bits) on interface 0
Ethernet II, Src: 08:00:27:d1:97:be (08:00:27:d1:97:be), Dst: ff:ff:ff:ff:ff:ff (ff:ff:ff:ff:ff:ff)
Internet Protocol Version 4, Src: doug-VirtualBox.local (10.0.0.139), Dst: 255.255.255.255 (255.255.255.255)
User Datagram Protocol, Src Port: 39207 (39207), Dst Port: 48899 (48899)
HF-A11ASSISTHREAD. <----NOTE Extra '.'

Note that in Windows, 59 bytes are transmitted, and in Linux, 60 are transmitted. an extra '.' has been appended to the message in Linux. The extra '.' has a hex value of 00. This extra padding isn't being accepted by the recipient of the message. The recipient can't be altered in any way.

Does anyone have any insight as to why an extra byte is being appended to the UDP message in Linux?

EDIT: Here is the complete code for the Linux and Windows implementations:

Linux:

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <assert.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

static const int PLUG_PORT = 48899;

static const char *network_config_init = "HF-A11ASSISTHREAD";
static const char *ack = "+ok";
static const char *ssid = "AT+WSSSID=NT_0004A334A523\r";
static const char *sec_settings = "AT+WSKEY=WPA2PSK,AES,dff073ee57cb\r";
static const char *station_mode = "AT+WMODE=STA\r";
static const char *reboot = "AT+Z\r";
static char plug_ip_address[16];

static int m_send_socket;

void send_broadcast_message(){
    printf("message to be sent: %s\n",network_config_init);

    struct sockaddr_in remote;
    memset((char *)&remote, 0,sizeof(remote));
    remote.sin_family = AF_INET;
    remote.sin_port = htons(PLUG_PORT);
    remote.sin_addr.s_addr = INADDR_BROADCAST;//htonl(INADDR_BROADCAST);

    int config_length = strlen(network_config_init);

    sendto(m_send_socket, network_config_init,strlen(network_config_init),0,(struct sockaddr *)&remote,sizeof(struct sockaddr_in));

}

void send_message(const char *message){
    printf("message to be sent: %s\n",message);

    struct sockaddr_in remote;
    memset((char *)&remote, 0,sizeof(remote));
    remote.sin_family = AF_INET;
    remote.sin_port = htons(PLUG_PORT);
    remote.sin_addr.s_addr = inet_addr(plug_ip_address);//INADDR_HF-A11ASSISTHREADBROADCAST;//htonl(INADDR_BROADCAST);

    sendto(m_send_socket, message,strlen(message),0,(struct sockaddr *)&remote,sizeof(struct sockaddr_in));
}

char *receive_message(char *received_message_buffer){
    struct sockaddr_in sender;
    memset((char *)&sender, 0,sizeof(sender));
    sender.sin_family = AF_INET;
    sender.sin_port = htons(PLUG_PORT);
    sender.sin_addr.s_addr = htonl(INADDR_ANY);
    unsigned int sender_size = sizeof(sender);

    assert(sizeof(*received_message_buffer) != 1024);
    memset(received_message_buffer,0,sizeof(*received_message_buffer));
    printf("waiting for reply:\n");
    recvfrom(m_send_socket,received_message_buffer,sizeof(*received_message_buffer),0,(struct sockaddr*)&sender,&sender_size);
    printf("receive result: %s\n",received_message_buffer);
    return received_message_buffer;
}

int main(int argc , char *argv[])
{
    char reply[1024];

    if((m_send_socket = socket(AF_INET , SOCK_DGRAM , 0 )) == -1)
        {
            printf("Could not create send socket\n : %d",m_send_socket);
        }


    int broadcastEnabled=1;

    setsockopt(m_send_socket, SOL_SOCKET, SO_BROADCAST, (char *)&broadcastEnabled, sizeof(broadcastEnabled));

    //scan for plugs
    send_broadcast_message();

    //get result from listening plugs
    receive_message(reply);

    //get ip address of plug that replied
    memset((char *)plug_ip_address,0,sizeof(plug_ip_address));

    int i = 0;
    while(reply[i] != ','){
        plug_ip_address[i] = reply[i];
        i++;
    }

    //acknowledge connection to plug
    send_message(ack);

    //send SSID of the access point to be connected to
    send_message(ssid);

    receive_message(reply);

    //send security details of the access point to be connected to
    send_message(sec_settings);

    //set the plug back to station mode
    send_message(station_mode);

    receive_message(reply);


    //reboot the plug; it should connect to the given access point after it has booted.
    send_message(reboot);

    close(m_send_socket);

    return 0;
}

Windows:

#include<stdio.h>
#include<winsock2.h>

static const int PLUG_PORT = 48899;

static const char *network_config_init = "HF-A11ASSISTHREAD";
static const char *ack = "+ok";
static const char *ssid = "AT+WSSSID=NT_0004A334A523\r";
static const char *sec_settings = "AT+WSKEY=WPA2PSK,AES,dff073ee57cb\r";
static const char *station_mode = "AT+WMODE=STA\r";
static const char *reboot = "AT+Z\r";
static char plug_ip_address[16];

static SOCKET m_send_socket;

void send_broadcast_message(){
    struct sockaddr_in remote;
    memset((char *)&remote, 0,sizeof(remote));
    remote.sin_family = AF_INET;
    remote.sin_port = htons(PLUG_PORT);
    remote.sin_addr.s_addr = INADDR_BROADCAST;//htonl(INADDR_BROADCAST);


    sendto(m_send_socket, network_config_init,strlen(network_config_init),0,(struct sockaddr *)&remote,sizeof(struct sockaddr_in));
}

send_message(char *message){
    struct sockaddr_in remote;
    memset((char *)&remote, 0,sizeof(remote));
    remote.sin_family = AF_INET;
    remote.sin_port = htons(PLUG_PORT);
    remote.sin_addr.s_addr = inet_addr(plug_ip_address);//INADDR_BROADCAST;//htonl(INADDR_BROADCAST);

    sendto(m_send_socket, message,strlen(message),0,(struct sockaddr *)&remote,sizeof(struct sockaddr_in));
    fflush(stdout);
}

char *receive_message(){
    char received_message_buffer[1024];
    struct sockaddr_in sender;
    memset((char *)&sender, 0,sizeof(sender));
    sender.sin_family = AF_INET;
    sender.sin_port = htons(PLUG_PORT);
    sender.sin_addr.s_addr = htonl(INADDR_ANY);
    int sender_size = sizeof(sender);

    memset((char *)received_message_buffer,0,sizeof(received_message_buffer));
    printf("waiting for reply:\n");
    fflush(stdout);
    recvfrom(m_send_socket,received_message_buffer,sizeof(received_message_buffer),0,(struct sockaddr*)&sender,&sender_size);
    printf("receive result: %s\n",received_message_buffer);
    fflush(stdout);
    return received_message_buffer;
}

int main(int argc , char *argv[])
{
    WSADATA wsa;
    struct sockaddr_in local;
    char received_message_buffer[1024];
    char * reply;

    if (WSAStartup(MAKEWORD(2,2),&wsa) != 0)
    {
        printf("Failed. Error Code : %d",WSAGetLastError());
        return 1;
    }

    if((m_send_socket = socket(PF_INET , SOCK_DGRAM , 0 )) == INVALID_SOCKET)
        {
            printf("Could not create send socket : %d" , WSAGetLastError());
        }

    memset((char *)&local,0,sizeof(local));

    int broadcastEnabled=1;

    setsockopt(m_send_socket, SOL_SOCKET, SO_BROADCAST, (char *)&broadcastEnabled, sizeof(broadcastEnabled));

    //scan for plugs
    send_broadcast_message();

    //get result from listening plugs
    reply = receive_message();

    //get ip address of plug that replied
    memset((char *)plug_ip_address,0,sizeof(plug_ip_address));

    int i = 0;
    while(reply[i] != ','){
        plug_ip_address[i] = reply[i];
        i++;
    }

    //acknowledge connection to plug
    send_message(ack);

    //send SSID of the access point to be connected to
    send_message(ssid);

    reply = receive_message();

    //send security details of the access point to be connected to
    send_message(sec_settings);

    //set the plug back to station mode
    send_message(station_mode);

    reply = receive_message();

    //reboot the plug; it should connect to the given access point after it has booted.
    send_message(reboot);

    closesocket(m_send_socket);
    WSACleanup();
    return 0;
}

Thanks

1

There are 1 answers

2
ecatmur On

The minimum frame length for Ethernet II is 64 octets on Layer 2, corresponding to a payload size of 46 octets without 802.1Q tag. The IP header takes a minimum 20 octets (without options) and the UDP header another 8, giving a maximum minimum payload length of 18 octets. Unfortunately, your payload "HF-A11ASSISTHREAD" is 17 bytes long, so it must be padded.

See also Removing padding from UDP packets in python (Linux)