ae ä
oe ö
ue ü
Ae Ä
Oe Ö
Ue Ü
sz ß

= Generic Circuits =

Ich habe mir mal erlaubt, Jeans altes Posting zu diese Thema als Vorlage zu nehmen, da ich die Ideen gröstenteils OK fand. -- tobias

Ziel: Der circd kann mit allen Netzzugängen umgehen, die von fli4l
angeboten werden, die da sind: ISDN, DSL (PPPoE, PPtP, PPtP über via
DHCP aufgesetzten Tunnel), Ethernet, ... Momentan kann er nur ISDN und
eingeschränkt DSL.

== Aktueller Zustand ==

Während des Bootens werden alle Circuits aufgesetzt (die
entsprechenden Interfaces konfiguriert, evtl. i?ppp-Dameons
gestartet, Konfig-Infos an den circd weitergereicht). 

Der circd wechselt zwischen den Circuits durch reines umsetzen der
routen und erfährt über ein dial in/hangup entweder über
''ip-up/ip-down'' oder durch lesen von ''/dev/isdninfo''.

Bandbreiten-Informationen liest er circuit-spezifisch über
ioctl-Aufrufe an den Kern.

Channel-Bundling wird basierend auf den gelesenen
Bandbreiten-Infos für isdn realisiert.

Momentan kennt circd alle moeglichen ISDN-Circuit-Varianten und
genau einen dsl-Circuit.

== Soll (draft) ==

Es gibt drei Circuit-Typen:

 1. dial in -- Nutzer wählen sich auf den Router ein (isdn oder modem)
 1. special routes -- Circuits bedienen Verbindungen zu speziellen Netzen
 1. default route circuits -- Diese Circuits stellen die normale Verbindung zum Internet her

Es muß möglich sein, daß dial in, special routes und ein
Default-Route Circuit gleichzeitig aktiv sind.
        
In einem ersten Schritt könnte man dial-in und special route
circuits handhaben wie bisher, die werden einfach beim booten
aufgesetzt und sind dann permanent aktiv.

Für die default route circuits würde ich folgendes vorschlagen:

Für jeden Circuit-Typ gibt es ein Script ''<typ>-circuit-ctrl'', das
folgende Operationen kann (pppoe dient jeweils als Beispiel für nähere Erläuterungen):

=== Typen ===
 1. ISDN
 1. PPPOE
 1. PPtP
 1. PPtP over DHCP
 1. Ethernet
 1. VPN (braucht einen der o.g. Circuits, auf den er aufbaut, d.h. er kann auch die Aktivierung veranlassen siehe auch Anmerkung von Claas)

=== <typ>-circuit-ctrl setup <params> ===

 * führt alle aktionen durch, die vor dem tatsächlichen starten eines Circuits getan
   werden müssen, kann auch ein NOP sein. Die rc-Scripte nutzen dieses Kommando, um
   die Circuits vorzubereiten

 * PPPOE: 
   * Das Schreiben von ''/etc/ppp/peers/circuit.*''
   * Schreiben der ImonD Infos (Time-Info, Accouning-Daten, Device-Type, Circuit-Typ und -Name)

=== <typ>-circuit-ctrl start circuit-name ===

 * Starten des Circuits
 * PPPOE:
   * Starten des pppd mit default route/demand option

=== <typ>-circuit-ctrl stop circuit-name ===

 * Stoppen des Circuits
 * PPPOE:
   * Beenden des pppd mit SIGTERM

=== <typ>-circuit-ctrl dial circuit-name ===

 * Einwählen des Circuits triggern
 * PPPoE:
   * dialmode auto: ping auf well known IP
   * dialmode manual: pppd mit option default route starten, ping auf well known ip

=== <typ>-circuit-ctrl hangup circuit-name ===
        
 * Auflegen des Circuits triggern
 * PPPoE
   * dialmode auto: HUP an den pppd, pppd legt auf und wählt sich bei traffic
     über die default route wieder neu ein
   * dialmode manual: HUP an pppd, pppd beendet sich, da er ohne demand option
     gestartet wurde, dial in muß von Hand getriggert werden

