1c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy/* IP tables module for matching IPsec policy 2c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy * 3c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy * Copyright (c) 2004,2005 Patrick McHardy, <kaber@trash.net> 4c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy * 5c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy * This program is free software; you can redistribute it and/or modify 6c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy * it under the terms of the GNU General Public License version 2 as 7c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy * published by the Free Software Foundation. 8c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy */ 98bee4bad03c5b601bd6cea123c31025680587cccJan Engelhardt#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 10c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy#include <linux/kernel.h> 11c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy#include <linux/module.h> 12c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy#include <linux/skbuff.h> 13c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy#include <linux/init.h> 14c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy#include <net/xfrm.h> 15c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy 16917b6fbd6e8dd952c64d1d7468897160467d2cc0Jan Engelhardt#include <linux/netfilter.h> 17c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy#include <linux/netfilter/xt_policy.h> 18c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy#include <linux/netfilter/x_tables.h> 19c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy 20c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardyMODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); 212ae15b64e6a1608c840c60df38e8e5eef7b2b8c3Jan EngelhardtMODULE_DESCRIPTION("Xtables: IPsec policy match"); 22c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardyMODULE_LICENSE("GPL"); 23c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy 241d93a9cbad608f6398ba6c5b588c504ccd35a2caJan Engelhardtstatic inline bool 25917b6fbd6e8dd952c64d1d7468897160467d2cc0Jan Engelhardtxt_addr_cmp(const union nf_inet_addr *a1, const union nf_inet_addr *m, 26917b6fbd6e8dd952c64d1d7468897160467d2cc0Jan Engelhardt const union nf_inet_addr *a2, unsigned short family) 27c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy{ 28c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy switch (family) { 29ee999d8b9573df1b547aacdc6d79f86eb79c25cdJan Engelhardt case NFPROTO_IPV4: 30917b6fbd6e8dd952c64d1d7468897160467d2cc0Jan Engelhardt return ((a1->ip ^ a2->ip) & m->ip) == 0; 31ee999d8b9573df1b547aacdc6d79f86eb79c25cdJan Engelhardt case NFPROTO_IPV6: 32917b6fbd6e8dd952c64d1d7468897160467d2cc0Jan Engelhardt return ipv6_masked_addr_cmp(&a1->in6, &m->in6, &a2->in6) == 0; 33c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy } 341d93a9cbad608f6398ba6c5b588c504ccd35a2caJan Engelhardt return false; 35c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy} 36c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy 37b9aed45507b657abab0b88da2c9b509a9dc462b1Ilpo Järvinenstatic bool 38a47362a226456d8db8207e618324a2278d05d3a7Jan Engelhardtmatch_xfrm_state(const struct xfrm_state *x, const struct xt_policy_elem *e, 39c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy unsigned short family) 40c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy{ 41c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy#define MATCH_ADDR(x,y,z) (!e->match.x || \ 42917b6fbd6e8dd952c64d1d7468897160467d2cc0Jan Engelhardt (xt_addr_cmp(&e->x, &e->y, (const union nf_inet_addr *)(z), family) \ 43c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy ^ e->invert.x)) 44c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy#define MATCH(x,y) (!e->match.x || ((e->x == (y)) ^ e->invert.x)) 45c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy 46917b6fbd6e8dd952c64d1d7468897160467d2cc0Jan Engelhardt return MATCH_ADDR(saddr, smask, &x->props.saddr) && 47917b6fbd6e8dd952c64d1d7468897160467d2cc0Jan Engelhardt MATCH_ADDR(daddr, dmask, &x->id.daddr) && 48c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy MATCH(proto, x->id.proto) && 49c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy MATCH(mode, x->props.mode) && 50c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy MATCH(spi, x->id.spi) && 51c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy MATCH(reqid, x->props.reqid); 52c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy} 53c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy 54c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardystatic int 55c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardymatch_policy_in(const struct sk_buff *skb, const struct xt_policy_info *info, 56c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy unsigned short family) 57c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy{ 58c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy const struct xt_policy_elem *e; 59a47362a226456d8db8207e618324a2278d05d3a7Jan Engelhardt const struct sec_path *sp = skb->sp; 60c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy int strict = info->flags & XT_POLICY_MATCH_STRICT; 61c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy int i, pos; 62c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy 63c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy if (sp == NULL) 64c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy return -1; 65c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy if (strict && info->len != sp->len) 66c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy return 0; 67c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy 68c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy for (i = sp->len - 1; i >= 0; i--) { 69c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy pos = strict ? i - sp->len + 1 : 0; 70c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy if (pos >= info->len) 71c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy return 0; 72c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy e = &info->pol[pos]; 73c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy 74dbe5b4aaafc715b12dbbea309d3d17958d01fd65Herbert Xu if (match_xfrm_state(sp->xvec[i], e, family)) { 75c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy if (!strict) 76c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy return 1; 77c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy } else if (strict) 78c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy return 0; 79c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy } 80c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy 81c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy return strict ? 1 : 0; 82c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy} 83c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy 84c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardystatic int 85c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardymatch_policy_out(const struct sk_buff *skb, const struct xt_policy_info *info, 86c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy unsigned short family) 87c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy{ 88c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy const struct xt_policy_elem *e; 89adf30907d63893e4208dfe3f5c88ae12bc2f25d5Eric Dumazet const struct dst_entry *dst = skb_dst(skb); 90c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy int strict = info->flags & XT_POLICY_MATCH_STRICT; 91c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy int i, pos; 92c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy 93c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy if (dst->xfrm == NULL) 94c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy return -1; 95c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy 96c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy for (i = 0; dst && dst->xfrm; dst = dst->child, i++) { 97c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy pos = strict ? i : 0; 98c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy if (pos >= info->len) 99c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy return 0; 100c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy e = &info->pol[pos]; 101c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy 102c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy if (match_xfrm_state(dst->xfrm, e, family)) { 103c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy if (!strict) 104c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy return 1; 105c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy } else if (strict) 106c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy return 0; 107c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy } 108c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy 109c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy return strict ? i == info->len : 0; 110c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy} 111c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy 112d3c5ee6d545b5372fd525ebe16988a5b6efeceb0Jan Engelhardtstatic bool 11362fc8051083a334578c3f4b3488808f210b4565fJan Engelhardtpolicy_mt(const struct sk_buff *skb, struct xt_action_param *par) 114c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy{ 115f7108a20dee44e5bb037f9e48f6a207b42e6ae1cJan Engelhardt const struct xt_policy_info *info = par->matchinfo; 116c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy int ret; 117c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy 118c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy if (info->flags & XT_POLICY_MATCH_IN) 119aa5fa3185791aac71c9172d4fda3e8729164b5d1Jan Engelhardt ret = match_policy_in(skb, info, par->family); 120c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy else 121aa5fa3185791aac71c9172d4fda3e8729164b5d1Jan Engelhardt ret = match_policy_out(skb, info, par->family); 122c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy 123c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy if (ret < 0) 1241d93a9cbad608f6398ba6c5b588c504ccd35a2caJan Engelhardt ret = info->flags & XT_POLICY_MATCH_NONE ? true : false; 125c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy else if (info->flags & XT_POLICY_MATCH_NONE) 1261d93a9cbad608f6398ba6c5b588c504ccd35a2caJan Engelhardt ret = false; 127c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy 128c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy return ret; 129c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy} 130c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy 131b0f38452ff73da7e9e0ddc68cd5c6b93c897ca0dJan Engelhardtstatic int policy_mt_check(const struct xt_mtchk_param *par) 132c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy{ 1339b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt const struct xt_policy_info *info = par->matchinfo; 134c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy 135c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy if (!(info->flags & (XT_POLICY_MATCH_IN|XT_POLICY_MATCH_OUT))) { 1368bee4bad03c5b601bd6cea123c31025680587cccJan Engelhardt pr_info("neither incoming nor outgoing policy selected\n"); 137bd414ee605ff3ac5fcd79f57269a897879ee4cdeJan Engelhardt return -EINVAL; 138c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy } 1399b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt if (par->hook_mask & ((1 << NF_INET_PRE_ROUTING) | 1409b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt (1 << NF_INET_LOCAL_IN)) && info->flags & XT_POLICY_MATCH_OUT) { 1418bee4bad03c5b601bd6cea123c31025680587cccJan Engelhardt pr_info("output policy not valid in PREROUTING and INPUT\n"); 142bd414ee605ff3ac5fcd79f57269a897879ee4cdeJan Engelhardt return -EINVAL; 143c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy } 1449b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt if (par->hook_mask & ((1 << NF_INET_POST_ROUTING) | 1459b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt (1 << NF_INET_LOCAL_OUT)) && info->flags & XT_POLICY_MATCH_IN) { 1468bee4bad03c5b601bd6cea123c31025680587cccJan Engelhardt pr_info("input policy not valid in POSTROUTING and OUTPUT\n"); 147bd414ee605ff3ac5fcd79f57269a897879ee4cdeJan Engelhardt return -EINVAL; 148c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy } 149c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy if (info->len > XT_POLICY_MAX_ELEM) { 1508bee4bad03c5b601bd6cea123c31025680587cccJan Engelhardt pr_info("too many policy elements\n"); 151bd414ee605ff3ac5fcd79f57269a897879ee4cdeJan Engelhardt return -EINVAL; 152c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy } 153bd414ee605ff3ac5fcd79f57269a897879ee4cdeJan Engelhardt return 0; 154c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy} 155c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy 156d3c5ee6d545b5372fd525ebe16988a5b6efeceb0Jan Engelhardtstatic struct xt_match policy_mt_reg[] __read_mostly = { 1574470bbc749e5551cce914529309456f631e25120Patrick McHardy { 1584470bbc749e5551cce914529309456f631e25120Patrick McHardy .name = "policy", 159ee999d8b9573df1b547aacdc6d79f86eb79c25cdJan Engelhardt .family = NFPROTO_IPV4, 160d3c5ee6d545b5372fd525ebe16988a5b6efeceb0Jan Engelhardt .checkentry = policy_mt_check, 161d3c5ee6d545b5372fd525ebe16988a5b6efeceb0Jan Engelhardt .match = policy_mt, 1624470bbc749e5551cce914529309456f631e25120Patrick McHardy .matchsize = sizeof(struct xt_policy_info), 1634470bbc749e5551cce914529309456f631e25120Patrick McHardy .me = THIS_MODULE, 1644470bbc749e5551cce914529309456f631e25120Patrick McHardy }, 1654470bbc749e5551cce914529309456f631e25120Patrick McHardy { 1664470bbc749e5551cce914529309456f631e25120Patrick McHardy .name = "policy", 167ee999d8b9573df1b547aacdc6d79f86eb79c25cdJan Engelhardt .family = NFPROTO_IPV6, 168d3c5ee6d545b5372fd525ebe16988a5b6efeceb0Jan Engelhardt .checkentry = policy_mt_check, 169d3c5ee6d545b5372fd525ebe16988a5b6efeceb0Jan Engelhardt .match = policy_mt, 1704470bbc749e5551cce914529309456f631e25120Patrick McHardy .matchsize = sizeof(struct xt_policy_info), 1714470bbc749e5551cce914529309456f631e25120Patrick McHardy .me = THIS_MODULE, 1724470bbc749e5551cce914529309456f631e25120Patrick McHardy }, 173c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy}; 174c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy 175d3c5ee6d545b5372fd525ebe16988a5b6efeceb0Jan Engelhardtstatic int __init policy_mt_init(void) 176c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy{ 177d3c5ee6d545b5372fd525ebe16988a5b6efeceb0Jan Engelhardt return xt_register_matches(policy_mt_reg, ARRAY_SIZE(policy_mt_reg)); 178c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy} 179c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy 180d3c5ee6d545b5372fd525ebe16988a5b6efeceb0Jan Engelhardtstatic void __exit policy_mt_exit(void) 181c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy{ 182d3c5ee6d545b5372fd525ebe16988a5b6efeceb0Jan Engelhardt xt_unregister_matches(policy_mt_reg, ARRAY_SIZE(policy_mt_reg)); 183c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy} 184c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardy 185d3c5ee6d545b5372fd525ebe16988a5b6efeceb0Jan Engelhardtmodule_init(policy_mt_init); 186d3c5ee6d545b5372fd525ebe16988a5b6efeceb0Jan Engelhardtmodule_exit(policy_mt_exit); 187c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardyMODULE_ALIAS("ipt_policy"); 188c4b885139203d37f76662c37ae645fe8e0f4e4e5Patrick McHardyMODULE_ALIAS("ip6t_policy"); 189