slaYer977
09.08.06, 22:17
Hallo,
ich habe eine kleines Kernelmodul geschrieben, welches die Funtionalität einer Firewall hat. Jedoch habe ich noch ein großes Problem. Ich bekomme von Netfilter nicht die richtigen Portnummern angezeigt. Wenn ich also per tcph->source auf den Source-Port zugreife und auch eine Konvertierung durchführe so bekomme ich, wenn das Paket von Extern kommt nicht die richtigen Ports angezeigt. Wenn ich auf der selben Maschine z.b. wget localhost aufrufe, werden die richtigen Ports angezeigt. Wobei dann auch noch zwei Pakete angezeigt werden, wo ich nicht verstehe, warum diese auch immer mitgeneriert werden.
Ich habe zunächst vermutet, dass Problem an meinem Fedora 4 System liegt. Dass dort evtl. irgendwelche Security Features (SELinux) dass ganze verursachen. Nun habe ich aber ein Ubuntu 6.06 auf einem Testsystem installiert und da habe ich das gleiche Problem. Als nächstes würde ich es mit Red Hat 9 probieren, doch da muss ich zuerst noch den Kernel neu kompilieren, damit ich Module per insmod laden kann.
Wäre nett, wenn mir einer sagen könnte, warum ich die falschen Portnummern zu Gesicht bekomme. Interessant ist auch, dass wenn ich von Extern komme es scheinbar keine Geige spiel, welchen Port ich anspreche (z.B. per Webbrowser 192.1.1.1:1234) Mir wird immer der selbe falsche Port angezeigt.
Hier zuerst mal die Ausgabe von der Konsole:
wget localhost
Source: 127.0.0.1 : 46670 Destination: 127.0.0.1 : 80
Source: 127.0.0.1 : 17664 Destination: 127.0.0.1 : 44 <--verstehe ich nicht
Source: 127.0.0.1 : 80 Destination: 127.0.0.1 : 46670
Source: 127.0.0.1 : 17664 Destination: 127.0.0.1 : 40 <--verstehe ich nicht
von extern per http://85.176.149.21:irgendeinport (meine öffentliche ip-adresse zu diesem zeitpunkt)
Source: 85.176.157.129 : 17664 Destination: 85.176.149.21 : 48
Ich habe mein Kernelmodul für die Fehleranalyse mal auf das Wesentliche reduziert:
(Da dass wget localhost ja scheinbar funktioniert, denke ich dass meine convert_port-Methode auch das richtige tut.)
//portprob.c
#include <linux/netfilter_ipv4.h>
#include </usr/src/kernels/2.6.11-1.1369_FC4-i686/include/net/icmp.h>
static struct nf_hook_ops in; /*NF_IP_PRE_ROUTING - Hook 1 */
static struct nf_hook_ops out; /*NF_IP_POST_ROUTING - Hook 4 */
//Array-Structure für eine IP-Adresse
struct addrarray{ unsigned char ipbyte[4]; };
/*Diese Funktion konvertiert eine IP-Adresse, die von netfilter als eine
* grosse Zahl im u32-Format übergeben wird, in vier eigenständige Bytes.
* Das Makro NIPUQAD wurde bewusst nicht verwendet.
*/
struct addrarray convert_ip(unsigned int ipaddress)
{
unsigned char rueckgabe;
unsigned int tmp;
unsigned int einbit = 0x01;
unsigned int *zeiger1;
struct addrarray addr;
int i;
int j;
int k;
//Zeiger zeigt auf die u32-ipadresse
zeiger1 = &ipaddress;
//for-schleife wird vier mal durchlaufen, da wir 4 Bytes haben wollen
for(j=1;j<=4;j++)
{
i=8*j-1;
k=i-7;
tmp=0;
//schleife wird 8mal durchlafuen. für jedes bit einmal.
for(; i>=k;i--)
{
einbit = 0x01;
einbit = (einbit << i);
if ((*zeiger1 & einbit)){tmp=tmp^einbit;};
}
rueckgabe=tmp>>k;
addr.ipbyte[j-1]=rueckgabe;
}
return addr;
}
/*Konvertierung der portnummer in das richtige format.
*/
unsigned int convert_port(unsigned int port)
{
unsigned int rueckgabe;
unsigned int einbit=0x01;
unsigned int *zeiger;
unsigned int tmp;
int j=1;
int i;
int k;
zeiger=&port;
rueckgabe=0;
for(;j<=2;j++)
{
i=8*j-1;
k=i-7;
tmp=0;
for(; i>=k;i--)
{
einbit = 0x01;
einbit = (einbit << i);
if ((*zeiger & einbit)){tmp=tmp^einbit;};
}
if(j==1){tmp<<=8;};
if(j==2){tmp>>=8;};
rueckgabe=rueckgabe^tmp;
}
return rueckgabe;
}
//MAIN FUNCTION
unsigned int main_hook(unsigned int hooknum,
struct sk_buff **skb_p,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff*))
{
struct sk_buff *skb = *skb_p;
struct iphdr *iph = skb->nh.iph;
struct tcphdr *tcph = skb->h.th;
struct udphdr *udph = skb->h.uh;
struct addrarray saddr;
struct addrarray daddr;
unsigned int sport = 0;
unsigned int dport = 0;
//some conversions
saddr = convert_ip(iph->saddr);
daddr = convert_ip(iph->daddr);
if(iph->protocol == 6)
{
sport = convert_port(tcph->source);
dport = convert_port(tcph->dest);
}
if(iph->protocol == 17)
{
sport = convert_port(udph->source);
dport = convert_port(udph->dest);
}
if((iph->protocol == 6) || (iph->protocol == 17))
{
printk("Source: %u.%u.%u.%u : %u Destination: %u.%u.%u.%u : %u \n" ,saddr.ipbyte[0],saddr.ipbyte[1],saddr.ipbyte[2],saddr.ipbyte[3], sport, daddr.ipbyte[0],daddr.ipbyte[1],daddr.ipbyte[2],daddr.ipbyte[3],
dport);
}
return 1;
}
//INIT Methode zum Laden des Moduls in den Kernel
int init_module()
{
printk("\n Modul has been loaded...\n");
in.hook = main_hook;
in.pf = PF_INET;
in.hooknum = NF_IP_PRE_ROUTING;
in.priority = NF_IP_PRI_FIRST;
out.hook = main_hook;
out.pf = PF_INET;
out.hooknum = NF_IP_POST_ROUTING;
out.priority = NF_IP_PRI_FIRST;
nf_register_hook(&in); /*register NF_IP_PRE_ROUTING hook*/
nf_register_hook(&out); /*register NF_IP_POST_ROUTING hook*/
return 0;
}
//CLEANUP zum entladen des Moduls aus dem Kernel
void cleanup_module()
{
printk("\n Modul has been unloaded...\n");
nf_unregister_hook(&in); /*unregister Module from Hook 1*/
nf_unregister_hook(&out); /*unregister Module from Hook 2*/
}
Bin für jede Hilfe sehr dankbar!
ich habe eine kleines Kernelmodul geschrieben, welches die Funtionalität einer Firewall hat. Jedoch habe ich noch ein großes Problem. Ich bekomme von Netfilter nicht die richtigen Portnummern angezeigt. Wenn ich also per tcph->source auf den Source-Port zugreife und auch eine Konvertierung durchführe so bekomme ich, wenn das Paket von Extern kommt nicht die richtigen Ports angezeigt. Wenn ich auf der selben Maschine z.b. wget localhost aufrufe, werden die richtigen Ports angezeigt. Wobei dann auch noch zwei Pakete angezeigt werden, wo ich nicht verstehe, warum diese auch immer mitgeneriert werden.
Ich habe zunächst vermutet, dass Problem an meinem Fedora 4 System liegt. Dass dort evtl. irgendwelche Security Features (SELinux) dass ganze verursachen. Nun habe ich aber ein Ubuntu 6.06 auf einem Testsystem installiert und da habe ich das gleiche Problem. Als nächstes würde ich es mit Red Hat 9 probieren, doch da muss ich zuerst noch den Kernel neu kompilieren, damit ich Module per insmod laden kann.
Wäre nett, wenn mir einer sagen könnte, warum ich die falschen Portnummern zu Gesicht bekomme. Interessant ist auch, dass wenn ich von Extern komme es scheinbar keine Geige spiel, welchen Port ich anspreche (z.B. per Webbrowser 192.1.1.1:1234) Mir wird immer der selbe falsche Port angezeigt.
Hier zuerst mal die Ausgabe von der Konsole:
wget localhost
Source: 127.0.0.1 : 46670 Destination: 127.0.0.1 : 80
Source: 127.0.0.1 : 17664 Destination: 127.0.0.1 : 44 <--verstehe ich nicht
Source: 127.0.0.1 : 80 Destination: 127.0.0.1 : 46670
Source: 127.0.0.1 : 17664 Destination: 127.0.0.1 : 40 <--verstehe ich nicht
von extern per http://85.176.149.21:irgendeinport (meine öffentliche ip-adresse zu diesem zeitpunkt)
Source: 85.176.157.129 : 17664 Destination: 85.176.149.21 : 48
Ich habe mein Kernelmodul für die Fehleranalyse mal auf das Wesentliche reduziert:
(Da dass wget localhost ja scheinbar funktioniert, denke ich dass meine convert_port-Methode auch das richtige tut.)
//portprob.c
#include <linux/netfilter_ipv4.h>
#include </usr/src/kernels/2.6.11-1.1369_FC4-i686/include/net/icmp.h>
static struct nf_hook_ops in; /*NF_IP_PRE_ROUTING - Hook 1 */
static struct nf_hook_ops out; /*NF_IP_POST_ROUTING - Hook 4 */
//Array-Structure für eine IP-Adresse
struct addrarray{ unsigned char ipbyte[4]; };
/*Diese Funktion konvertiert eine IP-Adresse, die von netfilter als eine
* grosse Zahl im u32-Format übergeben wird, in vier eigenständige Bytes.
* Das Makro NIPUQAD wurde bewusst nicht verwendet.
*/
struct addrarray convert_ip(unsigned int ipaddress)
{
unsigned char rueckgabe;
unsigned int tmp;
unsigned int einbit = 0x01;
unsigned int *zeiger1;
struct addrarray addr;
int i;
int j;
int k;
//Zeiger zeigt auf die u32-ipadresse
zeiger1 = &ipaddress;
//for-schleife wird vier mal durchlaufen, da wir 4 Bytes haben wollen
for(j=1;j<=4;j++)
{
i=8*j-1;
k=i-7;
tmp=0;
//schleife wird 8mal durchlafuen. für jedes bit einmal.
for(; i>=k;i--)
{
einbit = 0x01;
einbit = (einbit << i);
if ((*zeiger1 & einbit)){tmp=tmp^einbit;};
}
rueckgabe=tmp>>k;
addr.ipbyte[j-1]=rueckgabe;
}
return addr;
}
/*Konvertierung der portnummer in das richtige format.
*/
unsigned int convert_port(unsigned int port)
{
unsigned int rueckgabe;
unsigned int einbit=0x01;
unsigned int *zeiger;
unsigned int tmp;
int j=1;
int i;
int k;
zeiger=&port;
rueckgabe=0;
for(;j<=2;j++)
{
i=8*j-1;
k=i-7;
tmp=0;
for(; i>=k;i--)
{
einbit = 0x01;
einbit = (einbit << i);
if ((*zeiger & einbit)){tmp=tmp^einbit;};
}
if(j==1){tmp<<=8;};
if(j==2){tmp>>=8;};
rueckgabe=rueckgabe^tmp;
}
return rueckgabe;
}
//MAIN FUNCTION
unsigned int main_hook(unsigned int hooknum,
struct sk_buff **skb_p,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff*))
{
struct sk_buff *skb = *skb_p;
struct iphdr *iph = skb->nh.iph;
struct tcphdr *tcph = skb->h.th;
struct udphdr *udph = skb->h.uh;
struct addrarray saddr;
struct addrarray daddr;
unsigned int sport = 0;
unsigned int dport = 0;
//some conversions
saddr = convert_ip(iph->saddr);
daddr = convert_ip(iph->daddr);
if(iph->protocol == 6)
{
sport = convert_port(tcph->source);
dport = convert_port(tcph->dest);
}
if(iph->protocol == 17)
{
sport = convert_port(udph->source);
dport = convert_port(udph->dest);
}
if((iph->protocol == 6) || (iph->protocol == 17))
{
printk("Source: %u.%u.%u.%u : %u Destination: %u.%u.%u.%u : %u \n" ,saddr.ipbyte[0],saddr.ipbyte[1],saddr.ipbyte[2],saddr.ipbyte[3], sport, daddr.ipbyte[0],daddr.ipbyte[1],daddr.ipbyte[2],daddr.ipbyte[3],
dport);
}
return 1;
}
//INIT Methode zum Laden des Moduls in den Kernel
int init_module()
{
printk("\n Modul has been loaded...\n");
in.hook = main_hook;
in.pf = PF_INET;
in.hooknum = NF_IP_PRE_ROUTING;
in.priority = NF_IP_PRI_FIRST;
out.hook = main_hook;
out.pf = PF_INET;
out.hooknum = NF_IP_POST_ROUTING;
out.priority = NF_IP_PRI_FIRST;
nf_register_hook(&in); /*register NF_IP_PRE_ROUTING hook*/
nf_register_hook(&out); /*register NF_IP_POST_ROUTING hook*/
return 0;
}
//CLEANUP zum entladen des Moduls aus dem Kernel
void cleanup_module()
{
printk("\n Modul has been unloaded...\n");
nf_unregister_hook(&in); /*unregister Module from Hook 1*/
nf_unregister_hook(&out); /*unregister Module from Hook 2*/
}
Bin für jede Hilfe sehr dankbar!