linux ip 过滤器,Linux表驱动IP过滤器的基本工作过程

表驱动IP过滤器的基本工作过程

表驱动IP过滤器的基本工作过程

(1) Linux的IP过滤器主要采用了表驱动方法, 表驱动入口函数为ipt_do_table(), 驱动表称为IP表, 用ip_table结构描述. IP表是位置无关的数据块, 它由表头(ipt_table_info)和变长的规则链组成. 表头包含了IP表的尺寸,规则数量和不同的过滤编号对应的规则项的起始位置. 规则链是由多个变长的规则项组成, 每个规则项可分为匹配链和匹配靶两部分, 匹配链由IP匹配模板(ipt_entry)和可选的多个扩展匹配操作项组成, 匹配项由匹配结构(ipt_entry_match)和变长参数区组成, 匹配结构包含指向匹配器(ipt_match)模块的指针. 匹配靶则由靶结构(ipt_entry_target)和变长参数区组成, 靶结构包含指向靶处理(ipt_target)模块的指针.

(2) ipt_do_table()对输入的IP包首先沿着IP表规则项的链头IP模板进行匹配, 当规则头匹配成功时, 如果存在后继扩展匹配链, 则进行链式扩展匹配. 当所有的匹配都成功后, 则运行相应的规则靶, 如果规则靶函数返回IPT_CONTINUE, 则继续表中下一规则项匹配, 否则过滤过程结束并返回. 如果靶函数为空, 则说明它是一个标准靶(ipt_standard_target), 标准靶的参数区具有一个判别字(verdict), 它的值如果非负则表示它是一个转移靶, 指向另一个规则项. 如果判别字为负且等于IPT_RETURN, 则说明标准靶是一转移返回靶, 否则将判别字取反减一后作为过滤器的返回值中止过滤过程.

; include/linux/netfilter_ipv4/ip_tables.h:

#define IPT_TABLE_MAXNAMELEN 32

/* Furniture shopping... */

struct ipt_table 驱动表描述结构

{

struct list_head list;

/* A unique name... */

char name[IPT_TABLE_MAXNAMELEN];

/* Seed table: copied in register_table */

struct ipt_replace *table;

/* What hooks you will enter on */

unsigned int valid_hooks;

/* Lock for the curtain */

rwlock_t lock;

/* Man behind the curtain... */

struct ipt_table_info *private; 指向IP表

};

/* This structure defines each of the firewall rules. Consists of 3

parts which are 1) general IP header stuff 2) match specific

stuff 3) the target to perform if the rule matches */

struct ipt_entry 规则项起始匹配单元

{

struct ipt_ip ip; IP包匹配模板

/* Mark with fields that we care about. */

unsigned int nfcache;

/* Size of ipt_entry + matches */

u_int16_t target_offset; 匹配链尺寸

/* Size of ipt_entry + matches + target */

u_int16_t next_offset; 规则项尺寸

/* Back pointer */

unsigned int comefrom;

/* Packet and byte counters. */

struct ipt_counters counters;

/* The matches (if any), then the target. */

unsigned char elems[0];

};

struct ipt_counters

{

u_int64_t pcnt, bcnt; /* Packet and byte counters */

};

/* Yes, Virginia, you have to zero the padding. */

struct ipt_ip { IP头匹配模板

/* Source and destination IP addr */

struct in_addr src, dst;

/* Mask for src and dest IP addr */

struct in_addr smsk, dmsk;

char iniface[IFNAMSIZ], outiface[IFNAMSIZ];

unsigned char iniface_mask[IFNAMSIZ], outiface_mask[IFNAMSIZ];

/* Protocol, 0 = ANY */

u_int16_t proto;

/* Flags word */

u_int8_t flags;

/* Inverse flags */

u_int8_t invflags; 反匹配标志集

};

#define IPT_FUNCTION_MAXNAMELEN 30

struct ipt_entry_match 匹配操作结构

{

union {

struct {

u_int16_t match_size;

/* Used by userspace */

char name[IPT_FUNCTION_MAXNAMELEN];

} user;

struct {

u_int16_t match_size;

/* Used inside the kernel */

struct ipt_match *match;

} kernel;

/* Total length */

u_int16_t match_size;

} u;

unsigned char data[0];

};

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. */

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);

/* 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 if you are a module, otherwise NULL */

struct module *me;

};

struct ipt_entry_target 匹配靶

{

union {

struct {

u_int16_t target_size;

/* Used by userspace */

char name[IPT_FUNCTION_MAXNAMELEN];

} user;

struct {

u_int16_t target_size;

/* Used inside the kernel */

struct ipt_target *target;

} kernel;

/* Total length */

u_int16_t target_size;

} u;

unsigned char data[0];

};

/* Registration hooks for targets. */

struct ipt_target 靶处理器

{

struct list_head list;

const char name[IPT_FUNCTION_MAXNAMELEN];

/* Returns verdict. */

unsigned int (*target)(struct sk_buff **pskb,

unsigned int hooknum,

const struct net_device *in,

const struct net_device *out,

const void *targinfo,

void *userdata);

/* Called when user tries to insert an entry of this type:

hook_mask is a bitmask of hooks from which it can be

called. */

/* Should return true or false. */

int (*checkentry)(const char *tablename,

const struct ipt_entry *e,

void *targinfo,

unsigned int targinfosize,

unsigned int hook_mask);

/* Called when entry of this type deleted. */

void (*destroy)(void *targinfo, unsigned int targinfosize);

/* Set this to THIS_MODULE if you are a module, otherwise NULL */

struct module *me;

};

struct ipt_standard_target 标准靶

{

struct ipt_entry_target target;

int verdict; 判别字

};

/* The table itself */

struct ipt_table_info IP表表头结构

{

/* Size per table */

unsigned int size;

/* Number of entries: FIXME. --RR */

unsigned int number;

/* Entry points and underflows */

unsigned int hook_entry[NF_IP_NUMHOOKS];

unsigned int underflow[NF_IP_NUMHOOKS];

/* ipt_entry tables: one per CPU */

char entries[0] __attribute__((aligned(SMP_CACHE_BYTES)));

};

/* fn returns 0 to continue iteration */

#define IPT_MATCH_ITERATE(e, fn, args...)

