📄 ipsec_tunnel.c
字号:
/* * IPSEC Tunneling code. Heavily based on drivers/net/new_tunnel.c * Copyright (C) 1996, 1997 John Ioannidis. * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Richard Guy Briggs. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */char ipsec_tunnel_c_version[] = "RCSID $Id: ipsec_tunnel.c,v 1.227 2004/12/10 21:16:08 ken Exp $";#define __NO_VERSION__#include <linux/module.h>#include <linux/config.h> /* for CONFIG_IP_FORWARD */#include <linux/version.h>#include <linux/kernel.h> /* printk() */#include "openswan/ipsec_param.h"#ifdef MALLOC_SLAB# include <linux/slab.h> /* kmalloc() */#else /* MALLOC_SLAB */# include <linux/malloc.h> /* kmalloc() */#endif /* MALLOC_SLAB */#include <linux/errno.h> /* error codes */#include <linux/types.h> /* size_t */#include <linux/interrupt.h> /* mark_bh */#include <net/tcp.h>#include <net/udp.h>#include <linux/skbuff.h>#include <linux/netdevice.h> /* struct device, struct net_device_stats, dev_queue_xmit() and other headers */#include <linux/etherdevice.h> /* eth_type_trans */#include <linux/ip.h> /* struct iphdr */#include <linux/skbuff.h>#include <openswan.h>#ifdef NET_21# include <asm/uaccess.h># include <linux/in6.h># define ip_chk_addr inet_addr_type# define IS_MYADDR RTN_LOCAL# include <net/dst.h># undef dev_kfree_skb# define dev_kfree_skb(a,b) kfree_skb(a)# define PHYSDEV_TYPE#endif /* NET_21 */#include <asm/checksum.h>#include <net/icmp.h> /* icmp_send() */#include <net/ip.h>#ifdef NETDEV_23# include <linux/netfilter_ipv4.h>#endif /* NETDEV_23 */#include <linux/if_arp.h>#include "openswan/ipsec_kversion.h"#include "openswan/radij.h"#include "openswan/ipsec_life.h"#include "openswan/ipsec_xform.h"#include "openswan/ipsec_eroute.h"#include "openswan/ipsec_encap.h"#include "openswan/ipsec_radij.h"#include "openswan/ipsec_sa.h"#include "openswan/ipsec_tunnel.h"#include "openswan/ipsec_xmit.h"#include "openswan/ipsec_ipe4.h"#include "openswan/ipsec_ah.h"#include "openswan/ipsec_esp.h"#include "openswan/ipsec_kern24.h"#include <pfkeyv2.h>#include <pfkey.h>#include "openswan/ipsec_proto.h"#ifdef CONFIG_KLIPS_NAT_TRAVERSAL#include <linux/udp.h>#endifstatic __u32 zeroes[64];#ifdef CONFIG_KLIPS_DEBUGint debug_tunnel = 0;#endif /* CONFIG_KLIPS_DEBUG */DEBUG_NO_STATIC intipsec_tunnel_open(struct net_device *dev){ struct ipsecpriv *prv = dev->priv; /* * Can't open until attached. */ KLIPS_PRINT(debug_tunnel & DB_TN_INIT, "klips_debug:ipsec_tunnel_open: " "dev = %s, prv->dev = %s\n", dev->name, prv->dev?prv->dev->name:"NONE"); if (prv->dev == NULL) return -ENODEV; KLIPS_INC_USE; return 0;}DEBUG_NO_STATIC intipsec_tunnel_close(struct net_device *dev){ KLIPS_DEC_USE; return 0;}#ifdef NETDEV_23static inline int ipsec_tunnel_xmit2(struct sk_buff *skb){#ifdef NETDEV_25 /* 2.6 kernels */ return dst_output(skb);#else return ip_send(skb);#endif}#endif /* NETDEV_23 */enum ipsec_xmit_valueipsec_tunnel_strip_hard_header(struct ipsec_xmit_state *ixs){ /* ixs->physdev->hard_header_len is unreliable and should not be used */ ixs->hard_header_len = (unsigned char *)(ixs->iph) - ixs->skb->data; if(ixs->hard_header_len < 0) { KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_error:ipsec_xmit_strip_hard_header: " "Negative hard_header_len (%d)?!\n", ixs->hard_header_len); ixs->stats->tx_dropped++; return IPSEC_XMIT_BADHHLEN; } /* while ixs->physdev->hard_header_len is unreliable and * should not be trusted, it accurate and required for ATM, GRE and * some other interfaces to work. Thanks to Willy Tarreau * <willy@w.ods.org>. */ if(ixs->hard_header_len == 0) { /* no hard header present */ ixs->hard_header_stripped = 1; ixs->hard_header_len = ixs->physdev->hard_header_len; }#ifdef CONFIG_KLIPS_DEBUG if (debug_tunnel & DB_TN_XMIT) { int i; char c; printk(KERN_INFO "klips_debug:ipsec_xmit_strip_hard_header: " ">>> skb->len=%ld hard_header_len:%d", (unsigned long int)ixs->skb->len, ixs->hard_header_len); c = ' '; for (i=0; i < ixs->hard_header_len; i++) { printk("%c%02x", c, ixs->skb->data[i]); c = ':'; } printk(" \n"); }#endif /* CONFIG_KLIPS_DEBUG */ KLIPS_IP_PRINT(debug_tunnel & DB_TN_XMIT, ixs->iph); KLIPS_PRINT(debug_tunnel & DB_TN_CROUT, "klips_debug:ipsec_xmit_strip_hard_header: " "Original head,tailroom: %d,%d\n", skb_headroom(ixs->skb), skb_tailroom(ixs->skb)); return IPSEC_XMIT_OK;}enum ipsec_xmit_valueipsec_tunnel_SAlookup(struct ipsec_xmit_state *ixs){ unsigned int bypass; bypass = FALSE; /* * First things first -- look us up in the erouting tables. */ ixs->matcher.sen_len = sizeof (struct sockaddr_encap); ixs->matcher.sen_family = AF_ENCAP; ixs->matcher.sen_type = SENT_IP4; ixs->matcher.sen_ip_src.s_addr = ixs->iph->saddr; ixs->matcher.sen_ip_dst.s_addr = ixs->iph->daddr; ixs->matcher.sen_proto = ixs->iph->protocol; ipsec_extract_ports(ixs->iph, &ixs->matcher); /* * The spinlock is to prevent any other process from accessing or deleting * the eroute while we are using and updating it. */ spin_lock(&eroute_lock); ixs->eroute = ipsec_findroute(&ixs->matcher); if(ixs->iph->protocol == IPPROTO_UDP) { struct udphdr *t = NULL; KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:udp port check: " "fragoff: %d len: %d>%ld \n", ntohs(ixs->iph->frag_off) & IP_OFFSET, (ixs->skb->len - ixs->hard_header_len), (unsigned long int) ((ixs->iph->ihl << 2) + sizeof(struct udphdr))); if((ntohs(ixs->iph->frag_off) & IP_OFFSET) == 0 && ((ixs->skb->len - ixs->hard_header_len) >= ((ixs->iph->ihl << 2) + sizeof(struct udphdr)))) { t =((struct udphdr*)((caddr_t)ixs->iph+(ixs->iph->ihl<<2))); KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:udp port in packet: " "port %d -> %d\n", ntohs(t->source), ntohs(t->dest)); } ixs->sport=0; ixs->dport=0; if(ixs->skb->sk) {#ifdef NET_26 struct udp_sock *us; us = (struct udp_sock *)ixs->skb->sk; ixs->sport = ntohs(us->inet.sport); ixs->dport = ntohs(us->inet.dport);#else ixs->sport = ntohs(ixs->skb->sk->sport); ixs->dport = ntohs(ixs->skb->sk->dport);#endif } if(t != NULL) { if(ixs->sport == 0) { ixs->sport = ntohs(t->source); } if(ixs->dport == 0) { ixs->dport = ntohs(t->dest); } } } /* * practically identical to above, but let's be careful about * tcp vs udp headers */ if(ixs->iph->protocol == IPPROTO_TCP) { struct tcphdr *t = NULL; if((ntohs(ixs->iph->frag_off) & IP_OFFSET) == 0 && ((ixs->skb->len - ixs->hard_header_len) >= ((ixs->iph->ihl << 2) + sizeof(struct tcphdr)))) { t =((struct tcphdr*)((caddr_t)ixs->iph+(ixs->iph->ihl<<2))); } ixs->sport=0; ixs->dport=0; if(ixs->skb->sk) {#ifdef NET_26 struct tcp_tw_bucket *tw; tw = (struct tcp_tw_bucket *)ixs->skb->sk; ixs->sport = ntohs(tw->tw_sport); ixs->dport = ntohs(tw->tw_dport);#else ixs->sport = ntohs(ixs->skb->sk->sport); ixs->dport = ntohs(ixs->skb->sk->dport);#endif } if(t != NULL) { if(ixs->sport == 0) { ixs->sport = ntohs(t->source); } if(ixs->dport == 0) { ixs->dport = ntohs(t->dest); } } } /* default to a %drop eroute */ ixs->outgoing_said.proto = IPPROTO_INT; ixs->outgoing_said.spi = htonl(SPI_DROP); ixs->outgoing_said.dst.u.v4.sin_addr.s_addr = INADDR_ANY; KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_xmit_SAlookup: " "checking for local udp/500 IKE packet " "saddr=%x, er=0p%p, daddr=%x, er_dst=%x, proto=%d sport=%d dport=%d\n", ntohl((unsigned int)ixs->iph->saddr), ixs->eroute, ntohl((unsigned int)ixs->iph->daddr), ixs->eroute ? ntohl((unsigned int)ixs->eroute->er_said.dst.u.v4.sin_addr.s_addr) : 0, ixs->iph->protocol, ixs->sport, ixs->dport); /* * cheat for now...are we udp/500? If so, let it through * without interference since it is most likely an IKE packet. */ if (ip_chk_addr((unsigned long)ixs->iph->saddr) == IS_MYADDR && (ixs->eroute==NULL || ixs->iph->daddr == ixs->eroute->er_said.dst.u.v4.sin_addr.s_addr || INADDR_ANY == ixs->eroute->er_said.dst.u.v4.sin_addr.s_addr) && (ixs->iph->protocol == IPPROTO_UDP && ixs->sport == 500)) { /* Whatever the eroute, this is an IKE message * from us (i.e. not being forwarded). * Furthermore, if there is a tunnel eroute, * the destination is the peer for this eroute. * So %pass the packet: modify the default %drop. */ ixs->outgoing_said.spi = htonl(SPI_PASS); if(!(ixs->skb->sk) && ((ntohs(ixs->iph->frag_off) & IP_MF) != 0)) { KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_xmit_SAlookup: " "local UDP/500 (probably IKE) passthrough: base fragment, rest of fragments will probably get filtered.\n"); } bypass = TRUE; }#ifdef KLIPS_EXCEPT_DNS53 /* * * if we are udp/53 or tcp/53, also let it through a %trap or %hold, * since it is DNS, but *also* follow the %trap. * * we do not do this for tunnels, only %trap's and %hold's. * */ if (ip_chk_addr((unsigned long)ixs->iph->saddr) == IS_MYADDR && (ixs->eroute==NULL || ixs->iph->daddr == ixs->eroute->er_said.dst.u.v4.sin_addr.s_addr || INADDR_ANY == ixs->eroute->er_said.dst.u.v4.sin_addr.s_addr) && ((ixs->iph->protocol == IPPROTO_UDP || ixs->iph->protocol == IPPROTO_TCP) && ixs->dport == 53)) { KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_xmit_SAlookup: " "possible DNS packet\n"); if(ixs->eroute) { if(ixs->eroute->er_said.spi == htonl(SPI_TRAP) || ixs->eroute->er_said.spi == htonl(SPI_HOLD)) { ixs->outgoing_said.spi = htonl(SPI_PASSTRAP); bypass = TRUE; } } else { ixs->outgoing_said.spi = htonl(SPI_PASSTRAP); bypass = TRUE; } KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_xmit_SAlookup: " "bypass = %d\n", bypass); if(bypass && !(ixs->skb->sk) && ((ntohs(ixs->iph->frag_off) & IP_MF) != 0)) { KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_xmit_SAlookup: " "local port 53 (probably DNS) passthrough:" "base fragment, rest of fragments will " "probably get filtered.\n"); } }#endif if (bypass==FALSE && ixs->eroute) { ixs->eroute->er_count++; ixs->eroute->er_lasttime = jiffies/HZ; if(ixs->eroute->er_said.proto==IPPROTO_INT && ixs->eroute->er_said.spi==htonl(SPI_HOLD)) { KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_xmit_SAlookup: " "shunt SA of HOLD: skb stored in HOLD.\n"); if(ixs->eroute->er_last != NULL) { kfree_skb(ixs->eroute->er_last); } ixs->eroute->er_last = ixs->skb; ixs->skb = NULL; ixs->stats->tx_dropped++; spin_unlock(&eroute_lock); return IPSEC_XMIT_STOLEN; } ixs->outgoing_said = ixs->eroute->er_said; ixs->eroute_pid = ixs->eroute->er_pid; /* Copy of the ident for the TRAP/TRAPSUBNET eroutes */ if(ixs->outgoing_said.proto==IPPROTO_INT && (ixs->outgoing_said.spi==htonl(SPI_TRAP) || (ixs->outgoing_said.spi==htonl(SPI_TRAPSUBNET)))) { int len; ixs->ips.ips_ident_s.type = ixs->eroute->er_ident_s.type; ixs->ips.ips_ident_s.id = ixs->eroute->er_ident_s.id; ixs->ips.ips_ident_s.len = ixs->eroute->er_ident_s.len; if (ixs->ips.ips_ident_s.len) { len = ixs->ips.ips_ident_s.len * IPSEC_PFKEYv2_ALIGN - sizeof(struct sadb_ident); KLIPS_PRINT(debug_tunnel & DB_TN_XMIT, "klips_debug:ipsec_xmit_SAlookup: " "allocating %d bytes for ident_s shunt SA of HOLD: skb stored in HOLD.\n", len); if ((ixs->ips.ips_ident_s.data = kmalloc(len, GFP_ATOMIC)) == NULL) { printk(KERN_WARNING "klips_debug:ipsec_xmit_SAlookup: " "Failed, tried to allocate %d bytes for source ident.\n", len); ixs->stats->tx_dropped++; spin_unlock(&eroute_lock); return IPSEC_XMIT_ERRMEMALLOC; } memcpy(ixs->ips.ips_ident_s.data, ixs->eroute->er_ident_s.data, len); } ixs->ips.ips_ident_d.type = ixs->eroute->er_ident_d.type; ixs->ips.ips_ident_d.id = ixs->eroute->er_ident_d.id; ixs->ips.ips_ident_d.len = ixs->eroute->er_ident_d.len; if (ixs->ips.ips_ident_d.len)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -