Conversion of IPv6 to IPv4 gives 0.0.0.1 only - c++

I am writing a Java interposer (using LD_PRELOAD method) that modifies the recipient information in network communication system calls (connect/sendto).
Whenever Java tries to connect to another socket, I modify the intended recipient IP and port. Java uses IPv4-mapped-IPv6 addresses. So, I need to extract the IPv4 part of it. I achieve this using the method prescribed by Nicolas Bachschmidt at link.
The problem I am facing is that for every IPv4-mapped-IPv6 address, the result string (IPv4 part) I obtain is always 0.0.0.1. Instead it should be 10.0.0.1 (for ::ffff:10.0.0.1). I have tried this with different IP addresses. The result is always the same.
Two things I would like to mention that I think may be related:
When I tested the same program a month ago on my local network (that has 192.168.1.XXX IP addresses), the program worked correctly. Point being (I don't think) there is any problem with code. To verify this, I asked a question on stackoverflow to convert IPv4-mapped-IPv6 addresses to IPv4, the link of which is mentioned earlier).
I am trying to test this program now on my university network (that has 10.XXX.XXX.XXX IP addresses) and VirtualBox (NAT mode that also gives 10.XXX.XXX.XXX addresses). However, I have tried to connect to 10.0.0.1 and 12.0.0.1 in these cases. Both give 0.0.0.1.
What am I doing wrong?
UPDATE: In Java, socket connection is done by the usual method:
Socket conn = new Socket("10.0.0.1", 50021);
The code to interpose this connect() system call is as follows:
int connect(int fd, const struct sockaddr *sk, socklen_t sl)
{
struct sockaddr_in *lsk_in = (struct sockaddr_in *) sk;
struct sockaddr_in6 *lsk_in6 = (struct sockaddr_in6 *) sk;
struct sockaddr_in addr4;
unsigned int len;
int nbytes, oport, tport, ret, i;
char ip_address[30];
char buffer[1024];
char tempBuffer[1024];
if((lsk_in->sin_family == AF_INET) || (lsk_in->sin_family == AF_INET6))
{
if(lsk_in->sin_family == AF_INET)
{
oport = ntohs(lsk_in->sin_port);
memcpy(&addr4.sin_addr.s_addr, &lsk_in->sin_addr.s_addr, sizeof(addr4.sin_addr.s_addr));
}
else if(lsk_in->sin_family == AF_INET6)
{
oport = ntohs(lsk_in6->sin6_port);
//This is where the problem is. I always get 0.0.0.1
memcpy(&addr4.sin_addr.s_addr, lsk_in6->sin6_addr.s6_addr+12, sizeof(addr4.sin_addr.s_addr));
}
memset(buffer, '\0', sizeof(buffer));
sprintf(buffer, "%s%c%s%c%i", NAT_VM_CONNECT_RULE, NAT_VM_DELIMITER, (char *)inet_ntoa(addr4.sin_addr), NAT_VM_DELIMITER, oport);
nbytes = send(sock, buffer, strlen(buffer), 0);
if(DEBUG_MODE)
fprintf(stdout, "[LD_INTERPOSER] Sent[%s]\n", buffer);
memset(buffer, '\0', sizeof(buffer));
nbytes = recv(sock, buffer, sizeof(buffer), 0);
fprintf(stderr, "[LD_INTERPOSER] Received CONNECT [%s]\n", buffer);
memset(ip_address, '\0', sizeof(ip_address));
int pos = strrchr(buffer, NAT_VM_DELIMITER) - buffer;
strncpy(ip_address, buffer, pos);
ip_address[pos] = '\0';
tport = atoi(buffer + pos + 1);
if(lsk_in->sin_family == AF_INET)
{
lsk_in->sin_addr.s_addr = inet_addr(ip_address + 7);
lsk_in->sin_port = htons(tport);
}
else if(lsk_in->sin_family == AF_INET6)
{
inet_pton(AF_INET6, ip_address, &(lsk_in6->sin6_addr));
lsk_in6->sin6_port = htons(tport);
}
fprintf(stderr, "[LD_INTERPOSER] IP[%s], Port[%d] for VM[%s]\n", ip_address, tport, vm_ip);
}
return real_connect(fd, sk, sl);
}

Thanks to #ugoren hex dump technique (in comments), I was able to figure out that the IPv6 structure itself contained a 0.0.0.1 address. I realized that the problem may be due to different JDKs. The Java project was built using OpenJDK 7 while the PC I was using had OpenJDK 6. When I updated the JDK to version 7, the error disappeared. However, it has landed me to another error which is documented at a new stackoverflow question which I am still unable to resolve.

Related

How to fix 'Address already in use' returned by bind() in AF_UNIX

I'm familiarising myself with Unix Sockets for Inter-Process Communication, and following a guide here. Each time I run the program that acts as a server (referred to as echos.c in the guide), I am getting an error that says bind: Address already in use, except for the first time I run it after deleting all build files.
The error is coming from this section of code:
#define SOCK_PATH "echo_socket"
int main(void)
{
int s, s2, len;
socklen_t t;
struct sockaddr_un local, remote;
char str[100];
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
local.sun_family = AF_UNIX;
strcpy(local.sun_path, SOCK_PATH);
unlink(local.sun_path);
len = strlen(local.sun_path) + sizeof(local.sun_family);
if (bind(s, (struct sockaddr *)&local, len) == -1) {
perror("bind");
exit(1);
}
// ...
In the initial run, the program creates a socket file called echo_socke (I have checked this with ls -l, and it is strange that the name is missing the 't' to make it echo_socket), and then goes on to successfully bind and listen for the client process.
However, in subsequent runs where I do not delete the build files, I get the error bind: Address already in use, coming from the lines
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
Doing additional testing I found that unlink(local.sun_path) is returning a No such file or directory error, so I figure the socket file that the bind is attempting to access is not being found. Could this be due to the file name missing a character as mentioned earlier? (But it works on the first time around, so it can't be?). Any help figuring out what is going on would be much appreciated.

Directed UDP to IP address that doesn't exist

I am experiencing slowdowns when attempting to send a UDP message to an IP address that is non-existent. We read a list of IP/ports out of a configuration file and expect that those combinations will exist. In some situations, the remote machine may not be online yet and the IP will not exist on the network. In this case, i would prefer that we do not attempt to send the data.
I'm looking for suggestions on a good way to determine that the IP doesn't exist in order to skip sending the data. I do not want to completely remove it from the list because there is the chance that the machine may come online and i'd like to continue sending data.
Relevant code:
int SendData(const char *data, int size, bool openIfClosed)
{
std::lock_guard<std::mutex> lock(sendMutex);
//if the socket was not already opened, close it after i do my send
bool closeAfterSend = mySocket == INVALID_SOCKET ? true : false;
if (!OpenSocket(openIfClosed))
return 0;
sockaddr_in address;
address.sin_family = AF_INET;
address.sin_port = htons(remotePort);
address.sin_addr.s_addr = remoteIPAddress.GetIPAddressAsULong();
//check if remote address exists prior to send?
int bytesSent = sendto(mySocket, data,
size, 0, (struct sockaddr *)&address, sizeof(address));
if (bytesSent == size)
numMsgsOut++;
else
{
//fail
}
if (closeAfterSend && openIfClosed)
{
closesocket(mySocket);
mySocket = INVALID_SOCKET;
}
return bytesSent;
}

Execute a command on the server and send the result to the client in Windows

I'm writing a simple server program that executes a command and sends the result to the client. I read countless examples that involve using popen(), pipe(), dup2(), fork(), etc., but none of them worked for me and they didn't explain the code very well. I also tried to do it myself, but without success. Could you please provide me with a well documented example?
Here's the code that receives commands/messages from the client:
void server_receive() {
struct sockaddr_in from;
int from_len, recv_len;
char buf[BUFLEN], path[256]; // BUFLEN = 1024
// Getting the path for the command to execute
strcpy(path, getenv("SYSTEMDRIVE"));
strcat(path, "\\WINDOWS\\System32\\tasklist.exe");
from_len = sizeof(from);
memset(buf, '\0', BUFLEN);
// Receiving the command
// I'll add some if-else statements to handle various commands, but for
// now I just need to see if I can even get one to work.
if((recv_len = recvfrom(sockt, buf, BUFLEN, 0, (struct sockaddr*) &from, &from_len)) == SOCKET_ERROR) {
printf("[ERROR] recvfrom() failed: %d.\n\n", WSAGetLastError());
} else {
printf("Packet received from %s:%d\n", inet_ntoa(from.sin_addr), ntohs(from.sin_port));
printf("Data: %s\n\n", buf);
// Code to execute tasklist (I used _popen())
// and send everything back to the client (I used TransmitFile())
}
}
And here's the code that sends commands/messages to the server:
void client_send(char server[], unsigned short port) {
struct sockaddr_in to;
int s, to_len = sizeof(to);
char buf[BUFLEN]; // BUFLEN = 1024
char message[BUFLEN];
memset((char*) &to, 0, sizeof(to));
to.sin_family = AF_INET;
to.sin_port = htons(port);
to.sin_addr.S_un.S_addr = inet_addr(server);
while(true) {
printf("Enter message: ");
gets(message);
if (sendto(sockt, message, strlen(message), 0, (struct sockaddr*) &to, to_len) == SOCKET_ERROR) {
printf("[ERROR] sendto() failed: %d.\n\n" , WSAGetLastError());
}
memset(buf, '\0', BUFLEN);
if (recvfrom(sockt, buf, BUFLEN, 0, (struct sockaddr*) &to, &to_len) == SOCKET_ERROR) {
printf("[ERROR] recvfrom() failed: %d.\n\n", WSAGetLastError());
} else {
printf("Server's response: %s\n\n", buf); /* The result of tasklist
should be outputted by this line of code, however I'm concerned about the
relatively small receive length (BUFLEN = 1024).*/
}
}
}
Needless to say that these two functions are just a part of my code.
That you mention _popen (with the leading underscore) and TransmitFile indicates that you are on Windows, which doesn't have fork or pipe or related functions.
There are many alternatives to executing commands in Windows. One is through _popen as you already mentioned (but you don't say what's wrong with that method). Others include the "classic" system CRT function. And of course the Windows native CreateProcess function. If you want to open a "document" there's the ShellExecute function.
Knowing which functions are available will help you in your search for examples. Adding the term windows to your searches will help finding Windows-specific examples and tutorials. And adding the term msdn will help finding topics on the Microsoft Developer Network.

Bluetooth can receive data but cannot transmit it (socket programming in C++ to communicate Matlab)

I am using Raspberry Pi 3's internal bluetooth and I am writing a c++ code to connect the bluetooth of my windows PC. On the PC side, I use Matlab and I am able to send bytes to raspberry. However when I try to send bytes from raspberry to PC, I get the following error:
"Transport endpoint is not connected"
and Matlab says "Unsuccessful read: the specified amount of data was not returned within the timeout period".
Another interesting thing is that, when I try to send more than three bytes from Matlab, raspberry only receives the first three as if the rest did not exist. If I use two reads in a row, I am able to get 6 bytes and so on. Just pointing this odd fact since I thought it might be connected with my main problem and be a clue.
I have also tried to send a file manually, using the bluetooth symbol on menubar and it worked. So c++ code should be doing something different to cause this problem.
What is likely to be the cause of my problem? How can I send data from raspberry to my computer using c++?
My code is as follows:
(Referred website: http://people.csail.mit.edu/albert/bluez-intro/index.html)
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/rfcomm.h>
int main(int argc, char **argv)
{
struct sockaddr_rc loc_addr = { 0 }, rem_addr = { 0 };
char buf[1024] = { 0 };
int s, client, bytes_read;
socklen_t opt = sizeof(rem_addr);
// allocate socket
s = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
bdaddr_t tempBDADDR = {0};
// bind socket to port 1 of the first available
// local bluetooth adapter
loc_addr.rc_family = AF_BLUETOOTH;
loc_addr.rc_bdaddr = tempBDADDR;
loc_addr.rc_channel = (uint8_t) 1;
bind(s, (struct sockaddr *)&loc_addr, sizeof(loc_addr));
// put socket into listening mode
listen(s, 1);
// accept one connection
client = accept(s, (struct sockaddr *)&rem_addr, &opt);
ba2str( &rem_addr.rc_bdaddr, buf );
fprintf(stderr, "accepted connection from %s\n", buf);
memset(buf, 0, sizeof(buf));
// read data from the client
bytes_read = read(client, buf, sizeof(buf));
if( bytes_read > 0 ) {
printf("received [%s]\n", buf);
}
int status = 0;
// send a message
if( status == 0 ) {
status = write(s, "hello!", 6);
}
if( status < 0 ) perror("uh oh");
// close connection
close(client);
close(s);
return 0;
}
Matlab side is as straight forward as:
b = Bluetooth('raspberrypi', 1);
fopen(b);
fwrite(b, uint('1234'));
input = fread(b,6)
fclose(b);
clear('b');
EDIT:
Just figured that I do not get the "Transport endpoint is not connected" when I use the following line. However this only allows me to connect as client, whereas matlab only has a client type of connection. So now, I am able to send data to my computer from another socket without getting any errors, but cannot read it with matlab.
status = connect(s, (struct sockaddr *)&addr, sizeof(addr));
Just figured it out. Leaving this here in case it helps someone else as well.
When a connection is accepted, a new descriptor is returned (along with a new socket). This is a significant difference from connect(). So I was wrong at the following line.
status = write(s, "hello!", 6);
changing it to
status = write(client, "hello!", 6);
worked like a charm.
(Reference: http://users.pja.edu.pl/~jms/qnx/help/tcpip_4.25_en/prog_guide/sock_advanced_tut.html)

Losing data consistently over sockets (but not when using localhost connections)

I'm trying to get comfortable with socket programming. I've written a client/server game, and am seeing some strange results.
Below is the code for the client portion:
while(1){
char response[100];
memset(&buf[0], 0, sizeof(buf));
//buf[numbytes] = '\0';
socklen_t addr_len = sizeof their_addr;
if ((numbytes = recvfrom(sockfd, buf, MAXDATASIZE-1, 0, (struct sockaddr *)&their_addr, &addr_len)) == -1) {
perror("recv");
exit(1);
}
if (strcmp(buf, "exit 99") == 0){
close(sockfd);
return 0;
}
printf("%s\n",buf);
std::cin >> response;
struct msgstruct message;
message.send_data = response;
message.length = strlen(message.send_data);
int n = sendto(sockfd, response, strlen(response), 0, p->ai_addr, p->ai_addrlen);
}
This communicates through the "server", via the following code snippet:
int StartMasterMind(int client, sockaddr_storage addr_in)
{
struct sockaddr_storage their_addr = addr_in;
socklen_t addr_len;
char buf[MAXDATASIZE];
buf[MAXDATASIZE] = '\0';
sendMsg(client, "Welcome to ... M-A-S-T-E-R-M-I-N-D.\nThe game has begun.\n");
// [..] redacted for clarity
for (int i = 0; i < 8; ++i) {
sendMsg(client, "Please enter your guess: ");
addr_len = sizeof their_addr;
recv(client, buf, MAXDATASIZE-1, 0/*, (struct sockaddr *)&their_addr, &addr_len*/);
current_try = GetInputAsColorMap(buf);
// [..] redacted for clarity -- several for() loops below here
}
//basic message structure
struct msgstruct {
int length;
char* send_data;
};
//basic method for sending messages
int sendMsg(int client, char* theMsg)
{
msgstruct message;
message.send_data = theMsg;
message.length = strlen(message.send_data);
return (send(client, message.send_data, message.length, 0));
}
So, if I connect via local host: ./client localhost <port>, then everything appears to be ok:
c#ub1:~/Documents/dev$ ./client localhost 9990
client: connecting to 127.0.0.1
Welcome to ... M-A-S-T-E-R-M-I-N-D.
The game has begun.
Please enter your guess:
However, when connecting over the network from another VM, I consistently get:
c#ub1:~/Documents/dev$ ./client 192.168.1.111 9990
client: connecting to 192.168.1.111
Welcome to ... M-A-S-T-E-R-M-I-N-D.
The game has begun.
Notice the missing Please enter your guess: - I'm a bit at a loss for what to do here. I can't figure out why/when/where this data is getting dropped. Because of this, I'm a little afraid to continue, because I just assume somewhere I have a buffer that's going to overflow and wreck everything.
You're making all the usual mistakes. You're assuming that one send equals one receive. You're not making use of the read count returned by recv() when using he receive buffer. You're assuming that TCP is a messaging protocol. It's a byte-stream protocol.