Doubt with the internal structure of sockaddr_in

1

Hi, I'm studying sockets in C and I found myself in doubt about this structure:

struct sockaddr_in {
   short int            sin_family;
   unsigned short int   sin_port;
   struct in_addr       sin_addr;
   unsigned char        sin_zero[8];
};

When using the connect function:

int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);

The second argument is assumed to be a pointer to struct sockaddr that is another structure other than sockaddr_in :

struct sockaddr {
   unsigned short   sa_family;
   char             sa_data[14];
};

However, I've seen how a sockaddr_in is passed using a cast:

connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr))

( serv_addr is a struct sockaddr_in )

I tried to find answers in SO in English and I could understand that sockaddr_in has as a first element a sockaddr and by definition the pointer to a structure is its first element that would solve the problem if it were not that in the definition of the structure the first element is a short int sin_family; as I showed at the beginning.

Could someone explain this to me?

sources:

Unix Socket Client Example

SO question in English regarding this topic

    
asked by Cristofer Fuentes 11.03.2017 в 01:27
source

1 answer

2

I do not really understand the question.

When passing any data as a pointer, you are not obliged to use all the data ; for example

int arr[100] = { ... };

void algo( int *v ) {
  printf( "%d\n", *v );
}

algo( arr );

There, we pass a pointer to a block of 100 integers, but only use one, the first.

By this I mean that the function can receive anything, but only it (the function) really knows what it is going to use. It is our responsibility, however, to pass on compatible data with what the function expects.

In C versions prior to C99, it was very common to hide the actual data you were working with, creating a typedef in the header file, and then perform an% explicit cast inside the body of the functions:

prueba.h

typedef void *handle;

void algo( handle data );

and, in the implementation file:

prueba.c

#include "prueba.h"

struct RealData {
  int a;
  float b;
};

void algo( handle *h ) {
  struct RealData *rd = (struct RealData *)h;
  ...
}

This is done to prevent the user of our code from trastear with the most sensitive data; a kind of obfuscation ; an attempt to limit the visibility of the data.

It is possible to extend this technique, applying it to struct . With this extension, it is possible to create data in the stack, without using dynamic memory (which is the case of typedef void * ):

test.h

struct Data {
  char zero[sizeof(int) * 2];
};

void algo( struct Data * );

prueba.c

#include "prueba.h"

struct RealData {
  int a,b;
};

void algo( struct Data *d ) {
  struct RealData *rd = (struct RealData *)d;
  ...

main.c

#include "prueba.h"

int main( int argc, char **argv ) {
  struct Data d;

  algo( &d );
  ...

In this example, the user is really working with struct RealData , but unknowingly , and unable to access the fields of the structure. p>

As a last example, an advanced technique to achieve the same. Now, let's play with the linker. It is necessary to duplicate a lot of code here, since from the implementation you can not include the header file.

test.h

struct Data {
  char zero[sizeof( int ) * 2];
};

void algo( struct Data );

prueba.c

#include <stdio.h>

// NO INCLUIMOS EL 'prueba.h' !!

struct Data {
  int a, b;
};

void algo( struct Data d ) {
  printf( "%d, %d\n", d.a, d.b );
}

main.c

#include "algo.h"

int main( int argc, char **argv ) {
  struct Data d;

  algo( d );
  ...

As you can see, with this last technique you can pass data by value , keeping the obfuscation of them strong>.

In these techniques, the only important thing is that the size of the obfuscated data ( struct Data ) is equal or greater than the size of the actual data ( struct RealData ).

It's more; As indicated at the beginning of the answer, not even that is necessary. The only really important is that the real data is where the function waits; if the code of our function algo only uses the field RealData.a , we could pass it a int , that the function would not find out. And, we could even pass a float , that the function would continue to do its job. The results will be curious , but the function would not matter.

Well, after the roll that I released, we return to the question. You can consider struct sockaddr as an obfuscated version of struct sockaddr_in . As you've seen, it's not even necessary that they be the same size.

Why the two structures? Surely, for historical reasons; at some point, for certain functions, it became necessary to use the code without obfuscating ; over time, and because of its advantages, both structures were used interchangeably.

    
answered by 11.03.2017 / 07:24
source