NetBIOS with NAT using iptables helper module

Discussion in 'Linux Networking' started by lrwood, Jan 18, 2006.

  1. lrwood

    lrwood Guest

    Here are updates for the latest kernels (I am using the TFTP conntrack
    module to also have the netbios modules built. I also modify the
    Makefile created by make gconfig or make xconfig to include
    ip_conntrack_netbios.o and ip_nat_netbios.o).

    ==================================================================
    /usr/src/linux/include/linux/netfilter_ipv4/ip_conntrack_netbios.h
    ==================================================================

    #ifndef _IP_CT_TFTP
    #define _IP_CT_TFTP

    #define NETBIOS_PORT 138

    struct netbios_hdr
    {
    u_int8_t nodetype;
    u_int8_t flags;
    u_int16_t dgramid;
    u_int32_t srcip;
    u_int16_t srcport;
    u_int16_t length;
    u_int16_t offset;
    };


    extern unsigned int (*ip_nat_netbios_hook)(struct sk_buff **pskb,
    enum ip_conntrack_info ctinfo,
    struct ip_conntrack_expect *exp);

    #endif /* _IP_CT_TFTP */


    ==========================================================
    /usr/src/linux/net/ipv4/netfilter/ip_conntrack_netbios.c
    ==========================================================

    /*
    *
    * This program is free software; you can redistribute it and/or modify
    * it under the terms of the GNU General Public License version 2 as
    * published by the Free Software Foundation.
    *
    * Version: 0.0.2
    *
    */

    #include <linux/module.h>
    #include <linux/ip.h>
    #include <linux/udp.h>

    #include <net/udp.h>
    #include <net/tcp.h>

    #include <linux/netfilter.h>
    #include <linux/netfilter_ipv4/ip_tables.h>
    #include <linux/netfilter_ipv4/ip_conntrack_helper.h>
    #include <linux/netfilter_ipv4/ip_conntrack_netbios.h>
    #include <linux/moduleparam.h>

    MODULE_AUTHOR("Lance Wood <>");
    MODULE_DESCRIPTION("netbios connection tracking helper");
    MODULE_LICENSE("GPL");

    #define MAX_PORTS 8
    static int ports[MAX_PORTS];
    static int ports_c;

    #if 0
    #define DEBUGP(format, args...) printk("%s:%s:" format, \
    __FILE__, __FUNCTION__ , ##
    args)
    #else
    #define DEBUGP(format, args...)
    #endif

    unsigned int (*ip_nat_netbios_hook)(struct sk_buff **pskb,
    enum ip_conntrack_info ctinfo,
    struct ip_conntrack_expect *exp);
    EXPORT_SYMBOL_GPL(ip_nat_netbios_hook);

    static int netbios_help(struct sk_buff **pskb,
    struct ip_conntrack *ct,
    enum ip_conntrack_info ctinfo)
    {
    struct ip_conntrack_expect *exp;
    unsigned int ret = NF_ACCEPT;

    struct iphdr *iph = (*pskb)->nh.iph;
    struct udphdr *udph = (void *)iph + iph->ihl * 4;
    unsigned int udplen = (*pskb)->len - iph->ihl * 4;
    unsigned int datalen = udplen - sizeof(struct udphdr);
    struct netbios_hdr *nbh;

    /* deny short packets */
    if (datalen < sizeof(struct netbios_hdr))
    return NF_DROP;

    /* change addresses inside NetBIOS header */
    nbh = (struct netbios_hdr *)((char *)udph + sizeof(struct
    udphdr));
    nbh->srcip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
    nbh->srcport =
    ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.udp.port;

    /* fix checksums */
    (*pskb)->csum = csum_partial((char *)nbh, datalen, 0);
    udph->check = 0;
    udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr, udplen,
    IPPROTO_UDP, csum_partial((char
    *)udph,
    sizeof(struct udphdr),
    (*pskb)->csum));
    ip_send_check(iph);

    exp = ip_conntrack_expect_alloc(ct);
    if (exp == NULL)
    return NF_DROP;

    exp->tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
    exp->mask.src.ip = 0xffffffff;
    exp->mask.dst.ip = 0xffffffff;
    exp->mask.dst.u.udp.port = 0xffff;
    exp->mask.dst.protonum = 0xff;
    exp->expectfn = NULL;
    exp->master = ct;

    return ret;
    }

    static struct ip_conntrack_helper netbios[MAX_PORTS];
    static char netbios_names[MAX_PORTS][10];

    static void fini(void)
    {
    int i;

    for (i = 0 ; i < ports_c; i++) {
    DEBUGP("unregistering helper for port %d\n",
    ports);
    ip_conntrack_helper_unregister(&netbios);
    }
    }

    static int __init init(void)
    {
    int i, ret;
    char *tmpname;

    if (ports_c == 0)
    ports[ports_c++] = NETBIOS_PORT;

    for (i = 0; i < ports_c; i++) {
    /* Create helper structure */
    memset(&netbios, 0, sizeof(struct
    ip_conntrack_helper));

    netbios.tuple.dst.protonum = IPPROTO_UDP;
    netbios.tuple.src.u.udp.port = htons(ports);
    netbios.mask.dst.protonum = 0xFF;
    netbios.mask.src.u.udp.port = 0xFFFF;
    netbios.max_expected = 1;
    netbios.timeout = 5 * 60; /* 5 minutes */
    netbios.me = THIS_MODULE;
    netbios.help = netbios_help;

    tmpname = &netbios_names[0];
    if (ports == NETBIOS_PORT)
    sprintf(tmpname, "netbios");
    else
    sprintf(tmpname, "netbios-%d", i);
    netbios.name = tmpname;

    DEBUGP("port #%d: %d\n", i, ports);

    ret=ip_conntrack_helper_register(&netbios);
    if (ret) {
    printk("ERROR registering helper for port
    %d\n",
    ports);
    fini();
    return(ret);
    }
    }
    return(0);
    }

    module_init(init);
    module_exit(fini);



    ==========================================================
    /usr/src/linux/net/ipv4/netfilter/ip_nat_netbios.c
    ==========================================================
    /*
    * NAT module for NetBIOS datagram service, based
    * on work done by Matt Chapman <>
    */

    #include <linux/module.h>
    #include <linux/netfilter_ipv4.h>
    #include <linux/ip.h>
    #include <linux/udp.h>

    #include <linux/netfilter.h>
    #include <linux/netfilter_ipv4/ip_tables.h>
    #include <linux/netfilter_ipv4/ip_conntrack_helper.h>
    #include <linux/netfilter_ipv4/ip_conntrack_netbios.h>
    #include <linux/netfilter_ipv4/ip_nat_helper.h>
    #include <linux/netfilter_ipv4/ip_nat_rule.h>
    #include <linux/moduleparam.h>

    MODULE_DESCRIPTION("NAT helper for NetBIOS datagram service");
    MODULE_AUTHOR("Lance Wood <>");
    MODULE_LICENSE("GPL");

    static unsigned int help(struct sk_buff **pskb,
    enum ip_conntrack_info ctinfo,
    struct ip_conntrack_expect *exp)
    {


    exp->dir = IP_CT_DIR_REPLY;
    exp->expectfn = ip_nat_follow_master;
    if (ip_conntrack_expect_related(exp) != 0) {
    /* NOT NEEDED????*
    ip_conntrack_expect_free(exp);
    */
    return NF_DROP;
    }


    /* done */
    return NF_ACCEPT;

    }

    static void __exit fini(void)
    {
    ip_nat_netbios_hook = NULL;
    /* Make sure noone calls it, meanwhile. */
    synchronize_net();
    }

    static int __init init(void)
    {
    BUG_ON(ip_nat_netbios_hook);
    ip_nat_netbios_hook = help;
    return 0;
    }

    module_init(init);
    module_exit(fini);
     
    lrwood, Jan 18, 2006
    #1
    1. Advertisements

  2. lrwood

    lrwood Guest

    I was looking for a kernel module that could allow Windows clients
    behind an iptables firewall to use NAT. This allows for functions
    like domain authentication to work where under normal circumstances
    they would not because the SOURCE and DESTINATION IP addresses are
    carried in the UDP payload as well as the IP header.


    /*
    * NAT module for NetBIOS datagram service
    * This module has been tested with 2.4 and 2.6
    * kernels. It is a slight modification of the
    * version written by Matt Chapman.
    *
    * Matt Chapman <>
    */


    #include <linux/kernel.h>
    #include <linux/module.h>
    #include <linux/ip.h>
    #include <linux/udp.h>
    #include <net/tcp.h>
    #include <net/udp.h>


    #include <linux/netfilter_ipv4.h>
    #include <linux/netfilter_ipv4/ip_nat_helper.h>
    #include <linux/netfilter_ipv4/ip_conntrack.h>


    MODULE_DESCRIPTION("NAT helper for NetBIOS datagram service");
    MODULE_AUTHOR("Lance Wood");
    MODULE_LICENSE("GPL");


    /* UDP port for the datagram service */
    #define NETBIOS_PORT 138


    /* fixed part of a NetBIOS header */
    struct netbios_hdr
    {
    u_int8_t nodetype;
    u_int8_t flags;
    u_int16_t dgramid;
    u_int32_t srcip;
    u_int16_t srcport;
    u_int16_t length;
    u_int16_t offset;



    };


    /* do translation on a NetBIOS packet */

    static unsigned int netbios_nat(struct ip_conntrack *ct,
    struct ip_conntrack_expect *exp,
    struct ip_nat_info *info,
    enum ip_conntrack_info ctinfo,
    unsigned int hooknum,
    struct sk_buff **pskb)
    {
    struct iphdr *iph = (*pskb)->nh.iph;
    struct udphdr *udph = (void *)iph + iph->ihl * 4;
    unsigned int udplen = (*pskb)->len - iph->ihl * 4;
    unsigned int datalen = udplen - sizeof(struct udphdr);
    struct netbios_hdr *nbh;
    int dir;


    /* deny short packets */
    if (datalen < sizeof(struct netbios_hdr))
    return NF_DROP;


    /* only mangle things once: during POST_ROUTING in original
    direction,
    and during PRE_ROUTING in reply direction */
    dir = CTINFO2DIR(ctinfo);
    if (!((hooknum == NF_IP_POST_ROUTING && dir ==
    IP_CT_DIR_ORIGINAL)
    || (hooknum == NF_IP_PRE_ROUTING && dir ==
    IP_CT_DIR_REPLY)))
    return NF_ACCEPT;


    /* change addresses inside NetBIOS header */
    nbh = (struct netbios_hdr *)((char *)udph + sizeof(struct
    udphdr));
    nbh->srcip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
    nbh->srcport =
    ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.udp.port;


    /* fix checksums */
    (*pskb)->csum = csum_partial((char *)nbh, datalen, 0);
    udph->check = 0;
    udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr,
    udplen,
    IPPROTO_UDP,
    csum_partial((char *)udph,
    sizeof(struct udphdr),
    (*pskb)->csum));
    ip_send_check(iph);


    /* done */


    return NF_ACCEPT;



    }


    static struct ip_nat_helper ip_nat_netbios_helper;

    static void __exit fini(void)
    {
    ip_nat_helper_unregister(&ip_nat_netbios_helper);



    }


    static int __init init(void)
    {
    struct ip_nat_helper *hlpr = &ip_nat_netbios_helper;

    /*hlpr->list = { NULL, NULL };*/
    hlpr->tuple.dst.protonum = IPPROTO_UDP;
    hlpr->tuple.dst.u.udp.port = __constant_htons(NETBIOS_PORT);
    hlpr->mask.dst.protonum = 0xFFFF;
    hlpr->mask.dst.u.udp.port = 0xFFFF;
    hlpr->flags = 1;
    hlpr->me = THIS_MODULE;
    hlpr->help = netbios_nat;
    hlpr->name = "netbios";


    return ip_nat_helper_register(hlpr);



    }


    module_init(init);
    module_exit(fini);
     
    lrwood, Jan 18, 2006
    #2
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.