0

If I have a buffer containing these bytes:
510175126-94-51080

How can I extract the 75126-94-51 part from it(which is the IP) and print the correct IP?

for(int i = 0; i < bytes_recv; i++) { cout << static_cast<int>(temp[i]); } cout << endl;
edit: this is my output: 5 1 0 1 75 126 -94 -51 0 80

Wenfang Du
  • 8,804
  • 9
  • 59
  • 90
Adrian
  • 19,440
  • 34
  • 112
  • 219
  • 3
    Is the string always 18 characters long? What if the last part is 12221-94-51? it is ambiguous. What do you mean by "correct IP"? Is `75126-94-51` enough or you want `75.126.94.51`? You should supply more test cases. – Simone Feb 03 '11 at 14:06
  • SOrry i forgot to say i want in c/c++ . – Adrian Feb 03 '11 at 14:09
  • @Simone: i just now that the first 4 bytes represent something else,the last 2bytes(080) should be the port,so the rest is the IP(4 bytes)...so yes,it would differe... – Adrian Feb 03 '11 at 14:10
  • @Simon: im testing a proxy server,and the client asys this: opera.exe - 75.126.162.205:80 open so i guess the ip it should send me would be that 75.126.162.205 thats way i say corect ip – Adrian Feb 03 '11 at 14:14
  • 1
    @vBx do you have dots in your buffer? If not, you cannot tell if `12221-94-51` is `122.21.94.51` or `12.221.94.51`, unless you know they can only come from certain IP classes. – Simone Feb 03 '11 at 14:17
  • I dont think so,my buffer its exactly like 510175126-94-51080, witch contains 10 bytes, 1 byte(version) + 1 byte(type of connection) + 1 byte(reserved byte) + 1 byte(type of address) + 4 bytes(ip) + 2 bytes(port) , exactly in this order. – Adrian Feb 03 '11 at 14:21
  • The other option to what @Simone is saying is to have fixed field sizes, i.e. 075126094051 or 122021094051. But you need to do one or the other in any case if you're writing the buffer. –  Feb 03 '11 at 14:23
  • @vBx: You should rewrite your question. From your description of 10 bytes you should write this like: char buffer[10] = {5, 1, 0, 1, 75, 126, 162, 205, 80, 00}. – Zan Lynx Feb 03 '11 at 15:23
  • @vBx Please, rewrite your question telling us how you got from your 10 bytes, as you explained in the above comment, to a string like "510175126-94-51080". Otherwise, it is way too ambiguous. – Juliano Feb 03 '11 at 15:28
  • I am using protocol socks5 it always send me 10 bytes of data(if the address is of type IPv4. when i do bytes_recv = ::recv(...), it equals 10 bytes,and when i print the buffer it gives me that...i donnt know why... – Adrian Feb 03 '11 at 15:37
  • @vBx How did you print the buffer? That string doesn't look at all as any printable representation or serialization of a 10-byte buffer. Also, please, edit your question to clarify with the extra information you are giving in the comments. Make the question complete. – Juliano Feb 03 '11 at 16:08
  • @Juliano: i print it using static_cast(buffer[i]) – Adrian Feb 03 '11 at 16:18
  • @vBx, ok, iteractively, I see. Please, do not hide such information from your question. It is not our job to determine how you got that number, all of these comments, specially the last, must have been part of the question. The hyphens are not hyphens, they are minus signs. You are printing everything mended. You should print spaces between each number, or even better, print it in unsigned hexadecimal. It is impossible to determine if "51080" is "5 10 80", "51 0 80", "5 108 0" or something completely different. – Juliano Feb 03 '11 at 16:27

4 Answers4

2

A lot of information is missing from the question. So, you are reading the server reply from the SOCKS protocol. First, the buffer should not and will not have a fixed size of 10 bytes. It has 10 bytes if your address is IPv4 (which coincidently was exhausted a few days ago, time to think about IPv6). If the origin has a IPv6 address, the size of the server response is different.

From RFC 1928, section 6, the server reply has this format:

+----+-----+-------+------+----------+----------+
|VER | REP |  RSV  | ATYP | BND.ADDR | BND.PORT |
+----+-----+-------+------+----------+----------+
| 1  |  1  | X'00' |  1   | Variable |    2     |
+----+-----+-------+------+----------+----------+

Note that the address field has variable size. For IPv4, specifically, ATYP == 0x01 and BND.ADDR has size 4, which makes 1+1+1+1+4+2 = 10 bytes. But you should consider that other sizes are possible, specially if ATYP == 0x03, which makes BND.ADDR truly variable in length.

So, answering your question, considering that you have these bytes in a char buffer[] array (or pointer), you must first check the type of the address, then extract it like this:

#include <arpa/inet.h>

switch (buffer[3]) {
  case 0x01: {    /* IPv4 address */
    char result[INET_ADDRSTRLEN];
    inet_ntop(AF_INET, (void*)(&buffer[4]), result, sizeof result);
    std::cout << "IPv4: " << result << "\n";
    break;
  }

  case 0x04: {    /* IPv6 address */
    char result[INET6_ADDRSTRLEN];
    inet_ntop(AF_INET6, (void*)(&buffer[4]), result, sizeof result);
    std::cout << "IPv6: " << result << "\n";
    break;
  }

  default:
    std::cout << "Unsupported format.\n";
    break;
}
Community
  • 1
  • 1
Juliano
  • 39,173
  • 13
  • 67
  • 73
  • Can i use inet_ntoa ? for windows,i guess inet_ntop is only for windows ? – Adrian Feb 03 '11 at 18:23
  • ahh,wait there is an equivalent in windows – Adrian Feb 03 '11 at 18:32
  • inet_ntoa() is obsolete, and doesn't support IPv6. inet_ntop() is the new standard, it should be available for all POSIX operating systems, and also Windows. For Windows, see: http://msdn.microsoft.com/en-us/library/cc805843%28v=vs.85%29.aspx – Juliano Feb 03 '11 at 18:35
  • Yes,that is what I am trying to use,but i am having problem finding the header it is using...its not winsock2.h... – Adrian Feb 03 '11 at 18:53
  • Neither Ws2tcpip.h how it says on msdn website – Adrian Feb 03 '11 at 18:58
  • ok,i got it to work,it shows the IP perfect;y. Thanks a lot Juliano – Adrian Feb 03 '11 at 20:35
0

In Python:

input = '510175126-94-51080'
output = input[4:-3]

print output
Blender
  • 289,723
  • 53
  • 439
  • 496
  • Yes in python its easy :) i forgot to say in c/c++ – Adrian Feb 03 '11 at 14:09
  • @vBx: The above is easily translated to std::string methods in C++; the problem is whether the [assumptions](http://stackoverflow.com/questions/4887061/extract-ip-from-a-buffer-of-bytes#comment-5436189) are valid. – Fred Nurk Feb 03 '11 at 14:31
  • @Fred Nurk: yes,i guess your write,i will give it a shoot. – Adrian Feb 03 '11 at 14:39
  • using string i get this when i print the entire buffer: 51076-69123-78114-127-75 strange – Adrian Feb 03 '11 at 14:44
0

How are you getting this buffer? Is it part of a struct sockaddr_in?

Are you showing a decimal dump of bytes starting at the lowest address of the buffer?

What you want to do is get a pointer to the base (memory) address of the IP addr part and use ntohl() to translate it to host byte order, and likewise use ntohs to translate the port addr.

edit

Suppose you have

stuct sockaddr_in foo;
char str[16];
// do some stuff that initializes foo, e.g. a call to accept() returns

You can extract the IP address in dotted-quad form with

inet_ntop(AF_INET, &(foo.sin_addr), str, sizeof(str));
wades
  • 927
  • 9
  • 24
  • I dont know how to do how you say. I am using sockaddr_in to initialize the socket,and the buffer is of type char*. Can you help ? – Adrian Feb 03 '11 at 14:34
  • i used inet_ntoa because i windwos i dont have inet_ntop so i did this: struct sockaddr_in server; cout << inet_ntoa(server.sin_addr); but it only gives me 0.0.0.0 – Adrian Feb 03 '11 at 15:08
  • @vBX - can you post a code sample that shows what you are trying to do? By which I mean, show your struct `sockaddr_in` getting initialized and what you try to do with it after that? – wades Feb 03 '11 at 16:46
0

If you have the following buffer:

buffer[10] = {5, 1, 0, 1, 75, 126, 162, 205, 80, 00};

And you want it in C/C++. I would define a struct, like this:

#pragma pack(1)
struct buffer_s {
    uint8_t  version;
    uint8_t  reserve_1;
    uint8_t  atype;
    uint32_t ip;
    uint16_t port;
};
#pragma pack()

Then put it in a union:

union buffer_u {
    char buffer[10];
    struct buffer_s data;
};

Now you can declare union buffer_u buf and read bytes into buf.buffer. Then for the ip and port fields use ntohl and ntohs to convert network byte order to host byte order.

Zan Lynx
  • 53,022
  • 10
  • 79
  • 131
  • Unions are not supposed to work like that. You can only access the last member that you have written to. If you replace "union" with "struct" your application must still work (binary incompatible, but still work). – Juliano Feb 03 '11 at 16:07
  • @Juliano: I suppose. The alternative is casting the pointer to a char type. The end result is the same. – Zan Lynx Feb 03 '11 at 20:50