FILE
nf_socket_ipv4.c
File preview with syntax highlighting.
linux-6.19.14/net/ipv4/netfilter/nf_socket_ipv4.c
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Copyright (C) 2007-2008 BalaBit IT Ltd. 4 * Author: Krisztian Kovacs 5 */ 6#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 7#include <linux/module.h> 8#include <linux/skbuff.h> 9#include <net/tcp.h> 10#include <net/udp.h> 11#include <net/icmp.h> 12#include <net/sock.h> 13#include <net/inet_sock.h> 14#include <net/netfilter/nf_socket.h> 15#if IS_ENABLED(CONFIG_NF_CONNTRACK) 16#include <net/netfilter/nf_conntrack.h> 17#endif 18 19static int 20extract_icmp4_fields(const struct sk_buff *skb, u8 *protocol, 21 __be32 *raddr, __be32 *laddr, 22 __be16 *rport, __be16 *lport) 23{ 24 unsigned int outside_hdrlen = ip_hdrlen(skb); 25 struct iphdr *inside_iph, _inside_iph; 26 struct icmphdr *icmph, _icmph; 27 __be16 *ports, _ports[2]; 28 29 icmph = skb_header_pointer(skb, outside_hdrlen, 30 sizeof(_icmph), &_icmph); 31 if (icmph == NULL) 32 return 1; 33 34 if (!icmp_is_err(icmph->type)) 35 return 1; 36 37 inside_iph = skb_header_pointer(skb, outside_hdrlen + 38 sizeof(struct icmphdr), 39 sizeof(_inside_iph), &_inside_iph); 40 if (inside_iph == NULL) 41 return 1; 42 43 if (inside_iph->protocol != IPPROTO_TCP && 44 inside_iph->protocol != IPPROTO_UDP) 45 return 1; 46 47 ports = skb_header_pointer(skb, outside_hdrlen + 48 sizeof(struct icmphdr) + 49 (inside_iph->ihl << 2), 50 sizeof(_ports), &_ports); 51 if (ports == NULL) 52 return 1; 53 54 /* the inside IP packet is the one quoted from our side, thus 55 * its saddr is the local address */ 56 *protocol = inside_iph->protocol; 57 *laddr = inside_iph->saddr; 58 *lport = ports[0]; 59 *raddr = inside_iph->daddr; 60 *rport = ports[1]; 61 62 return 0; 63} 64 65static struct sock * 66nf_socket_get_sock_v4(struct net *net, struct sk_buff *skb, const int doff, 67 const u8 protocol, 68 const __be32 saddr, const __be32 daddr, 69 const __be16 sport, const __be16 dport, 70 const struct net_device *in) 71{ 72 switch (protocol) { 73 case IPPROTO_TCP: 74 return inet_lookup(net, skb, doff, saddr, sport, daddr, dport, 75 in->ifindex); 76 case IPPROTO_UDP: 77 return udp4_lib_lookup(net, saddr, sport, daddr, dport, 78 in->ifindex); 79 } 80 return NULL; 81} 82 83struct sock *nf_sk_lookup_slow_v4(struct net *net, const struct sk_buff *skb, 84 const struct net_device *indev) 85{ 86 __be32 daddr, saddr; 87 __be16 dport, sport; 88 const struct iphdr *iph = ip_hdr(skb); 89 struct sk_buff *data_skb = NULL; 90 u8 protocol; 91#if IS_ENABLED(CONFIG_NF_CONNTRACK) 92 enum ip_conntrack_info ctinfo; 93 struct nf_conn const *ct; 94#endif 95 int doff = 0; 96 97 if (iph->protocol == IPPROTO_UDP || iph->protocol == IPPROTO_TCP) { 98 struct tcphdr _hdr; 99 struct udphdr *hp; 100 101 hp = skb_header_pointer(skb, ip_hdrlen(skb), 102 iph->protocol == IPPROTO_UDP ? 103 sizeof(*hp) : sizeof(_hdr), &_hdr); 104 if (hp == NULL) 105 return NULL; 106 107 protocol = iph->protocol; 108 saddr = iph->saddr; 109 sport = hp->source; 110 daddr = iph->daddr; 111 dport = hp->dest; 112 data_skb = (struct sk_buff *)skb; 113 doff = iph->protocol == IPPROTO_TCP ? 114 ip_hdrlen(skb) + __tcp_hdrlen((struct tcphdr *)hp) : 115 ip_hdrlen(skb) + sizeof(*hp); 116 117 } else if (iph->protocol == IPPROTO_ICMP) { 118 if (extract_icmp4_fields(skb, &protocol, &saddr, &daddr, 119 &sport, &dport)) 120 return NULL; 121 } else { 122 return NULL; 123 } 124 125#if IS_ENABLED(CONFIG_NF_CONNTRACK) 126 /* Do the lookup with the original socket address in 127 * case this is a reply packet of an established 128 * SNAT-ted connection. 129 */ 130 ct = nf_ct_get(skb, &ctinfo); 131 if (ct && 132 ((iph->protocol != IPPROTO_ICMP && 133 ctinfo == IP_CT_ESTABLISHED_REPLY) || 134 (iph->protocol == IPPROTO_ICMP && 135 ctinfo == IP_CT_RELATED_REPLY)) && 136 (ct->status & IPS_SRC_NAT_DONE)) { 137 138 daddr = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip; 139 dport = (iph->protocol == IPPROTO_TCP) ? 140 ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.tcp.port : 141 ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port; 142 } 143#endif 144 145 return nf_socket_get_sock_v4(net, data_skb, doff, protocol, saddr, 146 daddr, sport, dport, indev); 147} 148EXPORT_SYMBOL_GPL(nf_sk_lookup_slow_v4); 149 150MODULE_LICENSE("GPL"); 151MODULE_AUTHOR("Krisztian Kovacs, Balazs Scheidler"); 152MODULE_DESCRIPTION("Netfilter IPv4 socket lookup infrastructure");
~/
Read-only file preview.