({

unsigned int __i;

int __ret = 0;

struct ipt_entry_match *__m;

for (__i = sizeof(struct ipt_entry);

__i < (e)->target_offset;

__i += __m->u.match_size) {

__m = (void *)(e) + __i;

__ret = fn(__m , ## args);

if (__ret != 0)

break;

}

__ret;

})

/* Standard return verdict, or do jump. */

#define IPT_STANDARD_TARGET ""

/* Error verdict. */

#define IPT_ERROR_TARGET "ERROR"

; net/ipv4/netfilter/ip_tables.c:

static LIST_HEAD(ipt_target);

static LIST_HEAD(ipt_match);

static LIST_HEAD(ipt_tables);

/* The built-in targets: standard (NULL) and error. */

static struct ipt_target ipt_standard_target

= { { NULL, NULL }, IPT_STANDARD_TARGET, NULL, NULL, NULL };

static struct ipt_target ipt_error_target

= { { NULL, NULL }, IPT_ERROR_TARGET, ipt_error, NULL, NULL };

static struct nf_sockopt_ops ipt_sockopts

= { { NULL, NULL }, PF_INET, IPT_BASE_CTL, IPT_SO_SET_MAX+1, do_ipt_set_ctl,

IPT_BASE_CTL, IPT_SO_GET_MAX+1, do_ipt_get_ctl, 0, NULL };

static struct ipt_match tcp_matchstruct

= { { NULL, NULL }, "tcp", &tcp_match, &tcp_checkentry, NULL };

static struct ipt_match udp_matchstruct

= { { NULL, NULL }, "udp", &udp_match, &udp_checkentry, NULL };

static struct ipt_match icmp_matchstruct

= { { NULL, NULL }, "icmp", &icmp_match, &icmp_checkentry, NULL };

static int __init init(void)

{

int ret;

/* Noone else will be downing sem now, so we won‘t sleep */

down(&ipt_mutex);

list_append(&ipt_target, &ipt_standard_target); 注册标准靶处理器

list_append(&ipt_target, &ipt_error_target); 注册出错靶处理器

list_append(&ipt_match, &tcp_matchstruct); 注册TCP包匹配器

list_append(&ipt_match, &udp_matchstruct); 注册UDP包匹配器

list_append(&ipt_match, &icmp_matchstruct); 注册ICMP包匹配器

up(&ipt_mutex);

/* Register setsockopt */

ret = nf_register_sockopt(&ipt_sockopts); 注册IP表用户接口

if (ret < 0) {

duprintf("Unable to register sockopts. ");

return ret;

}

#ifdef CONFIG_PROC_FS

if (!proc_net_create("ip_tables_names", 0, ipt_get_tables)) {

nf_unregister_sockopt(&ipt_sockopts);

return -ENOMEM;

}

#endif

printk("ip_tables: (c)2000 Netfilter core team ");

return 0;

}

/* Returns one of the generic firewall policies, like NF_ACCEPT. */

unsigned int

ipt_do_table(struct sk_buff **pskb,

unsigned int hook,

const struct net_device *in,

const struct net_device *out,

struct ipt_table *table,

void *userdata) 表驱动过滤器的入口函数

{

static const char nulldevname[IFNAMSIZ] = { 0 };

u_int16_t offset;

struct iphdr *ip;

void *protohdr;

u_int16_t datalen;

int hotdrop = 0;

/* Initializing verdict to NF_DROP keeps gcc happy. */

unsigned int verdict = NF_DROP;

const char *indev, *outdev;

void *table_base;

struct ipt_entry *e, *back;

/* Initialization */

ip = (*pskb)->nh.iph; 取IP头

protohdr = (u_int32_t *)ip + ip->ihl; 取传输头

datalen = (*pskb)->len - ip->ihl * 4; 取传输块长度

indev = in ? in->name : nulldevname; 取输入设备名称

outdev = out ? out->name : nulldevname; 取输出设备名称

/* We handle fragments by dealing with the first fragment as

* if it was a normal packet. All other fragments are treated

* normally, except that they will NEVER match rules that ask

* things we don‘t know, ie. tcp syn flag or ports). If the

* rule is also a fragment-specific rule, non-fragments won‘t

* match it. */

offset = ntohs(ip->frag_off) & IP_OFFSET; 取IP包片段所在的偏移

read_lock_bh(&table->lock);

IP_NF_ASSERT(table->valid_hooks & (1 << hook));

table_base = (void *)table->private->entries

+ TABLE_OFFSET(table->private,

cpu_number_map(smp_processor_id())); 取过滤表的规则区

e = get_entry(table_base, table->private->hook_entry[hook]); 取过滤编号对应的起始规则项

#ifdef CONFIG_NETFILTER_DEBUG

/* Check noone else using our table */

if (((struct ipt_entry *)table_base)->comefrom != 0xdead57ac

&& ((struct ipt_entry *)table_base)->comefrom != 0xeeeeeeec) {

printk("ASSERT: CPU #%u, %s comefrom(%p) = %X ",

smp_processor_id(),

table->name,

&((struct ipt_entry *)table_base)->comefrom,

((struct ipt_entry *)table_base)->comefrom);

}

((struct ipt_entry *)table_base)->comefrom = 0x57acc001;

#endif

/* For return from builtin chain */

back = get_entry(table_base, table->private->underflow[hook]);

do {

IP_NF_ASSERT(e);

IP_NF_ASSERT(back);

(*pskb)->nfcache |= e->nfcache;

if (ip_packet_match(ip, indev, outdev, &e->ip, offset)) { 匹配IP头成功

struct ipt_entry_target *t;

if (IPT_MATCH_ITERATE(e, do_match, 对匹配链进行链式匹配

*pskb, in, out,

offset, protohdr,

datalen, &hotdrop) != 0)

goto no_match;

ADD_COUNTER(e->counters, ntohs(ip->tot_len), 1); 刷新规则项中包和字节计数器

t = ipt_get_target(e); 取规则项的靶结构

IP_NF_ASSERT(t->u.kernel.target);

/* Standard target? */

if (!t->u.kernel.target->target) { 如果是标准靶

int v;

v = ((struct ipt_standard_target *)t)->verdict;

if (v < 0) {

/* Pop from stack? */

if (v != IPT_RETURN) { 如果不是返回靶

verdict = (unsigned)(-v) - 1; 求过滤器返回值

break; 退出过滤器

}

e = back;

back = get_entry(table_base,

back->comefrom);

continue;

}

if (table_base + v

!= (void *)e + e->next_offset) { 如果是转移靶

/* Save old back ptr in next entry */

struct ipt_entry *next

= (void *)e + e->next_offset;

next->comefrom

= (void *)back - table_base;

/* set back pointer to next entry */

back = next; 设置返回点

}

e = get_entry(table_base, v);

} else {

/* Targets which reenter must return

abs. verdicts */

#ifdef CONFIG_NETFILTER_DEBUG

((struct ipt_entry *)table_base)->comefrom

= 0xeeeeeeec;

#endif

verdict = t->u.kernel.target->target(pskb,

hook,

in, out,

t->data,

userdata); 调用靶函数

#ifdef CONFIG_NETFILTER_DEBUG

if (((struct ipt_entry *)table_base)->comefrom

!= 0xeeeeeeec

&& verdict == IPT_CONTINUE) {

printk("Target %s reentered! ",

t->u.kernel.target->name);

verdict = NF_DROP;

}

((struct ipt_entry *)table_base)->comefrom

= 0x57acc001;

#endif

/* Target might have changed stuff. */

ip = (*pskb)->nh.iph;

protohdr = (u_int32_t *)ip + ip->ihl;

datalen = (*pskb)->len - ip->ihl * 4;

if (verdict == IPT_CONTINUE) 继续下一规则项匹配

e = (void *)e + e->next_offset;

else

/* Verdict */

break;

}

} else { 规则项匹配不成功

no_match:

e = (void *)e + e->next_offset; 取下一规则项

}

} while (!hotdrop);

#ifdef CONFIG_NETFILTER_DEBUG

((struct ipt_entry *)table_base)->comefrom = 0xdead57ac;

#endif

read_unlock_bh(&table->lock);

#ifdef DEBUG_ALLOW_ALL

return NF_ACCEPT;

#else

if (hotdrop)

return NF_DROP;

else return verdict;

#endif

}

/* Returns whether matches rule or not. */

static inline int

ip_packet_match(const struct iphdr *ip,

const char *indev,

const char *outdev,

const struct ipt_ip *ipinfo,

int isfrag) IP头匹配器

{

size_t i;

unsigned long ret;

#define FWINV(bool,inv) ((bool) ^ !!(ipinfo->invflags & inv)) 如果模板中具有inv标志, 则bool值取反

if (FWINV((ip->saddr&ipinfo->smsk.s_addr) != ipinfo->src.s_addr,

IPT_INV_SRCIP) 匹配源地址模板

|| FWINV((ip->daddr&ipinfo->dmsk.s_addr) != ipinfo->dst.s_addr, 匹配目标地址模板

IPT_INV_DSTIP)) {

dprintf("Source or dest mismatch. ");

dprintf("SRC: %u.%u.%u.%u. Mask: %u.%u.%u.%u. Target: %u.%u.%u.%u.%s ",

NIPQUAD(ip->saddr),

NIPQUAD(ipinfo->smsk.s_addr),

NIPQUAD(ipinfo->src.s_addr),

ipinfo->invflags & IPT_INV_SRCIP ? " (INV)" : "");

dprintf("DST: %u.%u.%u.%u Mask: %u.%u.%u.%u Target: %u.%u.%u.%u.%s ",

NIPQUAD(ip->daddr),

NIPQUAD(ipinfo->dmsk.s_addr),

NIPQUAD(ipinfo->dst.s_addr),

ipinfo->invflags & IPT_INV_DSTIP ? " (INV)" : "");

return 0;

}

/* Look for ifname matches; this should unroll nicely. */

for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) { 匹配输入设备名模板

ret |= (((const unsigned long *)indev)^ ((const unsigned long *)ipinfo->iniface))

& ((const unsigned long *)ipinfo->iniface_mask);

}

if (FWINV(ret != 0, IPT_INV_VIA_IN)) {

dprintf("VIA in mismatch (%s vs %s).%s ",

indev, ipinfo->iniface,

ipinfo->invflags&IPT_INV_VIA_IN ?" (INV)":"");

return 0;

}

for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) { 匹配输出设备名模板

ret |= (((const unsigned long *)outdev)^ ((const unsigned long *)ipinfo->outiface))

& ((const unsigned long *)ipinfo->outiface_mask);

}

