root/net/netfilter/ipset/ip_set_getport.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. get_port
  2. ip_set_get_ip4_port
  3. ip_set_get_ip6_port
  4. ip_set_get_ip_port

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /* Copyright (C) 2003-2011 Jozsef Kadlecsik <kadlec@netfilter.org>
   3  *
   4  * This program is free software; you can redistribute it and/or modify
   5  * it under the terms of the GNU General Public License version 2 as
   6  * published by the Free Software Foundation.
   7  */
   8 
   9 /* Get Layer-4 data from the packets */
  10 
  11 #include <linux/ip.h>
  12 #include <linux/skbuff.h>
  13 #include <linux/icmp.h>
  14 #include <linux/icmpv6.h>
  15 #include <linux/sctp.h>
  16 #include <linux/netfilter_ipv6/ip6_tables.h>
  17 #include <net/ip.h>
  18 #include <net/ipv6.h>
  19 
  20 #include <linux/netfilter/ipset/ip_set_getport.h>
  21 #include <linux/export.h>
  22 
  23 /* We must handle non-linear skbs */
  24 static bool
  25 get_port(const struct sk_buff *skb, int protocol, unsigned int protooff,
  26          bool src, __be16 *port, u8 *proto)
  27 {
  28         switch (protocol) {
  29         case IPPROTO_TCP: {
  30                 struct tcphdr _tcph;
  31                 const struct tcphdr *th;
  32 
  33                 th = skb_header_pointer(skb, protooff, sizeof(_tcph), &_tcph);
  34                 if (!th)
  35                         /* No choice either */
  36                         return false;
  37 
  38                 *port = src ? th->source : th->dest;
  39                 break;
  40         }
  41         case IPPROTO_SCTP: {
  42                 struct sctphdr _sh;
  43                 const struct sctphdr *sh;
  44 
  45                 sh = skb_header_pointer(skb, protooff, sizeof(_sh), &_sh);
  46                 if (!sh)
  47                         /* No choice either */
  48                         return false;
  49 
  50                 *port = src ? sh->source : sh->dest;
  51                 break;
  52         }
  53         case IPPROTO_UDP:
  54         case IPPROTO_UDPLITE: {
  55                 struct udphdr _udph;
  56                 const struct udphdr *uh;
  57 
  58                 uh = skb_header_pointer(skb, protooff, sizeof(_udph), &_udph);
  59                 if (!uh)
  60                         /* No choice either */
  61                         return false;
  62 
  63                 *port = src ? uh->source : uh->dest;
  64                 break;
  65         }
  66         case IPPROTO_ICMP: {
  67                 struct icmphdr _ich;
  68                 const struct icmphdr *ic;
  69 
  70                 ic = skb_header_pointer(skb, protooff, sizeof(_ich), &_ich);
  71                 if (!ic)
  72                         return false;
  73 
  74                 *port = (__force __be16)htons((ic->type << 8) | ic->code);
  75                 break;
  76         }
  77         case IPPROTO_ICMPV6: {
  78                 struct icmp6hdr _ich;
  79                 const struct icmp6hdr *ic;
  80 
  81                 ic = skb_header_pointer(skb, protooff, sizeof(_ich), &_ich);
  82                 if (!ic)
  83                         return false;
  84 
  85                 *port = (__force __be16)
  86                         htons((ic->icmp6_type << 8) | ic->icmp6_code);
  87                 break;
  88         }
  89         default:
  90                 break;
  91         }
  92         *proto = protocol;
  93 
  94         return true;
  95 }
  96 
  97 bool
  98 ip_set_get_ip4_port(const struct sk_buff *skb, bool src,
  99                     __be16 *port, u8 *proto)
 100 {
 101         const struct iphdr *iph = ip_hdr(skb);
 102         unsigned int protooff = skb_network_offset(skb) + ip_hdrlen(skb);
 103         int protocol = iph->protocol;
 104 
 105         /* See comments at tcp_match in ip_tables.c */
 106         if (protocol <= 0)
 107                 return false;
 108 
 109         if (ntohs(iph->frag_off) & IP_OFFSET)
 110                 switch (protocol) {
 111                 case IPPROTO_TCP:
 112                 case IPPROTO_SCTP:
 113                 case IPPROTO_UDP:
 114                 case IPPROTO_UDPLITE:
 115                 case IPPROTO_ICMP:
 116                         /* Port info not available for fragment offset > 0 */
 117                         return false;
 118                 default:
 119                         /* Other protocols doesn't have ports,
 120                          * so we can match fragments.
 121                          */
 122                         *proto = protocol;
 123                         return true;
 124                 }
 125 
 126         return get_port(skb, protocol, protooff, src, port, proto);
 127 }
 128 EXPORT_SYMBOL_GPL(ip_set_get_ip4_port);
 129 
 130 #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
 131 bool
 132 ip_set_get_ip6_port(const struct sk_buff *skb, bool src,
 133                     __be16 *port, u8 *proto)
 134 {
 135         int protoff;
 136         u8 nexthdr;
 137         __be16 frag_off = 0;
 138 
 139         nexthdr = ipv6_hdr(skb)->nexthdr;
 140         protoff = ipv6_skip_exthdr(skb,
 141                                    skb_network_offset(skb) +
 142                                         sizeof(struct ipv6hdr), &nexthdr,
 143                                    &frag_off);
 144         if (protoff < 0 || (frag_off & htons(~0x7)) != 0)
 145                 return false;
 146 
 147         return get_port(skb, nexthdr, protoff, src, port, proto);
 148 }
 149 EXPORT_SYMBOL_GPL(ip_set_get_ip6_port);
 150 #endif
 151 
 152 bool
 153 ip_set_get_ip_port(const struct sk_buff *skb, u8 pf, bool src, __be16 *port)
 154 {
 155         bool ret;
 156         u8 proto;
 157 
 158         switch (pf) {
 159         case NFPROTO_IPV4:
 160                 ret = ip_set_get_ip4_port(skb, src, port, &proto);
 161                 break;
 162         case NFPROTO_IPV6:
 163                 ret = ip_set_get_ip6_port(skb, src, port, &proto);
 164                 break;
 165         default:
 166                 return false;
 167         }
 168         if (!ret)
 169                 return ret;
 170         switch (proto) {
 171         case IPPROTO_TCP:
 172         case IPPROTO_UDP:
 173                 return true;
 174         default:
 175                 return false;
 176         }
 177 }
 178 EXPORT_SYMBOL_GPL(ip_set_get_ip_port);

/* [<][>][^][v][top][bottom][index][help] */