3

I'm trying to create linux kernel module, that will inspect incoming packets. At the moment, I'm in process of extracting TCP header of packet and reading source and destination port -> However I'm getting incorrect values. I have hook function:

unsigned int hook_func(unsigned int hooknum, struct sk_buff *skb, 
                       const struct net_device *in, 
                       const struct net_device *out, 
                       int (*okfn)(struct sk_buff *)) 
{
    struct iphdr *ipp = (struct iphdr *)skb_network_header(skb);
    struct tcphdr *hdr;
    /* Using this to filter data from another machine */
    unsigned long ok_ip = 2396891328;

    /* Some problem, empty network packet. Stop it now. */
    if (!skb)
        return NF_ACCEPT;

    /* Just to track only packets coming from 1 IP */
    if (ipp->saddr != ok_ip)
        return NF_ACCEPT;

    /* Incomming packet is TCP */
    if (ipp->protocol == IPPROTO_TCP) {
        hdr = (struct tcphdr *) skb_transport_header(skb);
        printk(" TCP ports: source: %d, dest: %d .\n", ntohs(hdr->source), 
                                                       ntohs(hdr->dest));
    }
}

Now, when I try to telnet port 21(not listening there I get):

[ 4252.961912]  TCP ports: source: 17664, dest: 52 .
[ 4253.453978]  TCP ports: source: 17664, dest: 52 .
[ 4253.953204]  TCP ports: source: 17664, dest: 48 .

And when I telnet port 22 - SSH deamon listening there:

[ 4299.239940]  TCP ports: source: 17664, dest: 52 .
[ 4299.240527]  TCP ports: source: 17664, dest: 40 .
[ 4299.552566]  TCP ports: source: 17664, dest: 40 .

As visible from output I'm getting very weird results, anyone has idea where problem is coming from? when I compile module I have no errors / warnings. Version of kernel(headers): 3.7.10 . Not using SELinux or similar.

Sam Protsenko
  • 14,045
  • 4
  • 59
  • 75
LukasH
  • 63
  • 1
  • 1
  • 4
  • this might have to do with NAT redirection. Even though your packet is supposed to be leaving on port 21 and 22, the Router converts this to a dynamic port, and then the server is actually getting a request from this port. On the way back, the server's header shows this, and the router forwards it to you. I don't think the header is actually changed (or encapsulated) though, since hte router I think goes into the header and changes it. – KrisSodroski May 13 '13 at 18:46
  • You should try and print outgoing packets too. If they show the right port, then it is the router changing these values for you. – KrisSodroski May 13 '13 at 18:50
  • There is no NAT. Both machines are on ESX server, no VLANs. Machines are having IPs: 192.168.221.141/24 and 192.168.221.142/24 so I don't see any possibility how packet can be modified by anything. Also there are no iptables rules, all is set to accept. – LukasH May 13 '13 at 20:41
  • You need to define how they are connected to the network. Are they on a virtual lan (which you said they aren't), or are they connected to your physical network? If they're on the vlan, i can see there not being a switch/router, but if their entry point is physical, then I 100 percent doubt its not going through a router/switch. – KrisSodroski May 13 '13 at 20:49

2 Answers2

9

I had the same problem writing a small firewall for a networking class I just found out the problem I was having. I was casting the tcp header wrong. Try casting to tcp then accessing the port.

Here is a code snippet of it working

struct iphdr *ip_header;       // ip header struct
struct tcphdr *tcp_header;     // tcp header struct
struct udphdr *udp_header;     // udp header struct
struct sk_buff *sock_buff;

unsigned int sport ,
             dport;


sock_buff = skb;

if (!sock_buff)
    return NF_ACCEPT;

ip_header = (struct iphdr *)skb_network_header(sock_buff);
if (!ip_header)
    return NF_ACCEPT;


//if TCP PACKET
if(ip_header->protocol==IPPROTO_TCP)
{
    //tcp_header = (struct tcphdr *)skb_transport_header(sock_buff); //doing the cast this way gave me the same problem

    tcp_header= (struct tcphdr *)((__u32 *)ip_header+ ip_header->ihl); //this fixed the problem

    sport = htons((unsigned short int) tcp_header->source); //sport now has the source port
    dport = htons((unsigned short int) tcp_header->dest);   //dport now has the dest port
}
inferno
  • 106
  • 3
  • Thank you, `tcp_header= (struct tcphdr *)((__u32 *)ip_header+ ip_header->ihl);` Fixed my problem. – LukasH May 14 '13 at 05:23
  • 4
    You can also use these two functions to get the IP header and TCP header `ip_hdr(sock_buff)` and `tcp_hdr(sock_buff)` – IoT Jul 02 '14 at 11:47
6

To get the IP header or TCP header from a socket buffer (skb), just apply the functions ip_hdr(skb) and tcp_hdr(skb).

ruief
  • 436
  • 6
  • 9