=== <typ>-circuit-ctrl dialmode mode circuit-name ===

 * Ändert den Dialmode in der jeweiligen Circuit Konfiguration
 * PPPOE
   * editieren der /etc/ppp/peers  Datei des jeweiligen Circuits

=== <typ>-circuit-ctrl hup-timeout time circuit-name ===

 * setzen des hangup time outs für den Circuit
 * PPPOE
   * editieren der /etc/ppp/peers Datei des Circuits

=== <typ>-circuit-ctrl pause circuit-name ===

 * belässt den circuit im online Zustand unterdrückt aber den Traffic
 * PPPOE
   * setzen einer iptable Regel

=== <typ>-circuit-ctrl cont circuit-name ===

 * hebt die Trafficunterdrückung wieder auf
 * PPPOE
   * Löschen einer iptable Regel


=== <typ>-circuit-ctrl status circuit-name ===

 * Abfrage des online status für den Circuit

''<typ>-circuit-ctrl setup'' wird von den Startup-Scripten verwendet,
um die Circuits vorzubereiten, die anderen Operation werden vom
circd verwendet, um Circuits zu aktivieren, deaktivieren, zwischen
ihnen zu wechseln, dial und hangup auszulösen. Damit wäre der
circd unabhängig vom drunterliegenden Circuit-Typ.

