Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /******************************************************
- Laboratoire #3 : Programmation d'un serveur DNS
- Cours : LOG610
- Session : Hiver 2007
- Groupe : 01
- Projet : Laboratoire #3
- �tudiant(e)(s) : Maxime Bouchard
- Code(s) perm. : BOUM24028309
- Professeur : Michel Lavoie
- Nom du fichier : UDPReceiver.java
- Date cr�e : 2007-03-10
- Date dern. modif. X
- *******************************************************/
- import java.net.DatagramPacket;
- import java.net.DatagramSocket;
- import java.net.InetAddress;
- import java.net.InetSocketAddress;
- import java.nio.ByteBuffer;
- /**
- * Cette classe permet la r�ception d'un paquet UDP sur le port de r�ception
- * UDP/DNS. Elle analyse le paquet et extrait le hostname
- *
- * Il s'agit d'un Thread qui �coute en permanance
- * pour ne pas affecter le d�roulement du programme
- * @author Max
- *
- */
- public class UDPReceiver extends Thread {
- /**
- * Les champs d'un Packet UDP
- * --------------------------
- * En-t�te (12 octects)
- * Question : l'adresse demand�
- * R�ponse : l'adresse IP
- * Autorit� : info sur le serveur d'autorit�
- * Additionnel : information suppl�mentaire
- */
- /**
- * D�finition de l'En-t�te d'un Packet UDP
- * ---------------------------------------
- * Identifiant Param�tres
- * QDcount Ancount
- * NScount ARcount
- *
- *� identifiant est un entier permettant d�identifier la requete.
- *� parametres contient les champs suivant :
- * � QR (1 bit) : indique si le message est une question (0) ou une reponse (1).
- * � OPCODE (4 bits) : type de la requete (0000 pour une requete simple).
- * � AA (1 bit) : le serveur qui a fourni la reponse a-t�il autorite sur le domaine?
- * � TC (1 bit) : indique si le message est tronque.
- * � RD (1 bit) : demande d�une requete recursive.
- * � RA (1 bit) : indique que le serveur peut faire une demande recursive.
- * � UNUSED, AD, CD (1 bit chacun) : non utilises.
- * � RCODE (4 bits) : code de retour. 0 : OK, 1 : erreur sur le format de la requete, 2: probleme du serveur,
- * 3 : nom de domaine non trouve (valide seulement si AA), 4 : requete non supportee, 5 : le serveur refuse
- * de repondre (raisons de s�ecurite ou autres).
- * � QDCount : nombre de questions.
- * � ANCount, NSCount, ARCount : nombre d�entrees dans les champs �Reponse�, �Autorite�, �Additionnel�.
- */
- /**
- * Les champs Reponse, Autorite, Additionnel sont tous representes de la meme maniere :
- *
- * � Nom (16 bits) : Pour eviter de recopier la totalite du nom, on utilise des offsets. Par exemple si ce champ
- * vaut C0 0C, cela signifie qu�on a un offset (C0) de 12 (0C) octets. C�est-a-dire que le nom en clair se trouve
- * au 12eme octet du message.
- * � Type (16 bits) : idem que pour le champ Question.
- * � Class (16 bits) : idem que pour le champ Question.
- * � TTL (32 bits) : dur�ee de vie de l�entr�ee.
- * � RDLength (16 bits): nombre d�octets de la zone RDData.
- * � RDData (RDLength octets) : reponse
- */
- private ByteBuffer bb = null;
- protected final static int BUF_SIZE = 1024;
- protected String SERVER_DNS = null;
- protected int port = 53; // port de r�ception
- private String DomainName = "none";
- private String DNSFile = null;
- private String adrIP = null;
- private boolean RedirectionSeulement = false;
- private String adresseIP = "";
- private String adresseIPClient;
- private int portClient;
- public void setport(int p) {
- this.port = p;
- }
- public void setRedirectionSeulement(boolean b){
- this.RedirectionSeulement = b;
- }
- public String gethostNameFromPacket(){
- return DomainName;
- }
- public String getAdrIP(){
- return adrIP;
- }
- private void setAdrIP(String ip){
- adrIP = ip;
- }
- public void sethostNameFromPacket(String hostname){
- this.DomainName = hostname;
- }
- public String getSERVER_DNS(){
- return SERVER_DNS;
- }
- public void setSERVER_DNS(String server_dns){
- this.SERVER_DNS = server_dns;
- }
- public void UDPReceiver(String SERVER_DNS,int Port) {
- this.SERVER_DNS = SERVER_DNS;
- this.port = Port;
- }
- public void setDNSFile(String filename){
- DNSFile = filename;
- }
- private void findQueryDomainName() {
- //*Lecture du Query Domain name, a partir du 13 byte
- bb.position(12);
- byte[] byteOff = new byte[1];
- bb.get(byteOff);
- int offset = byteOff[0];
- //*Sauvegarde du Query Domain name
- this.DomainName = "";
- while(offset != 0) {
- byte[] section = new byte[offset];
- bb.get(section);
- DomainName += "." + new String(section);
- bb.get(byteOff);
- offset = byteOff[0];
- }
- DomainName = DomainName.replaceFirst(".", "");
- }
- public void run(){
- try{
- //*Creation d'un socket UDP
- DatagramSocket udpSocket = new DatagramSocket(port);
- //*Boucle infinie de recpetion
- while(true){
- byte[ ] data = new byte[BUF_SIZE];
- DatagramPacket packet = new DatagramPacket(data, data.length);
- //*Reception d'un paquet UDP via le socket
- udpSocket.receive(packet);
- data = packet.getData();
- //*Creation d'un ByteBuffer pour manipuler les bytes du paquet
- bb = ByteBuffer.wrap(data);
- //*Lecture et sauvegarde des deux premier bytes, qui specifie l'identifiant
- int id = bb.getShort();
- //*Lecture et sauvegarde du huitieme byte, qui specifie le nombre de reponse dans le message
- bb.position(7);
- byte[] byteRep = new byte[1];
- bb.get(byteRep);
- int rep = byteRep[0];
- //*Dans le cas d'une reponse
- if(rep == 1) {
- //*Trouve le nom de domaine
- findQueryDomainName();
- //*Passe par dessus Query Type et Query Class
- //*Passe par dessus les premiers champs du ressource record pour arriver au ressource data
- //*qui contient l'adresse IP associe au hostname (dans le fond saut de 16 bytes)
- bb.position(bb.position() + 16);
- //*Capture de l'adresse IP
- this.adresseIP = "";
- byte[] byteIP = new byte[1];
- for(int i=0; i < 4; i++) {
- bb.get(byteIP);
- int section = byteIP[0];
- if(section < 0)
- adresseIP += "." + (section + 256);
- else
- adresseIP += "." + section;
- }
- adresseIP = adresseIP.replaceFirst(".", "");
- //*Ajouter la correspondance dans le fichier seulement si une seule
- //*reponse dans le message DNS (cette apllication ne traite que ce cas)
- AnswerRecorder answerRecorder = new AnswerRecorder(DNSFile);
- answerRecorder.StartRecord(DomainName, adresseIP);
- //*Faire parvenir le paquet reponse au demandeur original, ayant emis une requete
- //*avec cet identifiant
- UDPAnswerPacketCreator udpResponse = new UDPAnswerPacketCreator();
- packet.setAddress(InetAddress.getByName(adresseIPClient));
- packet.setPort(portClient);
- packet.setData(udpResponse.CreateAnswerPacket(data, adresseIP));
- udpSocket.send(packet);
- //*Dans le cas d'une requete
- } else if (rep == 0) {
- //*Trouve le nom de domaine
- findQueryDomainName();
- //*Sauvegarde de l'adresse, du port et de l'identifiant de la requete
- this.adresseIPClient = packet.getAddress().getHostAddress();
- this.portClient = packet.getPort();
- //*Si le mode est redirection seulement
- if(RedirectionSeulement) {
- //*Rediriger le paquet vers le serveur DNS
- packet.setSocketAddress(new InetSocketAddress(SERVER_DNS, port));
- udpSocket.send(packet);
- //*Sinon
- } else {
- //*Rechercher l'adresse IP associe au Query Domain name dans le fichier de
- //*correspondance de ce serveur
- QueryFinder qFinder = new QueryFinder(DNSFile);
- String adressDomaine = qFinder.StartResearch(DomainName);
- //*Si la correspondance n'est pas trouvee
- if("none".equals(adressDomaine)){
- //*Rediriger le paquet vers le serveur DNS
- packet.setSocketAddress(new InetSocketAddress(SERVER_DNS, port));
- udpSocket.send(packet);
- //*Sinon
- } else {
- //*Creer le paquet de reponse a l'aide du UDPAnswerPaquetCreator
- UDPAnswerPacketCreator udpResponse = new UDPAnswerPacketCreator();
- packet.setData(udpResponse.CreateAnswerPacket(data, adressDomaine));
- //*Placer ce paquet dans le socket
- //*Envoyer le paquet
- udpSocket.send(packet);
- }
- }
- }
- }
- }catch(Exception e){
- System.err.println("Probl�me � l'ex�cution :");
- e.printStackTrace(System.err);
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement