/* ** This file is part of Filius, a network construction and simulation software. ** ** Originally created at the University of Siegen, Institute "Didactics of ** Informatics and E-Learning" by a students' project group: ** members (2006-2007): ** André Asschoff, Johannes Bade, Carsten Dittich, Thomas Gerding, ** Nadja Haßler, Ernst Johannes Klebert, Michell Weyer ** supervisors: ** Stefan Freischlad (maintainer until 2009), Peer Stechert ** Project is maintained since 2010 by Christian Eibl <filius@c.fameibl.de> ** and Stefan Freischlad ** Filius is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 2 of the License, or ** (at your option) version 3. ** ** Filius is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied ** warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ** PURPOSE. See the GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with Filius. If not, see <http://www.gnu.org/licenses/>. */ package filius.software.vermittlungsschicht; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.ListIterator; import java.util.Map.Entry; import filius.Main; import filius.hardware.NetzwerkInterface; import filius.hardware.Verbindung; import filius.hardware.knoten.InternetKnoten; import filius.software.netzzugangsschicht.EthernetFrame; import filius.software.system.InternetKnotenBetriebssystem; import filius.software.system.SystemSoftware; import filius.software.vermittlungsschicht.IP; /** * In dieser Klasse ist das Address Resolution Protocol (ARP) implementiert. * Insbesondere wird hier die ARP-Tabelle mit Eintraegen, die aus einer * IP-Adresse und einem Paar aus MAC-Adresse und Zeitpunkt der Eintragerstellung * besteht. */ public class ARP extends VermittlungsProtokoll { /** * Die ARP-Tabelle als Hashtabelle. Als Schluessel wird die IP-Adresse * verwendet. Der zugehoerige Wert ist ein String-Array mit der gesuchten * MAC-Adresse und dem Zeitpunkt, zu dem der Eintrag vorgenommen wurde. */ private HashMap<String, String[]> arpTabelle = new HashMap<String, String[]>(); /** * Der Thread zur Ueberwachung des Puffers mit eingehenden ARP-Paketen */ private ARPThread thread; /** * Standard-Konstruktor zur Initialisierung der zugehoerigen Systemsoftware * * @param systemAnwendung */ public ARP(SystemSoftware systemAnwendung) { super(systemAnwendung); Main.debug.println("INVOKED-2 ("+this.hashCode()+") "+getClass()+" (ARP), constr: ARP("+systemAnwendung+")"); } public void starten() { Main.debug.println("INVOKED ("+this.hashCode()+") "+getClass()+" (ARP), starten()"); arpTabelle = new HashMap<String, String[]>(); hinzuARPTabellenEintrag("255.255.255.255", "FF:FF:FF:FF:FF:FF"); thread = new ARPThread(this); thread.starten(); } public void beenden() { Main.debug.println("INVOKED ("+this.hashCode()+") "+getClass()+" (ARP), beenden()"); if (thread != null) thread.beenden(); } /** * Fuegt eine Zeile zur ARP Tabelle hinzu. Dabei werden IP Adresse und * MAC-Adresse uebergeben * * @author Thomas Gerding * * @param ipAdresse * @param macAdresse */ public void hinzuARPTabellenEintrag(String ipAdresse, String macAdresse) { Main.debug.println("INVOKED ("+this.hashCode()+") "+getClass()+" (ARP), hinzuARPTabellenEintrag("+ipAdresse+","+macAdresse+")"); Date tmpDate = new Date(); String tmpTime = "" + tmpDate.getTime(); String[] tmpString = { macAdresse, tmpTime }; synchronized (arpTabelle) { arpTabelle.put(ipAdresse, tmpString); arpTabelle.notify(); } // printARPTabelle(); } /** * Hilfsmethode fuer Debugging zur Ausgabe der ARP-Tabelle auf die * Standardausgabe */ private void printARPTabelle() { Main.debug.println("INVOKED ("+this.hashCode()+") "+getClass()+" (ARP), printARPTabelle()"); Iterator it = arpTabelle.entrySet().iterator(); Entry entry; Main.debug.println("ARP: ARP-Tabelle wurde aktualisiert."); while (it.hasNext()) { entry = (Entry) it.next(); Main.debug.println("\t" + entry.getKey() + " \t " + ((String[]) entry.getValue())[0]); } } /** * Liefert die MAC Adresse zu einer IP Adresse aus der ARP Tabelle zurueck. * Wenn kein passender Eintrag vorhanden ist, wird eine Broadcast-Anfrage * verschickt und auf eingehende Antworten gewartet. Wenn nach einem Timeout * ein passender Eintrag vorliegt, wird dieser zurueck gegeben. Andernfalls * wird null zurueck gegeben. * * @author Thomas Gerding * * @param ipAdresse * @return MAC Adresse, zu der die IP Adresse gehoert, oder null, wenn keine * MAC-Adresse bestimmt werden konnte */ public String holeARPTabellenEintrag(String zielIp) { Main.debug.println("INVOKED ("+this.hashCode()+") "+getClass()+" (ARP), holeARPTabellenEintrag("+zielIp+")"); if(zielIp.equals("127.0.0.1")) { return ((InternetKnotenBetriebssystem) holeSystemSoftware()).holeMACAdresse(); } if(holeSystemSoftware() instanceof InternetKnotenBetriebssystem) { if(zielIp.equals(((InternetKnotenBetriebssystem) holeSystemSoftware()).holeIPAdresse())) { return ((InternetKnotenBetriebssystem) holeSystemSoftware()).holeMACAdresse(); } } // Eintrag in ARP-Tabelle fuer gesuchte IP-Adresse? if (arpTabelle.get(zielIp) != null) { return ((String[]) arpTabelle.get(zielIp))[0]; } else { // ARP-Broadcast und warte auf Antwort for (int i = 0; arpTabelle.get(zielIp) == null && i < 3; i++) { sendeARPBroadcast(zielIp); synchronized (arpTabelle) { try { arpTabelle.wait(Verbindung.holeRTT()/10); } catch (InterruptedException e) { Main.debug.println("EXCEPTION ("+this.hashCode()+"): keine Anwort auf ARP-Broadcast fuer IP-Adresse " + zielIp + " eingegangen!"); e.printStackTrace(Main.debug); } } } // Abfrage in ARP-Tabelle nach Broadcast if (arpTabelle.get(zielIp) != null) { return ((String[]) arpTabelle.get(zielIp))[0]; } } Main.debug.println("ERROR ("+this.hashCode()+"): kein ARP-Tabellen-Eintrag fuer " + zielIp); return null; } /** Hilfsmethode zum Versenden einer ARP-Anfrage */ private void sendeARPBroadcast(String suchIp) { NetzwerkInterface nic = getBroadcastNic(suchIp); if (nic == null) { return; } ArpPaket arpPaket = new ArpPaket(); arpPaket.setProtokollTyp(EthernetFrame.ARP); arpPaket.setZielIp(suchIp); arpPaket.setZielMacAdresse("FF:FF:FF:FF:FF:FF"); arpPaket.setQuellIp(nic.getIp()); arpPaket.setQuellMacAdresse(nic.getMac()); ((InternetKnotenBetriebssystem) holeSystemSoftware()) .holeEthernet().senden(arpPaket, nic.getMac(), "FF:FF:FF:FF:FF:FF", EthernetFrame.ARP); } public NetzwerkInterface getBroadcastNic(String zielStr) { long netAddr, maskAddr, zielAddr = IP.inetAton(zielStr); NetzwerkInterface nic; long bestMask = -1; NetzwerkInterface bestNic = null; SystemSoftware firmware = holeSystemSoftware(); InternetKnoten knoten = (InternetKnoten) firmware.getKnoten(); ListIterator it = knoten.getNetzwerkInterfaces().listIterator(); while (it.hasNext()) { nic = (NetzwerkInterface) it.next(); maskAddr = IP.inetAton(nic.getSubnetzMaske()); if (maskAddr <= bestMask) { continue; } netAddr = IP.inetAton(nic.getIp()) & maskAddr; if (netAddr == (maskAddr & zielAddr)) { bestMask = maskAddr; bestNic = nic; } } return bestNic; } public ARPThread getARPThread() { return thread; } }