mirror of
https://github.com/RetroShare/RetroShare.git
synced 2024-12-28 08:59:37 -05:00
Add ability to retrieve External IP using DNS server.
IPV6 compatible.
This commit is contained in:
parent
56d34a8a2c
commit
a09db6717b
@ -41,8 +41,6 @@
|
||||
const rstime_t MAX_TIME_BEFORE_RETRY = 300 ; /* seconds before retrying an ip address */
|
||||
const rstime_t MAX_KEEP_DNS_ENTRY = 3600 ; /* seconds during which a DNS entry is considered valid */
|
||||
|
||||
static const std::string ADDR_AGENT = "Mozilla/5.0";
|
||||
|
||||
void *solveDNSEntries(void *p)
|
||||
{
|
||||
bool more_to_go = true ;
|
||||
|
@ -38,132 +38,10 @@
|
||||
#include <stdio.h>
|
||||
#include "util/rstime.h"
|
||||
|
||||
const uint32_t MAX_IP_STORE = 300; /* seconds ip address timeout */
|
||||
const uint32_t MAX_IP_STORE = 300; /* seconds ip address timeout */
|
||||
|
||||
//#define EXTADDRSEARCH_DEBUG
|
||||
|
||||
static const std::string ADDR_AGENT = "Mozilla/5.0";
|
||||
|
||||
static std::string scan_ip(const std::string& text)
|
||||
{
|
||||
std::set<unsigned char> digits ;
|
||||
digits.insert('0') ; digits.insert('3') ; digits.insert('6') ;
|
||||
digits.insert('1') ; digits.insert('4') ; digits.insert('7') ;
|
||||
digits.insert('2') ; digits.insert('5') ; digits.insert('8') ;
|
||||
digits.insert('9') ;
|
||||
|
||||
for(int i=0;i<(int)text.size();++i)
|
||||
{
|
||||
while(i < (int)text.size() && digits.find(text[i])==digits.end()) ++i ;
|
||||
|
||||
if(i>=(int)text.size())
|
||||
return "" ;
|
||||
|
||||
unsigned int a,b,c,d ;
|
||||
|
||||
if(sscanf(text.c_str()+i,"%u.%u.%u.%u",&a,&b,&c,&d) != 4)
|
||||
continue ;
|
||||
|
||||
if(a < 256 && b<256 && c<256 && d<256)
|
||||
{
|
||||
std::string s ;
|
||||
rs_sprintf(s, "%u.%u.%u.%u", a, b, c, d) ;
|
||||
return s;
|
||||
}
|
||||
}
|
||||
return "" ;
|
||||
}
|
||||
|
||||
static void getPage(const std::string& server_name,std::string& page)
|
||||
{
|
||||
page = "" ;
|
||||
int sockfd,n=0; // socket descriptor
|
||||
struct sockaddr_in serveur; // server's parameters
|
||||
memset(&serveur.sin_zero, 0, sizeof(serveur.sin_zero));
|
||||
|
||||
char buf[1024];
|
||||
char request[1024];
|
||||
#ifdef EXTADDRSEARCH_DEBUG
|
||||
std::cout << "ExtAddrFinder: connecting to " << server_name << std::endl ;
|
||||
#endif
|
||||
// socket creation
|
||||
|
||||
sockfd = unix_socket(PF_INET,SOCK_STREAM,0);
|
||||
if (sockfd < 0)
|
||||
{
|
||||
std::cerr << "ExtAddrFinder: Failed to create socket" << std::endl;
|
||||
return ;
|
||||
}
|
||||
|
||||
serveur.sin_family = AF_INET;
|
||||
|
||||
// get server's ipv4 adress
|
||||
|
||||
in_addr in ;
|
||||
|
||||
if(!rsGetHostByName(server_name.c_str(),in)) /* l'hôte n'existe pas */
|
||||
{
|
||||
std::cerr << "ExtAddrFinder: Unknown host " << server_name << std::endl;
|
||||
unix_close(sockfd);
|
||||
return ;
|
||||
}
|
||||
serveur.sin_addr = in ;
|
||||
serveur.sin_port = htons(80);
|
||||
|
||||
#ifdef EXTADDRSEARCH_DEBUG
|
||||
printf("Connection attempt\n");
|
||||
#endif
|
||||
std::cerr << "ExtAddrFinder: resolved hostname " << server_name << " to " << rs_inet_ntoa(in) << std::endl;
|
||||
|
||||
sockaddr_storage server;
|
||||
sockaddr_storage_setipv4(server, &serveur);
|
||||
sockaddr_storage_setport(server, 80);
|
||||
if(unix_connect(sockfd, server) == -1)
|
||||
{
|
||||
std::cerr << "ExtAddrFinder: Connection error to " << server_name << std::endl ;
|
||||
unix_close(sockfd);
|
||||
return ;
|
||||
}
|
||||
#ifdef EXTADDRSEARCH_DEBUG
|
||||
std::cerr << "ExtAddrFinder: Connection established to " << server_name << std::endl ;
|
||||
#endif
|
||||
|
||||
// envoi
|
||||
if(snprintf( request,
|
||||
1024,
|
||||
"GET / HTTP/1.0\r\n"
|
||||
"Host: %s:%d\r\n"
|
||||
"Connection: Close\r\n"
|
||||
"\r\n",
|
||||
server_name.c_str(), 80) > 1020)
|
||||
{
|
||||
std::cerr << "ExtAddrFinder: buffer overrun. The server name \"" << server_name << "\" is too long. This is quite unexpected." << std::endl;
|
||||
unix_close(sockfd);
|
||||
return ;
|
||||
}
|
||||
|
||||
if(send(sockfd,request,strlen(request),0)== -1)
|
||||
{
|
||||
std::cerr << "ExtAddrFinder: Could not send request to " << server_name << std::endl ;
|
||||
unix_close(sockfd);
|
||||
return ;
|
||||
}
|
||||
// recéption
|
||||
|
||||
while((n = recv(sockfd, buf, sizeof buf - 1, 0)) > 0)
|
||||
{
|
||||
buf[n] = '\0';
|
||||
page += std::string(buf,n) ;
|
||||
}
|
||||
// fermeture de la socket
|
||||
|
||||
unix_close(sockfd);
|
||||
#ifdef EXTADDRSEARCH_DEBUG
|
||||
std::cerr << "ExtAddrFinder: Got full page from " << server_name << std::endl ;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void* doExtAddrSearch(void *p)
|
||||
{
|
||||
|
||||
@ -173,15 +51,12 @@ void* doExtAddrSearch(void *p)
|
||||
|
||||
for(std::list<std::string>::const_iterator it(af->_ip_servers.begin());it!=af->_ip_servers.end();++it)
|
||||
{
|
||||
std::string page ;
|
||||
|
||||
getPage(*it,page) ;
|
||||
std::string ip = scan_ip(page) ;
|
||||
|
||||
std::string ip = "";
|
||||
rsGetHostByNameSpecDNS(*it,"myip.opendns.com",ip);
|
||||
if(ip != "")
|
||||
res.push_back(ip) ;
|
||||
#ifdef EXTADDRSEARCH_DEBUG
|
||||
std::cout << "ip found through " << *it << ": \"" << ip << "\"" << std::endl ;
|
||||
std::cout << "ip found through DNS " << *it << ": \"" << ip << "\"" << std::endl ;
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -315,9 +190,15 @@ ExtAddrFinder::ExtAddrFinder() : mAddrMtx("ExtAddrFinder")
|
||||
mFoundTS = time(NULL) - MAX_IP_STORE;
|
||||
sockaddr_storage_clear(mAddr);
|
||||
|
||||
_ip_servers.push_back(std::string( "checkip.dyndns.org" )) ;
|
||||
_ip_servers.push_back(std::string( "www.myip.dk" )) ;
|
||||
_ip_servers.push_back(std::string( "showip.net" )) ;
|
||||
_ip_servers.push_back(std::string( "www.displaymyip.com")) ;
|
||||
//https://unix.stackexchange.com/questions/22615/how-can-i-get-my-external-ip-address-in-a-shell-script
|
||||
//Enter direct ip so local DNS cannot change it.
|
||||
//DNS servers must recognize "myip.opendns.com"
|
||||
_ip_servers.push_back(std::string( "208.67.222.222" )) ;//resolver1.opendns.com
|
||||
_ip_servers.push_back(std::string( "208.67.220.220" )) ;//resolver2.opendns.com
|
||||
_ip_servers.push_back(std::string( "208.67.222.220" )) ;//resolver3.opendns.com
|
||||
_ip_servers.push_back(std::string( "208.67.220.222" )) ;//resolver4.opendns.com
|
||||
//Ipv6 server disabled as Current ip only manage ipv4 for now.
|
||||
//_ip_servers.push_back(std::string( "2620:119:35::35" )) ;//resolver1.opendns.com
|
||||
//_ip_servers.push_back(std::string( "2620:119:53::53" )) ;//resolver2.opendns.com
|
||||
}
|
||||
|
||||
|
@ -40,6 +40,51 @@ std::error_condition rs_errno_to_condition(int errno_code)
|
||||
{ return std::make_error_condition(static_cast<std::errc>(errno_code)); }
|
||||
|
||||
|
||||
std::ostream& hex_dump(std::ostream& os, const void *buffer,
|
||||
std::size_t bufsize, bool showPrintableChars /*= true*/)
|
||||
{
|
||||
if (buffer == nullptr) {
|
||||
return os;
|
||||
}
|
||||
auto oldFormat = os.flags();
|
||||
auto oldFillChar = os.fill();
|
||||
constexpr std::size_t maxline{8};
|
||||
// create a place to store text version of string
|
||||
char renderString[maxline+1];
|
||||
char *rsptr{renderString};
|
||||
// convenience cast
|
||||
const unsigned char *buf{reinterpret_cast<const unsigned char *>(buffer)};
|
||||
|
||||
for (std::size_t linecount=maxline; bufsize; --bufsize, ++buf) {
|
||||
os << std::setw(2) << std::setfill('0') << std::hex
|
||||
<< static_cast<unsigned>(*buf) << ' ';
|
||||
*rsptr++ = std::isprint(*buf) ? *buf : '.';
|
||||
if (--linecount == 0) {
|
||||
*rsptr++ = '\0'; // terminate string
|
||||
if (showPrintableChars) {
|
||||
os << " | " << renderString;
|
||||
}
|
||||
os << '\n';
|
||||
rsptr = renderString;
|
||||
linecount = std::min(maxline, bufsize);
|
||||
}
|
||||
}
|
||||
// emit newline if we haven't already
|
||||
if (rsptr != renderString) {
|
||||
if (showPrintableChars) {
|
||||
for (*rsptr++ = '\0'; rsptr != &renderString[maxline+1]; ++rsptr) {
|
||||
os << " ";
|
||||
}
|
||||
os << " | " << renderString;
|
||||
}
|
||||
os << '\n';
|
||||
}
|
||||
|
||||
os.fill(oldFillChar);
|
||||
os.flags(oldFormat);
|
||||
return os;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@ -211,3 +256,7 @@ void rslog(const RsLog::logLvl lvl, RsLog::logInfo *info, const std::string &msg
|
||||
lineCount++;
|
||||
}
|
||||
}
|
||||
/// All the lines before are DEPRECATED!!
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -318,3 +318,47 @@ void rslog(const RsLog::logLvl lvl, RsLog::logInfo *info, const std::string &msg
|
||||
#define PQL_DEBUG_ALERT RSL_DEBUG_ALERT
|
||||
#define PQL_DEBUG_BASIC RSL_DEBUG_BASIC
|
||||
#define PQL_DEBUG_ALL RSL_DEBUG_ALL
|
||||
|
||||
//From https://codereview.stackexchange.com/a/165162
|
||||
/**
|
||||
* @brief hex_dump: Send Hexadecimal Dump to stream
|
||||
* @param os: Output Stream
|
||||
* @param buffer: Buffer to send
|
||||
* @param bufsize: Buffer's size
|
||||
* @param showPrintableChars: If must send printable Char too
|
||||
* @return
|
||||
* basic string:
|
||||
* 61 62 63 64 65 66 31 32 | abcdef12
|
||||
* 33 34 35 36 00 7a 79 78 | 3456.zyx
|
||||
* 77 76 75 39 38 37 36 35 | wvu98765
|
||||
* 34 45 64 77 61 72 64 00 | 4Edward.
|
||||
*
|
||||
* wide string:
|
||||
* 41 00 00 00 20 00 00 00 | A... ...
|
||||
* 77 00 00 00 69 00 00 00 | w...i...
|
||||
* 64 00 00 00 65 00 00 00 | d...e...
|
||||
* 20 00 00 00 73 00 00 00 | ...s...
|
||||
* 74 00 00 00 72 00 00 00 | t...r...
|
||||
* 69 00 00 00 6e 00 00 00 | i...n...
|
||||
* 67 00 00 00 2e 00 00 00 | g.......
|
||||
*
|
||||
* a double
|
||||
* 49 92 24 49 92 24 09 40 | I.$I.$.@
|
||||
*/
|
||||
std::ostream& hex_dump(std::ostream& os, const void *buffer,
|
||||
std::size_t bufsize, bool showPrintableChars = true);
|
||||
|
||||
/**
|
||||
* @brief The hexDump struct
|
||||
* Enable to print dump calling like that:
|
||||
* const char test[] = "abcdef123456\0zyxwvu987654Edward";
|
||||
* RsDbg()<<hexDump(test, sizeof(test))<<std::endl;
|
||||
*/
|
||||
struct hexDump {
|
||||
const void *buffer;
|
||||
std::size_t bufsize;
|
||||
hexDump(const void *buf, std::size_t bufsz) : buffer{buf}, bufsize{bufsz} {}
|
||||
friend std::ostream &operator<<(std::ostream &out, const hexDump &hd) {
|
||||
return hex_dump(out, hd.buffer, hd.bufsize, true);
|
||||
}
|
||||
};
|
||||
|
@ -21,6 +21,9 @@
|
||||
* *
|
||||
*******************************************************************************/
|
||||
|
||||
//#define DEBUG_SPEC_DNS 1
|
||||
|
||||
#include "util/rsdebug.h"
|
||||
#include "util/rsnet.h"
|
||||
#include "util/rsthreads.h"
|
||||
#include "util/rsstring.h"
|
||||
@ -40,6 +43,72 @@
|
||||
#define BIG_ENDIAN 4321
|
||||
#endif
|
||||
|
||||
//https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-2
|
||||
constexpr uint16_t DNSC_IN = 1; //Internet (IN)
|
||||
//https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-4
|
||||
constexpr uint16_t DNST_A = 1; //Ipv4 address
|
||||
constexpr uint16_t DNST_AAAA =28; //Ipv6 address
|
||||
|
||||
///Need to pack as we use sizeof them. (avoid padding)
|
||||
#pragma pack(1)
|
||||
//DNS header structure
|
||||
struct DNS_HEADER
|
||||
{
|
||||
unsigned short id; // identification number
|
||||
|
||||
//Header flags https://www.bind9.net/dns-header-flags
|
||||
unsigned char rd :1; //bit 07 Recursion Desired, indicates if the client means a recursive query
|
||||
unsigned char tc :1; //bit 06 TrunCation, indicates that this message was truncated due to excessive length
|
||||
unsigned char aa :1; //bit 05 Authoritative Answer, in a response, indicates if the DNS server is authoritative for the queried hostname
|
||||
unsigned char opcode :4;//bit 01-04 The type can be QUERY (standard query, 0), IQUERY (inverse query, 1), or STATUS (server status request, 2)
|
||||
unsigned char qr :1; //bit 00 Indicates if the message is a query (0) or a reply (1)
|
||||
|
||||
unsigned char rcode :4; //bit 12-15 Response Code can be NOERROR (0), FORMERR (1, Format error), SERVFAIL (2), NXDOMAIN (3, Nonexistent domain), etc.
|
||||
unsigned char cd :1; //bit 11 Checking Disabled [RFC 4035][RFC 6840][RFC Errata 4927] used by DNSSEC
|
||||
unsigned char ad :1; //bit 10 Authentic Data [RFC 4035][RFC 6840][RFC Errata 4924] used by DNSSEC
|
||||
unsigned char z :1; //bit 09 Zero, reserved for future use
|
||||
unsigned char ra :1; //bit 08 Recursion Available [RFC 1035] in a response, indicates if the replying DNS server supports recursion
|
||||
|
||||
unsigned short q_count; // number of question entries
|
||||
unsigned short ans_count; // number of answer entries
|
||||
unsigned short auth_count; // number of authority resource records entries
|
||||
unsigned short add_count; // number of additional resource record entries
|
||||
};
|
||||
//// OpCode text https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-5
|
||||
//static const char *opcodetext[] = { "QUERY", "IQUERY", "STATUS",
|
||||
// "RESERVED3", "NOTIFY", "UPDATE",
|
||||
// "STATEFUL", "RESERVED7", "RESERVED8",
|
||||
// "RESERVED9", "RESERVED10", "RESERVED11",
|
||||
// "RESERVED12", "RESERVED13", "RESERVED14",
|
||||
// "RESERVED15" };
|
||||
//// RCode text https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-6
|
||||
//static const char *rcodetext[] = { "NOERROR", "FORMERR", "SERVFAIL",
|
||||
// "NXDOMAIN", "NOTIMP", "REFUSED",
|
||||
// "YXDOMAIN", "YXRRSET", "NXRRSET",
|
||||
// "NOTAUTH", "NOTZONE", "DSOTYPENI",
|
||||
// "RESERVED12", "RESERVED13", "RESERVED14",
|
||||
// "RESERVED15", "BADVERS", "BADKEY",
|
||||
// "BADTIME", "BADMODE", "BADNAME",
|
||||
// "BADALG", "BADTRUNC", "BADCOOKIE"};
|
||||
|
||||
//Constant sized fields of query structure
|
||||
//https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml
|
||||
struct QUESTION
|
||||
{
|
||||
unsigned short qtype; //https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-4
|
||||
unsigned short qclass; //https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-2
|
||||
};
|
||||
|
||||
//Constant sized fields of the resource record structure
|
||||
struct RR_DATA
|
||||
{
|
||||
unsigned short rtype; //https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-4
|
||||
unsigned short rclass; //https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-2
|
||||
unsigned int rttl; //Time To Live is the number of seconds left before the information expires. (32bits integer, so maximum 140 years)
|
||||
unsigned short data_len;//Lenght of following data
|
||||
};
|
||||
#pragma pack()
|
||||
|
||||
#ifndef ntohll
|
||||
uint64_t ntohll(uint64_t x)
|
||||
{
|
||||
@ -99,6 +168,248 @@ bool rsGetHostByName(const std::string& hostname, in_addr& returned_addr)
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool rsGetHostByNameSpecDNS(const std::string& servername, const std::string& hostname, std::string& returned_addr)
|
||||
{
|
||||
#ifdef DEBUG_SPEC_DNS
|
||||
RsDbg()<<__PRETTY_FUNCTION__<<" servername="<< servername << " hostname=" << hostname << std::endl;
|
||||
#endif
|
||||
|
||||
if (strlen(servername.c_str()) > 256)
|
||||
{
|
||||
RsErr()<<__PRETTY_FUNCTION__<<": servername is too long > 256 chars:"<<servername<<std::endl;
|
||||
return false;
|
||||
}
|
||||
if (strlen(hostname.c_str()) > 256)
|
||||
{
|
||||
RsErr()<<__PRETTY_FUNCTION__<<": hostname is too long > 256 chars:"<<hostname<<std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isIPV4 = false;
|
||||
in_addr dns_server_4; in6_addr dns_server_6;
|
||||
if (inet_pton(AF_INET, servername.c_str(), &dns_server_4))
|
||||
isIPV4 = true;
|
||||
else if (inet_pton(AF_INET6, servername.c_str(), &dns_server_6))
|
||||
isIPV4 = false;
|
||||
else if (rsGetHostByName(servername, dns_server_4))
|
||||
isIPV4 = true;
|
||||
else
|
||||
{
|
||||
RsErr()<<__PRETTY_FUNCTION__<<": servername is on an unknow format: "<<servername<<std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned char buf[65536];
|
||||
|
||||
struct sockaddr_in dest4;struct sockaddr_in6 dest6;
|
||||
if (isIPV4)
|
||||
{
|
||||
dest4.sin_family = AF_INET;
|
||||
dest4.sin_port = htons(53);
|
||||
dest4.sin_addr.s_addr = dns_server_4.s_addr;
|
||||
} else {
|
||||
dest6.sin6_family = AF_INET6;
|
||||
dest6.sin6_port = htons(53);
|
||||
dest6.sin6_flowinfo = 0;
|
||||
dest6.sin6_addr = dns_server_6;
|
||||
dest6.sin6_scope_id = 0;
|
||||
}
|
||||
|
||||
//Set the DNS structure to standard queries
|
||||
struct DNS_HEADER* dns = (struct DNS_HEADER *)&buf;
|
||||
dns->id = static_cast<unsigned short>(htons(getpid())); //Transaction Id
|
||||
//dns flags = 0x0100 Standard Query
|
||||
dns->qr = 0; //Query/Response: Message is a query
|
||||
dns->opcode = 0; //OpCode: Standard query
|
||||
dns->aa = 0; //Authoritative: Server is not an authority for domain
|
||||
dns->tc = 0; //TrunCated: Message is not truncated
|
||||
dns->rd = 1; //Recursion Desired: Do query recursively
|
||||
dns->ra = 0; //Recursion Available: Server cannot do recursive queries
|
||||
dns->z = 0; //Z: reserved
|
||||
dns->ad = 0; //Authentic Data: Answer/authority portion was not authenticated by the server
|
||||
dns->cd = 0; //Checking Disabled: Unacceptable
|
||||
dns->rcode = 0; //Response Code: No error
|
||||
|
||||
dns->q_count = htons(1); //1 Question
|
||||
dns->ans_count = 0; //0 Answer
|
||||
dns->auth_count = 0; //0 Authority RRs
|
||||
dns->add_count = 0; //0 Additional RRs
|
||||
size_t curSendSize = sizeof(struct DNS_HEADER);
|
||||
|
||||
//Point to the query server name portion
|
||||
unsigned char* qname =static_cast<unsigned char*>(&buf[curSendSize]);
|
||||
//First byte is Label Type: https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-10
|
||||
qname[0] = 0x04; //One Label with Normal label lower 6 bits is the length of the label
|
||||
memcpy(&qname[1],hostname.c_str(),strlen(hostname.c_str()));
|
||||
size_t qnameSize = strlen((const char*)qname);
|
||||
// Format Hostname like www.google.com to 3www6google3com
|
||||
{
|
||||
size_t last = qnameSize;
|
||||
for(size_t i = qnameSize-1 ; i > 0 ; i--)
|
||||
if(qname[i]=='.')
|
||||
{
|
||||
qname[i]=last-i-1;
|
||||
last = i;
|
||||
}
|
||||
}
|
||||
curSendSize += qnameSize +1; //With \0 terminator
|
||||
|
||||
//Point to the query constant portion
|
||||
struct QUESTION* qinfo =(struct QUESTION*)&buf[curSendSize];
|
||||
qinfo->qtype = htons(isIPV4 ? DNST_A : DNST_AAAA); //Type: A / AAAA(Host Address)
|
||||
qinfo->qclass = htons(DNSC_IN); //Class: IN
|
||||
curSendSize += sizeof(struct QUESTION);
|
||||
|
||||
#ifdef DEBUG_SPEC_DNS
|
||||
RsDbg()<<__PRETTY_FUNCTION__<< " Sending Packet: " << std::endl << hexDump(buf, curSendSize) << std::endl;
|
||||
#endif
|
||||
int s = isIPV4 ? socket(AF_INET , SOCK_DGRAM , IPPROTO_UDP)
|
||||
: socket(AF_INET6 , SOCK_DGRAM , IPPROTO_UDP) ; //UDP packet for DNS queries
|
||||
ssize_t send_size = sendto(s, (char*)buf, curSendSize, 0
|
||||
,isIPV4 ? (struct sockaddr*)&dest4
|
||||
: (struct sockaddr*)&dest6
|
||||
,isIPV4 ? sizeof(dest4)
|
||||
: sizeof(dest6)
|
||||
);
|
||||
if( send_size < 0)
|
||||
{
|
||||
RsErr()<<__PRETTY_FUNCTION__<<": Send Failed with size = " << send_size << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_SPEC_DNS
|
||||
RsDbg()<<__PRETTY_FUNCTION__<< " Waiting answer..." << std::endl;
|
||||
#endif
|
||||
//****************************************************************************************//
|
||||
//--- Receive the answer ---//
|
||||
//****************************************************************************************//
|
||||
socklen_t dest_size = static_cast<socklen_t>(sizeof dest4);
|
||||
ssize_t rec_size=recvfrom(s,(char*)buf , 65536 , 0 , (struct sockaddr*)&dest4 , &dest_size );
|
||||
if(rec_size <= 0)
|
||||
{
|
||||
RsErr()<<__PRETTY_FUNCTION__<<": Receive Failed"<<std::endl;
|
||||
return false;
|
||||
}
|
||||
#ifdef DEBUG_SPEC_DNS
|
||||
RsDbg()<<__PRETTY_FUNCTION__<< " Received: " << hexDump(buf, rec_size) << std::endl;
|
||||
#endif
|
||||
|
||||
|
||||
if (rec_size< static_cast<ssize_t>(sizeof(struct DNS_HEADER)) )
|
||||
{
|
||||
RsErr()<<__PRETTY_FUNCTION__<<": Request received too small to get DNSHeader."<<std::endl;
|
||||
return false;
|
||||
}
|
||||
#ifdef DEBUG_SPEC_DNS
|
||||
//Point to the header portion
|
||||
dns = (struct DNS_HEADER*) buf;
|
||||
RsDbg()<<__PRETTY_FUNCTION__<<" The response contains : " << std::endl
|
||||
<<ntohs(dns->q_count) << " Questions." << std::endl
|
||||
<<ntohs(dns->ans_count) << " Answers." << std::endl
|
||||
<<ntohs(dns->auth_count) << " Authoritative Servers." << std::endl
|
||||
<<ntohs(dns->add_count) << " Additional records." << std::endl;
|
||||
#endif
|
||||
size_t curRecSize = sizeof(struct DNS_HEADER);
|
||||
|
||||
|
||||
if (rec_size< static_cast<ssize_t>(curRecSize + 1 + sizeof(struct QUESTION)) )
|
||||
{
|
||||
RsErr()<<__PRETTY_FUNCTION__<<": Request received too small to get Question return."<<std::endl;
|
||||
return false;
|
||||
}
|
||||
//Point to the query portion
|
||||
unsigned char* qnameRecv =static_cast<unsigned char*>(&buf[curRecSize]);
|
||||
if (memcmp(qname,qnameRecv,qnameSize + 1 + sizeof(struct QUESTION)) )
|
||||
{
|
||||
RsErr()<<__PRETTY_FUNCTION__<<": Request received different from that sent."<<std::endl;
|
||||
return false;
|
||||
}
|
||||
curRecSize += qnameSize + 1 + sizeof(struct QUESTION);
|
||||
|
||||
if (rec_size< static_cast<ssize_t>(curRecSize + 2) )
|
||||
{
|
||||
RsErr()<<__PRETTY_FUNCTION__<<": Request received too small to get Answer return."<<std::endl;
|
||||
return false;
|
||||
}
|
||||
//Point to the Answer portion
|
||||
unsigned char* reader = &buf[curRecSize];
|
||||
|
||||
size_t rLabelSize=0;
|
||||
if((reader[0]&0xC0) == 0)
|
||||
{
|
||||
//Normal label lower 6 bits is the length of the label
|
||||
rLabelSize=(reader[0]&~(0xC0)*256) + reader[1];
|
||||
}
|
||||
else if ((reader[0]&0xC0) == 0xC0)
|
||||
{
|
||||
//Compressed label the lower 6 bits and the 8 bits from next octet form a pointer to the compression target.
|
||||
//Don't need to read it, maybe the same as in Query
|
||||
rLabelSize=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
RsErr()<<__PRETTY_FUNCTION__<<": Answer received with unmanaged label format."<<std::endl;
|
||||
return false;
|
||||
}
|
||||
curRecSize += 2 + rLabelSize;
|
||||
|
||||
if (rec_size< static_cast<ssize_t>(curRecSize + sizeof(struct RR_DATA)) )
|
||||
{
|
||||
RsErr()<<__PRETTY_FUNCTION__<<": Request received too small to get Data return."<<std::endl;
|
||||
return false;
|
||||
}
|
||||
//Point to the query portion
|
||||
struct RR_DATA* rec_data = (struct RR_DATA *)&buf[curRecSize];
|
||||
if (rec_data->rtype!=qinfo->qtype)
|
||||
{
|
||||
RsErr()<<__PRETTY_FUNCTION__<<": Answer's type received different from query sent."<<std::endl;
|
||||
return false;
|
||||
}
|
||||
if (rec_data->rclass!=qinfo->qclass)
|
||||
{
|
||||
RsErr()<<__PRETTY_FUNCTION__<<": Answer's class received different from query sent."<<std::endl;
|
||||
return false;
|
||||
}
|
||||
curRecSize += sizeof(struct RR_DATA);
|
||||
|
||||
if (rec_size< static_cast<ssize_t>(curRecSize + ntohs(rec_data->data_len)) )
|
||||
{
|
||||
RsErr()<<__PRETTY_FUNCTION__<<": Request received too small to get Full Data return."<<std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
//Retrieve Address
|
||||
if(ntohs(rec_data->data_len)==4)
|
||||
{
|
||||
if (isIPV4)
|
||||
{
|
||||
in_addr ipv4Add;
|
||||
ipv4Add.s_addr=*(in_addr_t*)&buf[curRecSize];
|
||||
#ifdef DEBUG_SPEC_DNS
|
||||
RsDbg()<<__PRETTY_FUNCTION__<< " Retrieve address: " << rs_inet_ntoa(ipv4Add) << std::endl;
|
||||
#endif
|
||||
returned_addr = rs_inet_ntoa(ipv4Add);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if(ntohs(rec_data->data_len)==16)
|
||||
{
|
||||
if (!isIPV4)
|
||||
{
|
||||
in6_addr ipv6Add;
|
||||
ipv6Add =*(in6_addr*)&buf[curRecSize];
|
||||
#ifdef DEBUG_SPEC_DNS
|
||||
RsDbg()<<__PRETTY_FUNCTION__<< " Retrieve address: " << rs_inet_ntoa(ipv6Add) << std::endl;
|
||||
#endif
|
||||
returned_addr = rs_inet_ntoa(ipv6Add);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
RsErr()<<__PRETTY_FUNCTION__<< " Retrieve unmanaged data size=" << ntohs(rec_data->data_len) << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isValidNet(const struct in_addr *addr)
|
||||
{
|
||||
// invalid address.
|
||||
@ -174,3 +485,18 @@ std::string rs_inet_ntoa(struct in_addr in)
|
||||
rs_sprintf(str, "%u.%u.%u.%u", (int) bytes[0], (int) bytes[1], (int) bytes[2], (int) bytes[3]);
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string rs_inet_ntoa(const in6_addr& in)
|
||||
{
|
||||
std::string str;
|
||||
rs_sprintf(str, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
|
||||
(int)in.s6_addr[0] , (int)in.s6_addr[1],
|
||||
(int)in.s6_addr[2] , (int)in.s6_addr[3],
|
||||
(int)in.s6_addr[4] , (int)in.s6_addr[5],
|
||||
(int)in.s6_addr[6] , (int)in.s6_addr[7],
|
||||
(int)in.s6_addr[8] , (int)in.s6_addr[9],
|
||||
(int)in.s6_addr[10], (int)in.s6_addr[11],
|
||||
(int)in.s6_addr[12], (int)in.s6_addr[13],
|
||||
(int)in.s6_addr[14], (int)in.s6_addr[15]);
|
||||
return str;
|
||||
}
|
||||
|
@ -84,11 +84,17 @@ bool isExternalNet(const struct in_addr *addr);
|
||||
// uses a re-entrant version of gethostbyname
|
||||
bool rsGetHostByName(const std::string& hostname, in_addr& returned_addr) ;
|
||||
|
||||
// Get hostName address using specific DNS server
|
||||
// Using it allow to direct ask our Address to IP, so no need to have a DNS (IPv4 or IPv6 ???).
|
||||
// If we ask to a IPv6 DNS Server, it respond for our IPv6 address.
|
||||
bool rsGetHostByNameSpecDNS(const std::string& servername, const std::string& hostname, std::string& returned_addr);
|
||||
|
||||
std::ostream& operator<<(std::ostream& o, const sockaddr_in&);
|
||||
std::ostream& operator<<(std::ostream& o, const sockaddr_storage&);
|
||||
|
||||
/* thread-safe version of inet_ntoa */
|
||||
std::string rs_inet_ntoa(struct in_addr in);
|
||||
std::string rs_inet_ntoa(const in6_addr &in);
|
||||
|
||||
|
||||
/***************************/
|
||||
|
@ -262,6 +262,7 @@ bool sockaddr_storage_setipv6(struct sockaddr_storage &addr, const sockaddr_in6
|
||||
}
|
||||
|
||||
#ifdef WINDOWS_SYS
|
||||
#ifndef InetPtonA
|
||||
int inet_pton(int af, const char *src, void *dst)
|
||||
{
|
||||
sockaddr_storage ss;
|
||||
@ -288,6 +289,7 @@ int inet_pton(int af, const char *src, void *dst)
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
bool sockaddr_storage_inet_pton( sockaddr_storage &addr,
|
||||
const std::string& ipStr )
|
||||
|
@ -719,6 +719,9 @@ behind a firewall or a VPN.</string>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>List of OpenDns servers used.</string>
|
||||
</property>
|
||||
<property name="editTriggers">
|
||||
<set>QAbstractItemView::NoEditTriggers</set>
|
||||
</property>
|
||||
|
Loading…
Reference in New Issue
Block a user