1/* 2 * iptables module to match inet_addr_type() of an ip. 3 * 4 * Copyright (c) 2004 Patrick McHardy <kaber@trash.net> 5 * (C) 2007 Laszlo Attila Toth <panther@balabit.hu> 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 */ 11#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 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 19#include <linux/netfilter_ipv4/ipt_addrtype.h> 20#include <linux/netfilter/x_tables.h> 21 22MODULE_LICENSE("GPL"); 23MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); 24MODULE_DESCRIPTION("Xtables: address type match for IPv4"); 25 26static inline bool match_type(struct net *net, const struct net_device *dev, 27 __be32 addr, u_int16_t mask) 28{ 29 return !!(mask & (1 << inet_dev_addr_type(net, dev, addr))); 30} 31 32static bool 33addrtype_mt_v0(const struct sk_buff *skb, struct xt_action_param *par) 34{ 35 struct net *net = dev_net(par->in ? par->in : par->out); 36 const struct ipt_addrtype_info *info = par->matchinfo; 37 const struct iphdr *iph = ip_hdr(skb); 38 bool ret = true; 39 40 if (info->source) 41 ret &= match_type(net, NULL, iph->saddr, info->source) ^ 42 info->invert_source; 43 if (info->dest) 44 ret &= match_type(net, NULL, iph->daddr, info->dest) ^ 45 info->invert_dest; 46 47 return ret; 48} 49 50static bool 51addrtype_mt_v1(const struct sk_buff *skb, struct xt_action_param *par) 52{ 53 struct net *net = dev_net(par->in ? par->in : par->out); 54 const struct ipt_addrtype_info_v1 *info = par->matchinfo; 55 const struct iphdr *iph = ip_hdr(skb); 56 const struct net_device *dev = NULL; 57 bool ret = true; 58 59 if (info->flags & IPT_ADDRTYPE_LIMIT_IFACE_IN) 60 dev = par->in; 61 else if (info->flags & IPT_ADDRTYPE_LIMIT_IFACE_OUT) 62 dev = par->out; 63 64 if (info->source) 65 ret &= match_type(net, dev, iph->saddr, info->source) ^ 66 (info->flags & IPT_ADDRTYPE_INVERT_SOURCE); 67 if (ret && info->dest) 68 ret &= match_type(net, dev, iph->daddr, info->dest) ^ 69 !!(info->flags & IPT_ADDRTYPE_INVERT_DEST); 70 return ret; 71} 72 73static int addrtype_mt_checkentry_v1(const struct xt_mtchk_param *par) 74{ 75 struct ipt_addrtype_info_v1 *info = par->matchinfo; 76 77 if (info->flags & IPT_ADDRTYPE_LIMIT_IFACE_IN && 78 info->flags & IPT_ADDRTYPE_LIMIT_IFACE_OUT) { 79 pr_info("both incoming and outgoing " 80 "interface limitation cannot be selected\n"); 81 return -EINVAL; 82 } 83 84 if (par->hook_mask & ((1 << NF_INET_PRE_ROUTING) | 85 (1 << NF_INET_LOCAL_IN)) && 86 info->flags & IPT_ADDRTYPE_LIMIT_IFACE_OUT) { 87 pr_info("output interface limitation " 88 "not valid in PREROUTING and INPUT\n"); 89 return -EINVAL; 90 } 91 92 if (par->hook_mask & ((1 << NF_INET_POST_ROUTING) | 93 (1 << NF_INET_LOCAL_OUT)) && 94 info->flags & IPT_ADDRTYPE_LIMIT_IFACE_IN) { 95 pr_info("input interface limitation " 96 "not valid in POSTROUTING and OUTPUT\n"); 97 return -EINVAL; 98 } 99 100 return 0; 101} 102 103static struct xt_match addrtype_mt_reg[] __read_mostly = { 104 { 105 .name = "addrtype", 106 .family = NFPROTO_IPV4, 107 .match = addrtype_mt_v0, 108 .matchsize = sizeof(struct ipt_addrtype_info), 109 .me = THIS_MODULE 110 }, 111 { 112 .name = "addrtype", 113 .family = NFPROTO_IPV4, 114 .revision = 1, 115 .match = addrtype_mt_v1, 116 .checkentry = addrtype_mt_checkentry_v1, 117 .matchsize = sizeof(struct ipt_addrtype_info_v1), 118 .me = THIS_MODULE 119 } 120}; 121 122static int __init addrtype_mt_init(void) 123{ 124 return xt_register_matches(addrtype_mt_reg, 125 ARRAY_SIZE(addrtype_mt_reg)); 126} 127 128static void __exit addrtype_mt_exit(void) 129{ 130 xt_unregister_matches(addrtype_mt_reg, ARRAY_SIZE(addrtype_mt_reg)); 131} 132 133module_init(addrtype_mt_init); 134module_exit(addrtype_mt_exit); 135