NetBIOS with NAT using iptables helper module

Discussion in 'Linux Networking' started by Lance, Nov 22, 2004.

  1. Lance

    Lance 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);
     
    Lance, Nov 22, 2004
    #1
    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.