Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I am new to C programming and I am learning about pointers.
Can somebody please explain what the below code means?
struct iphdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)
__u8 ihl:4,
version:4;
#elif defined (__BIG_ENDIAN_BITFIELD)
__u8 version:4,
ihl:4;
#else
#error "Please fix <asm/byteorder.h>"
#endif
__u8 tos;
__u16 tot_len;
__u16 id;
__u16 frag_off;
__u8 ttl;
__u8 protocol;
__u16 check;
__u32 saddr;
__u32 daddr;
/*The options start here. */
};
struct icmphdr
{
u_int8_t type; /* message type */
u_int8_t code; /* type sub-code */
u_int16_t checksum;
union
{
struct
{
u_int16_t id;
u_int16_t sequence;
} echo; /* echo datagram */
u_int32_t gateway; /* gateway address */
struct
{
u_int16_t __unused;
u_int16_t mtu;
} frag; /* path mtu discovery */
} un;
};
char datagram[4000];
struct iphdr *iph = (struct iphdr *) datagram;
struct icmphdr *icmphd = (struct icmphdr *) (datagram + sizeof (struct iphdr)); // what does this line do?
What does this do? Alphabets is the address of an array and we are adding some integer to it. What does it return on typecasting?
Record is some other structure.
Realy it is not a good practice to start C; but anyway:
char datagram[4000];
means 4000 elements of 8 bit.
struct iphdr *iph = (struct iphdr *) datagram;
this line tries to cast the address of the first element of the datagram array to a iphdr var. As iphdr contains 21 * 8bit, so from the first element till 21st element of datagram array will be accessible through iphdr structure with iph pointer. For example:
iph->tos is equal to datagram[2]
struct icmphdr *icmphd = (struct icmphdr *) (datagram + sizeof (struct iphdr));
this line means a jump from the start of the array till iphdr size; So it means that just exactly after the section of the array that is not accessible through iph pointer, will be accessible with icmphd pointer. As icmphdr is 8 byte, so 8 byte will accessible with icmphdr pointer. In another language, from the 22th element till the 29th element of the datagram array will be accessible through icmphdr structure. For example:
icmphd->code is equal to datagram[22]
icmphd->un.echo.id is equal to datagram[25],datagram[26]
icmphd->un.echo.gateway is equal to datagram[25],datagram[26],datagram[27],datagram[28]
icmphd->un.frag.mtu is equal to datagram[27],datagram[28]
this program tries to map a raw data(datagram) to structured data that have a specific meaning. Maybe you received datagram from a network, and the sender gave you the structure of that data as (iphdr and icmphdr)
Related
For the given C UNION below, what would be an efficient way to calculate a hash code for it? Should I use the raw binary data in memory? Or should I try to interpret the contents of the UNION to calculate the hash code?
#ifdef AF_INET6
#define SOCKADDR union { \
struct sockaddr_in him4; \
struct sockaddr_in6 him6; \
}
#define SOCKADDR_LEN (ipv6_available() ? sizeof(SOCKADDR) : \
sizeof(struct sockaddr_in))
#else
#define SOCKADDR union { struct sockaddr_in him4; }
#define SOCKADDR_LEN sizeof(SOCKADDR)
#endif
I have tried to cast it to (struct sockaddr_in *) and use the sa_in->sin_addr.s_addr and sa_in->sin_port. But that does not feel right. I'm ignoring struct sockaddr_in6 completely. Should I just use the raw memory data? How?
struct sockaddr_in6 {
sa_family_t sin6_family; /* AF_INET6 */
in_port_t sin6_port; /* port number */
uint32_t sin6_flowinfo; /* IPv6 flow information */
struct in6_addr sin6_addr; /* IPv6 address */
uint32_t sin6_scope_id; /* Scope ID (new in 2.4) */
};
struct in6_addr {
unsigned char s6_addr[16]; /* IPv6 address */
};
struct sockaddr_in{
short sin_family;
unsigned short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
You must interpret the actual content of the union, at least in general. The simple reason is that parts might be unused, i.e. not contribute to the effective value of the union. For example, a struct may have padding between members to align members. For a union, you can easily have padding at the end, when different union members have different sizes. If you ignore this, unions that are equal for all practical purposes will have different hash values.
So, I have to do library sending IPv4 packets (without libraries with prepared headers) and problem is that I can't access field in struct inside struct while using function, though eclipse does not see error, hint does not show that is possible.
Structs:
struct packet{
struct ipv4hdr * iphdr;
struct icmphdr * icmphdr;
char * data;
};
struct ipv4hdr{
u_int8_t version_length;
u_int8_t type;
u_int16_t total_length;
u_int16_t id;
u_int16_t frag_off;
u_int8_t ttl;
u_int8_t protocol;
u_int16_t checksum;
u_int32_t source;
u_int32_t destination;
};
Pointers to function (that is requirement, both work):
struct packet *(*packetCreate)() = dlsym(lib, "createPacket");
void (*setIP)(struct packet *, u_int8_t, u_int8_t, u_int16_t, char*, u_int8_t, char*) = dlsym(lib, "prepareIP");
Creation of struct packet:
struct packet * createPacket(){
struct packet * pack= malloc(sizeof(struct packet));
return pack;
}
Now, calling fields inside main does show posssible fields:
struct packet * pack = packetCreate();
pack->iphdr->(CTRL+space displays all the fields) //and eclipse automatically corrects all the . to ->
Meanwhile calling created pointer on function does not display fields while using hint and that causes segmentation fault (core dumped):
void prepareIP(struct packet * packet, u_int8_t length, u_int8_t type, u_int16_t id, char* destination, u_int8_t ttl, char *data){
packet->iphdr->type = type; //it is not treated by error, though any field causes crash
//meanwhile hint
packet->iphdr->(CTRL+space gets)ipv4hdr;
}
Question again is why I can't call specific field inside function that points to the original struct and how to do this inside that function
It looks like you forgot to allocate space for struct ipv4hdr * iphdr;.
But maybe this isn't even what you intended. Do you really want iphdr to be a pointer in your struct? It makes mucht more sense, if it was part of the struct, like this:
struct packet{
struct ipv4hdr iphdr; // notice that we do not use pointers here!
struct icmphdr icmphdr; // this looks curious to me - we have either an IP or an ICMP package, why both headers in the same package?
char * data;
};
I'm new to unix socket programming. I have some questions about unix sendto() function.
ssize_t sendto(int sockfd,
const void *buf,
size_t len,
int flags,
const struct sockaddr *dest_addr,
socklen_t addrlen);
My questions are:
(1) If port number in dest_addr is not set, how would the receiver host deal with the packet?
(2) How does this functions process info in dest_addr? I send IPv6 packet with this function, I have to use sockaddr_in6 struct which is a totally different with sockaddr_in struct:
struct sockaddr_in {
short sin_family; // e.g. AF_INET, AF_INET6
unsigned short sin_port; // e.g. htons(3490)
struct in_addr sin_addr; // see struct in_addr, below
char sin_zero[8]; // zero this if you want to
};
struct sockaddr_in6 {
u_int16_t sin6_family; // address family, AF_INET6
u_int16_t sin6_port; // port number, Network Byte Order
u_int32_t sin6_flowinfo; // IPv6 flow information
struct in6_addr sin6_addr; // IPv6 address
u_int32_t sin6_scope_id; // Scope ID
};
and why do we need a cast to struct sockaddr in sendto()? Looks like only sa_family is meaningful to this function. Then what about other fields?
Regarding 1: there is no special "undefined" value. Whatever value happens to be stored in this memory location will be taken as the desired port number.
Regarding 2: each struct sockaddr starts with an address family identifier. If the family is set to AF_INET, all functions will know to expect a struct sockaddr_in. Likewise for the other families. In that sense, I believe the example you posted (which seems to imply AF_INET6 can be a valid value of sin_family in a struct sockaddr_in) to be misleading.
This is the internet(IPv4) socket address structure defined in netinet/in.h
struct sockaddr_in {
uint8_t sin_len;
sa_family_t sin_family;
in_port_t sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
struct in_addr {
in_addr_t s_addr;
};
Here what is the need of separate structure only for address field.
Why can't we use following structure ?
struct sockaddr_in {
uint8_t sin_len;
sa_family_t sin_family;
in_port_t sin_port;
in_addr_t sin_addr;
char sin_zero[8];
};
It's for historical reasons. In the early days of socket programming, struct in_addr contained a union of various structures so you could get to the individual bytes. This union became unnecessary when subnetting and classless addressing came along, but switching out the struct for a simple unsigned long would break a lot of code, so it just stayed that way.
If you're interested in network programming and you haven't yet picked up a copy of UNIX Network Programming then I'd highly recommend doing so, it's a goldmine for little details like this.
I'm looking at functions such as connect() and bind() in C sockets and notice that they take a pointer to a sockaddr struct. I've been reading and to make your application AF-Independent, it is useful to use the sockaddr_storage struct pointer and cast it to a sockaddr pointer because of all the extra space it has for larger addresses.
What I am wondering is how functions like connect() and bind() that ask for a sockaddr pointer go about accessing the data from a pointer that points at a larger structure than the one it is expecting. Sure, you pass it the size of the structure you are providing it, but what is the actual syntax that the functions use to get the IP Address off the pointers to larger structures that you have cast to struct *sockaddr?
It's probably because I come from OOP languages, but it seems like kind of a hack and a bit messy.
Functions that expect a pointer to struct sockaddr probably typecast the pointer you send them to sockaddr when you send them a pointer to struct sockaddr_storage. In that way, they access it as if it was a struct sockaddr.
struct sockaddr_storage is designed to fit in both a struct sockaddr_in and struct sockaddr_in6
You don't create your own struct sockaddr, you usually create a struct sockaddr_in or a struct sockaddr_in6 depending on what IP version you're using. In order to avoid trying to know what IP version you will be using, you can use a struct sockaddr_storage which can hold either. This will in turn be typecasted to struct sockaddr by the connect(), bind(), etc functions and accessed that way.
You can see all of these structs below (the padding is implementation specific, for alignment purposes):
struct sockaddr {
unsigned short sa_family; // address family, AF_xxx
char sa_data[14]; // 14 bytes of protocol address
};
struct sockaddr_in {
short sin_family; // e.g. AF_INET, AF_INET6
unsigned short sin_port; // e.g. htons(3490)
struct in_addr sin_addr; // see struct in_addr, below
char sin_zero[8]; // zero this if you want to
};
struct sockaddr_in6 {
u_int16_t sin6_family; // address family, AF_INET6
u_int16_t sin6_port; // port number, Network Byte Order
u_int32_t sin6_flowinfo; // IPv6 flow information
struct in6_addr sin6_addr; // IPv6 address
u_int32_t sin6_scope_id; // Scope ID
};
struct sockaddr_storage {
sa_family_t ss_family; // address family
// all this is padding, implementation specific, ignore it:
char __ss_pad1[_SS_PAD1SIZE];
int64_t __ss_align;
char __ss_pad2[_SS_PAD2SIZE];
};
So as you can see, if the function expects an IPv4 address, it will just read the first 4 bytes (because it assumes the struct is of type struct sockaddr. Otherwise it will read the full 16 bytes for IPv6).
In C++ classes with at least one virtual function are given a TAG. That tag allows you to dynamic_cast<>() to any of the classes your class derives from and vice versa. The TAG is what allows dynamic_cast<>() to work. More or less, this can be a number or a string...
In C we are limited to structures. However, structures can also be assigned a TAG. In fact, if you look at all the structures that theprole posted in his answer, you will notice that they all start with 2 bytes (an unsigned short) which represents what we call the family of the address. This defines exactly what the structure is and thus its size, fields, etc.
Therefore you can do something like this:
int bind(int fd, struct sockaddr *in, socklen_t len)
{
switch(in->sa_family)
{
case AF_INET:
if(len < sizeof(struct sockaddr_in))
{
errno = EINVAL; // wrong size
return -1;
}
{
struct sockaddr_in *p = (struct sockaddr_in *) in;
...
}
break;
case AF_INET6:
if(len < sizeof(struct sockaddr_in6))
{
errno = EINVAL; // wrong size
return -1;
}
{
struct sockaddr_in6 *p = (struct sockaddr_in6 *) in;
...
}
break;
[...other cases...]
default:
errno = EINVAL; // family not supported
return -1;
}
}
As you can see, the function can check the len parameter to make sure that the length is enough to fit the expected structure and therefore they can reinterpret_cast<>() (as it would be called in C++) your pointer. Whether the data is correct in the structure is up to the caller. There is not much choice on that end. These functions are expected to verify all sorts of things before it uses the data and return -1 and errno whenever a problem is found.
So in effect, you have a struct sockaddr_in or struct sockaddr_in6 that you (reinterpret) cast to a struct sockaddr and the bind() function (and others) cast that pointer back to a struct sockaddr_in or struct sockaddr_in6 after they checked the sa_family member and verified the size.