how to connect to a bit torrent tracker in c - c

I am tying to connect to a bit torrent tracker, http://tracker.thepiratebay.org. The gethostbyname() keeps returning null, how should I fix this? Also do you see anything else wrong with this code?
int sock;
struct sockaddr_in servAddr;
int portNum = 80;
if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0){
printf("fail create socket");
return 0;
}
char *path = "http://tracker.thepiratebay.org/";
struct hostent *hp = gethostbyname(path);
if(hp==NULL){
printf("null");
else{
memset(&servAddr, 0, sizeof(servAddr));
servAddr.sin_family = AF_INET;
memcpy( (char *) &servAddr.sin_addr.s_addr, (char *) hp->h_addr, hp->h_length );
servAddr.sin_port = htons(portNum);
}
//send request to tracker server
if (send(sock, requestToSend, strlen(requestToSend), 0) != strlen(requestToSend)){
printf("fail send");
return 0;
}

The problem here is that http://tracker.thepiratebay.org/ is a URL, but gethostbyname() expects just the host name. The host name is tracker.thepiratebay.org.
It would make it much easier if you just use libcurl, which will handle all of that HTTP stuff for you. It is extremely common to use libcurl in applications that connect to HTTP servers; it is an excellent library. It's certainly easier than socket programming.
Use getaddrinfo()
The modern alternative to gethostbyname() is getaddrinfo(). It's not that gethostbyname() doesn't do what you want, rather, getaddrinfo() is simply better in every conceivable way.
struct addrinfo hint, *ap;
memset(&hint, 0, sizeof(hint));
hint.ai_family = AF_UNSPEC;
hint.ai_socktype = SOCK_STREAM;
int r = getaddrinfo("tracker.thepiratebay.org", "http", &hint, &ap);
This will not only get you the address for the host you want, but it will also fill in the port number. You can use "http" as the port, or you can use "80" for the port, they are the same thing (as long as /etc/services has the right entry).
Other problems
This line is wrong.
memcpy( (char *) &servAddr.sin_addr.s_addr, (char *) hp->h_addr, hp->h_length );
You don't know that gethostbyname() returned an IPv4 address, and it is foolish to try and copy it into a struct sockaddr_in. If gethostbyname() returned an IPv6 address, you have just smashed your stack and your program will crash -- or worse, it might not crash.
Either check that it returns an IPv4 address, or simply copy hp->h_addr into a generic struct sockaddr that was returned from malloc(hp->h_length). This is a bit ugly but it's the way it goes.
Finally, it is wrong to cast the arguments to memcpy(). It's not an error, but it's wrong. Don't do it, it can cause otherwise legitimate compiler errors to be suppressed, e.g., if you accidentally cast an int to char *.

Related

Server socket: get own IP direction after accept [duplicate]

I want to get the IP address of the computer my program is launched on, to be able then to send it to a client, but I always get 0.0.0.1 instead of the real IP address (like 127.0.0.1 for instance).
I'm currently able to get the port, but not the IP address.
How can I get it?
The best solution would be to be able to get it with a sockaddr_in. Here's what I'm currently doing:
int open_connection(char* ip, int* port)
{
int sock;
struct sockaddr_in sin;
socklen_t len;
int i;
i = 0;
len = sizeof(sin);
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
return (-1);
bzero(&sin, sizeof(struct sockaddr_in));
sin.sin_family = AF_INET;
if (bind(sock, (struct sockaddr *) &sin, sizeof(sin)) != 0)
perror("Error on bind");
if (getsockname(sock, (struct sockaddr *)&sin, &len) != 0)
perror("Error on getsockname");
strcpy(ip, inet_ntoa(sin.sin_addr)); // IP = 0.0.0.0
*port = sin.sin_port;
return (sock);
}
EDIT: I understand I was going on the wrong way with my way of thinking. So my question is: What's the best way to get your own IP address?
When you bind() a socket to 0.0.0.0, that is the only IP the socket has available when calling getsockname(). It means the socket is bound to all local interfaces. In order to get a specific IP from a socket, it has to be bound to a specific IP.
Using the socket API to get the machine's local IP(s) is the wrong approach anyway. A common mistake is to use gethostname() with gethostbyname() or getaddrinfo() to get the local IP list. Usually that works, but it has some hidden gotchas that can cause false information, but people tend to ignore that fact, or don't even know about it in the first place (I didn't know about it for years, but then I learned better).
Instead, you really should use platform-specific APIs for enumerating the local networking interfaces. That will provide more reliable information. Windows has GetAdaptersInfo() and GetAdaptersAddresses(). Other platforms have getifaddrs(). Those will tell you what local IPs are available. You can then bind() a socket to 0.0.0.0 in order to accept clients on any of those IPs, or bind() to a specific IP to accept clients only on that IP.
The sockets API allows you to enumerate the IP addresses assigned to your network interfaces, but it will not tell you what you "real IP" is if you are connecting to the Internet from behind a router.
The only way to know it is by asking someone outside. Thats how servers like FileZilla FTP Server do that. They instruct you to configure the URL to a "ip.php" script like this one in the server's settings so it can ask the Internet whats its public IP address, to use in Passive Mode.
You can also consider using STUN, a protocol widely used in VoIP to discover public IP.
You could call ioctl(sock, SIOCGIFADDR, adr)
see netdevice(7)
Following #Remy Lebeau's answer I wrote a function that return current machine's address. I have only tested this on macOS High Sierra.
interfaec can be anything among lo0, en0, etc.
ipVersion can be AF_INET or AF_INET6.
long int getInternalAddress(char* interface, sa_family_t ipVersion)
{
struct ifaddrs *ifaddrHead, *ifaddr;
/* int_8 */
sa_family_t family;
int n;
char *interfaceName;
if (getifaddrs(&ifaddrHead) != 0)
{
fprintf(stderr, "ifaddrs error");
}
/* iterate through address list */
for (ifaddr = ifaddrHead, n = 0; ifaddr != NULL; ifaddr = ifaddr->ifa_next, n++)
{
family = ifaddr->ifa_addr->sa_family;
interfaceName = ifaddr->ifa_name;
if (!family || family != ipVersion || strcmp(interfaceName, interface)) continue;
struct sockaddr *addr = ifaddr->ifa_addr;
struct sockaddr_in* addr_in = (struct sockaddr_in*) addr;
long int address = addr_in->sin_addr.s_addr;
freeifaddrs(ifaddrHead);
return address;
}
freeifaddrs(ifaddrHead);
return 0;
}
To use it,
int main()
{
long int address = getInternalAddress((char*) &"en0", AF_INET);
printf("%li\n", address);
return 0;
}
I'm still a beginner in C, if there is anything wrong please tell me.

Identifying the problems with connect( )

I have been working on a proxy server. It has to connect to another "monitor" program and get connection address information from that program. That program in running on a known ip and port. If I use the following to connect it works fine:
struct hostent *serv;
int sockfd;
struct sockaddr_in serv_addr;
serv = gethostbyname("localhost");
sockfd = socket(AF)INET, SOCK_STREAM, 0);
if (sockfd < 0)
/* Error handling */
bzero((char *) &serv_addr, sizeof (serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *) server->h_addr, (char *) &serv_addr.sin_addr.s_addr, server->h_length);
serv_addr.sin_port = htons(portno); // portno is an int holding the port number
if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
/* error handling */
However I wanted to use the exact ip address instead of local host, they may not alway be on the same machine, and gethostbyname () is obsolete. I attempted to use getaddrinfo() like this:
struct addrinfo hints, *server;
int sockfd, i;
char *host = "192.168.2.4";
char *port = "4044";
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = 0;
hints.ai_protocol = IPPROTO_TCP; // have also tried it with 0
i = getaddrinfo(host, port, &hints, &server);
if (i != 0)
/* Error handling */
sockfd = socket(server->ai_family, server->ai_socktype, server->ai_protocol);
freeaddrinfo (server); // have also tried without this line
if (sockfd < 0)
/* Error handling */
printf("Attempting to connect\n");
if (connect(sockfd, server->ai_addr, server->ai_addrlen) != -1)
/* Error handling */
printf("Connection attempt complete\n");
This second attempt hangs for a long time on the connect() command and finally returns in error. I have gone over the examples in several places and searched previous questions here on stackoverflow but can't find the problem, or why one works and the other doesn't. I think it has something to do with the server->ai_addr value but have not been able to verify it yet.
Any help would be appreciated, am I doing something obviously wrong? I don't know where else to look for more ideas to check.
EDIT UPDATE:
I have figured out one problem. In the line if (connect (/* */) != -1)
it should have been != 0. One of the samples I was looking at used a bind() statement instead. If I use the local host address with the second may it will work with that change. However I still can't connect to a specific ip address node. I am beginning to suspect that the ip address I was given isn't one that this computer can receive network traffic on. I am not sure how to check that though. I will see If I can figure out any more info on the error with using the specific ip address and edit again with the information.
EDIT UPDATE: I added #include and tried to print out the error code after the system call returns. I also printed out the return. It returns a -1 which according to the documentation I found just means an error occurred when I try to print out the errno it seg faults.
fprintf(stderr, "Error Code %s\n", errno); // seg faults
However changing it to:
fprintf(stderr, "Error Code %d\n", errno); // returns Error Code 60
Try to replace
hints.ai_flags = 0;
with
hints.ai_flags = AI_NUMERICHOST;
and see what happens.
The ip address that I was given is not the ip on the computer I am using. I finally decided that the ip address had to be the problem. I found the ip address on my computer and got the server program to bind to it. I also put it in as the ip address for the code included above instead of local host and it was able to connect regardless of rather the server was on that specific ip address or simply connected to INADDR_ANY.

How to get its own IP address with a socket address?

I want to get the IP address of the computer my program is launched on, to be able then to send it to a client, but I always get 0.0.0.1 instead of the real IP address (like 127.0.0.1 for instance).
I'm currently able to get the port, but not the IP address.
How can I get it?
The best solution would be to be able to get it with a sockaddr_in. Here's what I'm currently doing:
int open_connection(char* ip, int* port)
{
int sock;
struct sockaddr_in sin;
socklen_t len;
int i;
i = 0;
len = sizeof(sin);
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
return (-1);
bzero(&sin, sizeof(struct sockaddr_in));
sin.sin_family = AF_INET;
if (bind(sock, (struct sockaddr *) &sin, sizeof(sin)) != 0)
perror("Error on bind");
if (getsockname(sock, (struct sockaddr *)&sin, &len) != 0)
perror("Error on getsockname");
strcpy(ip, inet_ntoa(sin.sin_addr)); // IP = 0.0.0.0
*port = sin.sin_port;
return (sock);
}
EDIT: I understand I was going on the wrong way with my way of thinking. So my question is: What's the best way to get your own IP address?
When you bind() a socket to 0.0.0.0, that is the only IP the socket has available when calling getsockname(). It means the socket is bound to all local interfaces. In order to get a specific IP from a socket, it has to be bound to a specific IP.
Using the socket API to get the machine's local IP(s) is the wrong approach anyway. A common mistake is to use gethostname() with gethostbyname() or getaddrinfo() to get the local IP list. Usually that works, but it has some hidden gotchas that can cause false information, but people tend to ignore that fact, or don't even know about it in the first place (I didn't know about it for years, but then I learned better).
Instead, you really should use platform-specific APIs for enumerating the local networking interfaces. That will provide more reliable information. Windows has GetAdaptersInfo() and GetAdaptersAddresses(). Other platforms have getifaddrs(). Those will tell you what local IPs are available. You can then bind() a socket to 0.0.0.0 in order to accept clients on any of those IPs, or bind() to a specific IP to accept clients only on that IP.
The sockets API allows you to enumerate the IP addresses assigned to your network interfaces, but it will not tell you what you "real IP" is if you are connecting to the Internet from behind a router.
The only way to know it is by asking someone outside. Thats how servers like FileZilla FTP Server do that. They instruct you to configure the URL to a "ip.php" script like this one in the server's settings so it can ask the Internet whats its public IP address, to use in Passive Mode.
You can also consider using STUN, a protocol widely used in VoIP to discover public IP.
You could call ioctl(sock, SIOCGIFADDR, adr)
see netdevice(7)
Following #Remy Lebeau's answer I wrote a function that return current machine's address. I have only tested this on macOS High Sierra.
interfaec can be anything among lo0, en0, etc.
ipVersion can be AF_INET or AF_INET6.
long int getInternalAddress(char* interface, sa_family_t ipVersion)
{
struct ifaddrs *ifaddrHead, *ifaddr;
/* int_8 */
sa_family_t family;
int n;
char *interfaceName;
if (getifaddrs(&ifaddrHead) != 0)
{
fprintf(stderr, "ifaddrs error");
}
/* iterate through address list */
for (ifaddr = ifaddrHead, n = 0; ifaddr != NULL; ifaddr = ifaddr->ifa_next, n++)
{
family = ifaddr->ifa_addr->sa_family;
interfaceName = ifaddr->ifa_name;
if (!family || family != ipVersion || strcmp(interfaceName, interface)) continue;
struct sockaddr *addr = ifaddr->ifa_addr;
struct sockaddr_in* addr_in = (struct sockaddr_in*) addr;
long int address = addr_in->sin_addr.s_addr;
freeifaddrs(ifaddrHead);
return address;
}
freeifaddrs(ifaddrHead);
return 0;
}
To use it,
int main()
{
long int address = getInternalAddress((char*) &"en0", AF_INET);
printf("%li\n", address);
return 0;
}
I'm still a beginner in C, if there is anything wrong please tell me.

Get IP address of my computer on a local network by way of BSD sockets?

Since there is no function in BSD sockets to get the IP address, I did client/server program to establish the connection. One thread for each: server and client.
The IP address returned from "inet_ntoa" with localhost was 127.0.0.1.
But the network says my computer is this 10.0.0.7, and this address is what works.
How do I get the 10.0.0.7 address?
Thx
Here is my code:
DWORD WINAPI CIpAddressDlg::Thread_TcpServer(LPVOID iValue)
{
CIpAddressDlg *pp = (CIpAddressDlg*)iValue;
CString c;
char buffer[128];
int sinlen;
struct sockaddr_in sin;
int s, h;
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(4000); // Port
s = socket(AF_INET, SOCK_STREAM,0);
bind(s,(struct sockaddr*)&sin,sizeof(sin));
listen(s,1);
sinlen = sizeof(sin);
h=accept(s,(struct sockaddr*)&sin,&sinlen );
//get IP address
int len = sizeof sin;
if(::getsockname(h,(struct sockaddr*)&sin,&len) == -1)
pp->MessageBox("Error local host ip");
c.Format("%d\nlocal addr %s:%u\n errno: %d", sin.sin_addr, inet_ntoa(sin.sin_addr),ntohs(sin.sin_port), errno);
pp->MessageBox(c);
//verification of send
recv(h,buffer,sizeof(buffer),0);
pp->MessageBox(buffer);
send(h,buffer,strlen(buffer),0);
::closesocket(s);
return 0;
}
DWORD WINAPI CIpAddressDlg::Thread_TcpClient(LPVOID iValue)
{
CIpAddressDlg *pp = (CIpAddressDlg*)iValue;
CString c;
char buffer[128]= "Hello world";
struct sockaddr_in sin;
struct hostent *host;
int s;
host = gethostbyname("localhost");
memcpy(&(sin.sin_addr), host->h_addr,host->h_length);
sin.sin_family = host->h_addrtype;
sin.sin_port = htons(4000);
s = socket(AF_INET, SOCK_STREAM,0);
connect(s, (struct sockaddr*)&sin,sizeof(sin));
send(s,buffer,strlen(buffer)+1,0);
recv(s,buffer,sizeof(buffer),0);
::closesocket(s);
return 0;
}
Despite the intuitive appeal of the concept and, for that matter, widespread belief in said concept, computers do not have IP addresses.
Interfaces have IP addresses.
You can get a list of the interfaces and choose the first one. Unfortunately, getting a list of interfaces in most languages is system dependent.
The usual approach is to just use 0.0.0.0.
There are easier ways to get the "private" / "LAN" IP of the machine your program is running on. Your solution is very ingenuitive though.
I think the most straightforward is probably GetAdaptersAddresses. The example code on the MSDN page seems pretty thorough.
But if that requires a newer compiler version, consider GetAdaptersInfo. See "Method Three" here and some sample code here.
Also, it seems like you could also access the IP address via the WinSock API. See this example.
Lastly, just as a sidenote, there is a function in BSD sockets to do exactly this (getifaddrs()), its just not ported to Windows.

getpeername() Returns Wrong Data

I am writing my first sockets program on Linux and am trying to print the IP address and port of the peer I have connected to. I use getpeername() along with inet_ntop() and ntohs() to get the data out of the sockaddr_in struct. When I look at the results, I get an IP address that does not go to any server that I know of (ping fails) and says that I am listening to a port that netstat says is not being used.
What am I doing wrong? I should be getting 130.215.28.181:39000, but instead I am getting 209.94.72.137:18825 every time I run the program. Looking at netstat shows that I am indeed listening on port 39000.
Here is a snippet from my client program:
connect(sockfd,&serv_addr,sizeof(serv_addr))
// print welcome message
char ipstr[INET6_ADDRSTRLEN];
bzero(ipstr, 50);
struct sockaddr_in *address;
socklen_t address_len = sizeof(*address);
getpeername(sockfd, (struct sockaddr *) address, &address_len);
inet_ntop(AF_INET, &address->sin_addr, ipstr, sizeof(ipstr));
printf("Connection established successfully with %s:%i!\n", ipstr, ntohs(address->sin_port));
You're not allocating any memory for your sockaddr_in structure, you's just passing a pointer to some random memory location. Instead, allocate the address structure on the stack:
struct sockaddr_in addr;
socklen_t addr_len = sizeof(addr);
int err = getpeername(sockfd, (struct sockaddr *) &addr, &addr_len);
if (err != 0) {
// error
}
You should also be checking the return value of every function that is documented to return an error code. In particular, both connect and getpeername return error codes that you should be checking.

Resources