All BASIC

Message Boards => Code Challenges => Topic started by: AIR on March 18, 2019, 11:49:09 PM

Title: Retrieve your External IP address
Post by: AIR on March 18, 2019, 11:49:09 PM
Typically, when one is looking to retrieve their external IP address programmatically, one resorts to making an html request to a website like https://myexternalip.com/raw

For this challenge, the task is to retrieve your external IP using a *** DNS Query *** to resolver1.opendns.com.

The request you will send to that DNS server is: "myip.opendns.com".  The server is configured to respond to that specific request by returning the EXTERNAL IP address of the machine making the request.

Libraries, third party included, are allowed but shelling to a command line utility (like dig) or another programming language is not allowed.  Neither is scraping a webpage.

Obviously, you should NOT post your IP Address.

To test whether you are retrieving the correct IP address, either check it with the link provided at the begining of this post, or just google "my ip".

You can also check locally at a shell prompt, using:

Windows: nslookup myip.opendns.com. resolver1.opendns.com

Linux/macOS: dig +short myip.opendns.com @resolver1.opendns.com


To summarize:

DNS SERVER:   resolver1.opendns.com
DNS REQUEST: myip.opendns.com

AIR.



Title: Re: Retrieve your External IP address
Post by: AIR on March 18, 2019, 11:52:14 PM
PYTHON:

Code: Python
  1. #!/usr/bin/env python
  2.  
  3. import dns.resolver,socket
  4.  
  5. res = dns.resolver.Resolver(configure=False)
  6. res.nameservers = [socket.gethostbyname("resolver1.opendns.com")]
  7. print res.query('myip.opendns.com')[0]
  8.  

AIR.
Title: Re: Retrieve your External IP address
Post by: AIR on March 18, 2019, 11:55:16 PM
GO:

Code: Go
  1. package main
  2.  
  3. import (
  4.         "context"
  5.         "fmt"
  6.         "log"
  7.         "net"
  8. )
  9.  
  10. func customDialer(ctx context.Context, network, address string) (net.Conn, error) {
  11.         d := net.Dialer{}
  12.         return d.DialContext(ctx, network, net.JoinHostPort("resolver1.opendns.com", "53"))
  13. }
  14.  
  15. func main() {
  16.  
  17.         r := net.Resolver{
  18.                 PreferGo: true,
  19.                 Dial:     customDialer,
  20.         }
  21.  
  22.         ipaddr, err := r.LookupHost(context.Background(), "myip.opendns.com")
  23.         if err != nil {
  24.                 log.Fatal(err)
  25.         }
  26.  
  27.         fmt.Println("External IP:", ipaddr[0])
  28. }
  29.  

AIR.
Title: Re: Retrieve your External IP address
Post by: jalih on March 19, 2019, 11:25:56 AM
8th:

Code: [Select]

net:INET4 net:DGRAM net:socket var, socket

[ 0xaa, 0xaa, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  "myip", "opendns", "com", 0x00, 0x00, 0x01, 0x00, 0x01 ] "12b1s1c1s1c1s1c5b" pack var, message


: address-info
  "resolver1.opendns.com" 53 net:getaddrinfo null? if
    t:err? . cr bye
  then ;


: app:main
  socket @ address-info message @ 0 net:sendto null? if
    2drop t:err? . cr bye
  else
    drop
  then

  100 b:new 0 net:recvfrom null? if
    2drop t:err? . cr bye
  then

  \ Last four bytes from the response are IP address.
  dup 4 n:- swap b:slice "4:1B" unpack drop
  ' >s a:map
  "." a:join
  "External IP: " . . cr
  2drop
  bye ;
Title: Re: Retrieve your External IP address
Post by: AIR on March 19, 2019, 05:09:48 PM
Thanks, Jalih!

Works as expected on my Mac.

AIR.

Title: Re: Retrieve your External IP address
Post by: John on March 19, 2019, 06:12:48 PM
I hope this isn't cheating.

Code: Script BASIC
  1. IMPORT curl.bas
  2.  
  3. ch = curl::init()
  4. curl::option(ch,"URL","ipinfo.io")
  5. PRINT curl::perform(ch),"\n"
  6. curl::finish(ch)
  7.  


$ scriba myip.sb
{
  "ip": "#4.#9.#1.#11",
  "hostname": "c-#4-#9-#1-#11.hsd1.wa.comcast.net",
  "city": "Mount Vernon",
  "region": "Washington",
  "country": "US",
  "loc": "48.4352,-122.2080",
  "postal": "98273",
  "org": "AS33650 Comcast Cable Communications, LLC"
}
$


If you only want the ip, add a /ip to the end of the url.

$ scriba myip.sb
#4.#9.#1.#11

$

Title: Re: Retrieve your External IP address
Post by: AIR on March 19, 2019, 08:11:23 PM
Well, that's how it's typically done:  find a website that returns your IP. It's very simple to set that up yourself using a single line of PHP.

With that said, the challenge is to retrieve the info by querying the provided DNS server directly.

AIR.
Title: Re: Retrieve your External IP address
Post by: John on March 19, 2019, 08:42:52 PM
I figured my approach didn't meet the challenge requirements but it's sure is a quick way to get there.

On a positive note I might add this feature to sbhttpd  as a StatCounter like log.
Title: Re: Retrieve your External IP address
Post by: AIR on March 19, 2019, 09:17:05 PM
The challenge illustrates a language's ability to do high or low level socket programming by interacting with a DNS server, rather than a WEB server.

The Python, Go, and 8th examples show a more high level (abstracted) approach.

I'm finalizing a low level C example, which I'll post in a bit...

AIR.
Title: Re: Retrieve your External IP address
Post by: John on March 19, 2019, 09:22:17 PM
I tried using SB socket OPEN but couldn't figure out how to get it to work.

Port = 53 ?

How is the resolver url passed?

Title: Re: Retrieve your External IP address
Post by: AIR on March 19, 2019, 09:32:11 PM
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.
Title: Re: Retrieve your External IP address
Post by: AIR on March 19, 2019, 09:42:48 PM
C:

Code: C
  1. #include <resolv.h>
  2. #include <arpa/inet.h>
  3. #include <netdb.h>
  4. #include <string.h>
  5.  
  6. void set_dns_server(res_state res, const char *dns_server);
  7. void get_ip(res_state res, const char *host, char ip[]);
  8. int hostname_to_ip(const char * hostname , char* ip);
  9.  
  10.  
  11. int main (int argc, char **argv) {
  12.     struct __res_state res;
  13.     char ip[16], host_ip[16];
  14.     int result;
  15.  
  16.     result = hostname_to_ip("resolver1.opendns.com", host_ip);
  17.     set_dns_server(&res, host_ip);
  18.     get_ip(&res, "myip.opendns.com", ip);
  19.  
  20.     printf("External IP: %s\n",ip);
  21.  
  22.     return result;
  23. }
  24.  
  25. void set_dns_server(res_state res, const char *dns_server)
  26. {
  27.     res_ninit(res);
  28.     struct in_addr addr;
  29.     inet_aton(dns_server, &addr);
  30.    
  31.     res->nsaddr_list[0].sin_addr = addr;
  32.     res->nsaddr_list[0].sin_family = AF_INET;
  33.     res->nsaddr_list[0].sin_port = htons(NS_DEFAULTPORT);
  34.     res->nscount = 1;
  35. }
  36.  
  37. void get_ip(res_state res, const char *host, char ip[])
  38. {
  39.     u_char answer[NS_PACKETSZ];
  40.     int len = res_nquery(res, host, ns_c_in, ns_t_a, answer, sizeof(answer));
  41.    
  42.     ns_msg handle;
  43.     ns_initparse(answer, len, &handle);
  44.    
  45.    
  46.     if(ns_msg_count(handle, ns_s_an) > 0) {
  47.         ns_rr rr;
  48.         if(ns_parserr(&handle, ns_s_an, 0, &rr) == 0) {
  49.             strcpy(ip, inet_ntoa(*(struct in_addr *)ns_rr_rdata(rr)));
  50.         }
  51.     }
  52. }
  53.  
  54. int hostname_to_ip(const char * hostname , char* ip)
  55. {
  56.         struct hostent *he;
  57.         struct in_addr **addr_list;
  58.         int i;
  59.                
  60.         if ( (he = gethostbyname( hostname ) ) == NULL)
  61.         {
  62.                 // get the host info
  63.                 herror("gethostbyname");
  64.                 return 1;
  65.         }
  66.  
  67.         addr_list = (struct in_addr **) he->h_addr_list;
  68.        
  69.         for(i = 0; addr_list[i] != NULL; i++)
  70.         {
  71.                 //Return the first one;
  72.                 strcpy(ip , inet_ntoa(*addr_list[i]) );
  73.                 return 0;
  74.         }
  75.        
  76.         return 1;
  77. }
  78.  

Compile on Linux/macOS with:

gcc getip.c -lresolv -o getip

AIR.
Title: Re: Retrieve your External IP address
Post by: jalih on March 19, 2019, 10:39:08 PM
I don't know if SB native sockets exposes the functionality required to do this, I haven't looked.

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.
Title: Re: Retrieve your External IP address
Post by: John on March 20, 2019, 09:15:10 AM
I would like to see an example using raw sockets without the support libraries hiding what is really going on.
Title: Re: Retrieve your External IP address
Post by: AIR on March 20, 2019, 07:05:23 PM
Using libraries eliminates the need to reinvent the wheel.

That said, here is an example:

Code: C
  1. //DNS Query Program on Linux
  2. //Author : Silver Moon (m00n.silv3r@gmail.com)
  3. //Dated : 29/4/2009
  4.  
  5. //Modified by Armando I. Rivera (AIR)
  6. //to return public ip via opendns servers
  7. //Date: 03/20/2019
  8.  
  9. //Header Files
  10. #include<stdio.h>       //printf
  11. #include<string.h>      //strlen
  12. #include<stdlib.h>      //malloc
  13. #include<sys/socket.h>  //you know what this is for
  14. #include<arpa/inet.h>   //inet_addr , inet_ntoa , ntohs etc
  15. #include<netinet/in.h>
  16. #include<unistd.h>      //getpid
  17.  
  18. //List of DNS Servers registered on the system
  19. char dns_servers[10][100];
  20. int dns_server_count = 0;
  21.  
  22. //Types of DNS resource records :)
  23. #define T_A 1 //Ipv4 address
  24. #define T_NS 2 //Nameserver
  25. #define T_CNAME 5 // canonical name
  26. #define T_SOA 6 /* start of authority zone */
  27. #define T_PTR 12 /* domain name pointer */
  28. #define T_MX 15 //Mail server
  29.  
  30. //Function Prototypes
  31. void ngethostbyname (unsigned char* , int);
  32. void ChangetoDnsNameFormat (unsigned char*,unsigned char*);
  33. unsigned char* ReadName (unsigned char*,unsigned char*,int*);
  34. void get_dns_servers();
  35.  
  36. //DNS header structure
  37. struct DNS_HEADER
  38. {
  39.         unsigned short id; // identification number
  40.  
  41.         unsigned char rd :1; // recursion desired
  42.         unsigned char tc :1; // truncated message
  43.         unsigned char aa :1; // authoritive answer
  44.         unsigned char opcode :4; // purpose of message
  45.         unsigned char qr :1; // query/response flag
  46.  
  47.         unsigned char rcode :4; // response code
  48.         unsigned char cd :1; // checking disabled
  49.         unsigned char ad :1; // authenticated data
  50.         unsigned char z :1; // its z! reserved
  51.         unsigned char ra :1; // recursion available
  52.  
  53.         unsigned short q_count; // number of question entries
  54.         unsigned short ans_count; // number of answer entries
  55.         unsigned short auth_count; // number of authority entries
  56.         unsigned short add_count; // number of resource entries
  57. };
  58.  
  59. //Constant sized fields of query structure
  60. struct QUESTION
  61. {
  62.         unsigned short qtype;
  63.         unsigned short qclass;
  64. };
  65.  
  66. //Constant sized fields of the resource record structure
  67. #pragma pack(push, 1)
  68. struct R_DATA
  69. {
  70.         unsigned short type;
  71.         unsigned short _class;
  72.         unsigned int ttl;
  73.         unsigned short data_len;
  74. };
  75. #pragma pack(pop)
  76.  
  77. //Pointers to resource record contents
  78. struct RES_RECORD
  79. {
  80.         unsigned char *name;
  81.         struct R_DATA *resource;
  82.         unsigned char *rdata;
  83. };
  84.  
  85. //Structure of a Query
  86. typedef struct
  87. {
  88.         unsigned char *name;
  89.         struct QUESTION *ques;
  90. } QUERY;
  91.  
  92. int main( int argc , char *argv[])
  93. {
  94.         unsigned char hostname[] = "myip.opendns.com";
  95.  
  96.         // Set Custom DNS Servers
  97.         strcpy(dns_servers[0] , "208.67.222.222"); //resolver1.opendns.com
  98.         strcpy(dns_servers[1] , "208.67.220.220"); //resolver2.opendns.com
  99.        
  100.         //Now get the ip of this hostname , A record
  101.         ngethostbyname(hostname , T_A);
  102.  
  103.         return 0;
  104. }
  105.  
  106. /*
  107.  * Perform a DNS query by sending a packet
  108.  * */
  109. void ngethostbyname(unsigned char *host , int query_type)
  110. {
  111.         unsigned char buf[65536],*qname,*reader;
  112.         int i , j , stop , s;
  113.  
  114.         struct sockaddr_in a;
  115.  
  116.         struct RES_RECORD answers[20],auth[20],addit[20]; //the replies from the DNS server
  117.         struct sockaddr_in dest;
  118.  
  119.         struct DNS_HEADER *dns = NULL;
  120.         struct QUESTION *qinfo = NULL;
  121.  
  122.         s = socket(AF_INET , SOCK_DGRAM , IPPROTO_UDP); //UDP packet for DNS queries
  123.  
  124.         dest.sin_family = AF_INET;
  125.         dest.sin_port = htons(53);
  126.         dest.sin_addr.s_addr = inet_addr(dns_servers[0]); //dns servers
  127.  
  128.         //Set the DNS structure to standard queries
  129.         dns = (struct DNS_HEADER *)&buf;
  130.  
  131.         dns->id = (unsigned short) htons(getpid());
  132.         dns->qr = 0; //This is a query
  133.         dns->opcode = 0; //This is a standard query
  134.         dns->aa = 0; //Not Authoritative
  135.         dns->tc = 0; //This message is not truncated
  136.         dns->rd = 1; //Recursion Desired
  137.         dns->ra = 0; //Recursion not available! hey we dont have it (lol)
  138.         dns->z = 0;
  139.         dns->ad = 0;
  140.         dns->cd = 0;
  141.         dns->rcode = 0;
  142.         dns->q_count = htons(1); //we have only 1 question
  143.         dns->ans_count = 0;
  144.         dns->auth_count = 0;
  145.         dns->add_count = 0;
  146.  
  147.         //point to the query portion
  148.         qname =(unsigned char*)&buf[sizeof(struct DNS_HEADER)];
  149.  
  150.         ChangetoDnsNameFormat(qname , host);
  151.         qinfo =(struct QUESTION*)&buf[sizeof(struct DNS_HEADER) + (strlen((const char*)qname) + 1)]; //fill it
  152.  
  153.         qinfo->qtype = htons( query_type ); //type of the query , A , MX , CNAME , NS etc
  154.         qinfo->qclass = htons(1); //its internet (lol)
  155.  
  156.         // Send Packet
  157.         if( sendto(s,(char*)buf,sizeof(struct DNS_HEADER) + (strlen((const char*)qname)+1) + sizeof(struct QUESTION),0,(struct sockaddr*)&dest,sizeof(dest)) < 0)
  158.         {
  159.                 perror("sendto failed");
  160.         }
  161.  
  162.        
  163.         //Receive the answer
  164.         i = sizeof dest;
  165.  
  166.         if(recvfrom (s,(char*)buf , 65536 , 0 , (struct sockaddr*)&dest , (socklen_t*)&i ) < 0)
  167.         {
  168.                 perror("recvfrom failed");
  169.         }
  170.  
  171.  
  172.         dns = (struct DNS_HEADER*) buf;
  173.  
  174.         //move ahead of the dns header and the query field
  175.         reader = &buf[sizeof(struct DNS_HEADER) + (strlen((const char*)qname)+1) + sizeof(struct QUESTION)];
  176.  
  177.         //Start reading answers
  178.         stop=0;
  179.  
  180.         for(i=0;i<ntohs(dns->ans_count);i++)
  181.         {
  182.                 answers[i].name=ReadName(reader,buf,&stop);
  183.                 reader = reader + stop;
  184.  
  185.                 answers[i].resource = (struct R_DATA*)(reader);
  186.                 reader = reader + sizeof(struct R_DATA);
  187.  
  188.                 if(ntohs(answers[i].resource->type) == 1) //if its an ipv4 address
  189.                 {
  190.                         answers[i].rdata = (unsigned char*)malloc(ntohs(answers[i].resource->data_len));
  191.  
  192.                         for(j=0 ; j<ntohs(answers[i].resource->data_len) ; j++)
  193.                         {
  194.                                 answers[i].rdata[j]=reader[j];
  195.                         }
  196.  
  197.                         answers[i].rdata[ntohs(answers[i].resource->data_len)] = '\0';
  198.  
  199.                         reader = reader + ntohs(answers[i].resource->data_len);
  200.                 }
  201.                 else
  202.                 {
  203.                         answers[i].rdata = ReadName(reader,buf,&stop);
  204.                         reader = reader + stop;
  205.                 }
  206.         }
  207.  
  208.         //print answers
  209.         for(i=0 ; i < ntohs(dns->ans_count) ; i++)
  210.         {
  211.  
  212.                 if( ntohs(answers[i].resource->type) == T_A) //IPv4 address
  213.                 {
  214.                         long *p;
  215.                         p=(long*)answers[i].rdata;
  216.                         a.sin_addr.s_addr=(*p); //working without ntohl
  217.                         printf("External IP: %s\n",inet_ntoa(a.sin_addr));
  218.                 }
  219.         }
  220.  
  221.         return;
  222. }
  223.  
  224. /*
  225.  *
  226.  * */
  227. u_char* ReadName(unsigned char* reader,unsigned char* buffer,int* count)
  228. {
  229.         unsigned char *name;
  230.         unsigned int p=0,jumped=0,offset;
  231.         int i , j;
  232.  
  233.         *count = 1;
  234.         name = (unsigned char*)malloc(256);
  235.  
  236.         name[0]='\0';
  237.  
  238.         //read the names in 3www6google3com format
  239.         while(*reader!=0)
  240.         {
  241.                 if(*reader>=192)
  242.                 {
  243.                         offset = (*reader)*256 + *(reader+1) - 49152; //49152 = 11000000 00000000 ;)
  244.                         reader = buffer + offset - 1;
  245.                         jumped = 1; //we have jumped to another location so counting wont go up!
  246.                 }
  247.                 else
  248.                 {
  249.                         name[p++]=*reader;
  250.                 }
  251.  
  252.                 reader = reader+1;
  253.  
  254.                 if(jumped==0)
  255.                 {
  256.                         *count = *count + 1; //if we havent jumped to another location then we can count up
  257.                 }
  258.         }
  259.  
  260.         name[p]='\0'; //string complete
  261.         if(jumped==1)
  262.         {
  263.                 *count = *count + 1; //number of steps we actually moved forward in the packet
  264.         }
  265.  
  266.         //now convert 3www6google3com0 to www.google.com
  267.         for(i=0;i<(int)strlen((const char*)name);i++)
  268.         {
  269.                 p=name[i];
  270.                 for(j=0;j<(int)p;j++)
  271.                 {
  272.                         name[i]=name[i+1];
  273.                         i=i+1;
  274.                 }
  275.                 name[i]='.';
  276.         }
  277.         name[i-1]='\0'; //remove the last dot
  278.         return name;
  279. }
  280.  
  281. /*
  282.  * This will convert www.google.com to 3www6google3com
  283.  * got it :)
  284.  * */
  285. void ChangetoDnsNameFormat(unsigned char* dns,unsigned char* host)
  286. {
  287.         int lock = 0 , i;
  288.         strcat((char*)host,".");
  289.        
  290.         for(i = 0 ; i < strlen((char*)host) ; i++)
  291.         {
  292.                 if(host[i]=='.')
  293.                 {
  294.                         *dns++ = i-lock;
  295.                         for(;lock<i;lock++)
  296.                         {
  297.                                 *dns++=host[lock];
  298.                         }
  299.                         lock++; //or lock=i+1;
  300.                 }
  301.         }
  302.         *dns++='\0';
  303. }
  304.  

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
Title: Re: Retrieve your External IP address
Post by: AIR on March 21, 2019, 01:00:40 AM
MBC:

