📄 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 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.187 2002/03/23 19:55:17 rgb 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() *//* XXX-mcr remove this definition when the code has been properly rototiled */#define IPSEC_KLIPS1_COMPAT 1#include "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 <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/tcp.h> /* struct tcphdr */#include <linux/udp.h> /* struct udphdr */#include <linux/skbuff.h>#include <freeswan.h>#ifdef NET_21# define MSS_HACK_ /* experimental */# 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 proto_priv cb# 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>#ifdef MSS_HACK# include <net/tcp.h> /* TCP options */#endif /* MSS_HACK */#include "radij.h"#include "ipsec_life.h"#include "ipsec_xform.h"#include "ipsec_eroute.h"#include "ipsec_encap.h"#include "ipsec_radij.h"#include "ipsec_netlink.h"#include "ipsec_sa.h"#include "ipsec_tunnel.h"#include "ipsec_ipe4.h"#include "ipsec_ah.h"#include "ipsec_esp.h"#ifdef CONFIG_IPSEC_IPCOMP# include "ipcomp.h"#endif /* CONFIG_IPSEC_IPCOMP */#include <pfkeyv2.h>#include <pfkey.h>#include "ipsec_proto.h"static __u32 zeroes[64];#ifdef CONFIG_IPSEC_DEBUGint debug_tunnel = 0;int sysctl_ipsec_debug_verbose = 0;#endif /* CONFIG_IPSEC_DEBUG */int sysctl_ipsec_icmp = 0;int sysctl_ipsec_tos = 0;/* * If the IP packet (iph) is a carrying TCP/UDP, then set the encaps * source and destination ports to those from the TCP/UDP header. */static void extract_ports(struct iphdr * iph, struct sockaddr_encap * er){ struct udphdr *udp; switch (iph->protocol) { case IPPROTO_UDP: case IPPROTO_TCP: /* * The ports are at the same offsets in a TCP and UDP * header so hack it ... */ udp = (struct udphdr*)(((char*)iph)+(iph->ihl<<2)); er->sen_sport = udp->source; er->sen_dport = udp->dest; break; default: er->sen_sport = 0; er->sen_dport = 0; break; }}/* * A TRAP eroute is installed and we want to replace it with a HOLD * eroute. */static int create_hold_eroute(struct sk_buff * skb, struct iphdr * iph, uint32_t eroute_pid){ struct eroute hold_eroute; struct sa_id hold_said; struct sk_buff *first, *last; int error; first = last = NULL; memset((caddr_t)&hold_eroute, 0, sizeof(hold_eroute)); memset((caddr_t)&hold_said, 0, sizeof(hold_said)); hold_said.proto = IPPROTO_INT; hold_said.spi = htonl(SPI_HOLD); hold_said.dst.s_addr = INADDR_ANY; hold_eroute.er_eaddr.sen_len = sizeof(struct sockaddr_encap); hold_eroute.er_emask.sen_len = sizeof(struct sockaddr_encap); hold_eroute.er_eaddr.sen_family = AF_ENCAP; hold_eroute.er_emask.sen_family = AF_ENCAP; hold_eroute.er_eaddr.sen_type = SENT_IP4; hold_eroute.er_emask.sen_type = 255; hold_eroute.er_eaddr.sen_ip_src.s_addr = iph->saddr; hold_eroute.er_eaddr.sen_ip_dst.s_addr = iph->daddr; hold_eroute.er_emask.sen_ip_src.s_addr = INADDR_BROADCAST; hold_eroute.er_emask.sen_ip_dst.s_addr = INADDR_BROADCAST; hold_eroute.er_emask.sen_sport = ~0; hold_eroute.er_emask.sen_dport = ~0; hold_eroute.er_pid = eroute_pid; hold_eroute.er_count = 0; hold_eroute.er_lasttime = jiffies/HZ; hold_eroute.er_eaddr.sen_proto = iph->protocol; extract_ports(iph, &hold_eroute.er_eaddr);#ifdef CONFIG_IPSEC_DEBUG if (debug_pfkey) { char buf1[64], buf2[64]; subnettoa(hold_eroute.er_eaddr.sen_ip_src, hold_eroute.er_emask.sen_ip_src, 0, buf1, sizeof(buf1)); subnettoa(hold_eroute.er_eaddr.sen_ip_dst, hold_eroute.er_emask.sen_ip_dst, 0, buf2, sizeof(buf2)); KLIPS_PRINT(debug_pfkey, "klips_debug:ipsec_tunnel_start_xmit: " "calling breakeroute and makeroute for %s:%d->%s:%d %d HOLD eroute.\n", buf1, ntohs(hold_eroute.er_eaddr.sen_sport), buf2, ntohs(hold_eroute.er_eaddr.sen_dport), hold_eroute.er_eaddr.sen_proto); }#endif /* CONFIG_IPSEC_DEBUG */ if (ipsec_breakroute(&(hold_eroute.er_eaddr), &(hold_eroute.er_emask), &first, &last, 0)) { KLIPS_PRINT(debug_pfkey, "klips_debug:ipsec_tunnel_start_xmit: " "HOLD breakeroute found nothing.\n"); } else { KLIPS_PRINT(debug_pfkey, "klips_debug:ipsec_tunnel_start_xmit: " "HOLD breakroute deleted %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u %u\n", NIPQUAD(hold_eroute.er_eaddr.sen_ip_src), ntohs(hold_eroute.er_eaddr.sen_sport), NIPQUAD(hold_eroute.er_eaddr.sen_ip_dst), ntohs(hold_eroute.er_eaddr.sen_dport), hold_eroute.er_eaddr.sen_proto); } if (first != NULL) kfree_skb(first); if (last != NULL) kfree_skb(last); error = ipsec_makeroute(&(hold_eroute.er_eaddr), &(hold_eroute.er_emask), hold_said, eroute_pid, skb, NULL, NULL); if (error) { KLIPS_PRINT(debug_pfkey, "klips_debug:ipsec_tunnel_start_xmit: " "HOLD makeroute returned %d, failed.\n", error); } else { KLIPS_PRINT(debug_pfkey, "klips_debug:ipsec_tunnel_start_xmit: " "HOLD makeroute call successful.\n"); } return (error == 0);}#ifdef CONFIG_IPSEC_DEBUG_DEBUG_NO_STATIC voiddmp(char *s, caddr_t bb, int len){ int i; unsigned char *b = bb; if (debug_tunnel) { printk(KERN_INFO "klips_debug:ipsec_tunnel_:dmp: " "at %s, len=%d:", s, len); for (i=0; i < len; i++) { if(!(i%16)){ printk("\nklips_debug: "); } printk(" %02x", *b++); } printk("\n"); }}#else /* CONFIG_IPSEC_DEBUG */#define dmp(_x, _y, _z) #endif /* CONFIG_IPSEC_DEBUG */#ifndef SKB_COPY_EXPAND/* * This is mostly skbuff.c:skb_copy(). */struct sk_buff *skb_copy_expand(struct sk_buff *skb, int headroom, int tailroom, int priority){ struct sk_buff *n; unsigned long offset; /* * Do sanity checking */ if((headroom < 0) || (tailroom < 0) || ((headroom+tailroom) < 0)) { printk(KERN_WARNING "klips_error:skb_copy_expand: " "Illegal negative head,tailroom %d,%d\n", headroom, tailroom); return NULL; } /* * Allocate the copy buffer */ #ifndef NET_21 IS_SKB(skb);#endif /* !NET_21 */ n=alloc_skb(skb->end - skb->head + headroom + tailroom, priority); KLIPS_PRINT(debug_tunnel & DB_TN_CROUT, "klips_debug:skb_copy_expand: " "head=%p data=%p tail=%p end=%p end-head=%d tail-data=%d\n", skb->head, skb->data, skb->tail, skb->end, skb->end - skb->head, skb->tail - skb->data); if(n==NULL) return NULL; /* * Shift between the two data areas in bytes */ /* offset=n->head-skb->head; */ /* moved down a few lines */ /* Set the data pointer */ skb_reserve(n,skb->data-skb->head+headroom); /* Set the tail pointer and length */ if(skb_tailroom(n) < skb->len) { printk(KERN_WARNING "klips_error:skb_copy_expand: " "tried to skb_put %ld, %d available. This should never happen, please report.\n", (unsigned long int)skb->len, skb_tailroom(n)); dev_kfree_skb(n, FREE_WRITE); return NULL; } skb_put(n,skb->len); offset=n->head + headroom - skb->head; /* Copy the bytes */ memcpy(n->head + headroom, skb->head,skb->end-skb->head);#ifdef NET_21 n->csum=skb->csum; n->priority=skb->priority; n->dst=dst_clone(skb->dst); if(skb->nh.raw) n->nh.raw=skb->nh.raw+offset;#ifndef NETDEV_23 n->is_clone=0;#endif /* NETDEV_23 */ atomic_set(&n->users, 1); n->destructor = NULL; n->security=skb->security;#else /* NET_21 */ n->link3=NULL; n->when=skb->when; if(skb->ip_hdr) n->ip_hdr=(struct iphdr *)(((char *)skb->ip_hdr)+offset); n->saddr=skb->saddr; n->daddr=skb->daddr; n->raddr=skb->raddr; n->seq=skb->seq; n->end_seq=skb->end_seq; n->ack_seq=skb->ack_seq; n->acked=skb->acked; n->free=1; n->arp=skb->arp; n->tries=0; n->lock=0; n->users=0;#endif /* NET_21 */ n->protocol=skb->protocol; n->list=NULL; n->sk=NULL; n->dev=skb->dev; if(skb->h.raw) n->h.raw=skb->h.raw+offset; if(skb->mac.raw) n->mac.raw=skb->mac.raw+offset; memcpy(n->proto_priv, skb->proto_priv, sizeof(skb->proto_priv));#ifndef NETDEV_23 n->used=skb->used;#endif /* !NETDEV_23 */ n->pkt_type=skb->pkt_type; n->stamp=skb->stamp; #ifndef NET_21 IS_SKB(n);#endif /* !NET_21 */ return n;}#endif /* !SKB_COPY_EXPAND */#ifdef CONFIG_IPSEC_DEBUGvoidipsec_print_ip(struct iphdr *ip){ char buf[ADDRTOA_BUF]; printk(KERN_INFO "klips_debug: IP:"); printk(" ihl:%d", ip->ihl*4); printk(" ver:%d", ip->version); printk(" tos:%d", ip->tos); printk(" tlen:%d", ntohs(ip->tot_len)); printk(" id:%d", ntohs(ip->id)); printk(" %s%s%sfrag_off:%d", ip->frag_off & __constant_htons(IP_CE) ? "CE " : "", ip->frag_off & __constant_htons(IP_DF) ? "DF " : "", ip->frag_off & __constant_htons(IP_MF) ? "MF " : "", (ntohs(ip->frag_off) & IP_OFFSET) << 3); printk(" ttl:%d", ip->ttl); printk(" proto:%d", ip->protocol); if(ip->protocol == IPPROTO_UDP) printk(" (UDP)"); if(ip->protocol == IPPROTO_TCP) printk(" (TCP)"); if(ip->protocol == IPPROTO_ICMP) printk(" (ICMP)"); printk(" chk:%d", ntohs(ip->check)); addrtoa(*((struct in_addr*)(&ip->saddr)), 0, buf, sizeof(buf)); printk(" saddr:%s", buf); if(ip->protocol == IPPROTO_UDP) printk(":%d", ntohs(((struct udphdr*)((caddr_t)ip + (ip->ihl << 2)))->source)); if(ip->protocol == IPPROTO_TCP) printk(":%d", ntohs(((struct tcphdr*)((caddr_t)ip + (ip->ihl << 2)))->source)); addrtoa(*((struct in_addr*)(&ip->daddr)), 0, buf, sizeof(buf)); printk(" daddr:%s", buf); if(ip->protocol == IPPROTO_UDP) printk(":%d", ntohs(((struct udphdr*)((caddr_t)ip + (ip->ihl << 2)))->dest)); if(ip->protocol == IPPROTO_TCP) printk(":%d", ntohs(((struct tcphdr*)((caddr_t)ip + (ip->ihl << 2)))->dest)); if(ip->protocol == IPPROTO_ICMP) printk(" type:code=%d:%d", ((struct icmphdr*)((caddr_t)ip + (ip->ihl << 2)))->type, ((struct icmphdr*)((caddr_t)ip + (ip->ihl << 2)))->code); printk("\n"); if(sysctl_ipsec_debug_verbose) { __u8 *c; int i; c = ((__u8*)ip) + ip->ihl*4; for(i = 0; i < ntohs(ip->tot_len) - ip->ihl*4; i++ /*, c++*/) { if(!(i % 16)) { printk(KERN_INFO "klips_debug: @%03x:", i); } printk(" %02x", /***/c[i]); if(!((i + 1) % 16)) { printk("\n"); } } if(i % 16) { printk("\n"); } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -