BASIC User Group > Code Challenges

Retrieve your External IP address

<< < (3/5) > >>

AIR:
The key is being able to tell the socket that you wish to use a custom/specific DNS server for the query rather than the DNS as configured on the system.

I don't know if SB native sockets exposes the functionality required to do this, I haven't looked.

AIR.

AIR:
C:


--- Code: C ---#include <resolv.h>#include <arpa/inet.h>#include <netdb.h>#include <string.h> void set_dns_server(res_state res, const char *dns_server);void get_ip(res_state res, const char *host, char ip[]);int hostname_to_ip(const char * hostname , char* ip);  int main (int argc, char **argv) {    struct __res_state res;    char ip[16], host_ip[16];    int result;     result = hostname_to_ip("resolver1.opendns.com", host_ip);    set_dns_server(&res, host_ip);    get_ip(&res, "myip.opendns.com", ip);     printf("External IP: %s\n",ip);     return result;} void set_dns_server(res_state res, const char *dns_server){    res_ninit(res);    struct in_addr addr;    inet_aton(dns_server, &addr);        res->nsaddr_list[0].sin_addr = addr;    res->nsaddr_list[0].sin_family = AF_INET;    res->nsaddr_list[0].sin_port = htons(NS_DEFAULTPORT);    res->nscount = 1;} void get_ip(res_state res, const char *host, char ip[]){    u_char answer[NS_PACKETSZ];    int len = res_nquery(res, host, ns_c_in, ns_t_a, answer, sizeof(answer));        ns_msg handle;    ns_initparse(answer, len, &handle);            if(ns_msg_count(handle, ns_s_an) > 0) {        ns_rr rr;        if(ns_parserr(&handle, ns_s_an, 0, &rr) == 0) {            strcpy(ip, inet_ntoa(*(struct in_addr *)ns_rr_rdata(rr)));        }    }} int hostname_to_ip(const char * hostname , char* ip){        struct hostent *he;        struct in_addr **addr_list;        int i;                        if ( (he = gethostbyname( hostname ) ) == NULL)         {                // get the host info                herror("gethostbyname");                return 1;        }         addr_list = (struct in_addr **) he->h_addr_list;                for(i = 0; addr_list[i] != NULL; i++)         {                //Return the first one;                strcpy(ip , inet_ntoa(*addr_list[i]) );                return 0;        }                return 1;} 
Compile on Linux/macOS with:

gcc getip.c -lresolv -o getip

AIR.

jalih:

--- Quote from: AIR on March 19, 2019, 09:32:11 pm ---I don't know if SB native sockets exposes the functionality required to do this, I haven't looked.

--- End quote ---

If SB supports UDP datagram sockets, you can use the same approach that I used with 8th. You can construct DNS message by hand, send the question and receive the answer.

John:
I would like to see an example using raw sockets without the support libraries hiding what is really going on.

AIR:
Using libraries eliminates the need to reinvent the wheel.

That said, here is an example:


--- Code: C ---//DNS Query Program on Linux//Author : Silver Moon (m00n.silv3r@gmail.com)//Dated : 29/4/2009 //Modified by Armando I. Rivera (AIR)//to return public ip via opendns servers//Date: 03/20/2019 //Header Files#include<stdio.h>       //printf#include<string.h>      //strlen#include<stdlib.h>      //malloc#include<sys/socket.h>  //you know what this is for#include<arpa/inet.h>   //inet_addr , inet_ntoa , ntohs etc#include<netinet/in.h>#include<unistd.h>      //getpid //List of DNS Servers registered on the systemchar dns_servers[10][100];int dns_server_count = 0; //Types of DNS resource records :)#define T_A 1 //Ipv4 address#define T_NS 2 //Nameserver#define T_CNAME 5 // canonical name#define T_SOA 6 /* start of authority zone */#define T_PTR 12 /* domain name pointer */#define T_MX 15 //Mail server //Function Prototypesvoid ngethostbyname (unsigned char* , int);void ChangetoDnsNameFormat (unsigned char*,unsigned char*);unsigned char* ReadName (unsigned char*,unsigned char*,int*);void get_dns_servers(); //DNS header structurestruct DNS_HEADER{        unsigned short id; // identification number         unsigned char rd :1; // recursion desired        unsigned char tc :1; // truncated message        unsigned char aa :1; // authoritive answer        unsigned char opcode :4; // purpose of message        unsigned char qr :1; // query/response flag         unsigned char rcode :4; // response code        unsigned char cd :1; // checking disabled        unsigned char ad :1; // authenticated data        unsigned char z :1; // its z! reserved        unsigned char ra :1; // recursion available         unsigned short q_count; // number of question entries        unsigned short ans_count; // number of answer entries        unsigned short auth_count; // number of authority entries        unsigned short add_count; // number of resource entries}; //Constant sized fields of query structurestruct QUESTION{        unsigned short qtype;        unsigned short qclass;}; //Constant sized fields of the resource record structure#pragma pack(push, 1)struct R_DATA{        unsigned short type;        unsigned short _class;        unsigned int ttl;        unsigned short data_len;};#pragma pack(pop) //Pointers to resource record contentsstruct RES_RECORD{        unsigned char *name;        struct R_DATA *resource;        unsigned char *rdata;}; //Structure of a Querytypedef struct{        unsigned char *name;        struct QUESTION *ques;} QUERY; int main( int argc , char *argv[]){        unsigned char hostname[] = "myip.opendns.com";         // Set Custom DNS Servers        strcpy(dns_servers[0] , "208.67.222.222"); //resolver1.opendns.com        strcpy(dns_servers[1] , "208.67.220.220"); //resolver2.opendns.com                //Now get the ip of this hostname , A record        ngethostbyname(hostname , T_A);         return 0;} /* * Perform a DNS query by sending a packet * */void ngethostbyname(unsigned char *host , int query_type){        unsigned char buf[65536],*qname,*reader;        int i , j , stop , s;         struct sockaddr_in a;         struct RES_RECORD answers[20],auth[20],addit[20]; //the replies from the DNS server        struct sockaddr_in dest;         struct DNS_HEADER *dns = NULL;        struct QUESTION *qinfo = NULL;         s = socket(AF_INET , SOCK_DGRAM , IPPROTO_UDP); //UDP packet for DNS queries         dest.sin_family = AF_INET;        dest.sin_port = htons(53);        dest.sin_addr.s_addr = inet_addr(dns_servers[0]); //dns servers         //Set the DNS structure to standard queries        dns = (struct DNS_HEADER *)&buf;         dns->id = (unsigned short) htons(getpid());        dns->qr = 0; //This is a query        dns->opcode = 0; //This is a standard query        dns->aa = 0; //Not Authoritative        dns->tc = 0; //This message is not truncated        dns->rd = 1; //Recursion Desired        dns->ra = 0; //Recursion not available! hey we dont have it (lol)        dns->z = 0;        dns->ad = 0;        dns->cd = 0;        dns->rcode = 0;        dns->q_count = htons(1); //we have only 1 question        dns->ans_count = 0;        dns->auth_count = 0;        dns->add_count = 0;         //point to the query portion        qname =(unsigned char*)&buf[sizeof(struct DNS_HEADER)];         ChangetoDnsNameFormat(qname , host);        qinfo =(struct QUESTION*)&buf[sizeof(struct DNS_HEADER) + (strlen((const char*)qname) + 1)]; //fill it         qinfo->qtype = htons( query_type ); //type of the query , A , MX , CNAME , NS etc        qinfo->qclass = htons(1); //its internet (lol)         // Send Packet        if( sendto(s,(char*)buf,sizeof(struct DNS_HEADER) + (strlen((const char*)qname)+1) + sizeof(struct QUESTION),0,(struct sockaddr*)&dest,sizeof(dest)) < 0)        {                perror("sendto failed");        }                 //Receive the answer        i = sizeof dest;         if(recvfrom (s,(char*)buf , 65536 , 0 , (struct sockaddr*)&dest , (socklen_t*)&i ) < 0)        {                perror("recvfrom failed");        }          dns = (struct DNS_HEADER*) buf;         //move ahead of the dns header and the query field        reader = &buf[sizeof(struct DNS_HEADER) + (strlen((const char*)qname)+1) + sizeof(struct QUESTION)];         //Start reading answers        stop=0;         for(i=0;i<ntohs(dns->ans_count);i++)        {                answers[i].name=ReadName(reader,buf,&stop);                reader = reader + stop;                 answers[i].resource = (struct R_DATA*)(reader);                reader = reader + sizeof(struct R_DATA);                 if(ntohs(answers[i].resource->type) == 1) //if its an ipv4 address                {                        answers[i].rdata = (unsigned char*)malloc(ntohs(answers[i].resource->data_len));                         for(j=0 ; j<ntohs(answers[i].resource->data_len) ; j++)                        {                                answers[i].rdata[j]=reader[j];                        }                         answers[i].rdata[ntohs(answers[i].resource->data_len)] = '\0';                         reader = reader + ntohs(answers[i].resource->data_len);                }                else                {                        answers[i].rdata = ReadName(reader,buf,&stop);                        reader = reader + stop;                }        }         //print answers        for(i=0 ; i < ntohs(dns->ans_count) ; i++)        {                 if( ntohs(answers[i].resource->type) == T_A) //IPv4 address                {                        long *p;                        p=(long*)answers[i].rdata;                        a.sin_addr.s_addr=(*p); //working without ntohl                        printf("External IP: %s\n",inet_ntoa(a.sin_addr));                }        }         return;} /* *  * */u_char* ReadName(unsigned char* reader,unsigned char* buffer,int* count){        unsigned char *name;        unsigned int p=0,jumped=0,offset;        int i , j;         *count = 1;        name = (unsigned char*)malloc(256);         name[0]='\0';         //read the names in 3www6google3com format        while(*reader!=0)        {                if(*reader>=192)                {                        offset = (*reader)*256 + *(reader+1) - 49152; //49152 = 11000000 00000000 ;)                        reader = buffer + offset - 1;                        jumped = 1; //we have jumped to another location so counting wont go up!                }                else                {                        name[p++]=*reader;                }                 reader = reader+1;                 if(jumped==0)                {                        *count = *count + 1; //if we havent jumped to another location then we can count up                }        }         name[p]='\0'; //string complete        if(jumped==1)        {                *count = *count + 1; //number of steps we actually moved forward in the packet        }         //now convert 3www6google3com0 to www.google.com        for(i=0;i<(int)strlen((const char*)name);i++)         {                p=name[i];                for(j=0;j<(int)p;j++)                 {                        name[i]=name[i+1];                        i=i+1;                }                name[i]='.';        }        name[i-1]='\0'; //remove the last dot        return name;} /* * This will convert www.google.com to 3www6google3com  * got it :) * */void ChangetoDnsNameFormat(unsigned char* dns,unsigned char* host) {        int lock = 0 , i;        strcat((char*)host,".");                for(i = 0 ; i < strlen((char*)host) ; i++)         {                if(host[i]=='.')                 {                        *dns++ = i-lock;                        for(;lock<i;lock++)                         {                                *dns++=host[lock];                        }                        lock++; //or lock=i+1;                }        }        *dns++='\0';} 
AIR.

EDIT:  In the spirit of full attribution, here is the link to Silver Moon's post: https://www.binarytides.com/dns-query-code-in-c-with-linux-sockets

Navigation

[0] Message Index

[#] Next page

[*] Previous page

Go to full version