📄 sock.c
字号:
/* CIPE - encrypted IP over UDP tunneling sock.c - socket/input interface 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: sock.c,v 1.47 2004/03/06 22:16:41 olaf81825 Exp $ */#include "cipe.h"#include <linux/config.h>#include <linux/sched.h>#include <net/sock.h>#include <net/ip.h>#include <linux/tcp.h>#include <linux/etherdevice.h>#ifdef LINUX_21#include <asm/uaccess.h>#elsetypedef unsigned short mm_segment_t;#endif#ifdef LINUX_21#define kfreeskb(s,t) kfree_skb(s)#define saddr(skb) ((skb)->nh.iph->saddr)#define daddr(skb) ((skb)->nh.iph->daddr)#else#define kfreeskb(s,t) kfree_skb(s,t)#define saddr(skb) ((skb)->saddr)#define daddr(skb) ((skb)->daddr)#endif/* Rewire generic socket operations to our device-specific ones. We have new routines for close, sendmsg, recvmsg. */#ifndef LINUX_21#define user_data protinfo.af_packet.bound_dev#endif/* init struct cipe *c based on struct sock *sk */#define SOCKTOC(nam,sk,c) \ struct cipe *c=(struct cipe *)sk->sk_user_data; \ BUG_ON((!c) || (c->magic!=CIPE_MAGIC)); \ dprintk(DEB_CALL, (KERN_INFO "%s: " nam "\n", c->dev->name));/* Close the socket */void cipe_sock_close(struct sock *sock, timeout_t timeout){ SOCKTOC("sock_close",sock,c); c->sock=NULL; /* Put back the old protocol block and let it do the close */ sock->sk_prot=c->udp_prot; sock->sk_prot->close(sock, timeout); if (c->dev->flags&IFF_UP) { rtnl_LOCK(); dev_close(c->dev); rtnl_UNLOCK(); } else { cipe_close(c); }}/* Anything we send to this socket is in fact a key exchange block. Encode and encrypt it accordingly.*/int cipe_sendmsg(#ifdef LINUX_25 struct kiocb *iocb,#endif struct sock *sock, struct msghdr *msg#ifdef LINUX_25 , size_t len#else , int len#endif#ifndef LINUX_21 , int nonblock, int flags#endif ){ struct msghdr mymsg; struct iovec myio[2]; struct sockaddr_in sa; struct sockshdr sh; int e, n=0, ivs; unsigned char buf[KEYXCHGBLKMAX]; SOCKTOC("cipe_sendmsg",sock,c); ivs=crypto_tfm_alg_ivsize(c->key); if (!(c->flags&CIPF_HAVE_KEY) && !(msg->msg_flags&MSG_OOB)) return -EINVAL; if (len>KEYXCHGBLKMAX-ivs) return -EMSGSIZE; cipe_prnpad(buf, sizeof(buf)); memcpy_fromiovec(buf+ivs, msg->msg_iov, len); len+=ivs; if (!(msg->msg_flags&MSG_OOB)) { if (buf[ivs]>=CT_DUMMY) { buf[KEYXCHGTSPOS-1]='\0'; } else { if (len<KEYXCHGBLKMIN) return -EINVAL; } } (*(__u32 *)(buf+KEYXCHGTSPOS))=htonl(CURRENT_TIME_SEC); /* timestamp */ if (msg->msg_flags&MSG_OOB) { memset(buf, 0, ivs); } else { len=KEYXCHGBLKMIN+buf[sizeof(buf)-1]; /* random */ cipe_encrypt(c, buf, (int*)&len, TW_NEWKEY); } sa.sin_family=AF_INET; sa.sin_addr.s_addr=c->peeraddr; sa.sin_port=c->peerport; if (c->sockshost) { /* Prepend a socks header. */ memset(&sh, 0, sizeof(sh)); sh.atyp=1; sh.dstaddr=c->sockshost; sh.dstport=c->socksport; myio[n].iov_base=&sh; myio[n].iov_len=sizeof(sh); ++n; } myio[n].iov_base=&buf; myio[n].iov_len=len; if (c->sockshost) len+=sizeof(struct sockshdr); /* mymsg=*msg; */ mymsg.msg_name=&sa; mymsg.msg_namelen=sizeof(sa); mymsg.msg_iov=myio; mymsg.msg_iovlen=n+1; /* just to be sure */ mymsg.msg_control=NULL; mymsg.msg_controllen=0; mymsg.msg_flags=0; /* Call the real thing. Pretend this is user space segment. */ { mm_segment_t fs=get_fs(); set_fs(get_ds()); dprintk(DEB_KXC, (KERN_INFO "%s: real sendmsg len %ld text=%04x...\n", c->dev->name, (long)len, ntohs(*((unsigned short *)(myio[n].iov_base)))));#ifdef LINUX_25 e=c->udp_prot->sendmsg(NULL, sock, &mymsg, len);#else#ifdef LINUX_21 e=c->udp_prot->sendmsg(sock, &mymsg, len);#else e=c->udp_prot->sendmsg(sock, &mymsg, len, nonblock, flags);#endif#endif set_fs(fs); } return e;}/* Check if we have a new peer */static void checkpeer(struct cipe *c, __u32 saddr, __u16 sport){ if (c->sockshost) { if (c->sockshost==saddr && c->socksport==sport) return; /* sockshost and socksport contain the real peer's address and the configured/guessed peer is really the socks relayer! */ c->sockshost=saddr; c->socksport=sport; } else { if (c->peeraddr==saddr && c->peerport==sport) return; c->peeraddr=saddr; c->peerport=sport; } printk(KERN_NOTICE "%s: new peer %s:%d\n", c->dev->name, cipe_ntoa(saddr), ntohs(sport));}/* Decrypt a received packet. Requeue it or return kxc block. *//* On entry the packet starts with the original UDP header, ip_hdr and h.uh are set to the IP and UDP headers. */struct sk_buff *cipe_decrypt_skb(struct cipe *c, struct sock *sk, struct sk_buff *skb, int *msgflag){ struct sk_buff *n=NULL; int length; __u32 rsaddr; __u16 rsport;#ifdef DEBUG if (cipe_debug&DEB_PKIN) cipe_dump_packet("received", skb, 1);#endif length=ntohs(skb->h.uh->len)-sizeof(struct udphdr);#if 0 /* UDP should check this */ if (length!=skb->len-sizeof(struct udphdr)) { dprintk(DEB_INP, (KERN_INFO "%s: bogus UDP length (%d/%d)\n", c->dev->name, length, skb->len-sizeof(struct udphdr))); goto framerr; }#endif if (length<9+(c->sockshost?sizeof(struct sockshdr):0)) { /* XX hardcoded IV size */ printk(KERN_INFO "%s: got short packet from %s\n", c->dev->name, cipe_ntoa(saddr(skb))); goto framerr; } n=alloc_skb(skb->len, GFP_KERNEL); if (!n) { printk(KERN_WARNING "%s: cipe_decrypt_skb: out of memory\n", c->dev->name); ++c->stat.rx_dropped; return NULL; }#if 0 /*def LINUX_21*/ if (skb->sk) skb_set_owner_r(n, skb->sk);#endif#ifndef LINUX_21 n->free=1;#endif n->dev=c->dev; /* Copy the datagram into new buffer, skip IP header */ /* We must copy here because raw sockets get only a clone of the skbuff, so they would receive the plaintext */ dprintk(DEB_INP, (KERN_INFO DEVNAME ": sa=%s da=%s us=%d ud=%d ul=%d\n", cipe_ntoa(saddr(skb)), cipe_ntoa(daddr(skb)), ntohs(skb->h.uh->source), ntohs(skb->h.uh->dest), ntohs(skb->h.uh->len))); /* why did this get swapped?? */#ifdef LINUX_21 rsaddr=saddr(skb);#else rsaddr=daddr(skb);#endif rsport=skb->h.uh->source; skb_put(n,skb->len);#ifdef LINUX_24 if (skb_is_nonlinear(skb)) {#ifdef DEBUG dprintk(DEB_INP, (KERN_INFO DEVNAME ": skb is non linear, will linearize\n"));#endif if (skb_linearize(skb, GFP_KERNEL) != 0) { printk(KERN_WARNING "%s: cipe_decrypt_skb: out of memory\n", c->dev->name); goto error; } }#endif memcpy(n->data, skb->h.raw, skb->len); n->h.uh=(struct udphdr *)n->data; if (c->sockshost) { /* Pull out the SOCKS header and correct the peer's address. */ struct sockshdr *sh; sh=(struct sockshdr *)skb_pull(n, sizeof(struct udphdr)); dprintk(DEB_INP, (KERN_INFO "socks: fr=%d at=%d da=%s dp=%d\n", sh->frag, sh->atyp, cipe_ntoa(sh->dstaddr), ntohs(sh->dstport))); if (sh->frag || (sh->atyp!=1)) goto error; /* Pull out UDP header */#ifdef LINUX_21 n->nh.iph=(struct iphdr *)skb_pull(n, sizeof(struct sockshdr));#else n->ip_hdr=(struct iphdr *)skb_pull(n, sizeof(struct sockshdr));#endif /***saddr(n)=sh->dstaddr;*/ rsaddr=sh->dstaddr; rsport=n->h.uh->source=sh->dstport; length-=sizeof(struct sockshdr); } else { /* Pull out UDP header */#ifdef LINUX_21 n->nh.iph=(struct iphdr *) skb_pull(n, sizeof(struct udphdr));#else n->ip_hdr=(struct iphdr *) skb_pull(n, sizeof(struct udphdr));#endif /***saddr(n)=rsaddr;*/ n->h.uh->source=rsport; } if (!(*((__u32 *)n->data) & htonl(0x7FFFFFFF))) { dprintk(DEB_INP, (KERN_INFO "got unencrypted control packet (iv=0) len=%d\n", length)); skb_pull(n, 8); /* XX hardcoded IV size */ /* XX not sure about TW_CTRL handling... */ switch (*n->data) { /* Restrict what can be received unencrypted. */ case CT_DUMMY: case CT_DEBUG: case CT_CONFREQ: case CT_CONF: break; default: printk(KERN_WARNING "%s: got disallowed unencrypted control %02x\n", c->dev->name, *n->data); goto error; }#ifdef LINUX_21 get_fast_time(&n->stamp);#endif /* No checkpeer() here because not authenticated! */ n->h.uh->check=0; return n; } if (c->flags&CIPF_HAVE_KEY) { if (length%crypto_tfm_alg_ivsize(c->key)) { printk(KERN_INFO "%s: got bogus length=%d\n", c->dev->name, length); goto error; } switch (cipe_decrypt(c, n->data, &length)) { case TW_DATA: if (!c->flags&CIPF_MAY_STKEY && !c->flags&CIPF_HAVE_RKEY) { printk(KERN_ERR "%s: got data using invalid static key\n", c->dev->name); goto error; } break; case TW_CTRL: /* return it as a control block - out of band datagram */ *msgflag|=MSG_OOB; /* fall thru */ case TW_NEWKEY: /* return it as key exchange block - proper UDP datagram */ dprintk(DEB_INP, (KERN_DEBUG "TW_NEWKEY data=%p len=" FLEN " length=%d\n", n->data, n->len, length));#ifdef LINUX_21 get_fast_time(&n->stamp);#endif skb_trim(n, length); checkpeer(c, rsaddr, rsport);#if 0 n->saddr=c->myaddr; n->daddr=c->peeraddr;#endif n->h.uh->check=0; return n; default: /* Bogus packet etc. */ ++c->stat.rx_crc_errors; goto error; } } else if (!c->flags&CIPF_MAY_CLEAR) { goto error; } dprintk(DEB_INP, (KERN_DEBUG "TW_DATA data=%p len=" FLEN "length=%d\n", n->data, n->len, length)); skb_trim(n, length); checkpeer(c, rsaddr, rsport); /* adjust pointers */#ifdef VER_ETH n->protocol = eth_type_trans(n, c->dev); /* n->pkt_type = PACKET_HOST; */#else n->mac.raw=n->data; /* no hw header */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -