I am getting some compilation errors I can't figure out, and although I'm sure they're quite stupid I can't find an answer that helps me much through other channels.
Problem 1: (These are a part of a TCP protocol)
error: ‘TH_SYN’ undeclared (first use in this function)
error: ‘TH_ACK’ undeclared (first use in this function)
tcp.tcph_flags = TH_SYN;
tcp.tcph_flags = TH_ACK;
Problem 2:
error: conversion to non-scalar type requested
const int one = 1;
char buffer[PCKT_LEN];
struct sockaddr_in sin;
struct ipheader ip;
struct tcpheader tcp;
ip = (struct ipheader) buffer; /* ERROR POINTS HERE */
tcp = (struct tcpheader) buffer + ip.iph_ihl *4; /* AND HERE */
Problem 3:
warning: assignment makes integer from pointer without a cast
case 'i': dip = inet_addr(optarg);
dstip = (optarg); /* ERROR POINTS TO THIS LINE */
break;
Now I hope I've copied enough relevant information on the errors for you to be able to help, but if I've left something out let me know. For problem 1, I believe I am missing a header file of some sort but I don't know which. Problem 2 and 3 are pointer issues, but I'm not sure why they aren't correct. Thanks in advance :)
For the first problem, include the header defining TH_SYN and TH_ACK. On my system it's netinet/tcp.h
For the second problem, turn ipheader and tcpheader into pointers
For the third problem I think you need a strtoul but I'm unsure
For problem 1, you need
#include <netinet/tcp.h>
For problem 2, struct ipheader should be struct ipheader * in both your declaration and cast, as well as struct tcpheader should be struct tcpheader *
For problem 3, optarg is a pointer, and needs to be dereferenced, so refer to it as *optarg
Related
I'm trying to get into Socket programming and came across an article at https://www.tenouk.com/Module43a.html I'm having difficulty understanding as how a char array is cast into struct pointer
char buffer[PCKT_LEN];
struct ipheader *ip = (struct ipheader *) buffer;
//some code here
ip->iph_ihl = 5;
ip->iph_ver = 4;
ip->iph_tos = 16;
As per my understanding, pointer ip will now hold the address of buffer and values for members of struct ipheader will now be stored in buffer. Please help understanding the same. If I'm right, then how would we be able to print values stored in buffer?
You understanding is correct. The pointer *ip will point to buffer. char buffer[PCKT_LEN] is an array of size sizeof(char) * PCKT_LEN. Since a char is usually 1 byte long it is just a chunk of memory of PCKT_LEN bytes. PCKT_LEN is defined to be 8192
The amount of bytes needed to store a struct ipheader is much less than this. Try int a = sizeof(ipheader) and use a debugger to see the value assigned to a. For me it is 24 bytes, but it could be slightly different for you. This means that buffer can hold much more data than the struct ipheader needs. I haven't looked to deeply into the code, and I don't know much about socket programming. But one use for this could be to augment buffer with additional data outside of the struct. Since you know struct ipheader takes up sizeof(ipheader) bytes you will have sizeof(char)*8192 - sizeof(ipheader) left to augment the array.
Edit:
Upun further inspection, this is kinda what is happening:
struct ipheader *ip = (struct ipheader *) buffer;
struct udpheader *udp = (struct udpheader *) (buffer + sizeof(struct ipheader));
It tries to store the ip header at the beginning of the buffer, then it augments that same buffer with an udp header. By using buffer + sizeof(struct ipheader)
it makes sure that it stores the udp header after ipheader by offsetting buffer by sizeof(struct ipheader) bytes. Basically struct ipheader *ip points to the beginning of the buffer and struct udpheader *udp points to buffer + sizeof(struct ipheader). I hope this makes sense. Obviously there is still a lot of space left over in buffer so you could potentially augment it even further.
how a char array is cast into struct pointer
You can't do that safely. The code invokes undefined behavior:
char buffer[PCKT_LEN];
struct ipheader *ip = (struct ipheader *) buffer;
//some code here
ip->iph_ihl = 5;
ip->iph_ver = 4;
ip->iph_tos = 16;
That code violates the strict aliasing rule. That basically means memory that isn't a certain type of object can't be treated as being that type of object, with the exception that any non-char object can be treated as an array of char.
That's not what's happening in the posted code. In the posted code, a char array is being treated as if it were a struct ipheader.
The memory is not a struct ipheader - it's an array of char - so the code violates strict aliasing.
The casting from char * to struct ipheader * can also result in an improperly aligned object and violate 6.3.2.3 Pointers, paragraph 7:
A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined. ...
Code such as you've found here is unfortunately all too common as the x86-based machines that are the most common platform widely used by programmers are very forgiving of misaligned accesses, so such code tends to "work".
See Structure assignment in Linux fails in ARM but succeeds in x86 for an example of a platform where it doesn't work.
The compiler produces this warning when I'm working with some code which looks like -
....
for(p = res; p != NULL; p = p->ai_next) {
void *addr;
std::string ipVer = "IPv0";
if(p->ai_family == AF_INET) {
ipVer = "IPv4";
struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
addr = &(ipv4->sin_addr);
}
else {
ipVer = "IPv6";
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;
addr = &(ipv6->sin6_addr);
}
....
}
where p = res are of type struct addrinfo and the types producing warnings are sockaddr_in and sockaddr_in6. The warning comes from statements :
struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;
All I want to know is what is causing this warning and what can I do to correct it if this is not the proper way to do things. Could I use any of static_cast / dynamic_cast / reinterpret_cast here?
The exact warning is - cast from 'struct sockaddr *' to 'struct sockaddr_in *' increases required alignment from 2 to 4.
TLDR: This warning doesn't indicate an error in your code, but you can avoid it by using a poper c++ reinterpret_cast (thanks to #Kurt Stutsman).
Explanation:
Reason for the warning:
sockaddr consists of a unsigned short (usually 16 bit) and a char array, so its alignment requirement is 2.
sockaddr_in contains (among other things) a struct in_addr which has an alignment requirement of 4 which in turn means sockaddr_in also must be aligned to a 4 Byte boundary.
For that reason, casting an arbitrary sockaddr* to an sockaddr_in* changes the alignment requirement, and accessing the object via the new pointer would even violate aliasing rules and result in undefined behavior.
Why you can ignore it:
In your case, the object, p->ai_addr is pointing to, most likely is a sockaddr_in or sockaddr_in6 object anyway (as determined by checking ai_family) and so the operation is safe. However you compiler doesn't know that and produces a warning.
It is essentially the same thing as using a static_cast to cast a pointer to a base class to a pointer to a derived class - it is unsafe in the general case, but if you know the correct dynamic type extrinsically, it is well defined.
Solution:
I don't know a clean way around this (other than suppress the warning), which is not unusual with warnings enabled by -Weverything . You could copy the object pointed to by p->ai_addr byte by byte to an object of the appropriate type, but then you could (most likely) no longer use addr the same way as before, as it would now point to a different (e.g. local) variable.
-Weverything isn't something I would use for my usual builds anyway, because it adds far too much noise, but if you want to keep it, #Kurt Stutsman mentioned a good solution in the comments:
clang++ (g++ doesn't emit a warning in any case) doesn't emit a warning, if you use a reinterpret_cast instead of the c style cast (which you shouldn't use anyway), although both have (in this case) exactly the same functionality. Maybe because reinterpret_cast explicitly tells the compiler: "Trust me, I know, what I'm doing" .
On a side Note: In c++ code you don't need the struct keywords.
Well -Weverything enables quite a lot of warnings some of them are known to throw unwanted warnings.
Here your code fires the cast-align warning, that says explicitely
cast from ... to ... increases required alignment from ... to ...
And it is the case here because the alignement for struct addr is only 2 whereas it is 4 for struct addr_in.
But you (and the programmer for getaddrinfo...) know that the pointer p->ai_addr already points to an actual struct addr_in, so the cast is valid.
You can either:
let the warning fire and ignore it - after all it is just a warning...
silence it with -Wno-cast-align after -Weverything
I must admit that I seldom use -Weverything for that reason, and only use -Wall
Alternatively, if you know that you only use CLang, you can use pragmas to explicetely turn the warning only on those lines:
for(p = res; p != NULL; p = p->ai_next) {
void *addr;
std::string ipVer = "IPv0";
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wcast-align"
if(p->ai_family == AF_INET) {
ipVer = "IPv4";
struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
addr = &(ipv4->sin_addr);
}
else {
ipVer = "IPv6";
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;
addr = &(ipv6->sin6_addr);
}
#pragma clang diagnostic pop
....
}
To elaborate on the memcpy version. I thnk this is needed for ARM which cannot have misalligned data.
I created a struct that contains just the first two fields (I only needed port)
struct sockaddr_in_header {
sa_family_t sin_family; /* address family: AF_INET */
in_port_t sin_port; /* port in network byte order */
};
Then to get the port out, I used memcpy to move the data to the stack
struct sockaddr_in_header sinh;
unsigned short sin_port;
memcpy(&sinh, conn->local_sockaddr, sizeof(struct sockaddr_in_header));
And return the port
sin_port = ntohs(sinh.sin_port);
This answer is really related to getting the port on Arm
How do I cast sockaddr pointer to sockaddr_in on Arm
The powers that be think that to be the same question as this one, however I dont want to ignore warnings. Experience has taught me that is a bad idea.
I am getting the following error through the coverity tool -
overrun-buffer-arg: Overrunning struct type in_addr of 4 bytes by passing it to a function which accesses it at byte offset 7 using argument "8UL".
sample code:
static u_long addr;
static struct sockaddr_in remote_server;
addr = inet_addr(remote_servername);
memcpy((char *) &remote_server.sin_addr, (char *)&addr, sizeof(addr));
In the last line, I am getting the above error.
Can someone through some light on, what's going wrong.
Please let me know, if you need any more information.
inet_addr() returns an in_addr_t, not an u_long.
struct sockaddr_in's sin_addr is a struct in_addr, which holds an in_addr_t s_addr.
This should do the trick:
static struct sockaddr_in remote_server;
remote_server.sin_addr.s_addr = inet_addr(remote_servername);
Standard warning: Do not cast a pointer to/from void *.
For the message: read it carefully, it very well states the problem. Just a hint: Use proper types. You are apparently accessing a struct beyond its size. Which size doe u_long have actually?
addr should be serialized properly to an uint8_t[], respecting endianess. As you take sizeof() from the second argument, apparently the first argument is shorter.
Why do you not just assign, but use memcpy()? Check both have the same type.
I compile a C program in Solaris and get this warning.
line 68: warning: improper pointer/integer combination: op "="
My code contains
struct cmsghdr *cmsg;
Line 68 is
cmsg = CMSG_FIRSTHDR(&msg);
The structure cmsghdr and CMSG_FIRSTHDR is defined in socket.h as
#define CMSG_FIRSTHDR(m)
--
--
struct cmsghdr {
socklen_t cmsg_len;
int cmsg_level;
int cmsg_type;
};
I have included socket.h in my code. But still I get this error.
It is possible that the CMSG_FIRSTHDR macro doesn't do proper typecasting, so you have to do it yourself:
cmsg = (struct msghdr *) (CMSG_FIRSTHDR(&msg));
It might also be that there is some improper casting inside the macro itself, in which case there is nothing you can do, as it's in a system header.
please check what type SOL_SOCKET is. It needs to be int.
Change the type of the filed "cmsg_level" in your struct, if it dosen't match.
I guess SOL_SOCKET is a pointer, maybe int*
I am attempting to find the MAC address using pcap for a small project. As of right now the structure I am working with looks like this:
struct ethernet_header
{
u_char dhost[6];
u_char shost[6];
u_short type;
};
The call int the code simply loosk like:
void get_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet)
{
const struct ethernet_header *ethernet;
const struct ip_header *ip;
ethernet = (struct ethernet_header *)(packet);
ip = (struct ip_header *)(packet + 16);
printf("Destination MAC: %s\n", ethernet->dhost);
}
The error I am receiveing is
error: dereferencing pointer to incomplete type
Now as far as I know the packet var is being initalized properly because it is being used in other sections of the code without a problem. In the case of the ip struct, this also works fine with no errors. I know what is being loaded into that particluar address I just can't figure out whats going on. Anyone have any ideas.
error: dereferencing pointer to incomplete type
You missed including the header file which defines struct ethernet_header in the c file which has the function void get_packet().
The error is because the compiler cannot see the definition of the structure, most likely you are just forward declaring it. However, Since you dereference the pointer to structure the compiler must know the layout of the structure and hence must see the definition of the structure.
So just include it You need to include the header file which contains the definition of the structure in this particular c file.
These 2 lines are vulnerable to this type of error. Compiler is unable to typecast the data in any or both statements. typecast it with correct datatype, it will work.
ethernet = (struct ethernet_header *)(packet);
ip = (struct ip_header *)(packet + 16);