Code: Text
  1. $EXECON "-lresolv"
  2.  
  3. $HEADER
  4.     #include <resolv.h>
  5.     #include <arpa/inet.h>
  6.     #include <netdb.h>
  7. $HEADER
  8.  
  9. Const query = "myip.opendns.com"
  10.  
  11. dim he as hostent PTR, addr_list as in_addr PTR PTR, i
  12. dim res as __res_state, addr as in_addr, answer[512] as UCHAR
  13. dim ip$,length,handle as ns_msg, rr as ns_rr
  14.  
  15. he = gethostbyname( "resolver1.opendns.com" )
  16. addr_list = (in_addr **) he->h_addr_list
  17. ip$ = inet_ntoa(*addr_list[0])
  18.  
  19. res_ninit(&res)
  20. inet_aton(ip$, &addr)
  21. res.nsaddr_list[0].sin_addr = addr
  22. res.nsaddr_list[0].sin_family = AF_INET;
  23. res.nsaddr_list[0].sin_port = htons(NS_DEFAULTPORT);
  24. res.nscount = 1;
  25.  
  26. length = res_nquery(&res, query, ns_c_in, ns_t_a, answer, sizeof(answer))
  27. ns_initparse(answer, length, &handle)
  28. if ns_msg_count(handle, ns_s_an) > 0 then
  29.     if ns_parserr(&handle, ns_s_an, 0, &rr) = 0 then
  30.         ip$ = inet_ntoa(*(in_addr *)ns_rr_rdata(rr))
  31.     endif
  32. endif
  33.  
  34. print "External IP: ",ip$
  35.  

AIR.
Title: Re: Retrieve your External IP address
Post by: AIR on March 23, 2019, 11:33:09 AM
I would like to see an example using raw sockets without the support libraries hiding what is really going on.

Here's what that would look like in Python:

Code: Python
  1. #!/usr/bin/env python
  2.  
  3. import socket, sys
  4.    
  5. if __name__ == '__main__':
  6.  
  7.     server = (socket.gethostbyname("resolver1.opendns.com"), 53)
  8.  
  9.     prefix = "\x41\x41\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00"
  10.     suffix = "\x00\x00\x01\x00\x01"
  11.     message = "\x04\x6d\x79\x69\x70\x07\x6f\x70\x65\x6e\x64\x6e\x73\x03\x63\x6f\x6d"
  12.  
  13.     query = ''.join( (prefix,message,suffix) )
  14.  
  15.     try:
  16.         sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  17.         sock.settimeout(5)
  18.         sock.sendto(query, server)             
  19.         data, addr = sock.recvfrom(512)
  20.     except Exception, e:
  21.         print "No response from server", server,e
  22.         sock.close()
  23.         sys.exit()
  24.    
  25.     # get the response from the server 
  26.     response = str(data.split(',', 0)[0].encode("hex"))
  27.    
  28.     # check the RCODE value
  29.     if int(response[7:8]) == 0: # no error, get the ip address 
  30.  
  31.         # get the answer section from the server response
  32.         answer = response[2*len(query)+24:]    
  33.  
  34.         # get the RDATA from the answer
  35.         rdata = answer[:8]
  36.  
  37.         a = int(rdata, 16)     
  38.  
  39.         # convert result to human readable IP
  40.         ipaddress = '.'.join([ str(x) for x in (a >> 24 & 0xff, a >> 16 & 0xff, a >> 8 & 0xff, a & 0xff)])
  41.  
  42.         # Output the ipaddress
  43.         print "External IP: ", ipaddress
  44.  
  45.  
  46.     else:
  47.         # Catch-All error message
  48.         print "Error Communicating with Server"
  49.     sock.close()
  50.  

Couple of notes:

I hand-crafted the binary query/request that is sent to the dns server.  The alternative would have required the use of the "structs" or "binascii" modules.

AFAIK, SB Sockets are TCP only, so I don't think using Sockets there will work since this requires a UDP connection.

This works under macOS, Linux, and RasPi at this point.

AIR.
Title: Re: Retrieve your External IP address
Post by: John on March 23, 2019, 04:48:12 PM
Quote from: AIR
AFAIK, SB Sockets are TCP only, so I don't think using Sockets there will work since this requires a UDP connection.

 :(

I'll just have to be happy with myip.sb.
Title: Re: Retrieve your External IP address
Post by: AIR on March 23, 2019, 09:15:33 PM
Quote from: AIR
AFAIK, SB Sockets are TCP only, so I don't think using Sockets there will work since this requires a UDP connection.

 :(

I'll just have to be happy with myip.sb.

Way back around 2002-2004, Peter wrote a SB module called ssockets.  In the old mailing list, someone asked about UDP and Peter said that while this module was TCP only, that it should be fairly simple to modify it to use UDP.

I found the source on one of his old websites, and am looking it over...

AIR.
Title: Re: Retrieve your External IP address
Post by: John on March 23, 2019, 09:28:39 PM
Your memory is outstanding!

What I like about SB is I feel I only scratched the surface of it's feature set and there is still much to learn.

Peter mentioned on Twitter that the development Cycle for SB was 1997 to 2006.
Title: Re: Retrieve your External IP address
Post by: jalih on March 25, 2019, 08:09:54 AM
Couple of notes:

I hand-crafted the binary query/request that is sent to the dns server.  The alternative would have required the use of the "structs" or "binascii" modules.

AFAIK, SB Sockets are TCP only, so I don't think using Sockets there will work since this requires a UDP connection.

This works under macOS, Linux, and RasPi at this point.

AIR.

Here is updated 8th code that also checks RCODE for errors. Using pack and unpack words makes it really easy to handle buffer of message data.

Code: [Select]


net:INET4 net:DGRAM net:socket var, socket

[ 0xaa, 0xaa, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  "myip", "opendns", "com", 0x00, 0x00, 0x01, 0x00, 0x01 ] "12b1s1c1s1c1s1c5b" pack var, message


: address-info  \  -- ai
  "resolver1.opendns.com" 53 net:getaddrinfo ;


: app:main
  address-info null? if
    drop
    "Server address information lookup failed." . cr
    bye
  then

  socket @ swap message @ 0 net:sendto null? if
    drop
    "Error sending message." . cr
    net:close
    bye
  else
    drop
  then

  512 b:new 0 net:recvfrom null? if
    drop
    "No response from the server" . cr
    net:close
    bye
  then

  \ Test RCODE
  over 3 b:@ nip 0xf n:band not if
    \ Last four bytes from the response are the IP address.
    dup 4 n:- swap b:slice "4:1B" unpack drop
    ' >s a:map
    "." a:join
    "External IP: " . . cr
  else
    2drop
    "Error communicating with the server." . cr
  then
  drop
  net:close
  bye ;
Title: Re: Retrieve your External IP address
Post by: John on March 25, 2019, 08:53:44 AM
SB also supports binary pack/unpack. Just no UDP.  :-\
Title: Re: Retrieve your External IP address
Post by: AIR on March 29, 2019, 01:22:18 AM
I created a custom SB module to try this.

Code: Script BASIC
  1. include ip.bas
  2.  
  3. print "Public IP: " & IP::Public() & "\n"
  4.  
  5. print "Local IP: " & IP::Local("eth0") & "\n"
  6.  
  7. print "MAC Address for eth0: " & IP::MacAddress("eth0") & "\n"

OUTPUT:
riveraa@dpi:~/sb $ sb iptest.sb
Public IP: 24.188.233.50 <--not my real ip.  LOL.
Local IP: 192.168.1.64
MAC Address for eth0: b8:27:eb:2a:e9:22


All done in code, no calls to external web sites (which wouldn't be able to grab the MAC Address.  I hope!), or executing shell commands.

I used libresolv for the DNS Query, and SOCKET & IOCTL calls to get the local IP and MAC Address of the adapter.

I took a slightly different approach to putting the module together; I wrote the core code in pure C and then called the Functions from within the module after compiling the C file along with the interface.c file (similar to what I did with the JSON and SLRE modules).

This is a much cleaner approach since I didn't have to re-write the core code to work within the BES macro system.  All I had to do was plug in the Function calls and I was done.

Coded start to finish on my RasPi.  8)

I'll push this up later today after some cleanup and sleep, it's 4:20am where I am right now!

AIR.
Title: Re: Retrieve your External IP address
Post by: John on March 29, 2019, 07:53:30 AM
Quote
it's 4:20am

Here on the west coast 4:20 isn't about bedtime.  ;)

I have yet to find a language with an easier to use extension interface.

Looking forward to see your new extension module.