if (FWINV(ret != 0, IPT_INV_VIA_OUT)) {

dprintf("VIA out mismatch (%s vs %s).%s ",

outdev, ipinfo->outiface,

ipinfo->invflags&IPT_INV_VIA_OUT ?" (INV)":"");

return 0;

}

/* Check specific protocol */

if (ipinfo->proto 匹配IP传输协议码

&& FWINV(ip->protocol != ipinfo->proto, IPT_INV_PROTO)) {

dprintf("Packet protocol %hi does not match %hi.%s ",

ip->protocol, ipinfo->proto,

ipinfo->invflags&IPT_INV_PROTO ? " (INV)":"");

return 0;

}

/* If we have a fragment rule but the packet is not a fragment

* then we return zero */ 匹配IP包是否允许分片

if (FWINV((ipinfo->flags&IPT_F_FRAG) && !isfrag, IPT_INV_FRAG)) {

dprintf("Fragment rule but not fragment.%s ",

ipinfo->invflags & IPT_INV_FRAG ? " (INV)" : "");

return 0;

}

return 1;

}

static inline

int do_match(struct ipt_entry_match *m,

const struct sk_buff *skb,

const struct net_device *in,

const struct net_device *out,

int offset,

const void *hdr,

u_int16_t datalen,

int *hotdrop) 链式匹配中的匹配器接口

