📄 output.c
字号:
/* 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: linux-2.4.0-cipe-1.4.5.patch,v 1.6 2001/04/17 18:50:11 arjanv Exp $ */#include "cipe.h"#include <net/ip.h>#include <net/icmp.h>#include <linux/if_arp.h>#include <linux/socket.h>#include <linux/version.h>#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)#include <linux/netfilter_ipv4.h>#else#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) (okfn)(skb)#endif#ifdef DEBUGstatic void cipe_hexdump(const unsigned char *bp, unsigned int len){ static const __u16 p[16]={0,2,5,7,10,12,15,17,21,23,26,28,31,33,36,38}; static const char h[16]="0123456789abcdef"; short i=0, j=0; static /*?*/ char b[58]; printk(KERN_DEBUG "(cipe_hexdump %p %x)\n", bp, len); if (len>1024) len=1024; /* sanity */ memset(b, ' ', sizeof(b)); while (len-->0) { if (i>15) { b[sizeof(b)-1]=0; printk(KERN_DEBUG " %04x: %s\n", j, b); memset(b, ' ', sizeof(b)); i=0; j+=16; } b[p[i]]=h[*bp>>4]; b[p[i]+1]=h[*bp&15]; b[i+42]=(((*bp)&0x60)==0||*bp==127)?'.':*bp; ++bp; ++i; } b[sizeof(b)-1]=0; printk(KERN_DEBUG " %04x: %s\n", j, b);}void cipe_dump_packet(char *title, struct sk_buff *skb, int dumpskb){ LOCK_PRINTK; if (dumpskb) { printk(KERN_DEBUG "SKB:\n"); cipe_hexdump((unsigned char *)skb, sizeof(*skb)); } printk(KERN_DEBUG#ifdef LINUX_21 "%s: packet len=%x dev=%s\n",#else "%s: packet len=%lx dev=%s\n",#endif 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_select_ident(h,d) (h)->id=htons(ip_id_count++)#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/* Need this wrapper because NF_HOOK takes the function address, and ip_send was declared "extern inline" in the vague past. --RR */static inline int do_ip_send(struct sk_buff *skb){ return ip_send(skb);}int 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 = skb->nh.iph; u8 tos = old_iph->tos; u16 df = old_iph->frag_off&__constant_htons(IP_DF); u8 ttl = tunnel->cttl ? tunnel->cttl : old_iph->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 = ntohs(skb->nh.iph->tot_len); dprintk(DEB_OUT, (KERN_DEBUG "%s: cipe_xmit len=%d(%d)\n", dev->name, length, skb->len)); if (length!=skb->len) { printk(KERN_ERR "%s: cipe_xmit packet length problem\n", dev->name); goto tx_error_out; } 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; } if (skb->protocol != __constant_htons(ETH_P_IP)) goto tx_error_out; /* Tell the netfilter framework that this packet is not the same as the one before! */#ifdef CONFIG_NETFILTER nf_conntrack_put(skb->nfct); skb->nfct = NULL;#ifdef CONFIG_NETFILTER_DEBUG skb->nf_debug = 0;#endif#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 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; } if (rt->rt_src!=tunnel->myaddr) { printk(KERN_NOTICE "%s: changing my address: %s\n", dev->name, cipe_ntoa(rt->rt_src)); tunnel->myaddr=tunnel->sock->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; } mtu = rt->u.dst.pmtu - (cipehdrlen+cipefootlen); if (tunnel->sockshost) mtu -= sizeof(struct sockshdr); dprintk(DEB_OUT, (KERN_DEBUG "pmtu=%d dmtu=%d size=%d\n", mtu, tdev->mtu, skb->len)); if (mtu < 68) { printk(KERN_ERR "%s: MTU too small\n", dev->name); tunnel->stat.collisions++; goto tx_error; } 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 } if ((old_iph->frag_off&__constant_htons(IP_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; }#ifdef DEBUG if (cipe_debug&DEB_PKOU) cipe_dump_packet("original", skb, 0);#endif 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) {#ifndef VER_SHORT /* Add an IV */ cipe_cryptpad(skb_push(skb, blockSize)); length+=blockSize;#endif 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); ip_select_ident(iph, &rt->u.dst, tunnel->sock);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -