Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <string.h>
- #include <stdbool.h>
- #include <iostream>
- #include <string>
- #include <vector>
- #include <sstream>
- #include <regex>
- #ifdef __WIN32__
- #include <winsock2.h>
- #include <ws2tcpip.h>
- #else
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #endif
- #define PORT 8080
- #define MAXLINE 1024
- using namespace std;
- /*
- Spuštění aplikace
- Použití: dns [-r] [-x] [-6] -s server [-p port] adresa
- Pořadí parametrů je libovolné. Popis parametrů:
- -r: Požadována rekurze (Recursion Desired = 1), jinak bez rekurze.
- -x: Reverzní dotaz místo přímého.
- -6: Dotaz typu AAAA místo výchozího A.
- -s: IP adresa nebo doménové jméno serveru, kam se má zaslat dotaz.
- -p port: Číslo portu, na který se má poslat dotaz, výchozí 53.
- adresa: Dotazovaná adresa.
- */
- class DNS
- {
- public:
- string domainName;
- string IPaddress;
- void printname()
- {
- cout << "Domain name is: " << domainName << "\n";
- }
- void printIP()
- {
- cout << "IP address is: " << IPaddress << "\n";
- }
- };
- // GLOBAL VARIABLES
- int port = 53; // Destination port, default value is 53
- DNS destinationDNS; // Destination DNS server
- bool ipv6 = false; // Flag IPV4/IPV6
- bool reversed = false;
- bool recursion = false;
- int mySocket;
- char buffer[MAXLINE];
- string askingFor;
- struct sockaddr_in servaddr, cliaddr;
- int kill(int erNo)
- {
- if (erNo == 10)
- {
- fprintf(stderr, "Error: Empty label in the address\n");
- }
- else if (erNo == 11)
- {
- fprintf(stderr, "Error: Label has more than 63 characters\n");
- }
- else if (erNo == 12)
- {
- fprintf(stderr, "Error: Label contains forbidden character\n");
- }
- else if (erNo == 13)
- {
- fprintf(stderr, "Error: Domain name cannot end by dot character\n");
- }
- else if (erNo == 14)
- {
- fprintf(stderr, "Error: Wrong IPv4 format\n");
- }
- else if (erNo == 15)
- {
- fprintf(stderr, "Error: Port must be number\n");
- }
- else if (erNo == 16)
- {
- fprintf(stderr, "Error: No address to be asked for\n");
- }
- else
- {
- fprintf(stderr, "Error: Wrong argument number %d \n", erNo);
- }
- exit(-1);
- }
- bool checkDomainNameSyntax(string probablyDomainName)
- {
- /**
- * @brief Function checks whether given string is a domain name.
- * Checks the following rules:
- * 1) Label consists of 1 to 63 characters
- * 2) Full domain name consists of max 253 ASCII characters
- * 3) Domain name is not case-sensitive
- *
- */
- if (probablyDomainName.back() == '.')
- {
- // Domain name cannot end by dot symbol
- kill(13);
- }
- vector<string> tokens;
- stringstream check1(probablyDomainName);
- string intermediate;
- // Split into tokens by dot symbol
- while (getline(check1, intermediate, '.'))
- {
- tokens.push_back(intermediate);
- }
- // Looping through the token vector, check each member
- for (int i = 0; i < tokens.size(); i++)
- {
- if (tokens[i].empty())
- {
- //when label is empty
- kill(10);
- }
- else if (tokens[i].size() > 63)
- {
- // when label is too long
- kill(11);
- }
- else if (tokens[i].find_first_not_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890-") != std::string::npos)
- {
- // when label contains forbidden character
- kill(12);
- }
- }
- return true;
- }
- bool checkIPAdressSyntax(string probablyIPAdress)
- {
- if (probablyIPAdress.back() == '.')
- {
- // IP address cannot end by dot symbol
- kill(13);
- }
- vector<string> tokens;
- stringstream check1(probablyIPAdress);
- string intermediate;
- // Split into tokens by dot symbol
- while (getline(check1, intermediate, '.'))
- {
- tokens.push_back(intermediate);
- }
- // Looping through the token vector, check each member
- int IPv4_byte_length, IPv4_byte;
- for (int i = 0; i < tokens.size(); i++)
- {
- IPv4_byte_length = tokens.at(i).length();
- if(IPv4_byte_length > 3){
- return false;
- }else if(tokens[i].find_first_not_of("0123456789") != std::string::npos){
- return false;
- }
- IPv4_byte = stoi(tokens.at(i));
- if( !((IPv4_byte >= 0) && (IPv4_byte <= 255)) ){
- return false;
- }
- std::cout << "Byte " << i << " is: " << tokens.at(i) << IPv4_byte << "\n";
- }
- return true;
- }
- int setDNS(char *probablyServer, int argNo)
- {
- /**
- * @brief Function sets the DNS server/IP address. Option is required after -s.
- * @param1 Command line argument after -s option.
- * @param2 Actual position in the array of command line arguments.
- * @return Returns new position in the array of command line arguments.
- */
- int length = strlen(probablyServer);
- // converting char* to string variable using std::string::assign
- std::string givenDNS;
- givenDNS.assign(probablyServer, length);
- if (checkIPAdressSyntax(givenDNS))
- {
- destinationDNS.IPaddress = givenDNS;
- destinationDNS.printIP();
- }
- else if (checkDomainNameSyntax(givenDNS))
- {
- destinationDNS.domainName = givenDNS;
- destinationDNS.printname();
- }
- argNo++;
- // TODO: nesmí začínat pomlčkou
- return argNo;
- }
- int setPort(char *probablyPort, int argNo)
- {
- /**
- * @brief Function sets the destination port number. Default 53, if there is no integer given.
- * @param1 Command line argument after -p option.
- * @param2 Actual position in the array of command line arguments.
- * @return Returns new position in the array of command line arguments. Only increment if port number was given.
- */
- int length = strlen(probablyPort);
- for (int i = 0; i < length; i++)
- {
- if (!isdigit(probablyPort[i]))
- {
- // Argument contains a non-digit character (port number was not specified) -> set default value 53
- kill(15);
- }
- }
- port = atoi(probablyPort);
- argNo++;
- return argNo;
- }
- string changeAddressFormat(string askingFor)
- {
- /**
- * @brief Function changed host address format (www.seznam.cz to 3www6seznam2cz0)
- * @param1 Hostname given as argument to be transformed
- * @return Transformed string
- */
- istringstream iss(askingFor);
- vector<string> tokens;
- string token;
- string temporaryQname;
- int tokenLenght;
- string wwwPrefix("www");
- auto it = std::mismatch(wwwPrefix.begin(), wwwPrefix.end(), askingFor.begin());
- /*if( !(it.first == wwwPrefix.end()) ){
- // if 'www' is not a prefix of the given host name -> add
- // 3www to the beggining of temporaryQname
- temporaryQname.append("3wwww");
- }*/ TODO:
- // split by dot symbol into a string vector
- while (std::getline(iss, token, '.'))
- {
- if (!token.empty()){
- tokens.push_back(token);
- }
- }
- for (int i = 0; i < (tokens.capacity()-1); i++)
- {
- if(!tokens[i].empty()){
- tokenLenght = tokens[i].length();
- temporaryQname.append(std::to_string(tokenLenght));
- temporaryQname.append(tokens[i]);
- }
- }
- temporaryQname.append("0"); // has to end by 0
- return temporaryQname;
- }
- struct 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
- };
- struct QUESTION
- {
- unsigned short qtype;
- unsigned short qclass;
- };
- struct R_DATA
- {
- unsigned short type;
- unsigned short _class;
- unsigned int ttl;
- unsigned short data_len;
- };
- struct RES_RECORD
- {
- unsigned char *name;
- struct R_DATA *resource;
- unsigned char *rdata;
- };
- typedef struct
- {
- unsigned char *name;
- struct QUESTION *ques;
- } QUERY;
- int main(int argc, char *argv[])
- {
- int option;
- int i = 0;
- // duplicate cmd line arguments cause getopt changes order
- vector<string> argVector;
- for(int j = 1; j < argc; j++){
- argVector.push_back(argv[j]);
- }
- /*for (int i = 0; i < argVector.size(); i++)
- {
- cout << argVector[i] << "\n";
- }*/
- //printf("Args: %s %s %s %s %s %s %s \n", argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7]);
- while ((option = getopt(argc, argv, "rx6s:p::")) != -1)
- {
- i++;
- switch (option)
- {
- case 'r':
- //printf("got %d) %c \n", i, option);
- recursion = true;
- break;
- case 'x':
- //printf("got %d) %c \n", i, option);
- reversed = true;
- break;
- case '6':
- //printf("got %d) %c \n", i, option);
- ipv6 = true;
- break;
- case 's':
- // Option -s is followed by IP address or domain name of the server
- //printf("got %d) %c \n", i, option);
- for (int j = 0; j < argc; ++j)
- {
- if (strcmp(argv[j], "-s") == 0)
- {
- //cout << argv[j] << "\n";
- i = setDNS(argv[j + 1], j);
- }
- }
- break;
- case 'p':
- // Option -p is followed by port number otherwise its set to 53
- //printf("got %d) %c \n", i, option);
- for (int j = 0; j < argc; ++j)
- {
- if (strcmp(argv[j], "-p") == 0)
- {
- //cout << argv[j] << "\n";
- i = setPort(argv[j + 1], j);
- }
- }
- //i = setPort(argv[i + 1], i);
- break;
- case ':':
- fprintf(stderr, "Option requires a value\n");
- kill(i);
- break;
- case '?':
- if (strcmp(argv[i], "-s") == 0)
- {
- fprintf(stderr, "Option -s requires a value\n");
- exit(-1);
- }
- else
- {
- kill(i);
- }
- break;
- default:
- //printf("got %d) uknown: %c \n", i, option);
- //kill(i);
- break;
- }
- }
- // Finding requested address to ask for in the command line arguments
- for (int i = 0; i < argVector.size(); i++)
- {
- regex flagFollowed("^-[sp]$");
- regex flagSingle("^-[6rx]$");
- if (regex_match(argVector[i], flagFollowed)) // matches flag with attribute
- {
- i++;
- }
- else if (regex_match(argVector[i], flagSingle)) // matches flag without attribute
- {
- ;
- }
- else
- {
- askingFor = argVector[i];
- }
- }
- // Exit when no requested address found or
- if (askingFor.empty())
- {
- kill(16);
- }
- // Cheching requested domain name syntax
- checkDomainNameSyntax(askingFor);
- printf("!!!RECAP!!!\n");
- printf("Port var: %d\n", port);
- cout << "Asking for: " << askingFor << "\n";
- printf("IPV6: %d\n", (bool)ipv6);
- printf("Reverse: %d\n", (bool)reversed);
- printf("Recursion: %d\n", (bool)recursion);
- // Creating socket file descriptor
- #if defined(WIN32) // TODO:
- WSADATA Data;
- WSAStartup(MAKEWORD(2, 2), &Data); // 2.2 version
- #endif
- if ((mySocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
- {
- printf("\nSOCKET NA PICU!\n");
- perror("socket creation failed");
- exit(EXIT_FAILURE);
- }
- else
- {
- printf("\nDOBREJ SOCKET PANE!\n");
- }
- struct RES_RECORD answers[20], auth[20], addit[20]; //the replies from the DNS server
- struct sockaddr_in servaddr;
- unsigned char buf[65536], *qname, *reader;
- struct DNS_HEADER *dns = NULL;
- struct QUESTION *qinfo = NULL;
- dns = (struct DNS_HEADER *)&buf;
- memset(&servaddr, 0, sizeof(servaddr));
- // Filling server information
- servaddr.sin_family = AF_INET;
- servaddr.sin_port = htons(port);
- servaddr.sin_addr.s_addr = inet_addr("8.8.8.8");
- int pid = GetCurrentProcessId();
- dns -> id = (unsigned short) htons(pid);
- dns -> rd = recursion; // 1 = "Do query recursively"
- dns -> tc = 0; // 0 = "Message is not truncated"
- dns -> aa = 0; // authoritative answer = false(0)
- dns -> opcode = 0; // 0 = "Standard query"
- dns -> qr = 0; // 0 = "Message is a query(0)", response(1)
- dns -> rcode = 0; // response code (0=ok, 1=format error, 2=server failure, 3=domain doesnt exist)
- dns -> cd = 0; // chesking disabled
- dns -> ad = 0; // 0 = "Non-authenticated data: Unnacceptable"
- dns -> z = 0; // reserved
- dns -> ra = 0; // recursion available = false
- dns -> q_count = htons(1); // number of questions
- dns -> ans_count = 0; // number of answers
- dns -> auth_count = 0; // number of authority entries
- dns -> add_count = 0; // number of resource entries
- qname = (unsigned char *)&buf[sizeof(struct DNS_HEADER)+sizeof(struct QUESTION)];
- string addrDNSFormat = changeAddressFormat(askingFor);
- // Converting string to char array
- int length = addrDNSFormat.length();
- char addrChanged[length + 1];
- strcpy(addrChanged, addrDNSFormat.c_str());
- // filling the hostname
- //qname = (unsigned char *)addrChanged;
- /*unsigned char ch = 'a';
- unsigned char h = 'g';
- *qname = ch;
- *qname++ = h;*/
- for (int i = 0; i < 43; i++) //TODO:
- {
- *qname++;
- }
- for (int j = 0; j < 16; j++)
- {
- *qname = addrChanged[j];
- printf("TU: %c", addrChanged[j]);
- *qname++;
- }
- *qname++ = '\0';
- cout << askingFor;
- printf("\nqname: ");
- for (int i = 0; i < strlen((char *)qname); i++)
- {
- printf("%c", qname[i]);
- }
- printf("\n");
- printf("addrChanged: ");
- for (int i = 0; i < strlen((char*)addrChanged); i++)
- {
- printf("%c", addrChanged[i]);
- }
- printf("\n");
- qinfo = (struct QUESTION *)&buf[sizeof(struct DNS_HEADER) + (strlen((const char *)qname) + 1)];
- qinfo->qtype = htons(1); // requesting ipv4
- qinfo->qclass = htons(1); // stands for IN
- int n, len;
- //int bz = sendto(mySocket, hello, strlen(hello), 0, (const struct sockaddr *)&servaddr, sizeof(servaddr));
- //printf("Leti paket neco si prej! %d\n", bz);
- int er = sendto(mySocket, (char *)buf, sizeof(struct DNS_HEADER) + (strlen((const char *)qname) + 1) + sizeof(struct QUESTION), 0, (sockaddr *)&servaddr, sizeof(servaddr));
- printf("Leti paket neco si prej! %d\n", er);
- /*
- int i = sizeof(dest);
- recvfrom(mySocket, (char *)buf, 65536, 0, (sockaddr *)&dest, &i);
- */
- /*n = recvfrom(mySocket, (char *)buffer, MAXLINE, 1, (struct sockaddr *)&servaddr, &len);
- buffer[n] = '\0';
- printf("Server : %s\n", buffer);*/
- close(mySocket);
- #if defined(WIN32) //TODO:
- WSACleanup();
- #endif
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement