ipmatch - best-matching IP-Netze ausgeben
ipmatch ist eine Art Umkehrfunktion zu ipgrep: es findet IP-Netze, die die auf der Kommandozeile angegebenen IP-Nummern enthalten (ipgrep gibt IP-Nummern aus).
Das klingt ja ganz. Aber mal angenommen in der Liste der IP-Netze befinden sich z.B. 192.168.1.0/24 und 192.168.1.1/28. Wir suchen nun das Netz in dem die IP-Nummer 192.168.1.3 enthalten ist. Das sind natürlich beide Netze, aber das ist nicht ganz das, was ich will. Ich fänd's besser wenn nur das 192.168.1.1/28er Netz ausgegeben wird. Warum? Na ja, irgendwie würde ich sagen es passt einfach "besser". Das "besser" kommt daher, daß das zweite Netz die kleinere Netzwerkmaske hat.
Wofür das interessant ist? Mal angenommen wir kontrollieren Zugang zu einem Netzwerkdienst über die IP-Nummer des Clients, die Konfigurationsdatei sieht so aus:
# # /etc/allow-deny.conf # 192.168.1.0/24 deny 192.168.1.1/28 allow
und die Client IP-Nummer ist 192.168.1.4. Soll dieser Client Zugriff bekommen oder nicht? Ich würde sagen ja, weil das kleinere Netz spezieller ist als das größere.
Ok, zum Programm.
#!/usr/bin/gawk -f
#
#
# ipmatch <file> <ipnum> ...
#
# print best matchings network from list of networks stored in
# <file> for <ipnum>
#
...
ipval(), ipmask() und ipstr() wie vorher
...
BEGIN {
STDERR = "/dev/stderr";
networks = ARGV[1]; ARGV[1] = "";
while (getline <networks > 0) {
sub(/#.*$/, "", $0);
if (NF == 0)
continue;
net = $1;
if (index(net, "/") == 0)
net = net "/32";
k = index(net, "/");
ip = ipval(substr(net, 1, k-1));
mask = ipmask(substr(net, k+1));
first[net] = and(ip, mask);
last[net] = or(ip, compl(mask));
size[net] = last[net] - first[net] + 1;
rec[net] = $0;
}
k = 2;
while (k < ARGC) {
ipnum = ARGV[k++]; ARGV[k++] = "";
ip = ipval(ipnum);
net = "";
for (n in rec) {
if (first[n] <= ip && ip <= last[n]) {
if (net == "")
net = n;
else {
if (size[n] < size[net])
net = n;
}
}
}
if (net != "")
printf ("%s %s\n", ipnum, rec[net]);
}
exit (0);
}
Die while()-Schleife am Anfang des BEGIN Blocks liest die Datei der IP-Netze ein, berechnet die wesentlichen Daten für jedes Netz und speichert die komplette Zeile im rec[] Array.
Die zweite while()-Schleife nimmt dann jede auf der Kommandozeile angegebene IP-Nummer, testet jedes IP-Netz aus der Liste und findet das mit der kleinsten Netzwerkmaske. Wenn es tatsächlich ein Netz gibt, daß die jeweilige IP-Nummer enthält wird die entsprechende Zeile mit der IP-Nummer ausgegeben.
# ipmatch /etc/allow-deny.conf 192.168.1.33 192.168.1.3 192.168.1.33 192.168.1.0/24 deny 192.168.1.3 192.168.1.1/28 allow
So soll's sein.