FixBind
Kurzzusammenfassung: Ich suche einen Wrapper um bind(), der die Source-IP festnagelt.
Der Wrapper soll pro Programm konfigurierbar sein, d.h. unterschiedliche Programme (ggf. mit unterschiedlichen Parametern) bekommen unterschiedliche source IPs
Wenn ein Programm den bind() Wrapper anruft und dabei selbst explizit eine bestimmte Source-IP anfordert, dann gewinnt die vom Programm angeforderte IP.
Situation
ein
LAN mit zwei verschiedenen IPv6-Uplinks
einmal vom direkten Provider, schnell, dafür aber dynamisch wechselnd
einmal per VPN-Tunnel, statisch, dafür aber langsam
Der statische Prefix steht bei anderen Netzen (Kundennetzen etc) in Accesslisten und darf “mehr”
ein Linux- Rechner hat je eine IP-Adresse aus beiden Prefixen
über den bind() Call beim Socketaufbau kann ein Prozess auswählen welche IP-Adresse er für seine ausgehende Verbindung wählt
Das kann aber nicht jedes Programm. Git kann es zum Beispiel nicht.
Aufgabe
Programme, die die Accessliste benötigen, sollen die Adresse aus dem statischen prefix bnutzen
Andere Programme sollen die Adresse aus dem dynamischen Prefix benutzen
Das kann auch abhängig vom Rest der Kommandozeile entschieden werden müssen!
Lösung
Ein LD_PRELOAD-Wrapper um den bind()-Call, der abhängig von einer Konfiguationsdatei die Calls der gestarteten Binaries mit IP-Adress-Spezifischen Optionen, z.B. der IP-Adresse, anreichert
cmdline sei eine regexp, der erste Match der Kommandozeile gegen die Regexp gewinnt
srcip sei eine Liste von IP-Adressen und Netzen. Jeder Eintrag der Liste wird gegen die auf dem System vorhandenen Adressen gematcht, die erste passende Adresse wird genommen
addrlabel sei ein IP Adress Label (siehe /etc/gai.conf, ip addrlabel, RFC6724 Chapter 2.1 und 5). Die erste auf dem System gefundene passende Adresse wird genommen
Ergebnis: ein Prozess, dessen Kommandozeile auf einen der Ausdrücke in der Konfigurationsdatei passt, wird seine ausgehenden Netzwerkverbindungen mit der aus der Konfiguration gewonnenen Source-IP-Adresse aufbauen.
Fordert der Prozess explizit eine andere IP-Adresse an, gewinnt der explizite Wunsch des Prozesses.
Gedanken zur Konfiguration
pseudoyaml?
- cmdline: "git"
srcip:
- 2001:db8:1:2::/64
- 2001:db8:2:a100::/56
- cmdline: "ssh"
addrlabel: "8"
- cmdline: "curl.*http://foo.example/.*"
srcip:
- 192.168.182.28
Wenn man sich die Yaml-Library ersparen möchte könnte ich mir auch ein einfacheres Konfigformat vorstellen wie:
binaryname Ip-Prefix-List
/regexp/IP-prefix-List
IP-prefix-list kann auch “label-x” enthalten für ein addresslabel.
Verworfene Lösungen
Einfach für gewisse Zielhosts eine Route auf den langsamen, statischen Zugang setzen
Network Namespaces, Mandatory Access Control
Lösung in der Firewall / im Kernel
SOCKS
Das würde vermutlich gehen, aber den Aufwand würde ich mir ungerne ans Bein binden, sonst könnte ich einfach den dynamischen Prefix nur auf den SOCKS-Proxy routen und über “SOCKS/kein SOCKS” die Entscheidung treffen lassen, aber das ist doch im Prinzip Kapitulation vor der Aufgabe.
Beispielcode
bindwrapper() {
if(srcIP == NULL) {
srcIP = read_config(programmname);
// kennt man an der stelle den programmnamen des aufrufers überhaupt?
// Ich denke den kennt man über ${ENV[0]}.
// ggf. andere attribute setzen
}
bind(srcIP);
}
Wie einfach oder kompliziert du read_config() baust ist ja eher Nebenbaustelle, muss aber getan werden.
Blueprint könnte das hier sein: http://www.ryde.net/code/bind.c.txt
Hier mit IPv6_Support: https://gist.github.com/xperia64/4bf836ac526530de67b5984f80285bf8
Es gibt auch was ähnlich altes vom Pöttering: http://0pointer.de/lennart/projects/fixsrcip/
Daniel Lange hat dazu gebloggt: https://daniel-lange.com/archives/53-Binding-applications-to-a-specific-IP.html
Damit kannste die Konfiguration über ein Shellscript machen.
git() { export BIND_ADDR=$(setsrcaddr "$1"); LD_PRELOAD=./bind.so "$1"; }
setsrcaddr() liest dann deine config. und das geht in die .shellrc und fertig.
Die Lösung nimmt natürlich keine Rücksicht auf die Wunsch IP und weitere Attribute.
Das müsste man noch einbauen, und eigentlich hätte ich es schon gerne etwas schöner, und würde gerne ohne hunderte von Shell-Aliases auskokmmen.