Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * iptables module to match inet_addr_type() of an ip. | |
3 | * | |
4 | * Copyright (c) 2004 Patrick McHardy <kaber@trash.net> | |
e2cf5ecb | 5 | * (C) 2007 Laszlo Attila Toth <panther@balabit.hu> |
1da177e4 LT |
6 | * |
7 | * This program is free software; you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License version 2 as | |
9 | * published by the Free Software Foundation. | |
10 | */ | |
ff67e4e4 | 11 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
1da177e4 LT |
12 | #include <linux/kernel.h> |
13 | #include <linux/module.h> | |
14 | #include <linux/skbuff.h> | |
15 | #include <linux/netdevice.h> | |
16 | #include <linux/ip.h> | |
17 | #include <net/route.h> | |
18 | ||
de81bbea | 19 | #include <linux/netfilter/xt_addrtype.h> |
6709dbbb | 20 | #include <linux/netfilter/x_tables.h> |
1da177e4 LT |
21 | |
22 | MODULE_LICENSE("GPL"); | |
23 | MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); | |
de81bbea FW |
24 | MODULE_DESCRIPTION("Xtables: address type match"); |
25 | MODULE_ALIAS("ipt_addrtype"); | |
1da177e4 | 26 | |
d4ec52ba AD |
27 | static inline bool match_type(struct net *net, const struct net_device *dev, |
28 | __be32 addr, u_int16_t mask) | |
1da177e4 | 29 | { |
d4ec52ba | 30 | return !!(mask & (1 << inet_dev_addr_type(net, dev, addr))); |
1da177e4 LT |
31 | } |
32 | ||
d3c5ee6d | 33 | static bool |
62fc8051 | 34 | addrtype_mt_v0(const struct sk_buff *skb, struct xt_action_param *par) |
1da177e4 | 35 | { |
d4ec52ba | 36 | struct net *net = dev_net(par->in ? par->in : par->out); |
de81bbea | 37 | const struct xt_addrtype_info *info = par->matchinfo; |
eddc9ec5 | 38 | const struct iphdr *iph = ip_hdr(skb); |
1d93a9cb | 39 | bool ret = true; |
1da177e4 LT |
40 | |
41 | if (info->source) | |
d4ec52ba | 42 | ret &= match_type(net, NULL, iph->saddr, info->source) ^ |
e2cf5ecb | 43 | info->invert_source; |
1da177e4 | 44 | if (info->dest) |
d4ec52ba | 45 | ret &= match_type(net, NULL, iph->daddr, info->dest) ^ |
e2cf5ecb | 46 | info->invert_dest; |
e905a9ed | 47 | |
1da177e4 LT |
48 | return ret; |
49 | } | |
50 | ||
e2cf5ecb | 51 | static bool |
62fc8051 | 52 | addrtype_mt_v1(const struct sk_buff *skb, struct xt_action_param *par) |
e2cf5ecb | 53 | { |
d4ec52ba | 54 | struct net *net = dev_net(par->in ? par->in : par->out); |
de81bbea | 55 | const struct xt_addrtype_info_v1 *info = par->matchinfo; |
e2cf5ecb LAT |
56 | const struct iphdr *iph = ip_hdr(skb); |
57 | const struct net_device *dev = NULL; | |
58 | bool ret = true; | |
59 | ||
de81bbea | 60 | if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN) |
f7108a20 | 61 | dev = par->in; |
de81bbea | 62 | else if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT) |
f7108a20 | 63 | dev = par->out; |
e2cf5ecb LAT |
64 | |
65 | if (info->source) | |
d4ec52ba | 66 | ret &= match_type(net, dev, iph->saddr, info->source) ^ |
de81bbea | 67 | (info->flags & XT_ADDRTYPE_INVERT_SOURCE); |
e2cf5ecb | 68 | if (ret && info->dest) |
d4ec52ba | 69 | ret &= match_type(net, dev, iph->daddr, info->dest) ^ |
de81bbea | 70 | !!(info->flags & XT_ADDRTYPE_INVERT_DEST); |
e2cf5ecb LAT |
71 | return ret; |
72 | } | |
73 | ||
b0f38452 | 74 | static int addrtype_mt_checkentry_v1(const struct xt_mtchk_param *par) |
e2cf5ecb | 75 | { |
de81bbea | 76 | struct xt_addrtype_info_v1 *info = par->matchinfo; |
e2cf5ecb | 77 | |
de81bbea FW |
78 | if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN && |
79 | info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT) { | |
ff67e4e4 JE |
80 | pr_info("both incoming and outgoing " |
81 | "interface limitation cannot be selected\n"); | |
bd414ee6 | 82 | return -EINVAL; |
e2cf5ecb LAT |
83 | } |
84 | ||
9b4fce7a JE |
85 | if (par->hook_mask & ((1 << NF_INET_PRE_ROUTING) | |
86 | (1 << NF_INET_LOCAL_IN)) && | |
de81bbea | 87 | info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT) { |
ff67e4e4 JE |
88 | pr_info("output interface limitation " |
89 | "not valid in PREROUTING and INPUT\n"); | |
bd414ee6 | 90 | return -EINVAL; |
e2cf5ecb LAT |
91 | } |
92 | ||
9b4fce7a JE |
93 | if (par->hook_mask & ((1 << NF_INET_POST_ROUTING) | |
94 | (1 << NF_INET_LOCAL_OUT)) && | |
de81bbea | 95 | info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN) { |
ff67e4e4 JE |
96 | pr_info("input interface limitation " |
97 | "not valid in POSTROUTING and OUTPUT\n"); | |
bd414ee6 | 98 | return -EINVAL; |
e2cf5ecb LAT |
99 | } |
100 | ||
bd414ee6 | 101 | return 0; |
e2cf5ecb LAT |
102 | } |
103 | ||
104 | static struct xt_match addrtype_mt_reg[] __read_mostly = { | |
105 | { | |
106 | .name = "addrtype", | |
ee999d8b | 107 | .family = NFPROTO_IPV4, |
e2cf5ecb | 108 | .match = addrtype_mt_v0, |
de81bbea | 109 | .matchsize = sizeof(struct xt_addrtype_info), |
e2cf5ecb LAT |
110 | .me = THIS_MODULE |
111 | }, | |
112 | { | |
113 | .name = "addrtype", | |
ee999d8b | 114 | .family = NFPROTO_IPV4, |
e2cf5ecb LAT |
115 | .revision = 1, |
116 | .match = addrtype_mt_v1, | |
117 | .checkentry = addrtype_mt_checkentry_v1, | |
de81bbea | 118 | .matchsize = sizeof(struct xt_addrtype_info_v1), |
e2cf5ecb LAT |
119 | .me = THIS_MODULE |
120 | } | |
1da177e4 LT |
121 | }; |
122 | ||
d3c5ee6d | 123 | static int __init addrtype_mt_init(void) |
1da177e4 | 124 | { |
e2cf5ecb LAT |
125 | return xt_register_matches(addrtype_mt_reg, |
126 | ARRAY_SIZE(addrtype_mt_reg)); | |
1da177e4 LT |
127 | } |
128 | ||
d3c5ee6d | 129 | static void __exit addrtype_mt_exit(void) |
1da177e4 | 130 | { |
e2cf5ecb | 131 | xt_unregister_matches(addrtype_mt_reg, ARRAY_SIZE(addrtype_mt_reg)); |
1da177e4 LT |
132 | } |
133 | ||
d3c5ee6d JE |
134 | module_init(addrtype_mt_init); |
135 | module_exit(addrtype_mt_exit); |