I'd like to get a list of available devices (their IP address or hostname should be fine) connected to my local network. I've got some examples in C#, but I couldn't find any sample using C/C++. I'm familiar with the BSD socket API, just to clarify.
I have a "stub" kind of idea: maybe I should determine the range of the IP addresses that the devices on my LAN can potentially belong to, and then determine if they e. g. respond to PING, or something like that. How could I achieve these?
I want my application to run on Linux and iOS. That's why I'd prefer BSD sockets, or at a maximum, Foundation/GNUstep (although they are written in Objective-C).
You can also e.g. send an ICMP echo request packet to 224.0.0.1. This is a special all-nodes multicast address every node should respond to (except if a firewall rule or network policy setting prevents it).
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <netinet/ip_icmp.h>
#include <time.h>
#include <fcntl.h>
#include <signal.h>
#include <time.h>
// Define the Packet Constants
// ping packet size
#define PING_PKT_S 64
// Automatic port number
#define PORT_NO 0
// Automatic port number
#define PING_SLEEP_RATE 1000000
// Gives the timeout delay for receiving packets
// in seconds
#define RECV_TIMEOUT 1
// Performs a DNS lookup
char *dns_lookup(char *addr_host, struct sockaddr_in *addr_con)
{
//printf("\nResolving DNS..\n");
struct hostent *host_entity;
char *ip=(char*)malloc(NI_MAXHOST*sizeof(char));
int i;
if ((host_entity = gethostbyname(addr_host)) == NULL)
{
// No ip found for hostname
return NULL;
}
//filling up address structure
strcpy(ip, inet_ntoa(*(struct in_addr *)
host_entity->h_addr));
(*addr_con).sin_family = host_entity->h_addrtype;
(*addr_con).sin_port = htons (PORT_NO);
(*addr_con).sin_addr.s_addr = *(long*)host_entity->h_addr;
return ip;
}
// Resolves the reverse lookup of the hostname
char* reverse_dns_lookup(char *ip_addr)
{
struct sockaddr_in temp_addr;
socklen_t len;
char buf[NI_MAXHOST], *ret_buf;
temp_addr.sin_family = AF_INET;
temp_addr.sin_addr.s_addr = inet_addr(ip_addr);
len = sizeof(struct sockaddr_in);
if (getnameinfo((struct sockaddr *) &temp_addr, len, buf,
sizeof(buf), NULL, 0, NI_NAMEREQD))
{
//printf("Could not resolve reverse lookup of hostname\n");
return NULL;
}
ret_buf = (char*)malloc((strlen(buf) +1)*sizeof(char) );
strcpy(ret_buf, buf);
return ret_buf;
}
// Driver Code
int main(int argc, char *argv[])
{
int sockfd;
char *ip_addr, *reverse_hostname;
struct sockaddr_in addr_con;
int addrlen = sizeof(addr_con);
char net_buf[NI_MAXHOST];
int i=0;
for(int i=1;i<255;++i)
{
char ip[80];
sprintf(ip, "192.168.2.%d", i);
ip_addr = dns_lookup(ip, &addr_con);
if(ip_addr==NULL)
{
//printf("\nDNS lookup failed! Could not resolve hostname!\n");
continue;
}
reverse_hostname = reverse_dns_lookup(ip_addr);
if(reverse_hostname==NULL)
{
//printf("\nDNS lookup failed! Could not resolve hostname!\n");
continue;
}
//printf("\nTrying to connect to '%s' IP: %s\n",ip, ip_addr);
printf("\nReverse Lookup domain: %s",
reverse_hostname);
printf("\n %s \n", ip);
}
return 0;
}
Related
i wanted to send an icmp packet by writing my own IP header so i used the IP_HDRINCL option the code compiled and runs without any errors but there is no packet being sent when i run the program and capture packets using wireshark no error message from the program as well
here is the code:
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/ip_icmp.h>
#include <netinet/ip.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define BUFFSIZE 2048
char sendbuf[BUFFSIZE];
int seqno=0;
unsigned short chksum(void *data,int bytes){
unsigned int sum=0;
unsigned short *octate=data,result;
while(bytes>1){
sum+=*octate++;
bytes-=2;
}
if(bytes==1){
sum+=*(unsigned char *)octate;
}
while(sum>>16){
sum=(sum>>16)+(sum&0xffff);
}
result=~sum;
return result;
}
struct addrinfo * getaddr(char *name){ //convert user input host to address structure
int e;
struct addrinfo hints,*res;
memset(&hints,0,sizeof(hints));
hints.ai_flags=AI_CANONNAME;
hints.ai_family=AF_INET;
if(e=getaddrinfo(name,0,&hints,&res)!=0){
printf("getaddrinfo error: %s\n",gai_strerror(e));
}
return res;
}
void create_packet(struct sockaddr *d){
/* Creating IP Packet */
struct ip *ip;
ip=(struct ip*)sendbuf;
ip->ip_v=4;
ip->ip_hl=5;
ip->ip_tos=0;
ip->ip_len=20+8;
ip->ip_id=8848;
ip->ip_off=IP_DF;
ip->ip_ttl=7;
ip->ip_p=IPPROTO_ICMP;
char srcip[]="192.168.1.69";
struct addrinfo *source = getaddr(srcip);
struct sockaddr_in *dest=(struct sockaddr_in *)d;
struct sockaddr_in *src=(struct sockaddr_in *)source->ai_addr;
ip->ip_src=src->sin_addr;
ip->ip_dst=dest->sin_addr;
ip->ip_sum=0;
ip->ip_sum=chksum(ip,sizeof(*ip));
/* Creating ICMP Packet */
struct icmp *icmp;
icmp=(struct icmp *)(sendbuf+20);
icmp->icmp_type=ICMP_ECHO;
icmp->icmp_code=0;
icmp->icmp_id=getpid();
icmp->icmp_seq=++seqno;
icmp->icmp_cksum=0;
icmp->icmp_cksum=chksum(icmp,8);
}
void main(int argc,char **argv){
int sock;
int on=1;
struct addrinfo *addr=getaddr(argv[1]);
if((sock=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP))==-1){
perror("socket error: ");
return;
}
if(setsockopt(sock,IPPROTO_IP,IP_HDRINCL,&on,sizeof(on))==-1){
perror("setsockopt error");
return;
}
create_packet(addr->ai_addr);
if(sendto(sock,sendbuf,28,0,addr->ai_addr,addr->ai_addrlen)==-1){
perror("sendto error");
return;
}
}
While I can't be certain based on your code alone, I suspect that you're running this program on a little-endian processor (x86-based), and IP expects its numbers in big-endian order. This means that any multi-byte fields (ip_len, ip_off) are written in the wrong order. I suspect that if you change the following 2 lines:
ip->ip_len=20+8;
ip->ip_off=IP_DF;
to this:
ip->ip_len=htons(20+8);
ip->ip_off=htons(IP_DF);
that the packets will be properly sent.
Incidentally the ip->ip_id field is also in big-endian order, but unless you're sending multiple fragments it doesn't much matter.
I tried to implement a simple DNSIPv6 server in C. This is a very simple and first approach to do this. I read here: https://beej.us/guide/bgnet/html/multi/gethostbynameman.html that instead of using gethostbyname I should use getnameinfo. It works well with IPv6, but fails with IPv6 - when I provide IPv6, it gives me 0.0.0.0 instead of the hostname:
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#define SIZE 1024
int main()
{
char host[SIZE];
char service[SIZE];
struct sockaddr_in6 sa;
sa.sin6_family = AF_INET6;
inet_pton(AF_INET6, "64:ff9b::d8da:e477", &sa.sin6_addr);
int res = getnameinfo((struct sockaddr*)&sa, sizeof(sa), host, sizeof(host), service, sizeof(service), 0);
if(res)
{
exit(1);
}
else
{
printf("Hostname: %s\n", host);
printf("Service: %s\n", service);
}
return 0;
}
I am trying to get host information about the host with IP address 89.249.207.231. I know that it exists, because when I type the IP address in my browser's url field it finds the page. Here is my code in C.
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <errno.h>
int main()
{
struct in_addr addr;
inet_aton("89.249.207.231", &addr);
struct hostent* esu = gethostbyaddr((const char*)&addr),sizeof(addr), AF_INET);
printf("%s\n", esu->h_name);
return 0;
}
When I compile and run it, it gives "Segmentation fault". I can not understand the problem with my code.
Any hints and suggestions would be appreciated.
Thanks!
Even if the host exists, you may not be able to extract its hostname.
For example, the following code, without the deprecated functions that you use gives the result host=google-public-dns-a.google.com whereas with your host address gives could not resolve hostname.
The reason of your segfault, is that esu is NULL, because the function could not resolve a hostname by the given IP.
Here is the code:
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
int main()
{
struct sockaddr_in sa; /* input */
socklen_t len; /* input */
char hbuf[NI_MAXHOST];
memset(&sa, 0, sizeof(struct sockaddr_in));
/* For IPv4*/
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = inet_addr("8.8.8.8");
len = sizeof(struct sockaddr_in);
if (getnameinfo((struct sockaddr *) &sa, len, hbuf, sizeof(hbuf),
NULL, 0, NI_NAMEREQD)) {
printf("could not resolve hostname\n");
}
else {
printf("host=%s\n", hbuf);
}
return 0;
}
I am learning the Sockets networking API. In this process, I have written a simple Echo server that uses TCP. I wrote the code in such a way that, as long as the server is running, anything typed on the client's console should be echoed back to it. However, I am unable to achieve this. Although, for the first input, I get the echo, from next time onwards, I do not get any message.
I know, we can implement it to run for many clients using fork(), but I want to know the reason behind the blocking of the client, and if possible ways to correct it.
Here is the code for the client:
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <unistd.h>
#define MAXCOUNT 1024
int main(int argc, char* argv[])
{
int sfd;
char msg[MAXCOUNT];
char blanmsg[MAXCOUNT];
struct sockaddr_in saddr;
memset(&saddr,0,sizeof(saddr));
sfd = socket(AF_INET,SOCK_STREAM,0);
saddr.sin_family = AF_INET;
inet_pton(AF_INET,"127.0.0.1",&saddr.sin_addr);
saddr.sin_port = htons(5004);
connect(sfd,(struct sockaddr*) &saddr, sizeof(saddr));
for(; ;) {
memset(msg,0,MAXCOUNT);
memset(blanmsg,0,MAXCOUNT);
fgets(msg,MAXCOUNT,stdin);
send(sfd,msg,strlen(msg),0);
recv(sfd,blanmsg,sizeof(blanmsg),0);
printf("%s",blanmsg);
fflush(stdout);
}
exit(0);
}
Here is the code for the server:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#define MAXCOUNT 1024
int main(int argc, char* argv[])
{
int sfd,nsfd,n,i,cn;
char buf[MAXCOUNT];
socklen_t caddrlen;
struct sockaddr_in caddr,saddr; //Structs for Client and server Address in the Internet
sfd = socket(AF_INET,SOCK_STREAM,0);
memset(&saddr,0,sizeof(saddr)); //Clear the Server address structure
saddr.sin_family = AF_INET; //Internet Address Family
saddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
saddr.sin_port = htons(5004);
bind(sfd, (struct sockaddr*) &saddr,sizeof(saddr));
listen(sfd,1);
for(; ;) {
caddrlen = sizeof(caddr);
nsfd = accept(sfd,(struct sockaddr*) &caddr,&caddrlen);
cn = recv(nsfd,buf,sizeof(buf),0);
if(cn == 0) {
exit(0);
}
buf[cn] = '\0';
send(nsfd,buf,strlen(buf),0);
}
close(nsfd);
exit(0);
}
You shouldn't call accept within the loop on the server. Move the accept before the for loop on the server and it should work how you expect.
Calling accept in the loop like that will make the server block until a new connection comes in. Your client is only opening a single connection, so the server will block on the second call to accept.
Your code is doing precisely what you asked it to do. You told it to accept a connection, receive some data from that connection, send that data back to the connection, then accept another connection. That's what it's doing. I suspect you want to move the accept call outside the for loop.
I think you required a code which servers multiple clients as well as echo message to respective clients.
so just have a look to your code again and note down modification
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#define MAXCOUNT 1024
int main(int argc, char* argv[])
{
int sfd,nsfd,n,i,cn;
char buf[MAXCOUNT];
socklen_t caddrlen;
struct sockaddr_in caddr,saddr;
//Structs for Client and server Address in the Internet
sfd = socket(AF_INET,SOCK_STREAM,0);
memset(&saddr,0,sizeof(saddr)); //Clear the Server address structure
saddr.sin_family = AF_INET; //Internet Address Family
saddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
saddr.sin_port = htons(5004);
bind(sfd, (struct sockaddr*) &saddr,sizeof(saddr));
listen(sfd,5);/*request queue size*/
while(1)
{//main loop for cuncorent server
caddrlen = sizeof(caddr);
nsfd = accept(sfd,(struct sockaddr*) &caddr,&caddrlen);
if(fork()==0)
{//only child code for serving a particular client
for(; ;) {//loop for reading and writing back msg cotineously
cn = recv(nsfd,buf,sizeof(buf),0);
if(cn == 0) {
exit(0);
}
buf[cn] = '\0';
send(nsfd,buf,strlen(buf),0);
}//serving loop ends
close(nsfd);
exit(0);
}//child code ends
}//main while loop ends
exit(0);
}
I need to make a custom port scanner that scan only opened TCP and UDP ports. I'm working in standard C with sockets. For the moment i retrieve all ports in a range i set.
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdlib.h>
#include <errno.h>
int scanPort(struct hostent *hostaddr,int port){
char responce[1024];
char *message="checking port";
struct sockaddr_in server_address;
int socket_d;
int rval;
socket_d = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
if(socket_d == -1)
{
perror("Socket()\n");
return errno;
}
memset(&server_address,0,sizeof(server_address));
server_address.sin_family=AF_INET;
server_address.sin_port=htons(port);
memcpy(&server_address.sin_addr,hostaddr->h_addr,hostaddr->h_length);
rval = connect(socket_d,(struct sockaddr *) &server_address, sizeof(server_address));
if(rval == -1)
{
close(socket_d);
return 0;
}else{
close(socket_d);
return 1;
}
}
int main(int argc, char **argv)
{
if(argc < 4){
printf("Exemplu: ./portscanner <adresa_ip> <port_pornire> <port_oprire> \n");
return (EINVAL);
}
int startPort;
int endPort;
int port;
struct hostent *host_address;
host_address = gethostbyname( argv[1] );
startPort = atoi(argv[2]);
endPort = atoi(argv[3]);
for(port = startPort;port<=endPort;port++)
{
if(scanPort(host_address,port)==1){
printf("Port %d is open\n",port);
}
}
}
In the example you can see how i tried to resolve this problem. But i don't see a method to check only the TCP and UDP ports. Please help me with this.
Regards,
Badea Sorin!
There is a plenty ways to do it. I recommend you to install nmap and read the manual.
Many scan methods are implemented there and described in the manual.
You can also refer to the source code if you need more details.
Good luck.