Das Beispiel fuer pppoe liegt im svn im dsl-Paket unter source:trunk/dsl/opt/files/usr/local/bin/pppoe-circuit-ctrl.sh oder [http://os.inf.tu-dresden.de/~jw5/fli4l/pppoe-circuit-ctrl.sh hier]

== Accounting im ImonD ==

Hier wird das ganze leider wieder Device-spezifisch, da die Abfrage der
Bandbreiten Device-spezifisch ist und für ISDN auch Channel-Bundling
realisiert werden muss. Daher muss der ImonD den Typ des Circuit kennen,
damit es die entsprechende Methode zum Auslesen der Bandbreite anwenden
kann und er muss auch den tatsächlichen Namen des devices kennen. Dieser ergibt sich in der Regel erst nach em Start eines Circuits, der circd muß also eine Möglichkeit haben, nach dem starten eines Circuits den Device-Namen herauszubekommen. Beim pppd ist das einfach, wird er mit der Option ''linkname $circuitname'' gestartet legt er sowohl pid als auch genutztes device unter ''/var/run/'' ab . ''<typ>-circuit-ctrl'' braucht dann evtl. noch ein '''bundling [on|off]''', das nur bei ISDN etwas tut, bei allen anderen ein NOP ist.

Die Anzahl der verschiedenen Typen ist übersichtlich, daher lassen isch für die Subsysteme
hier im circd.c implenetieren. Wahlweise kann man ja, um ganz flexibel zu sein, eine
scriptorientierte Bandbreitenbestimmung mit einbauen, falls der Typ unbekannt sein sollte,
versucht der circd via <typ>-circuit-ctrl get-ibytes bzw. get-obytes die Bytes auszulesen.

Achtung: fehlerhaft implementierte Scripte können den circd blockieren.

Um es an dieser Stelle reaktiv zu halten, wäre etwa folgendes möglich:

{{{
#!application/x-sh
...
pipe(fds);
if ((pid = fork()) == 0) {
  close(1);
  close(fds[0]);
  dup(fds[1]);
  ret = (int)((unsigned int) system(cmd) >> 8);
  exit(ret);
} else {
  close(fds[1]);
  res = select(1, &read_fdset, NULL, NULL, &tv);
  if (res == 0) {
    /* timer expired - killing process */
    circd_syslog(...);
    kill(pid, SIGKILL);
    ...
  }
  if (res == 1 && FD_ISSET(fds[0], &read_fdset)) {
    /* read data */
  }
}
...
}}}

== Konfiguration für den User ==

Am Beispiel des DSL-Paketes:

{{{
#!application/x-sh
OPT_PPPOE='no'
PPPOE_FILTER='yes'
PPPOE_CIRCUIT_N='1'
PPPOE_CIRCUIT_1_NAME='DSL'
PPPOE_CIRCUIT_1_USEPEERDNS='yes'
PPPOE_CIRCUIT_1_ETH='eth1'
PPPOE_CIRCUIT_1_TYPE='sync'     # oder global lassen?
PPPOE_CIRCUIT_1_DEBUG='no'      # oder für alle gleichzeitig?
PPPOE_CIRCUIT_1_USER='anonymer'
PPPOE_CIRCUIT_1_PASS='surfer'
PPPOE_CIRCUIT_1_HUP_TIMEOUT='600'
PPPOE_CIRCUIT_1_CHARGEINT='60'
PPPOE_CIRCUIT_1_TIMES='Mo-Su:00-24:0.0:Y'
}}}

Sollte selbsterklärend sein...

=== Abhängigkeiten von Circuits ===

@babel: Irgendwie sollte es auch eine Abhängigkeit geben. Wenn z.B. eine VPN Verbindung eine bestimmte ISDN Verbindung (oder besser route) benötigt sollte das konfigurierbar sein. Ich hatte ja im devchat schonmal vorgeschlagen, dass man die unterschiedliche routen benutzt um auszuschliessen dass zwei "inkompatible" Circuits versuchen online zu gehen.




= Konfiguration und Verhalten eines Circuits =

== Derzeitige Konfigurationsmöglichkeiten ==
Ein Circuit ist entweder ein LCR Circuit oder nicht. Ein LCR-Circuit setzt immer die Defaultroute, wenn er aktiv wird.

In der Konfiguration gibt es folgende Möglichkeiten für einen LCR-Circuit:

 * Y Der Circuit wird in diesem Zeitraum als LCR Circuit verwendet
 * N Der Circuit ist manuell wählbar
 * D Der Circuit ist nicht wählbar

Für Non-LCR-Circuits gibt es derzeit keine Konfigurationsmöglichkeiten.

== Zukünftige Zustände und Konfigurationsmöglichkeiten ==

=== Mögliche Zustände eines Circuits ===

Ein Circuit kann in Zukunft folgende Zustände annehmen:

|| disabled   || Der Circuit ist nicht aktiv, kein Device existiert, keine Route          ||
|| starting   || Der Circuit wird gerade gestartet                                        ||
|| offline    || Der Circuit ist gestartet und geht auf Anforderung online                ||
|| dialing    || Die Verbindung wird aufgebaut                                            ||
|| online     || Der Circuit ist eingewählt, Verbindung besteht                           ||
|| paused     || Die Verbindung besteht, aber die Übertragung von Paketen ist unterbunden ||
|| hanging-up || Die Verbindung wird gerade getrennt                                      ||

Dabei sind starting, dialing und hanging-up nur Übergangszustände, die der circd melden kann, die hier aber keine weitere Rolle spielen.

Die Zustände disabled, offline und online wären für die Konfiguration interessant und bedürfen eines entsprechenden Modes. Dabei ist zwischen LCR und Non-LCR zu unterscheiden:

Für Non-LCR Circuits:

Bei Non-LCR Circuits müssen die Modes für jedes Zeit-Segment angegeben werden:

|| disabled || D || Der Circuit wird nicht gestartet, kein Interface existiert - der Circuit Zustand ist "disabled"   ||
|| offline  || S || Der Circuit wird gestartet mit der "on demand" Option - der Circuit geht in den Zustand "offline" ||
|| online   || O || Der Circuit wird gestartet und die Einwahl getriggert - der Circuit geht in den Zustand "online"  ||
|| paused   || P || Der Circuit wird, sofern er online ist, auf "Pause" gesetzt, kein Traffic wird weitergeleitet     ||

Für LCR Circuits:

Bei LCR-Circuits wird hingegen die Auswahlmöglichkeit angegeben, der Mode wird allgemein für das LCR angegeben.

|| disabled   || D || Der Circuit ist nicht in der Liste der LCR-Circuits zu sehen                 ||
|| selectable || N || Der Circuit ist in der Liste der LCR-Circuits sichtbar aber nicht aktiv      ||
|| active     || Y || Der Circuit ist aktiv: was genau passiert, wird vom LCR-Mode bestimmt (s.u.) ||

Der Mode für den LCR Algorithmus kann dann folgenden Wert annehmen:

|| off       || der aktive Circuit wird nicht gestartet und kann auch nicht manuell aktiviert werden - der Circuit Zustand ist "disabled" ||
|| manual    || der aktive Circuit wird nicht gestartet,kann aber später manual gestartet werden - der Circuit Zustand ist "disabled" ||
|| automatic || der aktive Circuit wird gestartet mit der "on demand" Option d.h. der Circuit geht in den Zustand "offline" ||
|| on        || der aktive Circuit wird gestartet und die Einwahl getriggert, danach befindet sich der Circuit im Zustand "online" ||

=== Zukünftige Konfiguration ===

Damit ergeben sich für die Zukunft folgende Konfigurationsmöglichkeiten:

Beispiel ISDN:

{{{
ISDN_CIRC_1_LCR='no'
ISDN_CIRC_1_TIMES='Mo-Fr:00-06:0.0148:D Mo-Fr:07-17:0.0148:S Mo-Fr:18-24:0.0148:D Sa-Su:00-24:0.0148:D'
}}}

Der Circuit wird Mo-Fr um 7 Uhr gestartet und kann on demand online gehen, in der sonstigen Zeit ist er abgeschaltet (disabled).

Beispiel VPN:

{{{
VPN_CIRC_1_LCR='no'
VPN_CIRC_1_TIMES='Mo-Fr:09-13:0.0148:O Mo-Fr:14-15:0.0148:P Mo-Fr:16-18:0.0148:O'
}}}

Der Circuit geht Mo-Fr um 9 Uhr online und wird für eine "Mittagspause" von 14 bis 16 Uhr gesperrt. Um 19 Uhr wird der Circuit abgeschaltet.

=== Userinterface ===
Es gibt synchrone und asynchrone Kommandos. Ein Kommando besteht aus dem Befehl sowie optionalen Parametern.

Es gibt verschiedene Befehlsebenen: None, User und Admin. Für die letzen beiden muss man sich vorher authentifiziert haben.

Problematik der Authentifizierung: sobald der User das Passwort übermittelt hat, ist der Client berechtigt, seinem Level entsprechende
Befehle abzusetzen. Wer im LAN die Pakete mitlesen kann, kann die Verbindung missbrauchen. Dafür muss er nur das nächste TCP Paket 
(mit der nächsten Sequenznummer) mit dem entsprechenden Befehl schicken. Kommandos, die das Kennwort im Klartext oder als md5hash
übertragen sind ebenfalls anfällig, da das md5 gehashte Kennwort schon zur Authentifizierung übertragen wurde. Es müsste ein 
Algorithmus verwendet werden, in dem das Kennwort nur einmal verwendet wird (Stichwort Replay-Attacke).

Somit ist die gesamte Authentifizierung nutzlos. Ein sicherer Kanal für die Übertragung ist notwendig.

	{ "channels", PASSWORD_STATE_NORMAL, 1<<0, cmd_channels, "", "show number of channels"},
	{ "charge", PASSWORD_STATE_NORMAL, 1<<1, cmd_charge, "#channel-id", "show charge"},
	{ "chargetime", PASSWORD_STATE_NORMAL, 1<<1, cmd_chargetime, "#channel-id",	"show sum of charge times"},
	{ "circuit", PASSWORD_STATE_NORMAL, 1<<1, cmd_circuit, "ci-index", "show name of circuit"},
	{ "circuits", PASSWORD_STATE_NORMAL, 1<<0, cmd_circuits, "", "show number of default route circuits"},
	{ "client-ip", PASSWORD_STATE_NORMAL, 1<<0 | 1<<1, cmd_clientip, "[ip-address]", "show/set ip address of client"},
	{ "cpu", PASSWORD_STATE_NORMAL, 1<<0, cmd_cpu, "", "show cpu usage"},
	{ "date", PASSWORD_STATE_NORMAL, 1<<0, cmd_date, "", "show date"},
	{ "delete", PASSWORD_STATE_ADMIN, 1<<2, cmd_delete, "filename pw", "delete a file"},
	{ "device", PASSWORD_STATE_NORMAL, 1<<1, cmd_device, "ci-index", "show device of circuit"},
	{ "dial", PASSWORD_STATE_NORMAL, 1<<0 | 1<<1, cmd_dial, "", "dial default route connection"},
	{ "dialmode", PASSWORD_STATE_NORMAL, 1<<0 | 1<<1, cmd_dialmode, "[auto|manual|off]", "get/set dialmode"},
	{ "disable", PASSWORD_STATE_NORMAL, 1<<0, cmd_disable, "", "hangup, set dialmode off"},
	{ "driverid", PASSWORD_STATE_NORMAL, 1<<1, cmd_driverid, "#channel-id", "show driver id of channel"},
	{ "enable", PASSWORD_STATE_NORMAL, 1<<0, cmd_enable, "", "set dialmode to 'auto'"},
	{ "fli4l-id", PASSWORD_STATE_NORMAL, 1<<0, cmd_fli4lid, "", "get fli4l-id"},
	{ "halt", PASSWORD_STATE_NORMAL, 1<<0, cmd_halt, "", "halt the router"},
	{ "hangup", PASSWORD_STATE_NORMAL, 1<<0 | 1<<1, cmd_hangup, "[#channel-id]", "hangup connections"},
	{ "highscore", PASSWORD_STATE_NORMAL, 1<<0, cmd_highscore, "", "get highscore"},
	{ "hostname", PASSWORD_STATE_NORMAL, 1<<0, cmd_hostname, "", "get hostname"},
	{ "hup-timeout", PASSWORD_STATE_ADMIN, 1<<1 | 1<<2, cmd_huptimeout, "ci-index [value]", "show/set hup-timeout of circuit"},
	{ "circd-log-file", PASSWORD_STATE_NORMAL, 1<<0, cmd_circdlogfile, "", "show logfile of circd"},
	{ "inout", PASSWORD_STATE_NORMAL, 1<<1, cmd_inout, "#channel-id", "show direction of channel"},
	{ "ip", PASSWORD_STATE_NORMAL, 1<<1, cmd_ip, "#channel-id", "show ip address of interface using channel"},
	{ "is-allowed", PASSWORD_STATE_NORMAL, 1<<1, cmd_isallowed, "dial|dialmode|route|reboot|circd-log|telmond-log|mgetty-log", "get permission"},
	{ "is-enabled", PASSWORD_STATE_NORMAL, 1<<0, cmd_isenabled, "", "return 1 if enabled, else 0"},
	{ "links", PASSWORD_STATE_NORMAL, 1<<1, cmd_links, "ci-index", "show number of links: 0, 1, or 2"},
	{ "log-dir", PASSWORD_STATE_NORMAL, 1<<1, cmd_logdir, "circd|telmond|mgetty", "get logdirectory"},
	{ "mgetty-log-file", PASSWORD_STATE_NORMAL, 1<<0, cmd_mgettylogfile, "", "show logfile of mgetty"},
	{ "online-time", PASSWORD_STATE_NORMAL, 1<<1, cmd_onlinetime, "#channel-id", "show current online time of channel"},
	{ "phone", PASSWORD_STATE_NORMAL, 1<<1, cmd_phone, "#channel-id", "show phone number/circuit name"},
	{ "pppoe", PASSWORD_STATE_NORMAL, 1<<0, cmd_pppoe, "", "return 1 if pppoe used, otherwise 0"},
	{ "quantity", PASSWORD_STATE_NORMAL, 1<<1, cmd_quantity, "#channel-id", "show transferred data quantity of channel"},
	{ "rate", PASSWORD_STATE_NORMAL, 1<<1, cmd_rate, "#channel-id", "show current transfer rate of channel"},
	{ "reboot", PASSWORD_STATE_NORMAL, 1<<0, cmd_reboot, "", "reboot the router"},
	{ "receive", PASSWORD_STATE_ADMIN, 1<<3, cmd_receive, "filename #bytes pw", "receive a file"},
	{ "removelink", PASSWORD_STATE_ADMIN, 1<<1, cmd_removelink, "ci-index", "remove link from channel"},
	{ "reset-circd-log-file", PASSWORD_STATE_ADMIN, 1<<0, cmd_resetcircdlogfile, "", "reset logfile of circd"},
	{ "reset-telmond-log-file", PASSWORD_STATE_ADMIN, 1<<0, cmd_resettelmondlogfile, "", "reset logfile of telmond"},
	{ "route", PASSWORD_STATE_NORMAL, 1<<0 | 1<<1, cmd_route, "[ci-index]", "get/set default route circuit"},
	{ "send", PASSWORD_STATE_ADMIN, 1<<2, cmd_send, "filename pw", "send a file"},
//	{ "set-status", PASSWORD_STATE_ADMIN, 1<<2, cmd_setstatus, "status", "set status of circd"},
	{ "status", PASSWORD_STATE_NORMAL, 1<<1, cmd_status, "#channel-id", "show status of channel"},
	{ "support", PASSWORD_STATE_ADMIN, 1<<1, cmd_support, "password", "show config/status of fli4l"},
	{ "sync", PASSWORD_STATE_NORMAL, 1<<0, cmd_sync, "", "synchronize cache with mounted devices"},
	{ "system", PASSWORD_STATE_NORMAL, 1<<0, cmd_system, "", "returns under which system circd is running"}, 
	{ "telmond-log-file", PASSWORD_STATE_NORMAL, 1<<0, cmd_telmondlogfile, "", "show logfile of telmond"},
	{ "time", PASSWORD_STATE_NORMAL, 1<<1, cmd_time, "#channel-id", "show sum of online times of channel"},
	{ "timetable", PASSWORD_STATE_NORMAL, 1<<0 | 1<<1, cmd_timetable, "[ci-index]", "show timetable"},
	{ "uptime", PASSWORD_STATE_NORMAL, 1<<0, cmd_uptime, "", "show router uptime (in seconds)"},
	{ "usage", PASSWORD_STATE_NORMAL, 1<<1, cmd_usage, "#channel-id", "show usage of channel"},

==== None ====
cmd_quit
cmd_salt
cmd_version
help [command]
md5pass [password]

==== User ====
cmd_ip
cmd_isenabled
cmd_fli4lid
cmd_highscore
cmd_hostname
cmd_dialmode
cmd_channels
cmd_timetable
cmd_circuits
cmd_date
cmd_route
cmd_pppoe
cmd_uptime
cmd_cpu
cmd_telmondlogfile
cmd_circdlogfile
cmd_mgettylogfile
cmd_clientip
cmd_enable
cmd_disable
cmd_reboot
cmd_halt
cmd_dial
cmd_hangup
cmd_sync
cmd_driverid
cmd_status
cmd_phone
cmd_onlinetime
cmd_time
cmd_chargetime
cmd_charge
cmd_usage
cmd_inout
cmd_quantity
cmd_rate
cmd_circuit
cmd_device
cmd_links
cmd_logdir
cmd_isallowed
cmd_system

==== Admin ====
0
cmd_resettelmondlogfile
cmd_resetcircdlogfile

1
cmd_addlink
cmd_removelink

2
cmd_adjusttime
cmd_huptimeout

insecure commands
cmd_receive - may block system and transfers pw in cleartext
cmd_delete  - transfers pw in cleartext
cmd_send    - may block system and transfers pw in cleartext
cmd_support - may block system and transfers pw in cleartext


	{ "delete",      PASSWORD_STATE_ADMIN, 1<<2,            cmd_delete,              "filename pw",        "delete a file"},
	{ "hup-timeout", PASSWORD_STATE_ADMIN, 1<<1 | 1<<2,     cmd_huptimeout,          "ci-index [value]",   "show/set hup-timeout of circuit"},
	{ "receive",     PASSWORD_STATE_ADMIN, 1<<3,            cmd_receive,             "filename #bytes pw", "receive a file"},
	{ "removelink",  PASSWORD_STATE_ADMIN, 1<<1,            cmd_removelink,          "ci-index",           "remove link from channel"},
	{ "reset-circd-log-file", PASSWORD_STATE_ADMIN, 1<<0,   cmd_resetcircdlogfile,   "",                   "reset logfile of circd"},
	{ "reset-telmond-log-file", PASSWORD_STATE_ADMIN, 1<<0, cmd_resettelmondlogfile, "",                   "reset logfile of telmond"},
	{ "send",        PASSWORD_STATE_ADMIN, 1<<2,            cmd_send,                "filename pw",        "send a file"},
//	{ "set-status",  PASSWORD_STATE_ADMIN, 1<<2,            cmd_setstatus,           "status",             "set status of circd"},
	{ "support",     PASSWORD_STATE_ADMIN, 1<<1,            cmd_support,             "password",           "show config/status of fli4l"},
