SHARE
TWEET

Untitled

a guest Nov 12th, 2019 70 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <string.h>
  5. #include <stdbool.h>
  6.  
  7. #include <iostream>
  8. #include <string>
  9. #include <vector>
  10. #include <sstream>
  11. #include <regex>
  12.  
  13. #ifdef __WIN32__
  14. #include <winsock2.h>
  15. #include <ws2tcpip.h>
  16. #else
  17. #include <sys/socket.h>
  18. #include <netinet/in.h>
  19. #include <arpa/inet.h>
  20. #endif
  21.  
  22. #define PORT 8080
  23. #define MAXLINE 1024
  24.  
  25.     using namespace std;
  26.  
  27. /*
  28. Spuštění aplikace
  29. Použití: dns [-r] [-x] [-6] -s server [-p port] adresa
  30.  
  31. Pořadí parametrů je libovolné. Popis parametrů:
  32. -r: Požadována rekurze (Recursion Desired = 1), jinak bez rekurze.
  33. -x: Reverzní dotaz místo přímého.
  34. -6: Dotaz typu AAAA místo výchozího A.
  35. -s: IP adresa nebo doménové jméno serveru, kam se má zaslat dotaz.
  36. -p port: Číslo portu, na který se má poslat dotaz, výchozí 53.
  37. adresa: Dotazovaná adresa.
  38. */
  39.  
  40. class DNS
  41. {
  42. public:
  43.     string domainName;
  44.     string IPaddress;
  45.  
  46.     void printname()
  47.     {
  48.         cout << "Domain name is: " << domainName << "\n";
  49.     }
  50.     void printIP()
  51.     {
  52.         cout << "IP address is: " << IPaddress << "\n";
  53.     }
  54. };
  55.  
  56. // GLOBAL VARIABLES
  57. int port = 53;           // Destination port, default value is 53
  58. DNS destinationDNS; // Destination DNS server
  59. bool ipv6 = false;  // Flag IPV4/IPV6
  60. bool reversed = false;
  61. bool recursion = false;
  62. int mySocket;
  63. char buffer[MAXLINE];
  64. string askingFor;
  65. struct sockaddr_in servaddr, cliaddr;
  66.  
  67. int kill(int erNo)
  68. {
  69.     if (erNo == 10)
  70.     {
  71.         fprintf(stderr, "Error: Empty label in the address\n");
  72.     }
  73.     else if (erNo == 11)
  74.     {
  75.         fprintf(stderr, "Error: Label has more than 63 characters\n");
  76.     }
  77.     else if (erNo == 12)
  78.     {
  79.         fprintf(stderr, "Error: Label contains forbidden character\n");
  80.     }
  81.     else if (erNo == 13)
  82.     {
  83.         fprintf(stderr, "Error: Domain name cannot end by dot character\n");
  84.     }
  85.     else if (erNo == 14)
  86.     {
  87.         fprintf(stderr, "Error: Wrong IPv4 format\n");
  88.     }
  89.     else if (erNo == 15)
  90.     {
  91.         fprintf(stderr, "Error: Port must be number\n");
  92.     }
  93.     else if (erNo == 16)
  94.     {
  95.         fprintf(stderr, "Error: No address to be asked for\n");
  96.     }
  97.     else
  98.     {
  99.         fprintf(stderr, "Error: Wrong argument number %d \n", erNo);
  100.     }
  101.     exit(-1);
  102. }
  103.  
  104. bool checkDomainNameSyntax(string probablyDomainName)
  105. {
  106.     /**
  107.      * @brief Function checks whether given string is a domain name.
  108.      * Checks the following rules:
  109.      *  1) Label consists of 1 to 63 characters
  110.      *  2) Full domain name consists of max 253 ASCII characters
  111.      *  3) Domain name is not case-sensitive
  112.      *  
  113.      */
  114.     if (probablyDomainName.back() == '.')
  115.     {
  116.         // Domain name cannot end by dot symbol
  117.         kill(13);
  118.     }
  119.     vector<string> tokens;
  120.     stringstream check1(probablyDomainName);
  121.     string intermediate;
  122.  
  123.     // Split into tokens by dot symbol
  124.     while (getline(check1, intermediate, '.'))
  125.     {
  126.         tokens.push_back(intermediate);
  127.     }
  128.  
  129.     // Looping through the token vector, check each member
  130.     for (int i = 0; i < tokens.size(); i++)
  131.     {
  132.         if (tokens[i].empty())
  133.         {
  134.             //when label is empty
  135.             kill(10);
  136.         }
  137.         else if (tokens[i].size() > 63)
  138.         {
  139.             // when label is too long
  140.             kill(11);
  141.         }
  142.         else if (tokens[i].find_first_not_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890-") != std::string::npos)
  143.         {
  144.             // when label contains forbidden character
  145.             kill(12);
  146.         }
  147.     }
  148.     return true;
  149. }
  150.  
  151. bool checkIPAdressSyntax(string probablyIPAdress)
  152. {
  153.     if (probablyIPAdress.back() == '.')
  154.     {
  155.         // IP address cannot end by dot symbol
  156.         kill(13);
  157.     }
  158.     vector<string> tokens;
  159.     stringstream check1(probablyIPAdress);
  160.     string intermediate;
  161.  
  162.     // Split into tokens by dot symbol
  163.     while (getline(check1, intermediate, '.'))
  164.     {
  165.         tokens.push_back(intermediate);
  166.     }
  167.  
  168.     // Looping through the token vector, check each member
  169.     int IPv4_byte_length, IPv4_byte;
  170.     for (int i = 0; i < tokens.size(); i++)
  171.     {
  172.         IPv4_byte_length = tokens.at(i).length();
  173.         if(IPv4_byte_length > 3){
  174.             return false;
  175.         }else if(tokens[i].find_first_not_of("0123456789") != std::string::npos){
  176.             return false;
  177.         }
  178.         IPv4_byte = stoi(tokens.at(i));
  179.         if( !((IPv4_byte >= 0) && (IPv4_byte <= 255)) ){
  180.             return false;
  181.         }
  182.     std::cout << "Byte " << i << " is: " << tokens.at(i) << IPv4_byte << "\n";
  183.     }
  184.     return true;
  185. }
  186.  
  187. int setDNS(char *probablyServer, int argNo)
  188. {
  189.     /**
  190.      * @brief Function sets the DNS server/IP address. Option is required after -s.
  191.      * @param1 Command line argument after -s option.
  192.      * @param2 Actual position in the array of command line arguments.
  193.      * @return Returns new position in the array of command line arguments.
  194.      */
  195.     int length = strlen(probablyServer);
  196.  
  197.     // converting char* to string variable using std::string::assign
  198.     std::string givenDNS;
  199.     givenDNS.assign(probablyServer, length);
  200.  
  201.     if (checkIPAdressSyntax(givenDNS))
  202.     {
  203.         destinationDNS.IPaddress = givenDNS;
  204.         destinationDNS.printIP();
  205.     }
  206.     else if (checkDomainNameSyntax(givenDNS))
  207.     {
  208.         destinationDNS.domainName = givenDNS;
  209.         destinationDNS.printname();
  210.     }
  211.     argNo++;
  212.     // TODO: nesmí začínat pomlčkou
  213.     return argNo;
  214. }
  215.  
  216. int setPort(char *probablyPort, int argNo)
  217. {
  218.     /**
  219.     * @brief Function sets the destination port number. Default 53, if there is no integer given.
  220.     * @param1 Command line argument after -p option.
  221.     * @param2 Actual position in the array of command line arguments.
  222.     * @return Returns new position in the array of command line arguments. Only increment if port number was given.
  223.     */
  224.     int length = strlen(probablyPort);
  225.     for (int i = 0; i < length; i++)
  226.     {
  227.         if (!isdigit(probablyPort[i]))
  228.         {
  229.             // Argument contains a non-digit character (port number was not specified) -> set default value 53
  230.             kill(15);
  231.         }
  232.     }
  233.     port = atoi(probablyPort);
  234.     argNo++;
  235.     return argNo;
  236. }
  237.  
  238. string changeAddressFormat(string askingFor)
  239. {
  240.     /**
  241.      * @brief Function changed host address format (www.seznam.cz to 3www6seznam2cz0)
  242.      * @param1 Hostname given as argument to be transformed
  243.      * @return Transformed string
  244.      */
  245.     istringstream iss(askingFor);
  246.     vector<string> tokens;
  247.     string token;
  248.     string temporaryQname;
  249.     int tokenLenght;
  250.     string wwwPrefix("www");
  251.  
  252.     auto it = std::mismatch(wwwPrefix.begin(), wwwPrefix.end(), askingFor.begin());
  253.     /*if( !(it.first == wwwPrefix.end()) ){
  254.         // if 'www' is not a prefix of the given host name -> add
  255.         // 3www to the beggining of temporaryQname
  256.         temporaryQname.append("3wwww");
  257.     }*/ TODO:
  258.  
  259.     // split by dot symbol into a string vector
  260.     while (std::getline(iss, token, '.'))
  261.     {
  262.         if (!token.empty()){
  263.             tokens.push_back(token);
  264.         }
  265.     }
  266.  
  267.     for (int i = 0; i < (tokens.capacity()-1); i++)
  268.     {
  269.         if(!tokens[i].empty()){
  270.             tokenLenght = tokens[i].length();
  271.             temporaryQname.append(std::to_string(tokenLenght));
  272.             temporaryQname.append(tokens[i]);
  273.         }
  274.     }
  275.     temporaryQname.append("0"); // has to end by 0
  276.    
  277.     return temporaryQname;
  278. }
  279.  
  280. struct DNS_HEADER
  281. {
  282.     unsigned short id;         // identification number
  283.     unsigned char rd : 1;      // recursion desired
  284.     unsigned char tc : 1;      // truncated message
  285.     unsigned char aa : 1;      // authoritive answer
  286.     unsigned char opcode : 4;  // purpose of message
  287.     unsigned char qr : 1;      // query/response flag
  288.     unsigned char rcode : 4;   // response code
  289.     unsigned char cd : 1;      // checking disabled
  290.     unsigned char ad : 1;      // authenticated data
  291.     unsigned char z : 1;       // its z! reserved
  292.     unsigned char ra : 1;      // recursion available
  293.     unsigned short q_count;    // number of question entries
  294.     unsigned short ans_count;  // number of answer entries
  295.     unsigned short auth_count; // number of authority entries
  296.     unsigned short add_count;  // number of resource entries
  297. };
  298.  
  299. struct QUESTION
  300. {
  301.     unsigned short qtype;
  302.     unsigned short qclass;
  303. };
  304.  
  305. struct R_DATA
  306. {
  307.     unsigned short type;
  308.     unsigned short _class;
  309.     unsigned int ttl;
  310.     unsigned short data_len;
  311. };
  312.  
  313. struct RES_RECORD
  314. {
  315.     unsigned char *name;
  316.     struct R_DATA *resource;
  317.     unsigned char *rdata;
  318. };
  319.  
  320. typedef struct
  321. {
  322.     unsigned char *name;
  323.     struct QUESTION *ques;
  324. } QUERY;
  325.  
  326. int main(int argc, char *argv[])
  327. {
  328.     int option;
  329.     int i = 0;
  330.    
  331.     // duplicate cmd line arguments cause getopt changes order
  332.     vector<string> argVector;
  333.     for(int j = 1; j < argc; j++){
  334.         argVector.push_back(argv[j]);
  335.     }
  336.     /*for (int i = 0; i < argVector.size(); i++)
  337.     {
  338.         cout << argVector[i] << "\n";
  339.     }*/
  340.  
  341.     //printf("Args: %s %s %s %s %s %s %s \n", argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7]);
  342.     while ((option = getopt(argc, argv, "rx6s:p::")) != -1)
  343.     {
  344.         i++;
  345.         switch (option)
  346.         {
  347.         case 'r':
  348.             //printf("got %d) %c \n", i, option);
  349.             recursion = true;
  350.             break;
  351.         case 'x':
  352.             //printf("got %d) %c \n", i, option);
  353.             reversed = true;
  354.             break;
  355.         case '6':
  356.             //printf("got %d) %c \n", i, option);
  357.             ipv6 = true;
  358.             break;
  359.         case 's':
  360.             // Option -s is followed by IP address or domain name of the server
  361.             //printf("got %d) %c \n", i, option);
  362.             for (int j = 0; j < argc; ++j)
  363.             {
  364.                 if (strcmp(argv[j], "-s") == 0)
  365.                 {
  366.                     //cout << argv[j] << "\n";
  367.                     i = setDNS(argv[j + 1], j);
  368.                 }
  369.             }
  370.             break;
  371.         case 'p':
  372.             // Option -p is followed by port number otherwise its set to 53
  373.             //printf("got %d) %c \n", i, option);
  374.             for (int j = 0; j < argc; ++j)
  375.             {
  376.                 if (strcmp(argv[j], "-p") == 0)
  377.                 {
  378.                     //cout << argv[j] << "\n";
  379.                     i = setPort(argv[j + 1], j);
  380.                 }
  381.             }
  382.             //i = setPort(argv[i + 1], i);
  383.             break;
  384.         case ':':
  385.             fprintf(stderr, "Option requires a value\n");
  386.             kill(i);
  387.             break;
  388.         case '?':
  389.             if (strcmp(argv[i], "-s") == 0)
  390.             {
  391.                 fprintf(stderr, "Option  -s requires a value\n");
  392.                 exit(-1);
  393.             }
  394.             else
  395.             {
  396.                 kill(i);
  397.             }
  398.             break;
  399.         default:
  400.             //printf("got %d) uknown: %c \n", i, option);
  401.             //kill(i);
  402.  
  403.             break;
  404.         }
  405.     }
  406.  
  407.     // Finding requested address to ask for in the command line arguments
  408.     for (int i = 0; i < argVector.size(); i++)
  409.     {
  410.         regex flagFollowed("^-[sp]$");
  411.         regex flagSingle("^-[6rx]$");
  412.         if (regex_match(argVector[i], flagFollowed)) // matches flag with attribute
  413.         {
  414.             i++;
  415.         }
  416.         else if (regex_match(argVector[i], flagSingle)) // matches flag without attribute
  417.         {
  418.             ;
  419.         }
  420.         else
  421.         {
  422.             askingFor = argVector[i];
  423.         }
  424.     }
  425.  
  426.     // Exit when no requested address found or
  427.     if (askingFor.empty())
  428.     {
  429.         kill(16);
  430.     }
  431.  
  432.     // Cheching requested domain name syntax
  433.     checkDomainNameSyntax(askingFor);
  434.  
  435.     printf("!!!RECAP!!!\n");
  436.     printf("Port var: %d\n", port);
  437.     cout << "Asking for: " << askingFor << "\n";
  438.     printf("IPV6: %d\n", (bool)ipv6);
  439.     printf("Reverse: %d\n", (bool)reversed);
  440.     printf("Recursion: %d\n", (bool)recursion);
  441.  
  442.     // Creating socket file descriptor
  443.  
  444. #if defined(WIN32) // TODO:
  445.     WSADATA Data;
  446.     WSAStartup(MAKEWORD(2, 2), &Data); // 2.2 version
  447. #endif
  448.  
  449.     if ((mySocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
  450.     {
  451.         printf("\nSOCKET NA PICU!\n");
  452.         perror("socket creation failed");
  453.         exit(EXIT_FAILURE);
  454.     }
  455.     else
  456.     {
  457.         printf("\nDOBREJ SOCKET PANE!\n");
  458.     }
  459.  
  460.     struct RES_RECORD answers[20], auth[20], addit[20]; //the replies from the DNS server
  461.     struct sockaddr_in servaddr;
  462.  
  463.     unsigned char buf[65536], *qname, *reader;
  464.     struct DNS_HEADER *dns = NULL;
  465.     struct QUESTION *qinfo = NULL;
  466.     dns = (struct DNS_HEADER *)&buf;
  467.  
  468.     memset(&servaddr, 0, sizeof(servaddr));
  469.     // Filling server information
  470.     servaddr.sin_family = AF_INET;
  471.     servaddr.sin_port = htons(53);
  472.     servaddr.sin_addr.s_addr = inet_addr("8.8.8.8");
  473.  
  474.     int pid = GetCurrentProcessId();
  475.  
  476.     dns -> id = (unsigned short) htons(pid);
  477.     dns -> rd = recursion; // 1 = "Do query recursively"
  478.     dns -> tc = 0; // 0 = "Message is not truncated"
  479.     dns -> aa = 0; // authoritative answer = false(0)
  480.     dns -> opcode = 0; // 0 = "Standard query"
  481.     dns -> qr = 0;       // 0 = "Message is a query(0)", response(1)
  482.     dns -> rcode = 0; // response code (0=ok, 1=format error, 2=server failure, 3=domain doesnt exist)
  483.     dns -> cd = 0; // chesking disabled
  484.     dns -> ad = 0; // 0 = "Non-authenticated data: Unnacceptable"
  485.     dns -> z = 0; // reserved
  486.     dns -> ra = 0; // recursion available = false
  487.     dns -> q_count = htons(1); // number of questions
  488.  
  489.     dns -> ans_count = 0; // number of answers
  490.     dns -> auth_count = 0; // number of authority entries
  491.     dns -> add_count = 0; // number of resource entries
  492.  
  493.     qname = (unsigned char *)&buf[sizeof(struct DNS_HEADER)];
  494.     string addrDNSFormat = changeAddressFormat(askingFor);
  495.  
  496.     // Converting string to char array
  497.     int length = addrDNSFormat.length();
  498.     char addrChanged[length + 1];
  499.     strcpy(addrChanged, addrDNSFormat.c_str());
  500.  
  501.     // filling the hostname
  502.     qname = (unsigned char *)addrChanged;
  503.     cout << askingFor;
  504.     printf("\nqname: ");
  505.     for (int i = 0; i < strlen((char *)qname); i++)
  506.     {
  507.         printf("%c", qname[i]);
  508.     }
  509.     printf("\n");
  510.     printf("addrChanged: ");
  511.     for (int i = 0; i < strlen((char*)addrChanged); i++)
  512.     {
  513.         printf("%c", addrChanged[i]);
  514.     }
  515.     printf("\n");
  516.  
  517.     qinfo = (struct QUESTION *)&buf[sizeof(struct DNS_HEADER) + (strlen((const char *)qname) + 1)];
  518.  
  519.     qinfo->qtype = htons(1);  // requesting ipv4
  520.     qinfo->qclass = htons(1); // stands for IN
  521.  
  522.     int n, len;
  523.  
  524.     //int bz = sendto(mySocket, hello, strlen(hello), 0, (const struct sockaddr *)&servaddr, sizeof(servaddr));
  525.     //printf("Leti paket neco si prej! %d\n", bz);
  526.  
  527.     int er = sendto(mySocket, (char *)buf, sizeof(struct DNS_HEADER) + (strlen((const char *)qname) + 1) + sizeof(struct QUESTION), 0, (sockaddr *)&servaddr, sizeof(servaddr));
  528.     printf("Leti paket neco si prej! %d\n", er);
  529. /*
  530.     int i = sizeof(dest);
  531.     recvfrom(mySocket, (char *)buf, 65536, 0, (sockaddr *)&dest, &i);
  532. */
  533.  
  534.     /*n = recvfrom(mySocket, (char *)buffer, MAXLINE, 1, (struct sockaddr *)&servaddr, &len);
  535.     buffer[n] = '\0';
  536.     printf("Server : %s\n", buffer);*/
  537.  
  538.     close(mySocket);
  539.  
  540. #if defined(WIN32) //TODO:
  541.     WSACleanup();
  542. #endif
  543.     return 0;
  544. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top