0

I want to send a packet using write systemcall. I create the packet, it's size is 46 byte. when I send the packet in my program in wireshark the length is 60 byte, 14 byte is padding. How can I send the packet without padding.

I can not use socket commands.

struct x {
 bool is_active;
 bool is_owner;
 int fd1;
 int fd2;
 char pkt_hdr[sizeof(struct ether_header) + sizeof(struct ip)];
 struct interface *ifp;
 int fd_bufflen;
 struct ipaddr src;
 uint8_t ibuf[IP_MAXPACKET];
 int family;
 struct vrrp_vrouter *vr;
 struct list *addrs;
 bool ad;
 bool ga;
 bool nd;
 uint8_t priority;
 uint16_t ma_val;
 uint16_t sk_tm;
 uint16_t ma_val;
 struct ethaddr vmac;
  struct {
    int state;
  } fsm;

  struct {
    uint32_t ad_cnt;
    uint32_t ar_cnt;
    uint32_t g_cnt;
    uint32_t un_cnt;
    uint32_t t_cnt;
  } stats;

  struct thread *t_ti;
  struct thread *t_adti;
  struct thread *t_read;
  struct thread *t_write;
};
.
.
.
size_t buf_len = pktsz + sizeof r->pkt_hdr;
. 
.
.

/* Ethernet Header */
struct ether_header *ether_hdr = (struct ether_header *)buf;
.
.
.

/* IP Header */

struct ip *ip_hdr = (struct ip *) (ether_hdr + 1);
ip_hdr->ip_len = htons(buf_len - sizeof(struct ether_header));
ip_hdr->ip_src = r->src.ipaddr_v4;
ip_hdr->ip_sum = in_cksum(ip_hdr, sizeof(struct ip));

/* Payload */
memcpy((void *)(buf + sizeof r->pkt_hdr), (const void *)pkt, pktsz);

ssize_t sent = write(fd, buf, buf_len);
free(buf);

buf_len is :46

pktsz : 12

sizeof r->pkt_hdr: 34

The length is 46.

