User Tools

Site Tools


fixbind

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
    • große Downloads von diesem Host möchte ich doch gerne über den schnellen Zugang machen
  • Network Namespaces, Mandatory Access Control
    • Ja, geht, ist aber overkill für die Aufgabe
  • Lösung in der Firewall / im Kernel
    • Sehr unschön, u.a. weil dann die Ausgabe von netstat und die Debugausgabe / Logs u.U. nicht richtig sind.
  • 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.

fixbind.txt · Last modified: 2021-04-21 21:11 by zugschlus