这个文件是2.4防火墙总处理程序的头文件。主要是向内核其他部分、应用程序提供接口。我将结合源文件一一说明。
#ifndef __LINUX_NETFILTER_H
#define __LINUX_NETFILTER_H
#ifdef __KERNEL__
#include
#include
#include
#include
#include
#include
#include
#endif
以下几个值是向内核提供的接口函数的返回值,也就是在ip_input.c ip_forward.c ip_output.c所调用宏调用的处理函数的返回值。
/* Responses from hook functions. */
#define NF_DROP 0 表示分组将要被丢弃,并且不返回ICMP信息
#define NF_ACCEPT 1 表示分组被接受
#define NF_STOLEN 2 表示异常分组
#define NF_QUEUE 3 表示分组将要提交给用户进程
#define NF_REPEAT 4 表示分组将要被继续处理
#define NF_MAX_VERDICT NF_REPEAT
/* Generic cache responses from hook functions. */
#define NFC_ALTERED 0x8000
#define NFC_UNKNOWN 0x4000
#ifdef __KERNEL__
#include
#ifdef CONFIG_NETFILTER
extern void netfilter_init(void);
/* Largest hook number + 1 */
#define NF_MAX_HOOKS 8
struct sk_buff; 向前声明结构
struct net_device;
声明hook函数类型
typedef unsigned int nf_hookfn(unsigned int hooknum,
struct sk_buff **skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *));
向内核提供的防火墙接口
struct nf_hook_ops
{
struct list_head list; 将多个接口函数组成链表
/* User fills in from here down. */
nf_hookfn *hook; hook函数指针,指向防火墙处理函数,它的返回值就是上面说明的值
int pf; 协议值,表示这个接口属于那个协议族
int hooknum;表示这个接口属于哪个HOOK LOCAL_INPUT、 LOCAL_OUT FORWARD、PREROUTING 还是 AFTERROUTING
/* Hooks are ordered in ascending priority. */
int priority; 接口的优先级
};
向用户进程提供的放火墙接口,用户进程通过这个接口设置规则。
struct nf_sockopt_ops
{
struct list_head list; 同上
int pf; 同上
当调用setsockopt和getsockopt系统调用时,用户通常给定命令常数。下面的范围就是给定命令常数的范围。这里要设置范围主要是因为ip_tables 和ipchains处理的命令常数的范围不同。
/* Non-inclusive ranges: use 0/0/NULL to never get called. */
int set_optmin;
int set_optmax;
int (*set)(struct sock *sk, int optval, void *user, unsigned int len);
int get_optmin;
int get_optmax;
int (*get)(struct sock *sk, int optval, void *user, int *len);
/* Number of users inside set() or get(). */
unsigned int use;指示当前有几个进程在使用该模块
struct task_struct *cleanup_task;这指针指向想要释放该接口的进程。如果有进程正在使用该接口,那么当前进程将被阻塞。最后当使用接口的进程使用完毕时,它通过该指针唤醒本进程,最终释放这个结构。
};
如注释所述,它主要是附加到每一个提交给用户进程的IP分组上(skbuff是报文的载体)
/* Each queued (to userspace) skbuff has one of these. */
struct nf_info
{
/* The ops struct which sent us to userspace. */
struct nf_hook_ops *elem;
/* If we're sent to userspace, this keeps housekeeping info */
int pf;
unsigned int hook;
struct net_device *indev, *outdev;
int (*okfn)(struct sk_buff *);
};
下面两个函数是提供给各个放火墙模块的HOOK注册函数。它实质上是为了建立内核与防火墙的接口链表,当用有分组达到是可以沿着链表一一处理
/* Function to register/unregister hook points. */
int nf_register_hook(struct nf_hook_ops *reg);
void nf_unregister_hook(struct nf_hook_ops *reg);
这是提供给各个防火墙模块的,用来设置处理用户进程set/getsockopt系统调用的注册函数。它将建立一个处理链表,当用户发出set/getsockopt系统调用时,由内核根据命令常数的范围判断防火墙内核的响应处理函数
/* Functions to register get/setsockopt ranges (non-inclusive). You
need to check permissions yourself! */
int nf_register_sockopt(struct nf_sockopt_ops *reg);
void nf_unregister_sockopt(struct nf_sockopt_ops *reg);
extern struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS]; HOOK链表
/* Activate hook; either okfn or kfree_skb called, unless a hook
returns NF_STOLEN (in which case, it's up to the hook to deal with
the consequences).
Returns -ERRNO if packet dropped. Zero means queued, stolen or
accepted.
*/
/* RR:
> I don't want nf_hook to return anything because people might forget
> about async and trust the return value to mean "packet was ok".
AK:
Just document it clearly, then you can expect some sense from kernel
coders :)
*/
/* This is gross, but inline doesn't cut it for avoiding the function
call in fast path: gcc doesn't inline (needs value tracking?). --RR */
下面这个宏就是提供给网络内核的接口宏。我们先看看它的参数。pf是指地址族,因为netfilter不光可以处理AF_INET还可以处理其它 协议,而HOOK是根据协议族分类的。hook指示五个HOOK中的哪一个规则链来处理调用该宏的分组。indev和outdev分别指示进入的网络接口 和发送的网络接口。okfn是指当防火墙处理完后,继续处理分组的网络内核函数,而不是防火墙模块的函数。从宏定义可以看出,当具体的地址族的具体 HOOK的规则连为空时,直接将分组控制权交给okfn,否则调用nf_hook_slow(),这个函数进一步调用hook函数处理链中的处理函数,别 忘了,前面我已经说过注册函数已经建立这个处理链表。最后将控制权交给okfn。
#ifdef CONFIG_NETFILTER_DEBUG
#define NF_HOOK nf_hook_slow
#else
#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) \
(list_empty(&nf_hooks[(pf)][(hook)]) \
? (okfn)(skb) \
: nf_hook_slow((pf), (hook), (skb), (indev), (outdev), (okfn)))
#endif
int nf_hook_slow(int pf, unsigned int hook, struct sk_buff *skb,
struct net_device *indev, struct net_device *outdev,
int (*okfn)(struct sk_buff *));
防火墙netfilter中的对应于系统调用(s)getsockopt的处理函数。
/* Call setsockopt() */
int nf_setsockopt(struct sock *sk, int pf, int optval, char *opt,
int len);
int nf_getsockopt(struct sock *sk, int pf, int optval, char *opt,
int *len);
/* Packet queuing */
用于处理递交给用户进程的分组的注册函数和处理函数
typedef int (*nf_queue_outfn_t)(struct sk_buff *skb,
struct nf_info *info, void *data);
extern int nf_register_queue_handler(int pf,
nf_queue_outfn_t outfn, void *data);
extern int nf_unregister_queue_handler(int pf);
extern void nf_reinject(struct sk_buff *skb,
struct nf_info *info,
unsigned int verdict);
以下的定义容易理解,这里不在说明
#ifdef CONFIG_NETFILTER_DEBUG
extern void nf_dump_skb(int pf, struct sk_buff *skb);
#endif
/* FIXME: Before cache is ever used, this must be implemented for real. */
extern void nf_invalidate_cache(int pf);
#else /* !CONFIG_NETFILTER */
#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) (okfn)(skb)
#endif /*CONFIG_NETFILTER*/
/* From arch/i386/kernel/smp.c:
*
* Why isn't this somewhere standard ??
*
* Maybe because this procedure is horribly buggy, and does
* not deserve to live. Think about signedness issues for five
* seconds to see why. - Linus
*/
/* Two signed, return a signed. */
#define SMAX(a,b) ((ssize_t)(a)>(ssize_t)(b) ? (ssize_t)(a) : (ssize_t)(b))
#define SMIN(a,b) ((ssize_t)(a)<(ssize_t)(b) ? (ssize_t)(a) : (ssize_t)(b))
/* Two unsigned, return an unsigned. */
#define UMAX(a,b) ((size_t)(a)>(size_t)(b) ? (size_t)(a) : (size_t)(b))
#define UMIN(a,b) ((size_t)(a)<(size_t)(b) ? (size_t)(a) : (size_t)(b))
/* Two unsigned, return a signed. */
#define SUMAX(a,b) ((size_t)(a)>(size_t)(b) ? (ssize_t)(a) : (ssize_t)(b))
#define SUMIN(a,b) ((size_t)(a)<(size_t)(b) ? (ssize_t)(a) : (ssize_t)(b))
#endif /*__KERNEL__*/
#endif /*__LINUX_NETFILTER_H*/
好了,现在我已经介绍完了netfilter的头文件,下一次我将来分析netfilter.c。进一步介绍这些变量、函数、结构将如何使用。
#ifndef __LINUX_NETFILTER_H
#define __LINUX_NETFILTER_H
#ifdef __KERNEL__
#include
#include
#include
#include
#include
#include
#include
#endif
以下几个值是向内核提供的接口函数的返回值,也就是在ip_input.c ip_forward.c ip_output.c所调用宏调用的处理函数的返回值。
/* Responses from hook functions. */
#define NF_DROP 0 表示分组将要被丢弃,并且不返回ICMP信息
#define NF_ACCEPT 1 表示分组被接受
#define NF_STOLEN 2 表示异常分组
#define NF_QUEUE 3 表示分组将要提交给用户进程
#define NF_REPEAT 4 表示分组将要被继续处理
#define NF_MAX_VERDICT NF_REPEAT
/* Generic cache responses from hook functions. */
#define NFC_ALTERED 0x8000
#define NFC_UNKNOWN 0x4000
#ifdef __KERNEL__
#include
#ifdef CONFIG_NETFILTER
extern void netfilter_init(void);
/* Largest hook number + 1 */
#define NF_MAX_HOOKS 8
struct sk_buff; 向前声明结构
struct net_device;
声明hook函数类型
typedef unsigned int nf_hookfn(unsigned int hooknum,
struct sk_buff **skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *));
向内核提供的防火墙接口
struct nf_hook_ops
{
struct list_head list; 将多个接口函数组成链表
/* User fills in from here down. */
nf_hookfn *hook; hook函数指针,指向防火墙处理函数,它的返回值就是上面说明的值
int pf; 协议值,表示这个接口属于那个协议族
int hooknum;表示这个接口属于哪个HOOK LOCAL_INPUT、 LOCAL_OUT FORWARD、PREROUTING 还是 AFTERROUTING
/* Hooks are ordered in ascending priority. */
int priority; 接口的优先级
};
向用户进程提供的放火墙接口,用户进程通过这个接口设置规则。
struct nf_sockopt_ops
{
struct list_head list; 同上
int pf; 同上
当调用setsockopt和getsockopt系统调用时,用户通常给定命令常数。下面的范围就是给定命令常数的范围。这里要设置范围主要是因为ip_tables 和ipchains处理的命令常数的范围不同。
/* Non-inclusive ranges: use 0/0/NULL to never get called. */
int set_optmin;
int set_optmax;
int (*set)(struct sock *sk, int optval, void *user, unsigned int len);
int get_optmin;
int get_optmax;
int (*get)(struct sock *sk, int optval, void *user, int *len);
/* Number of users inside set() or get(). */
unsigned int use;指示当前有几个进程在使用该模块
struct task_struct *cleanup_task;这指针指向想要释放该接口的进程。如果有进程正在使用该接口,那么当前进程将被阻塞。最后当使用接口的进程使用完毕时,它通过该指针唤醒本进程,最终释放这个结构。
};
如注释所述,它主要是附加到每一个提交给用户进程的IP分组上(skbuff是报文的载体)
/* Each queued (to userspace) skbuff has one of these. */
struct nf_info
{
/* The ops struct which sent us to userspace. */
struct nf_hook_ops *elem;
/* If we're sent to userspace, this keeps housekeeping info */
int pf;
unsigned int hook;
struct net_device *indev, *outdev;
int (*okfn)(struct sk_buff *);
};
下面两个函数是提供给各个放火墙模块的HOOK注册函数。它实质上是为了建立内核与防火墙的接口链表,当用有分组达到是可以沿着链表一一处理
/* Function to register/unregister hook points. */
int nf_register_hook(struct nf_hook_ops *reg);
void nf_unregister_hook(struct nf_hook_ops *reg);
这是提供给各个防火墙模块的,用来设置处理用户进程set/getsockopt系统调用的注册函数。它将建立一个处理链表,当用户发出set/getsockopt系统调用时,由内核根据命令常数的范围判断防火墙内核的响应处理函数
/* Functions to register get/setsockopt ranges (non-inclusive). You
need to check permissions yourself! */
int nf_register_sockopt(struct nf_sockopt_ops *reg);
void nf_unregister_sockopt(struct nf_sockopt_ops *reg);
extern struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS]; HOOK链表
/* Activate hook; either okfn or kfree_skb called, unless a hook
returns NF_STOLEN (in which case, it's up to the hook to deal with
the consequences).
Returns -ERRNO if packet dropped. Zero means queued, stolen or
accepted.
*/
/* RR:
> I don't want nf_hook to return anything because people might forget
> about async and trust the return value to mean "packet was ok".
AK:
Just document it clearly, then you can expect some sense from kernel
coders :)
*/
/* This is gross, but inline doesn't cut it for avoiding the function
call in fast path: gcc doesn't inline (needs value tracking?). --RR */
下面这个宏就是提供给网络内核的接口宏。我们先看看它的参数。pf是指地址族,因为netfilter不光可以处理AF_INET还可以处理其它 协议,而HOOK是根据协议族分类的。hook指示五个HOOK中的哪一个规则链来处理调用该宏的分组。indev和outdev分别指示进入的网络接口 和发送的网络接口。okfn是指当防火墙处理完后,继续处理分组的网络内核函数,而不是防火墙模块的函数。从宏定义可以看出,当具体的地址族的具体 HOOK的规则连为空时,直接将分组控制权交给okfn,否则调用nf_hook_slow(),这个函数进一步调用hook函数处理链中的处理函数,别 忘了,前面我已经说过注册函数已经建立这个处理链表。最后将控制权交给okfn。
#ifdef CONFIG_NETFILTER_DEBUG
#define NF_HOOK nf_hook_slow
#else
#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) \
(list_empty(&nf_hooks[(pf)][(hook)]) \
? (okfn)(skb) \
: nf_hook_slow((pf), (hook), (skb), (indev), (outdev), (okfn)))
#endif
int nf_hook_slow(int pf, unsigned int hook, struct sk_buff *skb,
struct net_device *indev, struct net_device *outdev,
int (*okfn)(struct sk_buff *));
防火墙netfilter中的对应于系统调用(s)getsockopt的处理函数。
/* Call setsockopt() */
int nf_setsockopt(struct sock *sk, int pf, int optval, char *opt,
int len);
int nf_getsockopt(struct sock *sk, int pf, int optval, char *opt,
int *len);
/* Packet queuing */
用于处理递交给用户进程的分组的注册函数和处理函数
typedef int (*nf_queue_outfn_t)(struct sk_buff *skb,
struct nf_info *info, void *data);
extern int nf_register_queue_handler(int pf,
nf_queue_outfn_t outfn, void *data);
extern int nf_unregister_queue_handler(int pf);
extern void nf_reinject(struct sk_buff *skb,
struct nf_info *info,
unsigned int verdict);
以下的定义容易理解,这里不在说明
#ifdef CONFIG_NETFILTER_DEBUG
extern void nf_dump_skb(int pf, struct sk_buff *skb);
#endif
/* FIXME: Before cache is ever used, this must be implemented for real. */
extern void nf_invalidate_cache(int pf);
#else /* !CONFIG_NETFILTER */
#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) (okfn)(skb)
#endif /*CONFIG_NETFILTER*/
/* From arch/i386/kernel/smp.c:
*
* Why isn't this somewhere standard ??
*
* Maybe because this procedure is horribly buggy, and does
* not deserve to live. Think about signedness issues for five
* seconds to see why. - Linus
*/
/* Two signed, return a signed. */
#define SMAX(a,b) ((ssize_t)(a)>(ssize_t)(b) ? (ssize_t)(a) : (ssize_t)(b))
#define SMIN(a,b) ((ssize_t)(a)<(ssize_t)(b) ? (ssize_t)(a) : (ssize_t)(b))
/* Two unsigned, return an unsigned. */
#define UMAX(a,b) ((size_t)(a)>(size_t)(b) ? (size_t)(a) : (size_t)(b))
#define UMIN(a,b) ((size_t)(a)<(size_t)(b) ? (size_t)(a) : (size_t)(b))
/* Two unsigned, return a signed. */
#define SUMAX(a,b) ((size_t)(a)>(size_t)(b) ? (ssize_t)(a) : (ssize_t)(b))
#define SUMIN(a,b) ((size_t)(a)<(size_t)(b) ? (ssize_t)(a) : (ssize_t)(b))
#endif /*__KERNEL__*/
#endif /*__LINUX_NETFILTER_H*/
好了,现在我已经介绍完了netfilter的头文件,下一次我将来分析netfilter.c。进一步介绍这些变量、函数、结构将如何使用。