�Լ�д Netfilter ƥ����

ArticleCategory:

KernelCorner

AuthorImage:

Photo of Nicolas Bouliane

TranslationInfo:[Author + translation history. mailto: or http://homepage]

original in en Nicolas Bouliane

en to zh ����

AboutTheAuthor:

Nicolas �������������һ�����ᶷʿ���Դ� 1998 �����Լ��ļ�����ϰ�װ�� Linux ֮�����ͳ����ڴ��ˡ�����ʱ����о� Linux ����Э��ջ��д�������������μ� OLS �� Linux ��صĻ��顣�� Nicolas ���ڼ����ǰ��ʱ����ϲ�����ƻõ�Ӱ����������� Richard Stallman �ķ�̸.

Abstract:

iptables/netfilter ��������ǿ������������ӹ��ܡ�Ҫ���ӹ��ܣ�������Ҫ�Լ�дһ���ں�ģ�鲢��������ע�ᡣҲ����˵������Ҫ���ӵĹ��ܵķ��࣬дһ�� iptables ģ�顣ͨ��д�Զ������չģ�飬�����ƥ�䡢�޸ġ����ӱ��ϴ�ʩ������һ�������İ�����ʵ�ϣ��㼸��������������˵����������κ������������顣 ��ҪС�ģ��ں�ģ���е�һ������п��ܵ���ϵͳ���̱�����

��������ҽ�����һ����д��ƥ�����ĹǼܡ�ͨ������Ǽܣ���ϣ������������� iptables/netfilter ��ܵĽ��������������⡣����Ҽ������Ѿ��� iptables ����һ���˽Ⲣ�һ�ʹ�� C ���ԡ�

������ӽ���������θ���Դ����Ŀ�� ip ��ַ��ƥ��һ������

ArticleIllustration:

[Illustration]

ArticleBody:

����

дһ�� iptables/netfilter ƥ��ģ��Ĵ��岽�����£�

1.0 iptables ģ��

iptables �����;�����Ͻ����Ǻ��û��������������û�Ҫ���͸�����̬����IJ�����

1.1 ���õ����ݽṹ�ͺ���

������һЩ�������ݽṹ�� <iptables/include/iptables.h>
�Ժ����оͽ����Կ�����Щ�ṹ����;�ˡ�
/* Include file for additions: new matches and targets. */
struct iptables_match
{
   struct iptables_match *next;

   ipt_chainlabel name;

   const char *version;

   /* Size of match data. */
   size_t size;

   /* Size of match data relevent for userspace comparison purposes */
   size_t userspacesize;

   /* Function which prints out usage message. */
   void (*help)(void);

   /* Initialize the match. */
   void (*init)(struct ipt_entry_match *m, unsigned int *nfcache);

   /* Function which parses command options; returns true if it
           ate an option */
   int (*parse)(int c, char **argv, int invert, unsigned int *flags,
           const struct ipt_entry *entry,
           unsigned int *nfcache,
           struct ipt_entry_match **match);

   /* Final check; exit if not ok. */
   void (*final_check)(unsigned int flags);

   /* Prints out the match iff non-NULL: put space at end */
   void (*print)(const struct ipt_ip *ip,
            const struct ipt_entry_match *match, int numeric);

   /* Saves the match info in parsable form to stdout. */
   void (*save)(const struct ipt_ip *ip,
           const struct ipt_entry_match *match);

   /* Pointer to list of extra command-line options */
   const struct option *extra_opts;

   /* Ignore these men behind the curtain: */
   unsigned int option_offset;
   struct ipt_entry_match *m;
   unsigned int mflags;
#ifdef NO_SHARED_LIBS
   unsigned int loaded; /* simulate loading so options are merged properly */
#endif
};

1.2 ����Ǽܳ���

1.2.1 ��ʼ��

�������ȳ�ʼ�� 'iptables_match' �ṹ�еij����ֶΣ�
static struct iptables_match ipaddr
= {
'Name' ����ĺ�������ļ�����Ҳ���� libipt_ipaddr����
�㲻�������λ�÷������Ķ��������������Զ�������Ŀ�ġ�
    .name            = "ipaddr",
��һ���ֶ� 'version' �� iptables �İ汾������������ֶζ������ڱ����û�̬����ͺ���̬�����ṹ�Ĵ�Сһ���Եġ�
    .version         = IPTABLES_VERSION,
    .size            = IPT_ALIGN(sizeof(struct ipt_ipaddr_info)),
    .userspacesize   = IPT_ALIGN(sizeof(struct ipt_ipaddr_info)),
'Help' ���û����� 'iptables -m module -h' ��ʱ��Ҫ���õĺ�����'Parse' ���û�����һ���¹����ʱ����õģ�������֤�����ĺϷ��ԡ�'print' ����ʹ�� 'iptables -L' ��ʱ����ʾǰ�����ӵĹ���ġ�
    .help            = &help,
    .init            = &init,
    .parse           = &parse,
    .final_check     = &final_check,
    .print           = &print,
    .save            = &save,
    .extra_opts      = opts
};
iptables �ܹ��ܹ�֧�ֶ�������⡣ÿ�����������ʹ�� <iptables/iptables.c> �ж���� 'register_match()' �� iptables ע�ᡣ�����������ģ�鱻 iptables ���ص�ʱ����á� ������Ϣ��ο�:'man dlopen'��
void _init(void)
{
   register_match(&ipaddr);
}

1.2.2 save ����

���������һ����Ҫ����Ĺ��򼯣��������� iptables �ṩ�Ĺ��� 'iptables-save'�������Ա��������еĹ�����Ȼ����Ҫ��չ�������������������Щ���������չͨ�� save ������ɡ�
static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
{
   const struct ipt_ipaddr_info *info = (const struct ipt_ipaddr_info *)match->data;
���Դ��ַ�ǹ����һ���ֵĻ�����ӡ����
   if (info->flags & IPADDR_SRC) {
      if (info->flags & IPADDR_SRC_INV)
         printf("! ");
      printf("--ipsrc ");
      print_ipaddr((u_int32_t *)&info->ipaddr.src);
   }
���Ŀ�ĵ�ַ�ǹ����һ���ֵĻ��ʹ�ӡĿ�ĵ�ַ��
   if (info->flags & IPADDR_DST) {
      if (info->flags & IPADDR_DST_INV)
         printf("! ");
      printf("--ipdst ");
      print_ipaddr((u_int32_t *)&info->ipaddr.dst);
   }
}

1.2.3 print ����

������� save ���̺�����ѧһ����Ҳ��һ�� print �������ڴ�ӡ�������� 'iptables -L' ��ʱ�򱻵��á����ǽ��������￴������ 'ipt_entry_match *match' ����;�����������Ѿ���������һ������ˣ��ǰɣ�
static void print(const struct ipt_ip *ip,
                  const struct ipt_entry_match *match,
                  int numeric)
{
   const struct ipt_ipaddr_info *info = (const struct ipt_ipaddr_info *)match->data;

   if (info->flags & IPADDR_SRC) {
         printf("src IP ");
      if (info->flags & IPADDR_SRC_INV)
         printf("! ");
      print_ipaddr((u_int32_t *)&info->ipaddr.src);
   }

   if (info->flags & IPADDR_DST) {
      printf("dst IP ");
      if (info->flags & IPADDR_DST_INV)
         printf("! ");
      print_ipaddr((u_int32_t *)&info->ipaddr.dst);
   }
}

1.2.4 final check ����

������������һ����ȷ�Լ��Ļ��ᡣ�����û����������֮�󡢲��������ո���ɵ�ʱ�򱻵��á�
static void final_check(unsigned int flags)
{
   if (!flags)
      exit_error(PARAMETER_PROBLEM, "ipt_ipaddr: Invalid parameters.");
}

1.2.5 parse ����

parse ������Ҫ��һ����������Ϊ����Ҫ����������ȷ�ԣ���д�����ǽ�����������̬�������Ϣ������ÿ�β��������ֵ�ʱ�򱻵��ã�Ҳ����˵������û�������������������������ͽ����Բ�ͬ�IJ������� c �������Ρ�
static int parse(int c, char **argv, int invert, unsigned int *flags,
                 const struct ipt_entry *entry,
                 unsigned int *nfcache,
                 struct ipt_entry_match **match)
{
����ʹ������ṹ����������Ҫ���ݸ�����̬�������Ϣ��'match' ָ�뱻���ݸ�������������ǿ���ÿ��ʹ��ͬ�������ݽṹ��һ�����򱻼����ˣ����ָ��ͱ����Ƶ��˺���̬�����ͨ�������ʽ���ں�ģ�����֪���û���Ҫ����ʲô������������Ĺؼ�������ô?����
   struct ipt_ipaddr_info *info = (struct ipt_ipaddr_info *)(*match)->data;
ÿ��������Ӧ��һ��������ֵ�����������ܸ��ݽ���IJ���������ȡ�����ж������������ǽ�����������ΰѲ��������ֵ��
   switch(c) {
���ȣ����Ǽ������Ƿ�ʹ���˶�Ρ����ʹ���˶�εĻ������� <iptables/iptables.c> �ж���� 'exit_error()' ������������������̴��� <iptables/include/iptables_common.h> �ж���� 'PARAMETER_PROBLEM' �Ĵ���״̬�Ƴ����������������ǵ�ͷ�ļ��ж���� 'IPADDR_SRC' ������ 'flags' �� 'info->flags'���Ժ����ǽ��������ͷ�ļ���

��Ȼ��������־��������࣬��������ȫ��ͬ�ġ�'flag' ���������������������� 'info->flags' ���������ںͺ���̬��������Ϣ�Ľṹ��һ���֡�
      case '1':
         if (*flags & IPADDR_SRC)
            exit_error(PARAMETER_PROBLEM, "ipt_ipaddr: Only use --ipsrc once!");
         *flags |= IPADDR_SRC;
         info->flags |= IPADDR_SRC;
������ȡ����־ '!' �Ƿ���ڣ�����еĻ����� 'info->flags' ��д��Ӧ��ֵ��
֮�����Ϊ����Ǽܳ�����д���ڲ����� 'parse_ipaddr' ���� IP ��ַ���ַ���ת��Ϊ 32 λֵ��
         if (invert)
            info->flags |= IPADDR_SRC_INV;

         parse_ipaddr(argv[optind-1], &info->ipaddr.src);
         break;
ͬ�����ǣ����Ǽ���Ƿ���ڶ�����ã���ǡ���ı�־��
      case '2':
         if (*flags & IPADDR_DST)
            exit_error(PARAMETER_PROBLEM, "ipt_ipaddr: Only use --ipdst once!");
         *flags |= IPADDR_DST;
         info->flags |= IPADDR_DST;
         if (invert)
            info->flags |= IPADDR_DST_INV;

         parse_ipaddr(argv[optind-1], &info->ipaddr.dst);
         break;

      default:
         return 0;
   }

   return 1;
}

1.2.6 options �ṹ

ǰ���У������Ѿ�̸����Ҫ��ÿ������ӳ�䵽һ��ֵ�� 'struct option' ����һ���ﵽ���Ŀ�ĵĺð취��Ҫ��õ���������ṹ�Ľ�һ����Ϣ��ǿ�ҽ����Ķ� 'man 3 getopt'��
static struct option opts[] = {
   { .name = "ipsrc",   .has_arg = 1,   .flag = 0,   .val = '1' },
   { .name = "ipdst",   .has_arg = 1,   .flag = 0,   .val = '2' },
   { .name = 0 }
};

1.2.7 init ����

init �������ڳ�ʼ��һЩ�ض��Ķ��������� netfilter �� cache ϵͳ�����ڲ��ع��࿼����������ľ�����;��
static void init(struct ipt_entry_match *m, unsigned int *nfcache)
{
   /* Can't cache this */
   *nfcache |= NFC_UNKNOWN;
}

1.2.7 help ����

�������ͨ�� 'iptables -m match_name -h' �����ã�������ʾ���õIJ�����
static void help(void)
{
   printf (
            "IPADDR v%s options:\n"
            "[!] --ipsrc \t\t The incoming ip addr matches.\n"
            "[!] --ipdst \t\t The outgoing ip addr matches.\n"
            "\n", IPTABLES_VERSION
         );
}

1.2.8 ͷ�ļ� 'ipt_ipaddr.h'

����ļ�������������Ҫ��һЩ������
#ifndef _IPT_IPADDR_H
#define _IPT_IPADDR_H
�����Ѿ���������ʹ������Щ�ض���ֵ�ˡ�
#define IPADDR_SRC   0x01     /* Match source IP addr */
#define IPADDR_DST   0x02     /* Match destination IP addr */

#define IPADDR_SRC_INV  0x10  /* Negate the condition */
#define IPADDR_DST_INV  0x20  /* Negate the condition */
�ṹ 'ipt_ipaddr_info' �ǽ�Ҫ������������̬������Ǹ����ݽṹ��
struct ipt_ipaddr {
   u_int32_t src, dst;
};

struct ipt_ipaddr_info {

   struct ipt_ipaddr ipaddr;
   
   /* Flags from above */
   u_int8_t flags;
   
};

#endif  

1.3 ��һ��С��

��һ�����У����������� iptables ������á����Ǽ�����ÿ�����������ݺ� 'ipt_ipaddr_info' ������ڱ�����Ϣ�Ľ�Ҫ������������̬����������һ����������Ҫ�ṹ������Ҳ������ iptables �ṹ�����ע��һ���µĿ⡣
Ӧ��ע�⣬�������һ��������ʾ�����ι����ĹǼܳ��򡣶��ң�'ipt_ipaddr_info' ���������ƵĶ��������� iptables/netfilter ��һ���֣���������������ӵ�һ���֡�

2.0 netfilter ģ��

һ��ƥ��ģ��Ĺ������Dz쿴ÿһ���յ��İ��������Ƿ����ij���о�׼�����ģ��Ҫ�����¹�����

2.1 ���õĺ��������ݽṹ

������һЩ�������ݽṹ����Щ���ݽṹ������ <linux/netfilter_ipv4/ip_tables.h>��
����������ṹ�Լ�ǰ��� iptables ���ֻ�����Ȥ�Ļ�������Կ��� Rusty Russell �� Harald Welte д�� netfilter hacking howto ��
struct ipt_match
{
   struct list_head list;

   const char name[IPT_FUNCTION_MAXNAMELEN];

   /* Return true or false: return FALSE and set *hotdrop = 1 to
           force immediate packet drop. */
   /* Arguments changed since 2.4, as this must now handle
           non-linear skbs, using skb_copy_bits and
           skb_ip_make_writable. */
   int (*match)(const struct sk_buff *skb,
           const struct net_device *in,
           const struct net_device *out,
           const void *matchinfo,
           int offset,
           int *hotdrop);

   /* Called when user tries to insert an entry of this type. */
   /* Should return true or false. */
   int (*checkentry)(const char *tablename,
           const struct ipt_ip *ip,
           void *matchinfo,
           unsigned int matchinfosize,
           unsigned int hook_mask);

   /* Called when entry of this type deleted. */
   void (*destroy)(void *matchinfo, unsigned int matchinfosize);

   /* Set this to THIS_MODULE. */
   struct module *me;
};

2.2 ����Ǽܳ���

2.2.1 ��ʼ��

����,���dz�ʼ�� 'ipt_match' ���ݽṹ�еij�����

static struct ipt_match ipaddr_match
= { 
'name' �����ģ����ļ����ַ���(Ҳ����˵ ipt_ipaddr)��
	.name       = "ipaddr",
������ֶ��ǿ�ܽ�Ҫʹ�õĻص�����.'match'�ǵ�һ�������͸����ģ���ʱ��Ҫ���õĺ���.
	.match      = match,
	.checkentry = checkentry,
	.me         = THIS_MODULE,
};
����ں�ģ��� init ������Ҫͨ��ָ��һ�� 'struct ipt_match' ��ָ����� 'ipt_register_match()' ���� netfilter ���ע��.���������ģ�鱻���ص�ʱ�����.
static int __init init(void)
{
	printk(KERN_INFO "ipt_ipaddr: init!\n");
	return ipt_register_match(&ipaddr_match);
}
����ģ����ں����Ƴ���ʱ����������ᱻ����.�������ǽ��еĹ�����ע��ƥ������
static void __exit fini(void)
{
	printk(KERN_INFO "ipt_ipaddr: exit!\n");
	ipt_unregister_match(&ipaddr_match);
}
������������������ģ��װ����Ƴ���ʱ�򱻵��á�
module_init(init);
module_exit(fini);

2.2.2 match ����

Linux �� TCP/IP Э��ջ����5�� netfilter ���ӡ�������һ��������֮��Э��ջ�Ѱ��͵���Ӧ�Ĺ��ӣ����ν���ÿ�����������ε���ÿ�����򡣵����ģ��õ�����ʱ�����ģ��Ϳ��Խ������Ĺ����ˡ�
static int match(const struct sk_buff *skb,
                 const struct net_device *in,
                 const struct net_device *out,
                 const void *matchinfo,
                 int offset,
                 const void *hdr,
                 u_int16_t datalen,
                 int *hotdrop)
{
ϣ���㻹�����������û�̬������������Щʲô�� :)�����ڰ��û�̬���򿽱����������ݽṹӳ�䵽��������
	const struct ipt_skeleton_info *info = matchinfo;
'skb' ������������Ҫ�����İ�����Ҫ�õ���������� linux �� TCP/IP Э��ջ�е������ǹ���ǿ������ݽṹ����Ϣ�����Կ��� Harald Welte д��һ��ɫ������ article (ftp://ftp.gnumonks.org/pub/doc/skb-doc.html) ��
   struct iphdr *iph = skb->nh.iph;
������Ǿ��Ǵ�ӡһЩ��Ȥ�Ķ������������dz���ʲô���ӡ��� 'NIPQUAD' �����Կɶ��ķ�ʽ��ʾһ�� IP ��ַ�������� <linux/include/linux/kernel.h> �ж���ġ�
   printk(KERN_INFO "ipt_ipaddr: IN=%s OUT=%s TOS=0x%02X "
                    "TTL=%x SRC=%u.%u.%u.%u DST=%u.%u.%u.%u "
                    "ID=%u IPSRC=%u.%u.%u.%u IPDST=%u.%u.%u.%u\n",

                    in ? (char *)in : "", out ? (char *)out : "", iph->tos,
                    iph->ttl, NIPQUAD(iph->saddr), NIPQUAD(iph->daddr),
                    ntohs(iph->id), NIPQUAD(info->ipaddr.src), NIPQUAD(info->ipaddr.dst)
         );
��������� '--ipsrc' ���������Dz쿴Դ��ַ�Ƿ�͹���ָ���ĵ�ַ��ƥ�䡣�����˿��Ƿ���־ '!'�����û��ƥ�䣬���Ƿ��� 0.
   if (info->flags & IPADDR_SRC) {
      if ( (ntohl(iph->saddr) != ntohl(info->ipaddr.src)) ^ !!(info->flags & IPADDR_SRC_INV) ) {
         
         printk(KERN_NOTICE "src IP %u.%u.%u.%u is not matching %s.\n",
                            NIPQUAD(info->ipaddr.src),
                            info->flags & IPADDR_SRC_INV ? " (INV)" : "");
         return 0;
      }
   }
������ǽ�����ȫ��ͬ�Ĺ�����ֻ�Dz쿴 '--ipdst' ������
   if (info->flags & IPADDR_DST) {
      if ( (ntohl(iph->daddr) != ntohl(info->ipaddr.dst)) ^ !!(info->flags & IPADDR_DST_INV) )  {

         printk(KERN_NOTICE "dst IP %u.%u.%u.%u is not matching%s.\n",
                            NIPQUAD(info->ipaddr.dst),
                            info->flags & IPADDR_DST_INV ? " (INV)" : "");
         return 0;
      }
   }
��������ɹ������� 1����������ƥ�����������
   return 1;
}

2.2.3 checkentry ����

checkentry ͨ�������һ�κϷ��Լ��Ļ��ᡣ��������ʱ��������Щ�������⡣���� post (http://www.mail-archive.com/[email protected]/msg00625.html) ��Ϊһ�����Ͱɡ���ƪ����Ҳ��һƪ netfilter hacking howto��
static int checkentry(const char *tablename,
                             const struct ipt_ip *ip,
                             void *matchinfo,
                             unsigned int matchsize,
                             unsigned int hook_mask)
{   
   const struct ipt_skeleton_info *info = matchinfo;

   if (matchsize != IPT_ALIGN(sizeof(struct ipt_skeleton_info))) {
      printk(KERN_ERR "ipt_skeleton: matchsize differ, you may have forgotten to recompile me.\n");
      return 0;
   }

   printk(KERN_INFO "ipt_skeleton: Registered in the %s table, hook=%x, proto=%u\n",
                    tablename, hook_mask, ip->proto);

   return 1;
}

2.3 �ڶ���С��

�ڵڶ����֣����ǽ��� netfilter ģ���Լ����ʹ���ض��ṹע�������������ǻ���������θ����û��ռ䲿�ָ������о�ƥ���ض��������

3.0 ���� iptables/netfilter

�����Ѿ����������дһ���µ� iptables/netfilter ƥ��ģ�顣�������ǽ��������ӵ��ں�����������������Ҽ�����֪����α����ںˡ����ȰѹǼ�ƥ���ļ�����������ҳ������������

3.1 iptables

���ڣ�����㻹û�� iptables ��Դ����Ļ������Դ� ftp://ftp.netfilter.org/pub/iptables/ ���ء�Ȼ�󿽱� 'libipt_ipaddr.c' �� <iptables/extensions/>��

���� <iptables/extensions/Makefile> �е�һ�У���Ӧ�ü��� 'ipaddr'��
PF_EXT_SLIB:=ah addrtype comment connlimit connmark conntrack dscp ecn
esp hashlimit helper icmp iprange length limit ipaddr mac mark
multiport owner physdev pkttype realm rpc sctp standard state tcp tcpmss
tos ttl udp unclean CLASSIFY CONNMARK DNAT DSCP ECN LOG MARK MASQUERADE
MIRROR NETMAP NOTRACK REDIRECT REJECT SAME SNAT TARPIT TCPMSS TOS TRACE
TTL ULOG

3.2 �ں�

���ȣ���Ӧ�ÿ��� 'ipt_ipaddr.c' �� <linux/net/ipv4/netfilter/>������ ' ipt_ipaddr.h' �� <linux/net/ipv4/netfilter/>����Щ���߿��ܻ���ʹ�� 2.4 �ںˣ�������ͬʱ�ṩ�� 2.4�� 2.6 ���ļ���

���� 2.4 �ںˣ��༭ <linux/net/ipv4/netfilter/Config.in> ������������ص��С�
# The simple matches.
  dep_tristate '  limit match support' CONFIG_IP_NF_MATCH_LIMIT $CONFIG_IP_NF_IPTABLES
  dep_tristate '  ipaddr match support' CONFIG_IP_NF_MATCH_IPADDR $CONFIG_IP_NF_IPTABLES
Ȼ�󣬱༭ <linux/Documentation/Configure.help> ������ص��С��Ҹ�����һЩ�ı����������ҵ�Ҫ�������ݵĵط���
limit match support
CONFIG_IP_NF_MATCH_LIMIT
  limit matching allows you to control the rate at which a rule can be
  ...
ipaddr match support
CONFIG_IP_NF_MATCH_IPADDR
  ipaddr matching. etc etc.
��������Ѽ��ص��м��뵽 <linux/net/ipv4/netfilter/Makefile> ֮�С�
# matches
obj-$(CONFIG_IP_NF_MATCH_HELPER) += ipt_helper.o
obj-$(CONFIG_IP_NF_MATCH_LIMIT) += ipt_limit.o
obj-$(CONFIG_IP_NF_MATCH_IPADDR) += ipt_ipaddr.o
Now for 2.6, files to edit are <linux/net/ipv4/netfilter/Kconfig> and <linux/net/ipv4/netfilter/Makefile>. �� 2.6 �ںˣ��༭���ļ�Ӧ���� <linux/net/ipv4/netfilter/Kconfig>�� <linux/net/ipv4/netfilter/Makefile>��

�ܽ�

����ʣ�µĵľ��Ǵ��±����Լ�������˵���ˡ�
Happy hacking!!
��л Samuel Jean.