{

/* Stop iteration if it doesn‘t match */

if (!m->u.kernel.match->match(skb, in, out, m->data, /* m->data为匹配项中的参数区 */

offset, hdr, datalen, hotdrop))

return 1;

else

return 0;

}

static unsigned int

ipt_error(struct sk_buff **pskb,

unsigned int hooknum,

const struct net_device *in,

const struct net_device *out,

const void *targinfo,

void *userinfo) 错误靶函数

{

if (net_ratelimit())

printk("ip_tables: error: `%s‘ ", (char *)targinfo);

return NF_DROP;

}

/* TCP matching stuff */

struct ipt_tcp TCP匹配操作项参数区

{

u_int16_t spts[2]; /* Source port range. */

u_int16_t dpts[2]; /* Destination port range. */

u_int8_t option; /* TCP Option iff non-zero*/

u_int8_t _mask; /* TCP flags mask byte */

u_int8_t _cmp; /* TCP flags compare byte */

u_int8_t invflags; /* Inverse flags */

};

static int

tcp_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) TCP匹配器函数

{

const struct tcphdr *tcp = hdr;

const struct ipt_tcp *tcpinfo = matchinfo;

/* To quote Alan:

Don‘t allow a fragment of TCP 8 bytes in. Nobody normal

causes this. Its a cracker trying to break in by doing a

flag overwrite to pass the direction checks.

*/

if (offset == 1) {

duprintf("Dropping evil TCP offset=1 frag. ");

*hotdrop = 1;

return 0;

} else if (offset == 0 && datalen < sizeof(struct tcphdr)) {

/* We‘ve been asked to examine this packet, and we

can‘t. Hence, no choice but to drop. */

duprintf("Dropping evil TCP offset=0 tinygram. ");

*hotdrop = 1;

return 0;

}

/* FIXME: Try tcp doff >> packet len against various stacks --RR */

#define FWINVTCP(bool,inv) ((bool) ^ !!(tcpinfo->invflags & inv))

/* Must not be a fragment. */

return !offset

&& port_match(tcpinfo->spts[0], tcpinfo->spts[1],

ntohs(tcp->source),

!!(tcpinfo->invflags & IPT_TCP_INV_SRCPT)) TCP源端口号是否在范围内

&& port_match(tcpinfo->dpts[0], tcpinfo->dpts[1],

ntohs(tcp->dest),

!!(tcpinfo->invflags & IPT_TCP_INV_DSTPT)) TCP目的端口号是否在范围内

&& FWINVTCP((((unsigned char *)tcp)[13]

& tcpinfo->_mask)

== tcpinfo->_cmp,

IPT_TCP_INV_FLAGS) 匹配TCP标志码

&& (!tcpinfo->option

|| tcp_find_option(tcpinfo->option, tcp, datalen,

tcpinfo->invflags

& IPT_TCP_INV_OPTION,

hotdrop)); 是否允许特定的TCP选项

}

/* Called when user tries to insert an entry of this type. */

static int

tcp_checkentry(const char *tablename,

const struct ipt_ip *ip,

void *matchinfo,

unsigned int matchsize,

unsigned int hook_mask) TCP匹配器参数初始化校验函数

{

const struct ipt_tcp *tcpinfo = matchinfo;

/* Must specify proto == TCP, and no unknown invflags */

return ip->proto == IPPROTO_TCP

&& !(ip->invflags & IPT_INV_PROTO)

&& matchsize == IPT_ALIGN(sizeof(struct ipt_tcp))

&& !(tcpinfo->invflags & ~IPT_TCP_INV_MASK);

}

/* UDP matching stuff */

struct ipt_udp

{

u_int16_t spts[2]; /* Source port range. */

u_int16_t dpts[2]; /* Destination port range. */

u_int8_t invflags; /* Inverse flags */

};

static int

udp_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) UDP匹配器函数

{

const struct udphdr *udp = hdr;

const struct ipt_udp *udpinfo = matchinfo;

if (offset == 0 && datalen < sizeof(struct udphdr)) {

/* We‘ve been asked to examine this packet, and we

can‘t. Hence, no choice but to drop. */

duprintf("Dropping evil UDP tinygram. ");

*hotdrop = 1;

return 0;

}

/* Must not be a fragment. */

return !offset

&& port_match(udpinfo->spts[0], udpinfo->spts[1],

ntohs(udp->source),

!!(udpinfo->invflags & IPT_UDP_INV_SRCPT))

&& port_match(udpinfo->dpts[0], udpinfo->dpts[1],

ntohs(udp->dest),

!!(udpinfo->invflags & IPT_UDP_INV_DSTPT));

}

/* Called when user tries to insert an entry of this type. */

static int

udp_checkentry(const char *tablename,

const struct ipt_ip *ip,

void *matchinfo,

unsigned int matchinfosize,

unsigned int hook_mask)

{

const struct ipt_udp *udpinfo = matchinfo;

/* Must specify proto == UDP, and no unknown invflags */

if (ip->proto != IPPROTO_UDP || (ip->invflags & IPT_INV_PROTO)) {

duprintf("ipt_udp: Protocol %u != %u ", ip->proto,

IPPROTO_UDP);

return 0;

}

if (matchinfosize != IPT_ALIGN(sizeof(struct ipt_udp))) {

duprintf("ipt_udp: matchsize %u != %u ",

matchinfosize, IPT_ALIGN(sizeof(struct ipt_udp)));

return 0;

}

if (udpinfo->invflags & ~IPT_UDP_INV_MASK) {

duprintf("ipt_udp: unknown flags %X ",

udpinfo->invflags);

return 0;

}

return 1;

}

/* ICMP matching stuff */

struct ipt_icmp

{

u_int8_t type; /* type to match */

u_int8_t code[2]; /* range of code */

u_int8_t invflags; /* Inverse flags */

};

static int

icmp_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 icmphdr *icmp = hdr;

const struct ipt_icmp *icmpinfo = matchinfo;

if (offset == 0 && datalen < 2) {

/* We‘ve been asked to examine this packet, and we

can‘t. Hence, no choice but to drop. */

duprintf("Dropping evil ICMP tinygram. ");

*hotdrop = 1;

return 0;

}

/* Must not be a fragment. */

return !offset

&& icmp_type_code_match(icmpinfo->type,

icmpinfo->code[0],

icmpinfo->code[1],

icmp->type, icmp->code,

!!(icmpinfo->invflags&IPT_ICMP_INV)); 匹配具有特定类型,控制码在某个范围内的ICMP包

}

/* Returns 1 if the type and code is matched by the range, 0 otherwise */

static inline int

icmp_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,

u_int8_t type, u_int8_t code,

int invert)

{

return (type == test_type && code >= min_code && code <= max_code)

^ invert;

}

/* Called when user tries to insert an entry of this type. */

static int

icmp_checkentry(const char *tablename,

const struct ipt_ip *ip,

void *matchinfo,

unsigned int matchsize,

unsigned int hook_mask)

{

const struct ipt_icmp *icmpinfo = matchinfo;

/* Must specify proto == ICMP, and no unknown invflags */

return ip->proto == IPPROTO_ICMP

&& !(ip->invflags & IPT_INV_PROTO)

&& matchsize == IPT_ALIGN(sizeof(struct ipt_icmp))

&& !(icmpinfo->invflags & ~IPT_ICMP_INV);

}

/* Returns 1 if the port is matched by the range, 0 otherwise */

static inline int

port_match(u_int16_t min, u_int16_t max, u_int16_t port, int invert)

{

int ret;

ret = (port >= min && port <= max) ^ invert;

return ret;

}

static int

tcp_find_option(u_int8_t option,

const struct tcphdr *tcp,

u_int16_t datalen,

int invert,

int *hotdrop)

{

unsigned int i = sizeof(struct tcphdr);

const u_int8_t *opt = (u_int8_t *)tcp;

duprintf("tcp_match: finding option ");

/* If we don‘t have the whole header, drop packet. */

if (tcp->doff * 4 > datalen) {

*hotdrop = 1;

return 0;

}

while (i < tcp->doff * 4) {

if (opt== option) return !invert;

if (opt< 2) i++;

else i += opt[i+1]?:1;

}

return invert;

}

static inline struct ipt_entry *

get_entry(void *base, unsigned int offset)

{

return (struct ipt_entry *)(base + offset);

}

/* Append. */

extern inline void

list_append(struct list_head *head, void *new)

{

ASSERT_WRITE_LOCK(head);

list_add((new), (head)->prev);

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值