diff options
author | Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | 2010-06-22 10:49:41 +0200 |
---|---|---|
committer | Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | 2010-06-22 10:49:41 +0200 |
commit | 020936c8c3375e1efe44a3087c891a4b2cbfe044 (patch) | |
tree | a94751e6f1f11bcf118129c343d1942bbf53e808 /kernel/include/linux/netfilter/ip_set_getport.h | |
parent | 97a12ba3f184a76c406eb5622ec21a4d4d6fc8bf (diff) |
ipset 5: last new feature addedv5.0-pre3
- the hash types can now store protocol together port, not only port
- lots of fixes everywhere: parser, error reporting, manpage
The last bits on the todo list before announcing ipset 5:
- recheck all the error messages
- add possibly more tests
- polish manpage
Diffstat (limited to 'kernel/include/linux/netfilter/ip_set_getport.h')
-rw-r--r-- | kernel/include/linux/netfilter/ip_set_getport.h | 99 |
1 files changed, 59 insertions, 40 deletions
diff --git a/kernel/include/linux/netfilter/ip_set_getport.h b/kernel/include/linux/netfilter/ip_set_getport.h index ffa89f1..680a89a 100644 --- a/kernel/include/linux/netfilter/ip_set_getport.h +++ b/kernel/include/linux/netfilter/ip_set_getport.h @@ -8,72 +8,91 @@ #define IPSET_INVALID_PORT 65536 /* We must handle non-linear skbs */ -static bool -get_port(u8 pf, const struct sk_buff *skb, bool src, u16 *port) -{ - unsigned short protocol; - unsigned int protoff; - int fragoff; - - switch (pf) { - case AF_INET: { - const struct iphdr *iph = ip_hdr(skb); - - protocol = iph->protocol; - fragoff = ntohs(iph->frag_off) & IP_OFFSET; - protoff = ip_hdrlen(skb); - break; - } - case AF_INET6: { - int protohdr; - unsigned short frag_off; - - protohdr = ipv6_find_hdr(skb, &protoff, -1, &frag_off); - if (protohdr < 0) - return false; - - protocol = protohdr; - fragoff = frag_off; - break; - } - default: - return false; - } - - /* See comments at tcp_match in ip_tables.c */ - if (fragoff) - return false; +static inline bool +get_port(const struct sk_buff *skb, int protocol, unsigned int protooff, + bool src, u16 *port, u8 *proto) +{ switch (protocol) { case IPPROTO_TCP: { struct tcphdr _tcph; const struct tcphdr *th; - th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph); + 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, protoff, sizeof(_udph), &_udph); + uh = skb_header_pointer(skb, protooff, sizeof(_udph), &_udph); if (uh == NULL) /* No choice either */ return false; *port = src ? uh->source : uh->dest; break; - } + } default: - return false; + if (*proto == IPSET_IPPROTO_TCPUDP) + return false; + break; } + if (*proto != IPSET_IPPROTO_TCPUDP) + *proto = protocol; + return true; } + +static inline bool +get_ip4_port(const struct sk_buff *skb, bool src, u16 *port, u8 *proto) +{ + const struct iphdr *iph = ip_hdr(skb); + unsigned int protooff = ip_hdrlen(skb); + int protocol = iph->protocol; + + if (!(*proto >= IPSET_IPPROTO_TCPUDP || *proto == protocol)) + return false; + + /* See comments at tcp_match in ip_tables.c */ + if (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, u16 *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; + + if (!(*proto >= IPSET_IPPROTO_TCPUDP || *proto == protocol)) + 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, u16 *port) +{ + u8 proto = IPSET_IPPROTO_TCPUDP; + + if (pf == AF_INET) + return get_ip4_port(skb, src, port, &proto); + else + return get_ip6_port(skb, src, port, &proto); +} #endif /* __KERNEL__ */ #endif /*_IP_SET_GETPORT_H*/ |