/*
** 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.LinkedList;
import java.util.ListIterator;
import java.util.StringTokenizer;
import filius.Main;
import filius.hardware.NetzwerkInterface;
import filius.hardware.knoten.InternetKnoten;
import filius.rahmenprogramm.I18n;
import filius.software.system.InternetKnotenBetriebssystem;
import filius.software.vermittlungsschicht.IP;
import filius.software.rip.RIPTable;
import filius.software.rip.RIPRoute;
/**
* Mit dieser Klasse wird die Weiterleitungstabelle implementiert. Es werden
* manuell erstellte Eintraege und aus der IP-Konfiguration der Netzwerkkarten
* des Knotens automatisch erzeugte Eintraege unterschieden. Gespeichert werden
* nur manuelle Eintraege. Ausserdem werden bei jeder Abfrage die automatischen
* Standard-Eintraege erzeugt.
*/
public class Weiterleitungstabelle implements I18n {
/**
* Die Tabelle mit den manuellen Eintraegen der Weiterleitungstabelle. Sie
* werden als String-Arrays in einer Liste verwaltet. Ein Eintrag besteht
* aus folgenden Elementen:
* <ol>
* <li> Netz-ID der Zieladresse als IP-Adresse </li>
* <li> Netzmaske zur Berechnung der Netz-ID aus dem ersten Wert </li>
* <li> Das Standard-Gateway, ueber die die Ziel-IP-Adresse erreicht wird,
* wenn sie sich nicht im gleichen Rechnernetz wie der eigene Rechner
* befindet </li>
* <li> Die IP-Adresse der Netzwerkkarte, ueber die die Ziel-IP-Adresse
* erreicht wird </li>
* </ol>
*/
private LinkedList<String[]> manuelleTabelle;
/**
* Eine Liste, in der angegeben wird, welche Eintraege in der erzeugten
* Tabelle automatisch erzeugt bzw. manuelle Eintraege sind
*/
private LinkedList<Boolean> manuelleEintraege;
/** Die Systemsoftware */
private InternetKnotenBetriebssystem firmware = null;
/**
* Im Standard-Konstruktor wird die Methode reset() aufgerufen. Damit werden
* alle manuellen Eintraege geloescht
*/
public Weiterleitungstabelle() {
reset();
}
/** Methode fuer den Zugriff auf die Systemsoftware */
public void setInternetKnotenBetriebssystem(
InternetKnotenBetriebssystem firmware) {
this.firmware = firmware;
}
/** Methode fuer den Zugriff auf die Systemsoftware */
public InternetKnotenBetriebssystem getInternetKnotenBetriebssystem() {
return firmware;
}
/**
* Methode fuer den Zugriff auf die manuellen Eintrage. Diese Methode sollte
* nur fuer das speichern genutzt werden!
*/
public void setManuelleTabelle(LinkedList<String[]> tabelle) {
this.manuelleTabelle = tabelle;
}
/**
* Methode fuer den Zugriff auf die manuellen Eintrage. Diese Methode sollte
* nur fuer das speichern genutzt werden!
*/
public LinkedList<String[]> getManuelleTabelle() {
return manuelleTabelle;
}
/**
* Methode zum hinzufuegen eines neuen Eintrags. Ein Eintrag besteht aus
* folgenden Elementen:
* <ol>
* <li> Netz-ID der Zieladresse als IP-Adresse </li>
* <li> Netzmaske zur Berechnung der Netz-ID aus dem ersten Wert </li>
* <li> Das Standard-Gateway, ueber die die Ziel-IP-Adresse erreicht wird,
* wenn sie sich nicht im gleichen Rechnernetz wie der eigene Rechner
* befindet </li>
* <li> Die IP-Adresse der Netzwerkkarte, ueber die die Ziel-IP-Adresse
* erreicht wird </li>
* </ol>
*
* @param netzwerkziel
* @param netzwerkmaske
* @param gateway
* @param schnittstelle
*/
public void addManuellenEintrag(String netzwerkziel, String netzwerkmaske,
String gateway, String schnittstelle) {
Main.debug.println("INVOKED ("+this.hashCode()+") "+getClass()+" (Weiterleitungstabelle), addManuellenEintrag("+netzwerkziel+","+netzwerkmaske+","+gateway+","+schnittstelle+")");
manuelleEintraege = null;
if (netzwerkziel != null && netzwerkmaske != null && gateway != null
&& schnittstelle != null) {
String[] tmpString = { netzwerkziel, netzwerkmaske, gateway,
schnittstelle };
manuelleTabelle.addLast(tmpString);
}
// printTabelle(messages.getString("sw_weiterleitungstabelle_msg1"),
// manuelleTabelle);
}
/**
* Hilfsmethode zum Debugging zur Ausgabe der Tabelleneintraege auf der
* Standardausgabe
*
* @param name
* der Name, der in der Tabellenueberschrift ausgegeben werden
* soll
* @param tabelle
* die auszugebende Tabelle
*/
public void printTabelle(String name) {
// Main.debug.println("INVOKED ("+this.hashCode()+") "+getClass()+" (Weiterleitungstabelle), printTabelle("+name+","+tabelle+")");
ListIterator it = holeTabelle().listIterator();
String[] eintrag;
Main.debug.println("DEBUG ("+name+") Weiterleitungstabelle (IP,mask,gw,if):");
while (it.hasNext()) {
eintrag = (String[]) it.next();
Main.debug.printf("DEBUG (%s) '%15s' | '%15s' | '%15s' | '%15s'\n", name, eintrag[0], eintrag[1], eintrag[2], eintrag[3]);
}
}
/**
* Zugriff auf die Liste, in der steht, welche Eintraege automatisch erzeugt
* bzw. manuell erstellt wurden
*/
public LinkedList<Boolean> holeManuelleEintraegeFlags() {
return manuelleEintraege;
}
/** Zuruecksetzen der Tabelle mit den manuellen Eintraegen */
public void reset() {
manuelleTabelle = new LinkedList<String[]>();
manuelleEintraege = null;
}
/**
* Methode fuer den Zugriff auf die Weiterleitungstabelle bestehend aus
* automatisch erzeugten und manuellen Eintraegen
*/
public LinkedList<String[]> holeTabelle() {
Main.debug.println("INVOKED ("+this.hashCode()+") "+getClass()+" (Weiterleitungstabelle), holeTabelle()");
InternetKnoten knoten;
NetzwerkInterface nic = null;
String gateway;
ListIterator it;
LinkedList<String[]> tabelle;
String[] tmp = new String[4];
tabelle = new LinkedList<String[]>(manuelleTabelle);
manuelleEintraege = new LinkedList<Boolean>();
for (int i = 0; i < tabelle.size(); i++)
manuelleEintraege.add(new Boolean(true));
if (firmware != null) {
// Eintrag fuer 'localhost'
tmp = new String[4];
tmp[0] = "127.0.0.0";
tmp[1] = "255.0.0.0";
tmp[2] = "127.0.0.1";
tmp[3] = "127.0.0.1";
tabelle.addFirst(tmp);
manuelleEintraege.addFirst(new Boolean(false));
knoten = (InternetKnoten) firmware.getKnoten();
// Eintrag fuer eigenes Rechnernetz
it = knoten.getNetzwerkInterfaces().listIterator();
while (it.hasNext()) {
nic = (NetzwerkInterface) it.next();
tmp = new String[4];
// tmp[0] = nic.getIp();
tmp[0] = berechneNetzkennung(nic.getIp(), nic.getSubnetzMaske());
tmp[1] = nic.getSubnetzMaske();
tmp[2] = nic.getIp();
tmp[3] = nic.getIp();
tabelle.addFirst(tmp);
manuelleEintraege.addFirst(new Boolean(false));
}
// Eintrag fuer eigene IP-Adresse
it = knoten.getNetzwerkInterfaces().listIterator();
while (it.hasNext()) {
nic = (NetzwerkInterface) it.next();
tmp = new String[4];
tmp[0] = nic.getIp();
tmp[1] = "255.255.255.255";
tmp[2] = "127.0.0.1";
tmp[3] = "127.0.0.1";
tabelle.addFirst(tmp);
manuelleEintraege.addFirst(new Boolean(false));
}
// Eintrag fuer Standardgateway, wenn es konfiguriert wurde
gateway = firmware.getStandardGateway();
if (gateway != null && !gateway.trim().equals("")) {
gateway = gateway.trim();
it = knoten.getNetzwerkInterfaces().listIterator();
tmp = null;
while (it.hasNext()) {
nic = (NetzwerkInterface) it.next();
if (nic != null
&& VermittlungsProtokoll
.gleichesRechnernetz(gateway, nic.getIp(),
nic.getSubnetzMaske())) {
tmp = new String[4];
tmp[0] = "0.0.0.0";
tmp[1] = "0.0.0.0";
tmp[2] = gateway;
tmp[3] = nic.getIp();
}
}
if (tmp == null) {
tmp = new String[4];
tmp[0] = "0.0.0.0";
tmp[1] = "0.0.0.0";
tmp[2] = gateway;
tmp[3] = firmware.holeIPAdresse();
}
tabelle.addLast(tmp);
manuelleEintraege.addLast(new Boolean(false));
}
}
return tabelle;
}
/**
* Methode, um aus einer IP-Adresse und einer Subnetzmaske eine
* Netzwerkkennung als String zu erzeugen. Bsp.: 192.168.2.6 und
* 255.255.255.0 wird zu 192.168.2.0
*/
private String berechneNetzkennung(String ipStr, String maskStr) {
long ipAddr = IP.inetAton(ipStr);
long maskAddr = IP.inetAton(maskStr);
long netAddr = ipAddr & maskAddr;
return IP.inetNtoa(netAddr);
}
/**
* Tabelle zur Abfrage der Weiterleitungstabelle nach einem passenden
* Eintrag fuer eine Ziel-IP-Adresse
*
* @param zielIP
* die Ziel-IP-Adresse
* @return das Ergebnis als String-Array bestehend aus der IP-Adresse des
* naechsten Gateways und der fuer den Versand zu verwendenden
* Schnittstelle
*/
public String[] holeWeiterleitungsZiele(String zielStr) {
RIPTable table = firmware.getRIPTable();
if (table == null) {
return holeStatisch(zielStr);
} else {
synchronized (table) {
return holeDynamisch(table, zielStr);
}
}
}
public String[] holeStatisch(String zielStr) {
long netAddr, maskAddr, zielAddr = IP.inetAton(zielStr);
String[] route;
long bestMask = -1;
String[] bestRoute = null;
ListIterator it = holeTabelle().listIterator();
while (it.hasNext()) {
route = (String[]) it.next();
maskAddr = IP.inetAton(route[1]);
if (maskAddr <= bestMask) {
continue;
}
netAddr = IP.inetAton(route[0]);
if (netAddr == (maskAddr & zielAddr)) {
bestMask = maskAddr;
bestRoute = new String[]{route[2], route[3]};
}
}
return bestRoute;
}
public String[] holeDynamisch(RIPTable table, String ip) {
// table must be synchronized by holeWeiterleitungsZiele
String[] bestRoute = null;
int bestHops = RIPTable.INFINITY - 1;
long bestMask = -1;
for (RIPRoute route : table.routes) {
if (route.netAddr.equals(berechneNetzkennung(ip, route.netMask))) {
if (bestHops < route.hops) {
continue;
}
if (bestHops > route.hops
|| bestMask < IP.inetAton(route.netMask)) {
bestRoute = new String[]{route.nextHop, route.nic};
bestHops = route.hops;
bestMask = IP.inetAton(route.netMask);
}
}
}
return bestRoute;
}
}