F.M
  • 463
  • 2
  • 7
  • 20
  • Try to re-arrange the structure members to reduce the padding bytes. – TruthSeeker Feb 25 '20 at 08:30
  • Suggest to put up your code as well, without which, this would just be a guessing game! – th33lf Feb 25 '20 at 08:40
  • @th33lf I edit the post and added a part of code. – F.M Feb 25 '20 at 08:53
  • 1. There is no declaration of structs used. 2. For this kind of communicaton structs have to be packed. – 0___________ Feb 25 '20 at 08:56
  • We could help if you show the structure definitions. Padding may be avoided by reorganizing fields. Based on [this explanation](https://www.geeksforgeeks.org/how-to-avoid-structure-padding-in-c/) we could use pragma directives but these may depend on the compiler. – chmike Feb 25 '20 at 09:03
  • Re-organizing a struct to hopefully avoid padding is a brittle solution, not portable and vulnerable to changes during maintenance. Either serialize the data properly or pack the struct. And you may have to convert to network endianess regardless. – Lundin Feb 25 '20 at 09:16
  • As @Lundin mentioned, Serialization is right thing for you structure, You must not store/send pointers but data . Your structure has pointers like `struct interface *ifp;` – TruthSeeker Feb 25 '20 at 09:25
  • Umm yeah my posted answer kind of assumes that you know basic C. Obviously you can't soft copy a struct containing pointers and then send pointers over the network. That has nothing to do with padding or endianess, but with fundamental knowledge of pointers and computer memory... – Lundin Feb 25 '20 at 09:28
  • Though what has `struct x` to do with anything? You don't seem to be using it? – Lundin Feb 25 '20 at 09:31
  • You can use #pragma pack(1) , most of the compiler support it. – Sanjeev Feb 25 '20 at 09:58
  • @Sanjeev How #pragma pack(1) will help to pack pointers? – TruthSeeker Feb 25 '20 at 09:59
  • @F.M by showing `struct x` you have opened pandora's box. If `buf` is of type `struct x` your problems boils down to object serialization than struct padding. Would you mind to mention the type of `buf`? – TruthSeeker Feb 25 '20 at 10:03
  • @TruthSeeker, Complier will not add any padding in structure. Generally in structure every variable or field in memory getting store by 4/8 byte aligned by default so if field size is less or not a multiple of 4/8 then to make it aligned padding is added. If we say #pragma pack(1) then telling the compiler to not add any padding and pointer will no longer be 4/8 multiple of. It hit little bit performance as to fetch this unaligned field there may be more read operation compared to aligned one. – Sanjeev Feb 25 '20 at 10:05
  • 1
    @Sanjeev: some Hardware throws exception in case of unaligned access. Now question is not how to pad/pack the struct, does it needs serialization? – TruthSeeker Feb 25 '20 at 10:09
  • @TruthSeeker buf is char *. I calloc the buf with the size `buf_len` – F.M Feb 25 '20 at 10:10
  • @TruthSeeker `memcpy((void *)buf, (const void *)r->pkt_hdr, sizeof r->pkt_hdr);` – F.M Feb 25 '20 at 10:12
  • @F.M, Could you please mention exact struct which needs to be packed? It is hard to understand how `struct x` is related to `buf` ? – TruthSeeker Feb 25 '20 at 10:14
  • @TruthSeeker `static void func(struct x *r) {` This is the function that the code is in it. – F.M Feb 25 '20 at 10:25
  • @F.M `pkt_hdr` header is just a array and it's size is derived from `struct ether_header` and `struct ip`. And definition of both structs are missing in your question. Please go through [How to create a Minimal, Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example) – TruthSeeker Feb 25 '20 at 11:19
  • 1
    @TruthSeeker Even x86 can blow up on unaligned accesses caused by packed structures: https://stackoverflow.com/questions/46790550/c-undefined-behavior-strict-aliasing-rule-or-incorrect-alignment/46790815#46790815 – Andrew Henle Feb 25 '20 at 11:21
  • **Ethernet can't send packets shorter than 64 bytes** - including the 4-byte checksum which Wireshark does not display. So 60 bytes. – user253751 Feb 25 '20 at 11:52
  • @TruthSeeker These structs are in unix. we should include the header files. – F.M Feb 25 '20 at 12:32
  • @ user253751 I saw some packets in wireshark that are less than 60 byte. – F.M Feb 25 '20 at 12:33

2 Answers2

1

Unfortunately struct are pretty bad in general when it comes for storing protocols, because of their alignment and padding requirements. This means that you cannot use memcpy etc on the whole struct. Instead the struct has to be serialized before sent over a data communications protocol, to discard padding.

Simplified example:

typedef struct
{
  int i;
  char c;
} foo_t;

void foo_serialize (uint8_t dst[5], const foo_t* src)
{
  memcpy(dst, &src->i, 4);
  dst[4] = src->c;
}

A similar de-serialization routine is necessary on the receiver side.

Yet another option is to "pack" the struct with non-standard #pragma pack(1) and similar. That removes padding, but padding is there for a reason. If you pack the struct, your program may end up reading it misaligned, which could lead to slower code or on some systems hardware exceptions.


But at the same time you also need to convert to network endianess. Big endian is commonly used in most data protocols. Rewriting the above example to also convert from little to big endian:

void foo_serialize (uint8_t dst[5], const foo_t* src)
{
  dst[0] = ((uint32_t)src->i >> 24) & 0xFFu;
  dst[1] = ((uint32_t)src->i >> 16) & 0xFFu;
  dst[2] = ((uint32_t)src->i >>  8) & 0xFFu;
  dst[3] = ((uint32_t)src->i >>  0) & 0xFFu;
  dst[4] = src->c;
}

There is also the POSIX htonl function (host endian to network endian, long format), but since that function isn't portable outside POSIX PC computers, it kind of defeats its own purpose.

Lundin
  • 195,001
  • 40
  • 254
  • 396
1

Packing prevents compiler from doing padding - this has to be explicitly requested - under GCC using __attribute__((__packed__)).

For more explanation please go through the following link : https://www.geeksforgeeks.org/structure-member-alignment-padding-and-data-packing/

  • [` __attribute__((__packed__))` is unsafe](https://stackoverflow.com/questions/8568432/is-gccs-attribute-packed-pragma-pack-unsafe). And [even on x86, misaligned access caused by packed structures can fail](https://stackoverflow.com/questions/46790550/c-undefined-behavior-strict-aliasing-rule-or-incorrect-alignment/46790815#46790815). – Andrew Henle Feb 25 '20 at 11:19
  • We have faced similar kind of issue while implementing an application that will talk to the wlan device driver and get some information from the driver. So at that time we fixed the issue using __attribute__((__packed__)). But after using the __attribute__((__packed__)) we must be extremely careful about the structure size. @AndrewHenle – Vikas Vijayan Feb 25 '20 at 11:51
  • And by doing that, you have written code where every developer who touches the code for its entire lifetime must be aware to never take the address of any member of that packed structure. Have you documented that in your code? Are you training newly-hired developers that they have to be aware of that? – Andrew Henle Feb 25 '20 at 11:59
  • @AndrewHenle obviously I have documented about that. We have some advantages by doing that as well. Moreover I didn't meant for any argument. Just want to make you know that we can do like that. Thanks. – Vikas Vijayan Feb 25 '20 at 12:31