What happen when we receive a truncated DNS response? - sockets

I am coding a very simple program to send CERT query and receive response from a DNS by UDP and using wireshark for debugging. I send the query as an hex string and receive response from the same socket but, even I can see the complete string (response) in wireshark, the response printed by my program is truncated. Can anyone explain to me what exactly happen when receiving a response?. I measure the response is the same query I sent!. Please give an advice, something is wrong in my code and do not know how a response should be caught. Thanks.
char recv_buffer[4096]; //to allocate the response
//sending query and receiving response
to = sendto(sock, buffer, sizeof(buffer), 0, (struct sockaddr *) &sock_addr, sizeof(sock_addr));
printf("sent %d bytes to 140.113.216.171\n", to);
int len = sizeof(recv_buffer);
bzero(&recv_buffer, len); //filling with 0 the recv_buffer
from = recvfrom(sock, recv_buffer, len, 0, NULL, NULL);
printf("received %d bytes from 140.113.216.171\n", from);
//Printing the string received
for(int c=0;c<from;c++){
printf("%c",recv_buffer[c]);
}

//Printing the string received
for(int c=0;c<to;c++){
you probably meant from not to here, since you want to have the number of bytes received, not sent.

Related

Is recv(bufsize) guaranteed to receive all the data if sended data is smaller then bufsize?

For example:
Client Side
...
socket.connect(server_address)
data = some_message_less_than_100_bytes
socket.sendall(data)
...
Server Side
...
socket.accept()
socket.recv(1024)
...
Is the server side guaranteed to receive the data in one recv()?
If not, how does the standard solution using header for specifying message length even works?
The header itself could have been split and we have to check if header has been correctly received.
Or the header is fixed length? So that the receiver can always interpret the first few bytes in the same way no matter in how many pieces that data is sent?
Actually I'm trying to do something like this
Client
while():
send()
recv()
Server
recv()
while():
send() # Acknowledge to client
recv()
which is suggested by ravi in Linux socket: How to make send() wait for recv()
but I figured out the problem described above.
Is the ravi's answer assuming that both client and server will receive what the other sent in a single recv()?
Update
I would very like to post the image but I can't because of low reputation...
Following link is the HTTP Frame Format
https://datatracker.ietf.org/doc/html/rfc7540#section-4
It indeed used a fixed length solution, so that no matter in how many pieces the header is split it can work with the same way.
So I guess, some sort of 'fixed' length is the only solution? Even if the header size itself is variable, it then probably have some promised bits to indicate how long the header would be. Am I right?
Is the server side guaranteed to receive the data in one recv()?
For UDP, yes. recv() will return either 1 whole datagram, or an error. Though, if the buffer size is smaller than the datagram then the data will be truncated and you can't recover it.
For TCP, no. The only guarantee you have is that if no error occurs then recv() will return at least 1 byte but no more than the specified buffer size, it can return any number of bytes in between.
If not, how does the standard solution using header for specifying message length even works? The header itself could have been split and we have to check if header has been correctly received. Or the header is fixed length?
It can go either way, depending on the particular format of the header. Many protocols use fixed-length headers, and many protocols use variable-length headers.
Either way, you may have to call send() multiple times to ensure you send all the relevant bytes, and call recv() multiple times to ensure you receive all them. There is no 1:1 relationship between sends and reads in TCP.
Is the ravi's answer assuming that both client and server will receive what the other sent in a single recv()?
Ravi's answer makes no assumptions whatsoever about the number of bytes sent by send() and received by recv(). His answer is presented in a more higher-level perspective. But, it is very trivial to force the required behavior, eg:
int sendAll(int sckt, void *data, int len)
{
char *pdata = (char*) data;
while (len > 0) {
int res = send(sckt, pdata, len, 0);
if (res > 0) {
pdata += res;
len -= res;
}
else if (errno != EINTR) {
if ((errno != EWOULDBLOCK) && (errno != EAGAIN)) {
return -1;
}
/*
optional: use select() or (e)poll to
wait for the socket to be writable ...
*/
}
}
return 0;
}
int recvAll(int sckt, void *data, int len)
{
char *pdata = (char*) data;
while (len > 0) {
int res = recv(sckt, pdata, len, 0);
if (res > 0) {
pdata += res;
len -= res;
}
else if (res == 0) {
return 0;
}
else if (errno != EINTR) {
if ((errno != EWOULDBLOCK) && (errno != EAGAIN)) {
return -1;
}
/*
optional: use select() or (e)poll to
wait for the socket to be readable ...
*/
}
}
return 1;
}
This way, you can use sendAll() to send the message header followed by the message data, and recvAll() to receive the message header followed by the message data.
Is the server side guaranteed to receive the data in one recv()?
No.
TCP is a byte stream, not a message protocol. While it will likely work with small messages and an empty send buffer in most cases, it will start to fail if the data send get larger than the MTU of the underlying data link. TCP does not guarantee any atomar send-recv pair though for anything but a single octet. So don't count on it even for small data.

How to know if it is safe to keep reading from a socket inputStream (avoid read blocks)

I'll give you a little bit of context first:
I have a class that is supposed to write in a socket some querys and then read the answers.
Here it is the code that is supposed to read from the inputStream:
private String getDataFromInputStream() throws IOException
{
StringBuilder sb = new StringBuilder();
InputStream stream = this.socket.getInputStream();
byte[] buff = new byte[1024];
int bytesRead = 0;
while(bytesRead >= 0)
{
bytesRead = stream.read(buff);
if (bytesRead > 0) sb.append(new String(buff, 0, bytesRead));
}
return sb.toString();
}
If the returned result is OK, this method works great, but if, for some reason, the InputStream.read keeps waiting for input it, of course, blocks.
So I changed that code to this one:
private String getDataFromInputStream() throws IOException
{
StringBuilder sb = new StringBuilder();
InputStream stream = this.socket.getInputStream();
byte[] buff = new byte[1024];
int bytesRead = 0;
while(stream.available() > 0)
{
bytesRead = stream.read(buff);
if (bytesRead > 0) sb.append(new String(buff, 0, bytesRead));
}
return sb.toString();
}
But here's the new problem: The second piece of code doesn't read the whole response. It just returns a fragment of the full response.
I know that the available() method returns 0 because the stream doesn't have more data to be read inside the buffer but there is more data to be read from the socket.
So how can I make a method flexible enought to read the whole thing even if it takes some time to the Stream to buffer the response and, also doesn't block when expecting input?
I need to get the whole response if the query succeeded and to close the input so it won't block, if the command failed and the socket is expecting any input.
Since you're using a socket, you'll need the source to tell you how much data it wants to send. That may be present in the first few bytes that is sent (in which case you wait for that specific number of bytes first) otherwise you'll have to modify the source to provide that information. This is what TCP and UDP packets do as well, where the header to the packets include the length of the data so that the client knows how many bytes to wait for.

Cancelling retransmissions on a L2CAP socket

I was wondering if anyone can assist me with a problem that I have with C Bluetooth programming (Linux Bluez).
I am using Ubuntu 10.04, BlueZ 4.60.
My goal is to have a L2CAP socket in which there will be minimal delay for sending data between 2 computers.
So far I managed to open an L2CAP socket, but this socket has endless retransmissions and I'm trying to change it. I want to have no retransmissions at all because I need the data to be transfer fast with minimal delay and the reliability of the data is not important.
I found an example online that deals with changing the flush timout for the socket and by that causing that if a packet is not acked after a certain period of time it is dropped and the next data in the buffer is sent.
The problem is that this example doesn't work :-(
Here is my code, this method is called after the bind command:
int set_flush_timeout(bdaddr_t *ba, int timeout)
{
int err = 0, dd, dev_id;
struct hci_conn_info_req *cr = 0;
struct hci_request rq = { 0 };
struct {
uint16_t handle;
uint16_t flush_timeout;
} cmd_param;
struct {
uint8_t status;
uint16_t handle;
} cmd_response;
// find the connection handle to the specified bluetooth device
cr = (struct hci_conn_info_req*) malloc(
sizeof(struct hci_conn_info_req) +
sizeof(struct hci_conn_info));
bacpy( &cr->bdaddr, ba );
cr->type = ACL_LINK;
dev_id = hci_get_route( NULL);
dd = hci_open_dev( dev_id );
if( dd < 0 ) {
err = dd;
goto cleanup;
}
err = ioctl(dd, HCIGETCONNINFO, (unsigned long) cr );
if( err ) goto cleanup;
// build a command packet to send to the bluetooth microcontroller
cmd_param.handle = cr->conn_info->handle;
cmd_param.flush_timeout = htobs(timeout);
rq.ogf = OGF_HOST_CTL;
rq.ocf = 0x28;
rq.cparam = &cmd_param;
rq.clen = sizeof(cmd_param);
rq.rparam = &cmd_response;
rq.rlen = sizeof(cmd_response);
rq.event = EVT_CMD_COMPLETE;
// send the command and wait for the response
err = hci_send_req( dd, &rq, 1 );
if( err ) goto cleanup;
if( cmd_response.status ) {
err = -1;
errno = bt_error(cmd_response.status);
}
cleanup:
free(cr);
if( dd >= 0) close(dd);
return err;
}
What is my mistake?
Does anyone know another option that will solve my problem.
Code examples will also be great!!
Thanks!!
This code to set the automatic flush time out seems to be correct.
You can make sure by ensuring that you are getting "Success" in response to this command's command complete event.
I suspect that the issue might be in your packet sending code, note that for the automatic flush timeout to take effect the individual packets should be marked as automatically flushable, The HCI data packet has the Packet_Boundary_Flag which you can sent to indicate if individual packets are flushable.
Also note that the Flush timeout has to be large enough to allow for enough time so that the packets gets a transmission attempt, the way the flush timeout are defined can cause the packet to be flushed even without the packet being transmitted even once, so you need to tune it. By definition Flush timeout start when the packet is Queued for transmission.

SIP Registration Issue

I am currently working on SIP sample application.
I am trying to do the registration using C based Socket programming on Unix. I have been successfully being able to get register with PJSIP, but when the same parameters I am sending with normal socket programming, then I am not being able to receive any response from server.
Here is the source code:
char *server = (char *)serverAddress; // First arg: server address/name
char *echoString = "Request msg REGISTER/cseq=46476 (tdta0x8857200)\r\nREGISTER sip:DOMAIN_NAME SIP/2.0\r\nVia: SIP/2.0/UDP 192.168.1.120:51648;rport;branch=z9hG4bKPjwEt4VvIVdjIJKRmEJbkidYDAu-zQbIqv\r\nMax-Forwards: 70\r\nFrom: <sip:USER_NAME#DOMAIN_NAME>;tag=epCBN7JXsQE1nnI5d5SOZe9a5ujRyI67\r\nTo: <sip:USER_NAME#DOMAIN_NAME>\r\nCall-ID: .5yYCqh2jEYdy5T4kxhzxwDYEkCO1XlD\r\nCSeq: 46476 REGISTER\r\nContact: <sip:USER_NAME#192.168.1.120:51648;ob>\r\nExpires: 300\r\nAllow: PRACK, INVITE, ACK, BYE, CANCEL, UPDATE, SUBSCRIBE, NOTIFY, REFER, MESSAGE, OPTIONS\r\nAuthorization: Digest username=\"USER_NAME\", realm=\"asterisk\", nonce=\"3b63254c\", uri=\"sip:DOMAIN_NAME\", response=\"9e8fc78829d143a58fba5a79f6ad44fd\", algorithm=MD5\r\nContent-Length: 0";
size_t echoStringLen = strlen(echoString);
// Third arg (optional): server port/service
char *servPort = (char *)service;
// Tell the system what kind(s) of address info we want
struct addrinfo addrCriteria; // Criteria for address match
memset(&addrCriteria, 0, sizeof(addrCriteria)); // Zero out structure
addrCriteria.ai_family = AF_UNSPEC; // For the following fields, a zero value means
// Any address family "don't care"
addrCriteria.ai_socktype = SOCK_DGRAM; // Only datagram sockets
addrCriteria.ai_protocol = IPPROTO_UDP; // Only UDP protocol
// Get address(es)
struct addrinfo *servAddr; // List of server addresses
int rtnVal = getaddrinfo(server, servPort, &addrCriteria, &servAddr);
if (rtnVal != 0)
DieWithUserMessage("getaddrinfo() failed", gai_strerror(rtnVal));
// Create a datagram/UDP socket
int sock = socket(servAddr->ai_family, servAddr->ai_socktype,
servAddr->ai_protocol); // Socket descriptor for client
if (sock < 0)
DieWithSystemMessage("socket() failed");
// Send the string to the server
ssize_t numBytes = sendto(sock, echoString, echoStringLen, 0,
servAddr->ai_addr, servAddr->ai_addrlen);
if (numBytes < 0)
DieWithSystemMessage("sendto() failed");
else if (numBytes != echoStringLen)
DieWithUserMessage("sendto() error", "sent unexpected number of bytes");
// Receive a response
struct sockaddr_storage fromAddr; // Source address of server
// Set length of from address structure (in-out parameter)
socklen_t fromAddrLen = sizeof(fromAddr);
char buffer[100 + 1]; // I/O buffer
numBytes = recvfrom(sock, buffer, 100, 0,
(struct sockaddr *) &fromAddr, &fromAddrLen);
if (numBytes < 0)
DieWithSystemMessage("recvfrom() failed");
else if (numBytes != 100)
DieWithUserMessage("recvfrom() error", "received unexpected number of bytes");
// Verify reception from expected source
int value = SockAddrsEqual(servAddr->ai_addr, (struct sockaddr *) &fromAddr);
if (value == 0)
DieWithUserMessage("recvfrom()", "received a packet from unknown source");
freeaddrinfo(servAddr);
buffer[echoStringLen] = '\0'; // Null-terminate received data
printf("Received: %s\n", buffer); // Print the echoed string
close(sock);
exit(0);
When I am trying to debug the code, then the breakpoint gets disappeared from recvfrom method call as follows.
numBytes = recvfrom(sock, buffer, 100, 0, (struct sockaddr *) &fromAddr, &fromAddrLen);
Thanks in advance for your co-operation.
If you are not getting a response from the Registrar server it's most likely because it couldn't understand the REGISTER request you sent it or rejected it as a duplicate. More that likely you will need to get a bit more sophisticated about how you are constructing your REGISTER request rather than simply sending a hard coded string.
Apart from that one obvious thing you could try is to add the required \r\n\r\n onto the end of your echoString. All SIP requests are required to end the header portion with a double line break and that is missing from your string.
recvfrom() blocks until a response is received, unless you set the socket to non-blocking. A better approach would be to use select() with a timeout (like a second or two). Better still would be to then put the entire thing into a loop which retries some number of times (like three or four).
Remember that UDP makes no guarantees that your datagram will be delivered: it is entirely up to you to decide when you've waited long enough and need to try again.
Also, check that the values being set in servAddr by getaddrinfo() make sense. If the address or port number is wrong, your packet may silently disappear.
If you confirm that this is socket issue then good to trace.
But if you are not sure then for this kind of issue use network analyze application (wireshark) & see the packet you send & receive. Then look into socket issue.

How read the TCP packet of a stream using a socket in C?

let me first tell what I am trying to do.
I am trying to write a very simple proxy server.
I used the socket API to create a socket.
socket = socket(AF_INET, SOCK_STREAM, 0));
my proxy server worked fine until I tried it for a streaming data.
So what I did was my server socket listened to the requests and parsed them and then forwarded them to the actual server, I then used the read() call to read the packet & I blindly forward it back to the client.
For all html pages and images it works fine. but when I try to forward a streaming video I am not able to do it.
My socket always returns the application layer data (HTTP packet) but in a streaming video only the first packet is http and rest all are just TCP packets. So I am able to forward only the first HTTP packet. When I try to read the other packets which contain data (which are all TCP) I don't get anything at the application layer (which is obvious as there is nothing at application layer in those packets ). So I am stuck and I do not know how to read those packets from TCP layer (I dont wanna use raw socket) and get my job done.
thanks in advance
You have to parse the packet header to know how much data to read from the socket. at first, use a ring buffer (a circular one!) for example the BSD sys/queue.h to order the received data from the stream.
The code below shows how to extract header_length, total_length, source and destination Address of an IPv4 packet in layer 3. refer to IPv4 packet layout to understand offsets:
typedef struct {
unsigned char version;
unsigned char header_length;
unsigned short total_length;
struct in_addr src;
struct in_addr dst;
} Packet;
int rb_packet_write_out(RingBuffer *b, int fd, int count) {
int i;
for (i = 0; i < count; i++) {
if (b->level < 20) {
return i;
}
Packet p;
unsigned char *start = b->blob + b->read_cursor;
unsigned char b1 = start[0];
p.version = b1 >> 4;
p.header_length = b1 & 0xf;
p.total_length = bigendian_deserialize_uint16(start + 2);
if (b->level < p.total_length) {
return i;
}
memcpy(&(p.src), start + 12, 4);
memcpy(&(p.dst), start + 16, 4);
char s[5], d[5];
inet_ntop(AF_INET, &(p.src), s, INET_ADDRSTRLEN);
inet_ntop(AF_INET, &(p.dst), d, INET_ADDRSTRLEN);
L_DEBUG("Packet: v%u %s -> %s (%u)", p.version, s, d, p.total_length);
}
return i;
}
If you use the socket API, then you are on the layer below HTTP, that is, to you everything is "just TCP". If the connection is stuck somewhere, it is most likely that something else is broken. Note there is no guarantee that the HTTP request or reply header will even fit in a single packet; they just usually do.
An HTTP 1.1 compliant streaming server will use "Content-Encoding: chunked" and report the length of each chunk rather than the length of the entire file, you should keep that in mind when proxying.
So what I did was my server socket
listened to the requests and parsed
them
Why? An HTTP proxy doesn't have to parse anything except the first line of the request, to know where to make the upstream connection to. Everything else is just copying bytes in both directions.