📄 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: 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 + -