From 07d2ca530d353bc8a2b401674732ec3ba3d11977 Mon Sep 17 00:00:00 2001 From: Jozsef Kadlecsik Date: Thu, 20 Jan 2011 18:51:54 +0100 Subject: The get_ip*_port functions are too large to be inlined, moved into the core. --- kernel/Kbuild | 2 +- .../include/linux/netfilter/ipset/ip_set_getport.h | 125 +------------------ kernel/ip_set_bitmap_port.c | 4 +- kernel/ip_set_getport.c | 135 +++++++++++++++++++++ kernel/ip_set_hash_ipport.c | 8 +- kernel/ip_set_hash_ipportip.c | 8 +- kernel/ip_set_hash_ipportnet.c | 8 +- kernel/ip_set_hash_netport.c | 8 +- 8 files changed, 160 insertions(+), 138 deletions(-) create mode 100644 kernel/ip_set_getport.c diff --git a/kernel/Kbuild b/kernel/Kbuild index 8713c5b..d6c6e3b 100644 --- a/kernel/Kbuild +++ b/kernel/Kbuild @@ -1,7 +1,7 @@ NOSTDINC_FLAGS += -I$(M)/include EXTRA_CFLAGS := -DCONFIG_IP_SET_MAX=$(IP_SET_MAX) -ip_set-y := ip_set_core.o pfxlen.o +ip_set-y := ip_set_core.o ip_set_getport.o pfxlen.o obj-m += ip_set.o xt_set.o obj-m += ip_set_bitmap_ip.o ip_set_bitmap_ipmac.o ip_set_bitmap_port.o obj-m += ip_set_hash_ip.o ip_set_hash_ipport.o ip_set_hash_ipportip.o diff --git a/kernel/include/linux/netfilter/ipset/ip_set_getport.h b/kernel/include/linux/netfilter/ipset/ip_set_getport.h index a5d243c..33d9fbe 100644 --- a/kernel/include/linux/netfilter/ipset/ip_set_getport.h +++ b/kernel/include/linux/netfilter/ipset/ip_set_getport.h @@ -1,126 +1,13 @@ #ifndef _IP_SET_GETPORT_H #define _IP_SET_GETPORT_H -#ifdef __KERNEL__ -#include -#include -#include -#include - #define IPSET_INVALID_PORT 65536 -/* We must handle non-linear skbs */ -static inline bool -get_port(const struct sk_buff *skb, int protocol, unsigned int protooff, - bool src, __be16 *port, u8 *proto) -{ - switch (protocol) { - case IPPROTO_TCP: { - struct tcphdr _tcph; - const struct tcphdr *th; - - th = skb_header_pointer(skb, protooff, sizeof(_tcph), &_tcph); - if (th == NULL) - /* No choice either */ - return false; - - *port = src ? th->source : th->dest; - break; - } - case IPPROTO_UDP: { - struct udphdr _udph; - const struct udphdr *uh; - - uh = skb_header_pointer(skb, protooff, sizeof(_udph), &_udph); - if (uh == NULL) - /* No choice either */ - return false; - - *port = src ? uh->source : uh->dest; - break; - } - case IPPROTO_ICMP: { - struct icmphdr _icmph; - const struct icmphdr *ic; - - ic = skb_header_pointer(skb, protooff, sizeof(_icmph), &_icmph); - if (ic == NULL) - return false; - - *port = (__force __be16)((ic->type << 8) & ic->code); - break; - } - case IPPROTO_ICMPV6: { - struct icmp6hdr _icmph; - const struct icmp6hdr *ic; - - ic = skb_header_pointer(skb, protooff, sizeof(_icmph), &_icmph); - if (ic == NULL) - return false; - - *port = (__force __be16)((ic->icmp6_type << 8) & ic->icmp6_code); - break; - } - default: - break; - } - *proto = protocol; - - return true; -} - -static inline bool -get_ip4_port(const struct sk_buff *skb, bool src, __be16 *port, u8 *proto) -{ - const struct iphdr *iph = ip_hdr(skb); - unsigned int protooff = ip_hdrlen(skb); - int protocol = iph->protocol; - - /* See comments at tcp_match in ip_tables.c */ - if (protocol <= 0 || (ntohs(iph->frag_off) & IP_OFFSET)) - return false; - - return get_port(skb, protocol, protooff, src, port, proto); -} - -static inline bool -get_ip6_port(const struct sk_buff *skb, bool src, __be16 *port, u8 *proto) -{ - unsigned int protooff = 0; - int protocol; - unsigned short fragoff; - - protocol = ipv6_find_hdr(skb, &protooff, -1, &fragoff); - if (protocol <= 0 || fragoff) - return false; - - return get_port(skb, protocol, protooff, src, port, proto); -} - -static inline bool -get_ip_port(const struct sk_buff *skb, u8 pf, bool src, __be16 *port) -{ - bool ret; - u8 proto; - - switch (pf) { - case AF_INET: - ret = get_ip4_port(skb, src, port, &proto); - case AF_INET6: - ret = get_ip6_port(skb, src, port, &proto); - default: - return false; - } - if (!ret) - return ret; - switch (proto) { - case IPPROTO_TCP: - case IPPROTO_UDP: - return true; - default: - return false; - } -} -#endif /* __KERNEL__ */ +extern bool ip_set_get_ip4_port(const struct sk_buff *skb, bool src, + __be16 *port, u8 *proto); +extern bool ip_set_get_ip6_port(const struct sk_buff *skb, bool src, + __be16 *port, u8 *proto); +extern bool ip_set_get_ip_port(const struct sk_buff *skb, u8 pf, bool src, + __be16 *port); #endif /*_IP_SET_GETPORT_H*/ diff --git a/kernel/ip_set_bitmap_port.c b/kernel/ip_set_bitmap_port.c index 17303c6..7e3f473 100644 --- a/kernel/ip_set_bitmap_port.c +++ b/kernel/ip_set_bitmap_port.c @@ -73,7 +73,7 @@ bitmap_port_kadt(struct ip_set *set, const struct sk_buff *skb, __be16 __port; u16 port = 0; - if (!get_ip_port(skb, pf, flags & IPSET_DIM_ONE_SRC, &__port)) + if (!ip_set_get_ip_port(skb, pf, flags & IPSET_DIM_ONE_SRC, &__port)) return -EINVAL; port = ntohs(__port); @@ -311,7 +311,7 @@ bitmap_port_timeout_kadt(struct ip_set *set, const struct sk_buff *skb, __be16 __port; u16 port = 0; - if (!get_ip_port(skb, pf, flags & IPSET_DIM_ONE_SRC, &__port)) + if (!ip_set_get_ip_port(skb, pf, flags & IPSET_DIM_ONE_SRC, &__port)) return -EINVAL; port = ntohs(__port); diff --git a/kernel/ip_set_getport.c b/kernel/ip_set_getport.c new file mode 100644 index 0000000..968c570 --- /dev/null +++ b/kernel/ip_set_getport.c @@ -0,0 +1,135 @@ +/* Copyright (C) 2003-2011 Jozsef Kadlecsik + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* Get Layer-4 data from the packets */ + +#include +#include +#include +#include +#include +#include + +#include + +/* We must handle non-linear skbs */ +static bool +get_port(const struct sk_buff *skb, int protocol, unsigned int protooff, + bool src, __be16 *port, u8 *proto) +{ + switch (protocol) { + case IPPROTO_TCP: { + struct tcphdr _tcph; + const struct tcphdr *th; + + th = skb_header_pointer(skb, protooff, sizeof(_tcph), &_tcph); + if (th == NULL) + /* No choice either */ + return false; + + *port = src ? th->source : th->dest; + break; + } + case IPPROTO_UDP: { + struct udphdr _udph; + const struct udphdr *uh; + + uh = skb_header_pointer(skb, protooff, sizeof(_udph), &_udph); + if (uh == NULL) + /* No choice either */ + return false; + + *port = src ? uh->source : uh->dest; + break; + } + case IPPROTO_ICMP: { + struct icmphdr _icmph; + const struct icmphdr *ic; + + ic = skb_header_pointer(skb, protooff, sizeof(_icmph), &_icmph); + if (ic == NULL) + return false; + + *port = (__force __be16)((ic->type << 8) & ic->code); + break; + } + case IPPROTO_ICMPV6: { + struct icmp6hdr _icmph; + const struct icmp6hdr *ic; + + ic = skb_header_pointer(skb, protooff, sizeof(_icmph), &_icmph); + if (ic == NULL) + return false; + + *port = (__force __be16)((ic->icmp6_type << 8) & ic->icmp6_code); + break; + } + default: + break; + } + *proto = protocol; + + return true; +} + +bool +ip_set_get_ip4_port(const struct sk_buff *skb, bool src, + __be16 *port, u8 *proto) +{ + const struct iphdr *iph = ip_hdr(skb); + unsigned int protooff = ip_hdrlen(skb); + int protocol = iph->protocol; + + /* See comments at tcp_match in ip_tables.c */ + if (protocol <= 0 || (ntohs(iph->frag_off) & IP_OFFSET)) + return false; + + return get_port(skb, protocol, protooff, src, port, proto); +} +EXPORT_SYMBOL_GPL(ip_set_get_ip4_port); + +bool +ip_set_get_ip6_port(const struct sk_buff *skb, bool src, + __be16 *port, u8 *proto) +{ + unsigned int protooff = 0; + int protocol; + unsigned short fragoff; + + protocol = ipv6_find_hdr(skb, &protooff, -1, &fragoff); + if (protocol <= 0 || fragoff) + return false; + + return get_port(skb, protocol, protooff, src, port, proto); +} +EXPORT_SYMBOL_GPL(ip_set_get_ip6_port); + +bool +ip_set_get_ip_port(const struct sk_buff *skb, u8 pf, bool src, __be16 *port) +{ + bool ret; + u8 proto; + + switch (pf) { + case AF_INET: + ret = ip_set_get_ip4_port(skb, src, port, &proto); + case AF_INET6: + ret = ip_set_get_ip6_port(skb, src, port, &proto); + default: + return false; + } + if (!ret) + return ret; + switch (proto) { + case IPPROTO_TCP: + case IPPROTO_UDP: + return true; + default: + return false; + } +} +EXPORT_SYMBOL_GPL(ip_set_get_ip_port); diff --git a/kernel/ip_set_hash_ipport.c b/kernel/ip_set_hash_ipport.c index dd92563..415639d 100644 --- a/kernel/ip_set_hash_ipport.c +++ b/kernel/ip_set_hash_ipport.c @@ -144,8 +144,8 @@ hash_ipport4_kadt(struct ip_set *set, const struct sk_buff *skb, ipset_adtfn adtfn = set->variant->adt[adt]; struct hash_ipport4_elem data = { }; - if (!get_ip4_port(skb, flags & IPSET_DIM_TWO_SRC, - &data.port, &data.proto)) + if (!ip_set_get_ip4_port(skb, flags & IPSET_DIM_TWO_SRC, + &data.port, &data.proto)) return -EINVAL; ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip); @@ -383,8 +383,8 @@ hash_ipport6_kadt(struct ip_set *set, const struct sk_buff *skb, ipset_adtfn adtfn = set->variant->adt[adt]; struct hash_ipport6_elem data = { }; - if (!get_ip6_port(skb, flags & IPSET_DIM_TWO_SRC, - &data.port, &data.proto)) + if (!ip_set_get_ip6_port(skb, flags & IPSET_DIM_TWO_SRC, + &data.port, &data.proto)) return -EINVAL; ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6); diff --git a/kernel/ip_set_hash_ipportip.c b/kernel/ip_set_hash_ipportip.c index 04cd079..4712c3c 100644 --- a/kernel/ip_set_hash_ipportip.c +++ b/kernel/ip_set_hash_ipportip.c @@ -149,8 +149,8 @@ hash_ipportip4_kadt(struct ip_set *set, const struct sk_buff *skb, ipset_adtfn adtfn = set->variant->adt[adt]; struct hash_ipportip4_elem data = { }; - if (!get_ip4_port(skb, flags & IPSET_DIM_TWO_SRC, - &data.port, &data.proto)) + if (!ip_set_get_ip4_port(skb, flags & IPSET_DIM_TWO_SRC, + &data.port, &data.proto)) return -EINVAL; ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip); @@ -399,8 +399,8 @@ hash_ipportip6_kadt(struct ip_set *set, const struct sk_buff *skb, ipset_adtfn adtfn = set->variant->adt[adt]; struct hash_ipportip6_elem data = { }; - if (!get_ip6_port(skb, flags & IPSET_DIM_TWO_SRC, - &data.port, &data.proto)) + if (!ip_set_get_ip6_port(skb, flags & IPSET_DIM_TWO_SRC, + &data.port, &data.proto)) return -EINVAL; ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6); diff --git a/kernel/ip_set_hash_ipportnet.c b/kernel/ip_set_hash_ipportnet.c index 2b06d51..b64730c 100644 --- a/kernel/ip_set_hash_ipportnet.c +++ b/kernel/ip_set_hash_ipportnet.c @@ -168,8 +168,8 @@ hash_ipportnet4_kadt(struct ip_set *set, const struct sk_buff *skb, if (adt == IPSET_TEST) data.cidr = HOST_MASK; - if (!get_ip4_port(skb, flags & IPSET_DIM_TWO_SRC, - &data.port, &data.proto)) + if (!ip_set_get_ip4_port(skb, flags & IPSET_DIM_TWO_SRC, + &data.port, &data.proto)) return -EINVAL; ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip); @@ -453,8 +453,8 @@ hash_ipportnet6_kadt(struct ip_set *set, const struct sk_buff *skb, if (adt == IPSET_TEST) data.cidr = HOST_MASK; - if (!get_ip6_port(skb, flags & IPSET_DIM_TWO_SRC, - &data.port, &data.proto)) + if (!ip_set_get_ip6_port(skb, flags & IPSET_DIM_TWO_SRC, + &data.port, &data.proto)) return -EINVAL; ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6); diff --git a/kernel/ip_set_hash_netport.c b/kernel/ip_set_hash_netport.c index 72ca57e..b0251f3 100644 --- a/kernel/ip_set_hash_netport.c +++ b/kernel/ip_set_hash_netport.c @@ -164,8 +164,8 @@ hash_netport4_kadt(struct ip_set *set, const struct sk_buff *skb, if (adt == IPSET_TEST) data.cidr = HOST_MASK; - if (!get_ip4_port(skb, flags & IPSET_DIM_TWO_SRC, - &data.port, &data.proto)) + if (!ip_set_get_ip4_port(skb, flags & IPSET_DIM_TWO_SRC, + &data.port, &data.proto)) return -EINVAL; ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip); @@ -411,8 +411,8 @@ hash_netport6_kadt(struct ip_set *set, const struct sk_buff *skb, if (adt == IPSET_TEST) data.cidr = HOST_MASK; - if (!get_ip6_port(skb, flags & IPSET_DIM_TWO_SRC, - &data.port, &data.proto)) + if (!ip_set_get_ip6_port(skb, flags & IPSET_DIM_TWO_SRC, + &data.port, &data.proto)) return -EINVAL; ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6); -- cgit v1.2.3