redleo85 redleo85 - 11 months ago 60
C Question

Parse 6-byte IP/Port string to in_addr structure in c

I'm trying to build a little bittorrent client to store data in the bittorrent dht.
Since much of the bittorrent functionality is not needed I'm trying to stay as simple as possible, since it only needs to function in a couple of limited use cases.

I'm trying to parse information about new nodes from a message, which I get from a bootstrap node. The information about each node is 26-bytes long. 20-bytes is node ID, 4 bytes IP address and 2 bytes port number. All the info is in binary.
I want to store the ip address and port number in a struct (myNode) which has got an in_addr parameter for the IP and unsinged short for the port.

typedef struct myNode {
unsigned char id[21];
struct in_addr ip;
unsigned short port;
} myNode;

The parsing of the ID works fine. But the parsing of the IP and port fails. Sometimes it works, mostly it does not and never both work at the same time. I think there might be something wrong with the bitwise shift I'm doing, but I don't know what. When I printf the IP in hex after parsing I mostly get something like this:


So it seems like the first to shifts are not working. The other bits are correct. What am I doing wrong?

int get_nodes_from_find_node(char *msg, myNode *setme) {
char *fnstr = "nodes";
char *pos, *ptr;
long lenNodes;
int nrNodes, i = 0, k = 0;

pos = strstr(msg, fnstr); // Find nodes section.
if(pos == NULL) { return -1; }
pos += strlen(fnstr);

lenNodes = strtoul(pos, &ptr, 10); // Save the length of the nodes section in lenNodes
nrNodes = lenNodes / 26; // Get number of nodes, about which info is delivered.
pos = ptr+1; // Set pos to first node.

while(nrNodes > 0) {
for(k=0;k<20;k++,pos++) { // First 20 bytes are ID.
setme[i].id[k] = *pos;
setme[i].id[20] = '\0'; // Make ID a Null-terminated string.

setme[i].ip.s_addr = (*pos << 24) | (*(pos+1) << 16) | (*(pos+2) << 8) | *(pos+3); // Next 4 bytes are IP in network byte order.
pos += 4;

setme[i].port = (*pos << 8) | *(pos+1); // Last 2 bytes are port.
pos += 2;

return 0;

Answer Source

Your problem is in (*pos << 24) | (*(pos+1) << 16) | (*(pos+2) << 8) | *(pos+3).

If any of the values in pos[0,...,3] is negative, then the entire expression is negative.