Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.11-rc2 331 lines 9.8 kB view raw
1/* 2 * xt_conntrack - Netfilter module to match connection tracking 3 * information. (Superset of Rusty's minimalistic state match.) 4 * 5 * (C) 2001 Marc Boucher (marc@mbsi.ca). 6 * (C) 2006-2012 Patrick McHardy <kaber@trash.net> 7 * Copyright © CC Computer Consultants GmbH, 2007 - 2008 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License version 2 as 11 * published by the Free Software Foundation. 12 */ 13#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 14#include <linux/module.h> 15#include <linux/skbuff.h> 16#include <net/ipv6.h> 17#include <linux/netfilter/x_tables.h> 18#include <linux/netfilter/xt_conntrack.h> 19#include <net/netfilter/nf_conntrack.h> 20 21MODULE_LICENSE("GPL"); 22MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>"); 23MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>"); 24MODULE_DESCRIPTION("Xtables: connection tracking state match"); 25MODULE_ALIAS("ipt_conntrack"); 26MODULE_ALIAS("ip6t_conntrack"); 27 28static bool 29conntrack_addrcmp(const union nf_inet_addr *kaddr, 30 const union nf_inet_addr *uaddr, 31 const union nf_inet_addr *umask, unsigned int l3proto) 32{ 33 if (l3proto == NFPROTO_IPV4) 34 return ((kaddr->ip ^ uaddr->ip) & umask->ip) == 0; 35 else if (l3proto == NFPROTO_IPV6) 36 return ipv6_masked_addr_cmp(&kaddr->in6, &umask->in6, 37 &uaddr->in6) == 0; 38 else 39 return false; 40} 41 42static inline bool 43conntrack_mt_origsrc(const struct nf_conn *ct, 44 const struct xt_conntrack_mtinfo2 *info, 45 u_int8_t family) 46{ 47 return conntrack_addrcmp(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3, 48 &info->origsrc_addr, &info->origsrc_mask, family); 49} 50 51static inline bool 52conntrack_mt_origdst(const struct nf_conn *ct, 53 const struct xt_conntrack_mtinfo2 *info, 54 u_int8_t family) 55{ 56 return conntrack_addrcmp(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3, 57 &info->origdst_addr, &info->origdst_mask, family); 58} 59 60static inline bool 61conntrack_mt_replsrc(const struct nf_conn *ct, 62 const struct xt_conntrack_mtinfo2 *info, 63 u_int8_t family) 64{ 65 return conntrack_addrcmp(&ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3, 66 &info->replsrc_addr, &info->replsrc_mask, family); 67} 68 69static inline bool 70conntrack_mt_repldst(const struct nf_conn *ct, 71 const struct xt_conntrack_mtinfo2 *info, 72 u_int8_t family) 73{ 74 return conntrack_addrcmp(&ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3, 75 &info->repldst_addr, &info->repldst_mask, family); 76} 77 78static inline bool 79ct_proto_port_check(const struct xt_conntrack_mtinfo2 *info, 80 const struct nf_conn *ct) 81{ 82 const struct nf_conntrack_tuple *tuple; 83 84 tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; 85 if ((info->match_flags & XT_CONNTRACK_PROTO) && 86 (nf_ct_protonum(ct) == info->l4proto) ^ 87 !(info->invert_flags & XT_CONNTRACK_PROTO)) 88 return false; 89 90 /* Shortcut to match all recognized protocols by using ->src.all. */ 91 if ((info->match_flags & XT_CONNTRACK_ORIGSRC_PORT) && 92 (tuple->src.u.all == info->origsrc_port) ^ 93 !(info->invert_flags & XT_CONNTRACK_ORIGSRC_PORT)) 94 return false; 95 96 if ((info->match_flags & XT_CONNTRACK_ORIGDST_PORT) && 97 (tuple->dst.u.all == info->origdst_port) ^ 98 !(info->invert_flags & XT_CONNTRACK_ORIGDST_PORT)) 99 return false; 100 101 tuple = &ct->tuplehash[IP_CT_DIR_REPLY].tuple; 102 103 if ((info->match_flags & XT_CONNTRACK_REPLSRC_PORT) && 104 (tuple->src.u.all == info->replsrc_port) ^ 105 !(info->invert_flags & XT_CONNTRACK_REPLSRC_PORT)) 106 return false; 107 108 if ((info->match_flags & XT_CONNTRACK_REPLDST_PORT) && 109 (tuple->dst.u.all == info->repldst_port) ^ 110 !(info->invert_flags & XT_CONNTRACK_REPLDST_PORT)) 111 return false; 112 113 return true; 114} 115 116static inline bool 117port_match(u16 min, u16 max, u16 port, bool invert) 118{ 119 return (port >= min && port <= max) ^ invert; 120} 121 122static inline bool 123ct_proto_port_check_v3(const struct xt_conntrack_mtinfo3 *info, 124 const struct nf_conn *ct) 125{ 126 const struct nf_conntrack_tuple *tuple; 127 128 tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; 129 if ((info->match_flags & XT_CONNTRACK_PROTO) && 130 (nf_ct_protonum(ct) == info->l4proto) ^ 131 !(info->invert_flags & XT_CONNTRACK_PROTO)) 132 return false; 133 134 /* Shortcut to match all recognized protocols by using ->src.all. */ 135 if ((info->match_flags & XT_CONNTRACK_ORIGSRC_PORT) && 136 !port_match(info->origsrc_port, info->origsrc_port_high, 137 ntohs(tuple->src.u.all), 138 info->invert_flags & XT_CONNTRACK_ORIGSRC_PORT)) 139 return false; 140 141 if ((info->match_flags & XT_CONNTRACK_ORIGDST_PORT) && 142 !port_match(info->origdst_port, info->origdst_port_high, 143 ntohs(tuple->dst.u.all), 144 info->invert_flags & XT_CONNTRACK_ORIGDST_PORT)) 145 return false; 146 147 tuple = &ct->tuplehash[IP_CT_DIR_REPLY].tuple; 148 149 if ((info->match_flags & XT_CONNTRACK_REPLSRC_PORT) && 150 !port_match(info->replsrc_port, info->replsrc_port_high, 151 ntohs(tuple->src.u.all), 152 info->invert_flags & XT_CONNTRACK_REPLSRC_PORT)) 153 return false; 154 155 if ((info->match_flags & XT_CONNTRACK_REPLDST_PORT) && 156 !port_match(info->repldst_port, info->repldst_port_high, 157 ntohs(tuple->dst.u.all), 158 info->invert_flags & XT_CONNTRACK_REPLDST_PORT)) 159 return false; 160 161 return true; 162} 163 164static bool 165conntrack_mt(const struct sk_buff *skb, struct xt_action_param *par, 166 u16 state_mask, u16 status_mask) 167{ 168 const struct xt_conntrack_mtinfo2 *info = par->matchinfo; 169 enum ip_conntrack_info ctinfo; 170 const struct nf_conn *ct; 171 unsigned int statebit; 172 173 ct = nf_ct_get(skb, &ctinfo); 174 175 if (ct) { 176 if (nf_ct_is_untracked(ct)) 177 statebit = XT_CONNTRACK_STATE_UNTRACKED; 178 else 179 statebit = XT_CONNTRACK_STATE_BIT(ctinfo); 180 } else 181 statebit = XT_CONNTRACK_STATE_INVALID; 182 183 if (info->match_flags & XT_CONNTRACK_STATE) { 184 if (ct != NULL) { 185 if (test_bit(IPS_SRC_NAT_BIT, &ct->status)) 186 statebit |= XT_CONNTRACK_STATE_SNAT; 187 if (test_bit(IPS_DST_NAT_BIT, &ct->status)) 188 statebit |= XT_CONNTRACK_STATE_DNAT; 189 } 190 if (!!(state_mask & statebit) ^ 191 !(info->invert_flags & XT_CONNTRACK_STATE)) 192 return false; 193 } 194 195 if (ct == NULL) 196 return info->match_flags & XT_CONNTRACK_STATE; 197 if ((info->match_flags & XT_CONNTRACK_DIRECTION) && 198 (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) ^ 199 !(info->invert_flags & XT_CONNTRACK_DIRECTION)) 200 return false; 201 202 if (info->match_flags & XT_CONNTRACK_ORIGSRC) 203 if (conntrack_mt_origsrc(ct, info, xt_family(par)) ^ 204 !(info->invert_flags & XT_CONNTRACK_ORIGSRC)) 205 return false; 206 207 if (info->match_flags & XT_CONNTRACK_ORIGDST) 208 if (conntrack_mt_origdst(ct, info, xt_family(par)) ^ 209 !(info->invert_flags & XT_CONNTRACK_ORIGDST)) 210 return false; 211 212 if (info->match_flags & XT_CONNTRACK_REPLSRC) 213 if (conntrack_mt_replsrc(ct, info, xt_family(par)) ^ 214 !(info->invert_flags & XT_CONNTRACK_REPLSRC)) 215 return false; 216 217 if (info->match_flags & XT_CONNTRACK_REPLDST) 218 if (conntrack_mt_repldst(ct, info, xt_family(par)) ^ 219 !(info->invert_flags & XT_CONNTRACK_REPLDST)) 220 return false; 221 222 if (par->match->revision != 3) { 223 if (!ct_proto_port_check(info, ct)) 224 return false; 225 } else { 226 if (!ct_proto_port_check_v3(par->matchinfo, ct)) 227 return false; 228 } 229 230 if ((info->match_flags & XT_CONNTRACK_STATUS) && 231 (!!(status_mask & ct->status) ^ 232 !(info->invert_flags & XT_CONNTRACK_STATUS))) 233 return false; 234 235 if (info->match_flags & XT_CONNTRACK_EXPIRES) { 236 unsigned long expires = nf_ct_expires(ct) / HZ; 237 238 if ((expires >= info->expires_min && 239 expires <= info->expires_max) ^ 240 !(info->invert_flags & XT_CONNTRACK_EXPIRES)) 241 return false; 242 } 243 return true; 244} 245 246static bool 247conntrack_mt_v1(const struct sk_buff *skb, struct xt_action_param *par) 248{ 249 const struct xt_conntrack_mtinfo1 *info = par->matchinfo; 250 251 return conntrack_mt(skb, par, info->state_mask, info->status_mask); 252} 253 254static bool 255conntrack_mt_v2(const struct sk_buff *skb, struct xt_action_param *par) 256{ 257 const struct xt_conntrack_mtinfo2 *info = par->matchinfo; 258 259 return conntrack_mt(skb, par, info->state_mask, info->status_mask); 260} 261 262static bool 263conntrack_mt_v3(const struct sk_buff *skb, struct xt_action_param *par) 264{ 265 const struct xt_conntrack_mtinfo3 *info = par->matchinfo; 266 267 return conntrack_mt(skb, par, info->state_mask, info->status_mask); 268} 269 270static int conntrack_mt_check(const struct xt_mtchk_param *par) 271{ 272 int ret; 273 274 ret = nf_ct_netns_get(par->net, par->family); 275 if (ret < 0) 276 pr_info("cannot load conntrack support for proto=%u\n", 277 par->family); 278 return ret; 279} 280 281static void conntrack_mt_destroy(const struct xt_mtdtor_param *par) 282{ 283 nf_ct_netns_put(par->net, par->family); 284} 285 286static struct xt_match conntrack_mt_reg[] __read_mostly = { 287 { 288 .name = "conntrack", 289 .revision = 1, 290 .family = NFPROTO_UNSPEC, 291 .matchsize = sizeof(struct xt_conntrack_mtinfo1), 292 .match = conntrack_mt_v1, 293 .checkentry = conntrack_mt_check, 294 .destroy = conntrack_mt_destroy, 295 .me = THIS_MODULE, 296 }, 297 { 298 .name = "conntrack", 299 .revision = 2, 300 .family = NFPROTO_UNSPEC, 301 .matchsize = sizeof(struct xt_conntrack_mtinfo2), 302 .match = conntrack_mt_v2, 303 .checkentry = conntrack_mt_check, 304 .destroy = conntrack_mt_destroy, 305 .me = THIS_MODULE, 306 }, 307 { 308 .name = "conntrack", 309 .revision = 3, 310 .family = NFPROTO_UNSPEC, 311 .matchsize = sizeof(struct xt_conntrack_mtinfo3), 312 .match = conntrack_mt_v3, 313 .checkentry = conntrack_mt_check, 314 .destroy = conntrack_mt_destroy, 315 .me = THIS_MODULE, 316 }, 317}; 318 319static int __init conntrack_mt_init(void) 320{ 321 return xt_register_matches(conntrack_mt_reg, 322 ARRAY_SIZE(conntrack_mt_reg)); 323} 324 325static void __exit conntrack_mt_exit(void) 326{ 327 xt_unregister_matches(conntrack_mt_reg, ARRAY_SIZE(conntrack_mt_reg)); 328} 329 330module_init(conntrack_mt_init); 331module_exit(conntrack_mt_exit);