⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 output.c

📁 cipe 编程
💻 C
📖 第 1 页 / 共 2 页
字号:
/*   CIPE - encrypted IP over UDP tunneling   output.c - the sending part of the CIPE device   Copyright 1996 Olaf Titz <olaf@bigred.inka.de>   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.*//* $Id: output.c,v 1.52 2004/03/06 22:16:41 olaf81825 Exp $ */#include "cipe.h"#include <net/checksum.h>#include <net/ip.h>#include <net/icmp.h>#include <linux/if_arp.h>#include <linux/socket.h>#include <linux/version.h>#ifdef LINUX_24#include <linux/netfilter.h>#include <linux/netfilter_ipv4.h>#endif#ifdef DEBUG#include "../lib/hexdump.c"void cipe_dump_packet(char *title, struct sk_buff *skb, int dumpskb){    LOCK_PRINTK;    if (dumpskb) {	printk(KERN_DEBUG "SKB (%s):\n", skb->dev?skb->dev->name:"");	cipe_hexdump((unsigned char *)skb, sizeof(*skb));    }    printk(KERN_DEBUG           "%s: packet len=" FLEN " dev=%s\n",           title, skb->len, skb->dev?skb->dev->name:"<none>");    cipe_hexdump((unsigned char *)skb->data, skb->tail-skb->data);    UNLOCK_PRINTK;}#endif#ifdef LINUX_21/* An adapted version of Linux 2.1 net/ipv4/ipip.c output routine. */#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,37)#define ip_ident(h,d) (h)->id=htons(ip_id_count++)#else#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)#define ip_ident(h,d) ip_select_ident(h,d)#else#define ip_ident(h,d) ip_select_ident(h,d,NULL)#endif#endif#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,36)/* this is not exactly the newer kernel's routine, it just does what we need */struct sk_buff *skb_copy_expand(struct sk_buff *skb, int max_headroom,				int max_tailroom, int gfp){    struct sk_buff *n=alloc_skb(skb->len+max_headroom+max_tailroom, gfp);    if (n) {	skb_reserve(n, max_headroom);	skb_put(n,skb->len);	memcpy(n->data,skb->data,skb->len);	n->priority=skb->priority;	n->protocol=skb->protocol;	n->dev=skb->dev;	n->dst=dst_clone(skb->dst);	memcpy(n->cb, skb->cb, sizeof(skb->cb));	n->used=skb->used;	n->is_clone=0;	atomic_set(&n->users, 1);	n->pkt_type=skb->pkt_type;	n->stamp=skb->stamp;	n->security=skb->security;#ifdef CONFIG_IP_FIREWALL	n->fwmark = skb->fwmark;#endif    }    return n;}#endif#ifdef LINUX_24/* Need this wrapper because NF_HOOK takes the function address */static inline int do_ip_send(struct sk_buff *skb){	return ip_send(skb);}#endifint cipe_xmit(struct sk_buff *skb, struct NET_DEVICE *dev){        struct cipe *tunnel = (struct cipe*)(dev->priv);	struct rtable *rt = NULL;			/* Route to the other host */	struct NET_DEVICE *tdev;			/* Device to other host */	struct iphdr  *old_iph;	u8     	tos = 0;	u16	df = 0;	u8	ttl;	struct iphdr  *iph;			/* Our new IP header */        struct udphdr *udph;	int    	max_headroom;			/* The extra header space needed */	int    	max_tailroom;	u32    	dst = tunnel->peeraddr;	int    	mtu;        int     length = skb->len;       	dprintk(DEB_OUT, (KERN_INFO "%s: cipe_xmit len=%d\n", dev->name,			  length));        if (tunnel->magic!=CIPE_MAGIC) {            printk(KERN_ERR DEVNAME                   ": cipe_xmit called with wrong struct\n");            return 0;        }	if (tunnel->recursion++) {        	printk(KERN_ERR "%s: cipe_xmit reentrance\n", dev->name);		tunnel->stat.collisions++;		goto tx_error_out;	}#ifdef DEBUG        if (cipe_debug&DEB_PKOU)            cipe_dump_packet("original", skb, 1);#endif#ifdef VER_ETH	/* A packet can contain anything. If sending from a bridge,	   the header pointers are invalid. So compute our own. */	old_iph = (skb->protocol==htons(ETH_P_IP))	          ? (struct iphdr*)(skb->data+ETH_HLEN)	          : NULL;#else	old_iph = skb->nh.iph; /* we get only proper IP packets */#endif	if (old_iph) {	    int ilen = ntohs(old_iph->tot_len)#ifdef VER_ETH		        +ETH_HLEN#endif		                 ;	    if (length!=ilen) {		printk(KERN_ERR "%s: cipe_xmit packet length problem %d/%d\n",		       dev->name, length, ilen);		goto tx_error_out;	    }	    tos = old_iph->tos;	    if (!tunnel->flags&CIPF_IGNORE_DF)	    	df = old_iph->frag_off&__constant_htons(IP_DF);	    ttl = tunnel->cttl ? tunnel->cttl : old_iph->ttl;	} else {	    ttl = tunnel->cttl ? tunnel->cttl : 64; /* XX */	}#ifndef VER_ETH	if (skb->protocol != __constant_htons(ETH_P_IP))		goto tx_error_out;#endif#if 0        dprintk(DEB_OUT, (KERN_DEBUG "routing dst=%s src=%s tos=%x oif=%d\n",                          cipe_ntoa(0, dst), cipe_ntoa(1, tunnel->myaddr),                          RT_TOS(tos), tunnel->sock->bound_dev_if));#endif#ifdef LINUX_25	{            struct flowi fl = { .oif = SOCK(tunnel)->sk_bound_dev_if,                                .nl_u = { .ip4_u =                                          { .daddr = dst,                                            .saddr = IOPT(tunnel)->rcv_saddr,                                            .tos = RT_TOS(tos) } },                                .proto = IPPROTO_UDP };            if (ip_route_output_key(&rt, &fl)) {                dprintk(DEB_OUT, (KERN_NOTICE "%s: no route\n", dev->name));                tunnel->stat.tx_carrier_errors++;                dst_link_failure(skb);                goto tx_error_out;            }	}#else	if (ip_route_output(&rt, dst, tunnel->sock->rcv_saddr, RT_TOS(tos),                            tunnel->sock->bound_dev_if)) {            dprintk(DEB_OUT, (KERN_NOTICE "%s: no route\n", dev->name));            tunnel->stat.tx_carrier_errors++;            dst_link_failure(skb);            goto tx_error_out;        }#endif        if (rt->rt_src!=tunnel->myaddr) {            printk(KERN_NOTICE "%s: changing my address: %s\n", dev->name,                   cipe_ntoa(rt->rt_src));            tunnel->myaddr=IOPT(tunnel)->saddr=rt->rt_src;	}	tdev = rt->u.dst.dev;        dprintk(DEB_OUT, (KERN_DEBUG "route dev=%s flags=%x type=%x\n",                          tdev->name, rt->rt_flags, rt->rt_type));	if (tdev == dev) {        	printk(KERN_ERR "%s: looped route\n", dev->name);		tunnel->stat.collisions++;		goto tx_error;	}	if (tunnel->flags&CIPF_FORCE_MTU) {		mtu = dev->mtu;	} else {        	mtu = dst_pmtu(&rt->u.dst) - (cipehdrlen+cipefootlen);        	if (tunnel->sockshost)            		mtu -= sizeof(struct sockshdr);        }        dprintk(DEB_OUT, (KERN_DEBUG "pmtu=%d dmtu=%d size=%d df=%d forcemtu=%d ignoredf=%d\n",                          mtu, tdev->mtu, skb->len, df,                          (tunnel->flags&CIPF_FORCE_MTU)?1:0,                          (tunnel->flags&CIPF_IGNORE_DF)?1:0));	if (mtu < 68) {        	printk(KERN_ERR "%s: MTU too small\n", dev->name);		tunnel->stat.collisions++;		goto tx_error;	}#ifdef LINUX_25	if (skb->dst)		skb->dst->ops->update_pmtu(skb->dst, mtu);#else	if (skb->dst && mtu < skb->dst->pmtu) {		skb->dst->pmtu = mtu;        	dprintk(DEB_OUT, (KERN_NOTICE "%s: adjusting PMTU\n", dev->name));#if 0                /* TEST: is this OK? */		icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));                goto tx_error;#endif        }#endif	if (old_iph && df && mtu < ntohs(old_iph->tot_len)) {        	dprintk(DEB_OUT, (KERN_NOTICE "%s: fragmentation needed\n", dev->name));		icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));		goto tx_error;	}        max_headroom = ((tdev->hard_header_len+cipehdrlen+			 ((tunnel->sockshost) ? sizeof(struct sockshdr) : 0)	                )+16)&(~15);        max_tailroom = (tunnel->flags&CIPF_HAVE_KEY) ? cipefootlen : 0;	{	    struct sk_buff *n= skb_copy_expand(skb, max_headroom,                                               max_tailroom, GFP_ATOMIC);            if (!n) {                printk(KERN_INFO "%s: Out of memory, dropped packet\n",                       dev->name);                goto tx_error;            }            if (skb->sk)                    skb_set_owner_w(n, skb->sk);	    dev_kfree_skb(skb);            skb = n;        }	memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));	dst_release(skb->dst);	skb->dst = &rt->u.dst;	skb->protocol = htons(ETH_P_IP);	if (tunnel->flags&CIPF_HAVE_KEY) {	    /* Add an IV */            int ivs = crypto_tfm_alg_ivsize(tunnel->key);	    cipe_cryptpad_iv(skb_push(skb, ivs), ivs);	    length+=ivs;            if (!tunnel->flags&CIPF_MAY_STKEY && !tunnel->flags&CIPF_HAVE_SKEY)                /* Attempt to encrypt data using invalid static key */                goto tx_error;	    cipe_encrypt(tunnel, skb->data, &length, TW_DATA);	    /* This is incorrect - the tail room gets first used and then	       reserved. Doesn't matter in the current (2.0.29) implementation	       of skb_put though. Alternative solution would ruin the nice	       module separation - we don't need to know the real amount	       of padding here. */	    if (length-skb->len > skb->end-skb->tail) {		printk(KERN_ERR "%s: tailroom problem %d %d %d\n",		       dev->name, length, skb->len, skb->end-skb->tail);		goto tx_error;	    }	    (void) skb_put(skb, length-skb->len);	} else if (!tunnel->flags&CIPF_MAY_CLEAR) {	    goto tx_error;	}        if (tunnel->sockshost) {	    /* Install a SOCKS header */	    struct sockshdr *sh = (struct sockshdr *)		skb_push(skb, sizeof(struct sockshdr));	    memset(sh, 0, 4);	    sh->atyp=1;	    /* sockshost and socksport contain the real peer's address	       and the configured/guessed peer is really the socks relayer! */	    sh->dstaddr=tunnel->sockshost;	    sh->dstport=tunnel->socksport;	    length+=sizeof(struct sockshdr);	}        /* Install our new headers */        udph = skb->h.uh = (struct udphdr *) skb_push(skb, sizeof(struct udphdr));	skb->mac.raw = skb_push(skb, sizeof(struct iphdr));        iph = skb->nh.iph = (struct iphdr *) skb->mac.raw;	/*	 *	Push down and install the CIPE/UDP header.	 */	iph->version    =	4;	iph->ihl        =	sizeof(struct iphdr)>>2;	iph->tos        =	tos;	iph->tot_len    =	htons(skb->len);        iph->frag_off   =	df;        iph->ttl        =	ttl;	iph->protocol   =	IPPROTO_UDP;	iph->saddr      =	rt->rt_src;	iph->daddr      =	rt->rt_dst;	ip_ident(iph, &rt->u.dst);	ip_send_check(iph);        udph->source = tunnel->myport;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -