Blame view

net/netfilter/xt_ipcomp.c 2.84 KB
81f7e3824   Eric Lee   Initial Release, ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
  /*  Kernel module to match IPComp parameters for IPv4 and IPv6
   *
   *  Copyright (C) 2013 WindRiver
   *
   *  Author:
   *  Fan Du <fan.du@windriver.com>
   *
   *  Based on:
   *  net/netfilter/xt_esp.c
   *
   *  This program is free software; you can redistribute it and/or
   *  modify it under the terms of the GNU General Public License
   *  as published by the Free Software Foundation; either version
   *  2 of the License, or (at your option) any later version.
   */
  
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  #include <linux/in.h>
  #include <linux/module.h>
  #include <linux/skbuff.h>
  #include <linux/ip.h>
  
  #include <linux/netfilter/xt_ipcomp.h>
  #include <linux/netfilter/x_tables.h>
  
  MODULE_LICENSE("GPL");
  MODULE_AUTHOR("Fan Du <fan.du@windriver.com>");
  MODULE_DESCRIPTION("Xtables: IPv4/6 IPsec-IPComp SPI match");
  MODULE_ALIAS("ipt_ipcomp");
  MODULE_ALIAS("ip6t_ipcomp");
  
  /* Returns 1 if the spi is matched by the range, 0 otherwise */
  static inline bool
  spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, bool invert)
  {
  	bool r;
  	pr_debug("spi_match:%c 0x%x <= 0x%x <= 0x%x
  ",
  		 invert ? '!' : ' ', min, spi, max);
  	r = (spi >= min && spi <= max) ^ invert;
  	pr_debug(" result %s
  ", r ? "PASS" : "FAILED");
  	return r;
  }
  
  static bool comp_mt(const struct sk_buff *skb, struct xt_action_param *par)
  {
  	struct ip_comp_hdr _comphdr;
  	const struct ip_comp_hdr *chdr;
  	const struct xt_ipcomp *compinfo = par->matchinfo;
  
  	/* Must not be a fragment. */
  	if (par->fragoff != 0)
  		return false;
  
  	chdr = skb_header_pointer(skb, par->thoff, sizeof(_comphdr), &_comphdr);
  	if (chdr == NULL) {
  		/* We've been asked to examine this packet, and we
  		 * can't.  Hence, no choice but to drop.
  		 */
  		pr_debug("Dropping evil IPComp tinygram.
  ");
  		par->hotdrop = true;
  		return 0;
  	}
  
  	return spi_match(compinfo->spis[0], compinfo->spis[1],
  			 ntohs(chdr->cpi),
  			 !!(compinfo->invflags & XT_IPCOMP_INV_SPI));
  }
  
  static int comp_mt_check(const struct xt_mtchk_param *par)
  {
  	const struct xt_ipcomp *compinfo = par->matchinfo;
  
  	/* Must specify no unknown invflags */
  	if (compinfo->invflags & ~XT_IPCOMP_INV_MASK) {
  		pr_err("unknown flags %X
  ", compinfo->invflags);
  		return -EINVAL;
  	}
  	return 0;
  }
  
  static struct xt_match comp_mt_reg[] __read_mostly = {
  	{
  		.name		= "ipcomp",
  		.family		= NFPROTO_IPV4,
  		.match		= comp_mt,
  		.matchsize	= sizeof(struct xt_ipcomp),
  		.proto		= IPPROTO_COMP,
  		.checkentry	= comp_mt_check,
  		.me		= THIS_MODULE,
  	},
  	{
  		.name		= "ipcomp",
  		.family		= NFPROTO_IPV6,
  		.match		= comp_mt,
  		.matchsize	= sizeof(struct xt_ipcomp),
  		.proto		= IPPROTO_COMP,
  		.checkentry	= comp_mt_check,
  		.me		= THIS_MODULE,
  	},
  };
  
  static int __init comp_mt_init(void)
  {
  	return xt_register_matches(comp_mt_reg, ARRAY_SIZE(comp_mt_reg));
  }
  
  static void __exit comp_mt_exit(void)
  {
  	xt_unregister_matches(comp_mt_reg, ARRAY_SIZE(comp_mt_reg));
  }
  
  module_init(comp_mt_init);
  module_exit(comp_mt_exit);