Just before starting, sorry for my english... i'm french.
I'm developing (in C language) a wireshark dissector to dissect a specific protocol to the company (it's owner of it) where I work but I have a problems when messages are several TCP frames ... I can not reassemble the messages when a message is broken into two different frames TCP, I can not reform it in one message...
I read the readme.dissector and try using two methods:
First method:
tcp_dissect_pdus(tvb, pinfo, tree, dns_desegment, 2,
get_dns_pdu_len, dissect_dns_tcp_pdu, data);
return tvb_captured_length(tvb);
Second method :
guint offset = 0;
while(offset < tvb_reported_length(tvb)) {
gint available = tvb_reported_length_remaining(tvb, offset);
gint len = tvb_strnlen(tvb, offset, available);
if( -1 == len ) {
/* we ran out of data: ask for more */
pinfo->desegment_offset = offset;
pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT;
return (offset + available);
}
col_set_str(pinfo->cinfo, COL_INFO, "C String");
len += 1; /* Add one for the '\0' */
if (tree) {
proto_tree_add_item(tree, hf_cstring, tvb, offset, len,
ENC_ASCII|ENC_NA);
}
offset += (guint)len;
}
/* if we get here, then the end of the tvb coincided with the end of a
string. Happy days. */
return tvb_captured_length(tvb);
But impossible to reassemble the message, I do not understand why ... can you help me please?
I hope you understand my problem ...: /
Related
I am writing an ESP32 project which receives an UDP packet and based on it some action should be carried out. There are those commands:
FON
FOFF
MSC <INT> <INT>
TC <INT>
I receive the message like this:
void receiveUdpMessages(){
int udpMsgLength = Udp.parsePacket();
if(udpMsgLength != 0){
byte udpPacket[udpMsgLength+1];
IPAddress senderIp = Udp.remoteIP();
Udp.read(udpPacket, udpMsgLength);
udpPacket[udpMsgLength] = 0;
Udp.flush();
Serial.println("Received UDP Message from : " + String(senderIp[0]) + "." + String(senderIp[1]) + "." + String(senderIp[2])+ "."+ String(senderIp[3]));
processReceivedMessage((char *)udpPacket);
}
}
and this is the processReceivedMessage method:
void processReceivedMessage(char *message){
if(strncmp("FON",message,3)==0){
setParameters(ct, 100);
}else if(strncmp("FOFF",message,4)==0){
setParameters(ct, 0);
}else if(strncmp("MSC",message,3)==0){
}else if(strncmp("TC",message,2)==0){
}
}
My question is what is the best way to split both of the ints for the parameterized commands? Also if you notice any sort of issue with above code please tell me I did not have an opportunity to test it yet.
So there's actually two seperate steps here:
Find where the integers substrings start in your message
Convert those substrings to actual ints
For step 1, there are many ways to do this, but using strchr is probably the easiest for your purposes.
For step 2, either use atoi or the safer-but-harder-to-use strtol
Here's an example for the MSC message, the one for processing the TC message will be very similar.
I've kept it as one function for clarity, but there's scope for refactoring it.
void process_msc_message(char * message)
{
int integers[2];
// strchr returns a pointer to the space character
char* substring = strchr(message, ' ');
if (substring)
{
// atoi will convert the first number it finds in the given string
integers[0] = atoi(substring);
}
// Jump forward to the next number
substring = strchr(substring+1, ' ');
if (substring)
{
integers[1] = atoi(substring);
}
// Do something with the integers...
}
I red about netmap which allows user programmers to access packets in the user space, that means user applications can read / send network packets very quickly using this netamp.
netmap :
http://info.iet.unipi.it/~luigi/netmap/
Can any one who are very familiar with netamp, tell me should we create entire packet that we want to send out, or we using the stack features to send it out.
Edit : here is example on how to use this api
https://www.freebsd.org/cgi/man.cgi?query=netmap&sektion=4
#include <net/netmap_user.h>
void sender(void)
{
struct netmap_if *nifp;
struct netmap_ring *ring;
struct nmreq nmr;
struct pollfd fds;
fd = open("/dev/netmap", O_RDWR);
bzero(&nmr, sizeof(nmr));
strcpy(nmr.nr_name, "ix0");
nmr.nm_version = NETMAP_API;
ioctl(fd, NIOCREGIF, &nmr);
p = mmap(0, nmr.nr_memsize, fd);
nifp = NETMAP_IF(p, nmr.nr_offset);
ring = NETMAP_TXRING(nifp, 0);
fds.fd = fd;
fds.events = POLLOUT;
for (;;) {
poll(&fds, 1, -1);
while (!nm_ring_empty(ring)) {
i = ring->cur;
buf = NETMAP_BUF(ring, ring->slot[i].buf_index);
// here they are saying to construct the packet
... prepare packet in buf ...
ring->slot[i].len = ... packet length ...
ring->head = ring->cur = nm_ring_next(ring, i);
}
}
}
You need to create entire packed, including ethernet, ip and tcp headers. Netmap completely bypasses kernel network stack, so you need to do all work yourself.
I'm just learning how to handle sockets and TCP connections in C. I've got an application (a long one) which basically sends and receives char arrays with the system call write from server to client and vice versa (two separate C applications of course). As long as I use it with a local connection, on the same PC, running the server on a terminal and the client on an another, everything just works fine and the data arrives at the destination. But if I try it with the server on one computer and the client on another but on the same internet line, passing to the client an address like 192.168.1.X (took from the machine on which the server is running), after the connection is established, I've got an error that tells me that the number of expected bytes (which I pass before sending the real char[]) isn't arrived. Same thing if I try the server on my PC, and the client on another one with a different line on a different provider.
There's something I'm missing, are there any limitations in sending a bunch of bytes in sequence?
The code where the error pops up.
SERVER SIDE:
r=htonl(lghstr);
w=write(myFd,&r,sizeof(int));//writes the number of incoming bytes
if(w<0) perror("writeServer4"),exit(-1);
w=write(myFd,tmp->string,lghstr);
if(w<0) perror("writeServer5"),exit(-1);
if(w!=lghstr) perror("ERROR");
CLIENT SIDE
rC=read(fdc,&cod,sizeof(int));//read incoming number of bytes
lghstr=ntohl(cod);
if(rC<0) perror("readClient3"),exit(-1);
rC=read(fdc,dest,lghstr);
if(rC<0) perror("readClient4"),exit(-1);
if(rC!=lghstr) perror("error : "), printf("didn't read the right number of bytes"),exit(-1);
Now this is basically repeated a lot of times, let's even say 300 times, and it's with big numbers that the program doesn't work.
This is the problem:
rC=read(fdc,dest,lghstr);
...
if(rC!=lghstr) perror("error : ")
The #1 fallacy with socket programming is expecting that recv() and read() will return exactly the same number of bytes corresponding to the write/send call made by the other side.
In reality, partial data is extremely likely and expected. The simple workaround is to loop on read/recv until you get the exact number of bytes expected:
size_t count = 0;
while (count < lghstr)
{
ssize_t readresult = read(fdc, dest+count, lghstr-count);
if (readresult == -1)
{
// socket error - handle appropriately (typically, just close the connection)
}
else if (readresult == 0)
{
// The other side closed the connection - handle appropriately (close the connection)
}
else
{
count += readresult;
}
}
The other alternative to looping is to the use the MSG_WAITALL flag with the socket. This means, using recv() instead of read(). You'll still need to handle the error cases.
rc = recv(fdc, dest, lghstr, MSG_WAITALL);
if (rc == -1)
{
// socket error
}
else if (rc == 0)
{
// socket closed by remote
}
else if (rc < lghstr)
{
// the other side likely closed the connection and this is residual data (next recv will return 0)
}
You do ntohl() on one side and not the other. That might be interpreting the bytes with the wrong value.
You should printf() the bytes on both sides and see what the int is being evaluated to.
Edit: I'm convinced this is a programming bug for the record.
If I had to guess, I'd say that you are not synchronous with the other side for some reason. You say this runs 'about 300 times'.
Try adding a magic integer to the protocol.
Heres an example of a client that sends in this order.
A magic integer which is always constant.
A lengh of bytes about to be sent.
The bytes to be sent.
This uses scatter gather mechanics (its nicer for serialization) but other than that it effectively is doing the same thing yours is doing, as a client, just adding a magic value.
When the receiver receives the data, it can validate that the data is coming in the right order, by checking what the magic number was that came in. If the magic is wrong it means the client or server has lost themselves positionally in the stream.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <err.h>
#include <time.h>
#define MAGIC 0xDEADBEEFLU
#define GARBAGE_MAX 65536
const int iterations = 3000;
char * create_garbage_buf(
void)
{
int rc = -1;
int fd = -1;
char *buf = NULL;
buf = malloc(GARBAGE_MAX);
if (!buf)
err(1, "Cannot allocate buf");
fd = open("/dev/urandom", O_RDONLY);
if (fd < 0)
err(1, "Cannot open urandom");
rc = read(fd, buf, GARBAGE_MAX);
if (rc < 0)
err(1, "Cannot read from urandom");
else if (rc != GARBAGE_MAX)
errx(1, "Expected %d bytes, but got %d reading from urandom",
GARBAGE_MAX, rc);
close(fd);
return buf;
}
int main() {
int fd, offset, i, rc;
uint32_t magic = MAGIC;
uint32_t blen = 0;
char *buf = NULL;
struct iovec vecs[3];
/* Seed poor random number generator */
srand(time(NULL));
/* Use a file for demonstration, but a socket will do just fine */
fd = open("/dev/null", O_WRONLY);
/* Create some garbage to send */
buf = create_garbage_buf();
if (fd < 0)
err(1, "Cannot open file");
/* The first vector, is always the magic */
vecs[0].iov_len = sizeof(uint32_t);
vecs[0].iov_base = &magic;
for (i=0; i < iterations; i++) {
/* The second vector represents lengh of what we send
* in this demonstration it is a number between 0 and
* GARBAGE_MAX/2.
*/
blen = rand() % (GARBAGE_MAX / 2);
vecs[1].iov_len = sizeof(uint32_t);
vecs[1].iov_base = &blen;
/* The last record is the data to send. Its another random
* number between 0 and GARBAGE_MAX which represents the offset
* in our garbage data to send */
offset = rand() % (GARBAGE_MAX / 2);
vecs[2].iov_len = blen;
vecs[2].iov_base = &buf[offset];
rc = writev(fd, vecs, 3);
if (rc < 0)
err(1, "Could not write data");
if (rc != (sizeof(uint32_t)*2 + blen))
errx(1, "Did not write proper number of bytes to handle");
printf("Wrote %u bytes from offset %u in garbage\n", blen, offset);
}
free(buf);
printf("Done!\n");
return 0;
}
Closely read the documentation for read()/write() and learn that those two functions do not necessarily read()/write() as much bytes as they were told to, but few. So looping around such calls counting until all data expected had been read/written is a good idea, not to say an essential necessity.
For examples how this could be done for writing you might like to have look at this answer: https://stackoverflow.com/a/24260280/694576 and for reading on this answer: https://stackoverflow.com/a/20149925/694576
I'm trying to use zlib's inflate to decompress some data I received from an http packet.
The packet is as follows:
The packet, itself, says that it's encoded with gzip, so I think it should work. However, when I run the data through the inflate function, I get "invalid block type". To be clear, I'm only passing in the highlighted portion of the packet to the inflate function. What am I missing?
Here is the code I'm using to decompress the data:
int Decompress(const u_char* strStreamIn, int nStreamInLen, u_char* strStreamOut)
{
int ret = -1;
int err = -1;
z_stream strm = {0};
strm.total_in = strm.avail_in = nStreamInLen;
strm.total_out = strm.avail_out = nStreamInLen * 6;
strm.next_in = (Bytef*) strStreamIn;
strm.next_out = (Bytef*) strStreamOut;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
err = inflateInit2(&strm, -MAX_WBITS);
if (err == Z_OK) {
err = inflate(&strm, Z_FINISH);
if (err == Z_STREAM_END) {
ret = strm.total_out;
}
else {
inflateEnd(&strm);
return err;
}
}
else {
inflateEnd(&strm);
return err;
}
inflateEnd(&strm);
return ret;
}
Yes, you need to use inflateInit2() with the second parameter as 31 to request gzip decompression. If you are feeding it the 1f 8b 08 00 ..., then you won't get "unknown header flags set". That must not be what you're doing.
By the way, it does nothing to set total_in and total_out where you do, since they are set to zero by inflateInit[2](). Setting them to the values you did in an effective location, e.g. after inflateInit, makes no sense either.
Setting avail_out to six times the input size is a guess, and won't always be sufficient. If it's not sufficient, then you'll get an error with Z_FINISH. You should be using a loop to call inflate() as many times as needed to process the input and produce the output.
I recommend that you read zlib.h, and then read how to use zlib.
I am currently in the process of making a Client and Server in the Unix/Windows environment but right now I am just working on the Unix side of it. One of the function we have to create for the program is similar to the list function in Unix which shows all files within a dir but we also have to show more information about the file such as its owner and creation date. Right now I am able to get all this information and print it to the client however we have to also add that once the program has printing 40 lines it waits for the client to push any key before it continues to print.
I have gotta the program to sort of do this but it will cause my client and server to become out of sync or at least the std out to become out of sync. This means that if i enter the command 'asdad' it should print invalid command but it won't print that message until i enter another command. I have added my list functions code below. I am open to suggestions how how to complete this requirement as the method I have chosen does not seem to be working out.
Thank-you in advance.
Server - Fork Function: This is called when the list command is enter. eg
fork_request(newsockfd, "list", buf);
int fork_request(int fd, char req[], char buf[])
{
#ifndef WIN
int pid = fork();
if (pid ==-1)
{
printf("Failed To Fork...\n");
return-1;
}
if (pid !=0)
{
wait(NULL);
return 10;
}
dup2(fd,1); //redirect standard output to the clients std output.
close(fd); //close the socket
execl(req, req, buf, NULL); //run the program
exit(1);
#else
#endif
}
Here is the function used to get all the info about a file in a dir
void longOutput(char str[])
{
char cwd[1024];
DIR *dip;
struct dirent *dit;
int total;
char temp[100];
struct stat FileAttrib;
struct tm *pTm;
int fileSize;
int lineTotal;
if(strcmp(str, "") == 0)
{
getcwd(cwd, sizeof(cwd));
}
else
{
strcpy (cwd, str);
}
if (cwd != NULL)
{
printf("\n Using Dir: %s\n", cwd);
dip = opendir(cwd);
if(dip != NULL)
{
while ((dit = readdir(dip)) != NULL)
{
printf("\n%s",dit->d_name);
stat(dit->d_name, &FileAttrib);
pTm = gmtime(&FileAttrib.st_ctime);
fileSize = FileAttrib.st_size;
printf("\nFile Size: %d Bytes", fileSize);
printf("\nFile created on: %.2i/%.2i/%.2i at %.2i:%.2i:%.2i GMT \n", (pTm->tm_mon + 1), pTm->tm_mday,(pTm->tm_year % 100),pTm->tm_hour,pTm->tm_min, pTm->tm_sec);;
lineTotal = lineTotal + 4;
if(lineTotal == 40)
{
printf("40 Lines: Waiting For Input!");
fflush(stdout);
gets(&temp);
}
}
printf("\n %d \n", lineTotal);
}
else
{
perror ("");
}
}
}
At here is the section of the client where i check that a ! was not found in the returned message. If there is it means that there were more lines to print.
if(strchr(command,'!') != NULL)
{
char temp[1000];
gets(&temp);
}
Sorry for the long post but if you need anything please just ask.
Although, I didn't see any TCP/IP code, I once had a similar problem when I wrote a server-client chat program in C++. In my case, the problem was that I didn't clearly define how messages were structured in my application. Once, I defined how my protocol was suppose to work--it was a lot easier to debug communication problems.
Maybe you should check how your program determines if a message is complete. In TCP, packets are guaranteed to arrive in order with no data loss, etc. Much like a conversation over a telephone. The only thing you have to be careful of is that it's possible to receive a message partially when you read the buffer for the socket. The only way you know to stop reading is when you determine a message is complete. This could be as simple as two '\n' characters or "\n\r".
If you are using UDP, then that is a completely different beast all together (i.e. messages can arrive out of order and can be lost in transit, et cetera).
Also, it looks like you are sending across strings and no binary data. If this is the case, then you don't have to worry about endianess.