📄 device.c
字号:
/* CIPE - encrypted IP over UDP tunneling device.c - the net device driver 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: device.c,v 1.56 2004/08/03 08:21:17 olaf81825 Exp $ */#include "cipe.h"#include "version.h"#include <stddef.h>#include <linux/if_arp.h>#include <linux/sched.h>#include <linux/etherdevice.h>#ifdef LINUX_21#include <asm/uaccess.h>#include <linux/rtnetlink.h>#include <linux/notifier.h>#else#define register_netdevice register_netdev#define unregister_netdevice unregister_netdev#endif/*** Globals ***/static const char driver_version[]=VERSION;struct cipe_ctrl **cipe_ctrls = NULL;/* Parameters settable via insmod, from module.c */extern int cipe_maxdev;#ifdef DEBUGextern int cipe_debug;#endif/* clear all potentially sensitive info and stats */static void cipe_zero_c(struct cipe *c){#define freekey(K) \ if (c->K) { \ cipe_free_tfm(c->K); \ c->K = NULL; \ } /* clear and free keys */ freekey(key); freekey(skey); freekey(rkey); /* clear other parameters */ /* NB. this nulls the key pointers */ memset(&(c->peeraddr), 0, offsetof(struct cipe, udp_prot)-offsetof(struct cipe, peeraddr)); /* reset these to sensible values */ c->tmo_keyxchg = 10*HZ; c->tmo_keylife = 10*60*HZ;#undef freekey}/* weak but fast PRNG, used for padding only */static __u32 prnseed;void cipe_prnpad(unsigned char *buf, int len){ while (len>0) { prnseed=prnseed*0x01001001+1; if (len>=2) { *(__u16 *)buf=prnseed>>16; len-=2; buf+=2; } else { *buf=(prnseed>>24)^jiffies; return; } }}#ifdef DO_LOCK_PRINTKspinlock_t cipe_printk_lock = SPIN_LOCK_UNLOCKED;#endif/* inet_ntoa() for multiple use. */#ifdef __SMP__#define NTOABUFS 16#else#define NTOABUFS 4#endifstatic char ntoabuf[NTOABUFS][16];static int ntoaptr=0;#ifdef LINUX_21spinlock_t cipe_ntoa_lock=SPIN_LOCK_UNLOCKED;#endifconst char *cipe_ntoa(const __u32 addr){ const unsigned char *x=(const unsigned char *)&addr; char *p; int b, i;#ifdef LINUX_21 unsigned long flags; spin_lock_irqsave(&cipe_ntoa_lock, flags);#endif b=ntoaptr; if (++b>=NTOABUFS) b=0; ntoaptr=b;#ifdef LINUX_21 spin_unlock_irqrestore(&cipe_ntoa_lock, flags);#endif p=ntoabuf[b]; for (i=0; i<4; ++i) { int k=x[i]/100; int l=(x[i]/10)%10; if (k) *p++=k+'0'; if (k || l) *p++=l+'0'; *p++=(x[i]%10)+'0'; if (i<3) *p++='.'; } *p='\0'; return ntoabuf[b];}/*** IOCTL handlers ***/#ifdef SIOCGIFCIPPARstatic int cipe_getpar(struct NET_DEVICE *dev, struct siocgifcippar *parm){ DEVTOCIPE(dev,c,-ENODEV); memset(parm->socks, 0, sizeof(parm->socks)); if (c->sockshost&&c->socksport) { parm->socks.sin_family=PF_INET; parm->socks.sin_port=c->socksport; parm->socks.sin_addr.s_addr=c->sockshost; } parm->tmo_keyxchg=c->tmo_keyxchg/HZ; parm->tmo_keylife=c->tmo_keylife/HZ; parm->flags=c->flags; parm->cttl=c->cttl; *parm->cname=0; /* currently no name info available */ return 0;}#endifstatic int cipe_setpar(struct NET_DEVICE *dev, struct siocsifcippar *parm){ DEVTOCIPE(dev,c,-ENODEV); if (parm->socks.sin_family==PF_INET) { c->sockshost=parm->socks.sin_addr.s_addr; c->socksport=parm->socks.sin_port; } if (parm->tmo_keyxchg>10*60*HZ) return -EINVAL; if (parm->tmo_keyxchg) c->tmo_keyxchg=parm->tmo_keyxchg*HZ; if (parm->tmo_keylife>24*60*60*HZ) return -EINVAL; if (parm->tmo_keylife) c->tmo_keylife=parm->tmo_keylife*HZ; c->flags=(parm->flags&CIPF_MASK_EXT)|(c->flags&CIPF_MASK_INT); c->cttl=parm->cttl; printk(KERN_DEBUG "crypto_alloc_tfm `%s'\n", parm->cname); if (!(c->key=cipe_alloc_tfm(parm->cname, CRYPTO_TFM_MODE_CBC))) return(-ENXIO); if (crypto_tfm_alg_blocksize(c->key)!=8||crypto_tfm_alg_ivsize(c->key)!=8) printk(KERN_WARNING "%s: %s: unsupported cipher block size\n", dev->name, parm->cname); if (crypto_tfm_alg_ivsize(c->key)>MAXIVSIZE) { printk(KERN_ERR "%s: %s: cipher ivsize too big\n", dev->name, parm->cname); return(-ENXIO); } if (!(c->skey=cipe_alloc_tfm(parm->cname, CRYPTO_TFM_MODE_CBC))) return(-ENXIO); if (!(c->rkey=cipe_alloc_tfm(parm->cname, CRYPTO_TFM_MODE_CBC))) return(-ENXIO); dprintk(DEB_CALL, (KERN_DEBUG "%s: setpar %s:%d %ld %ld %04x %d\n", dev->name, cipe_ntoa(c->sockshost), ntohs(c->socksport), c->tmo_keyxchg, c->tmo_keylife, c->flags, c->cttl)); return 0;}static int cipe_setkey(struct NET_DEVICE *dev, struct siocsifcipkey *parm){ DEVTOCIPE(dev,c,-ENODEV);#define ExpandUserKey(K) \ crypto_cipher_setkey(c->K, parm->thekey, parm->keylen);#define NullKey(K) \ crypto_cipher_setkey(c->K, "\0\0\0\0\0\0\0\0", 8); dprintk(DEB_KXC, (KERN_INFO "%s: setkey %d\n", dev->name, parm->which)); switch (parm->which) { case KEY_STATIC: ExpandUserKey(key); c->flags|=CIPF_HAVE_KEY+CIPF_NOTIFY_DERR; break; case KEY_SEND: ExpandUserKey(skey); c->timeskey=jiffies+c->tmo_keylife; c->cntskey=0; c->flags|=CIPF_HAVE_SKEY; break; case KEY_RECV: ExpandUserKey(rkey); c->timerkey=jiffies+2*c->tmo_keylife; /* allow for fuzz */ c->cntrkey=0; c->flags|=CIPF_HAVE_RKEY; break; case KEY_STATIC+KEY_INVAL: c->flags&=~(CIPF_HAVE_KEY|CIPF_HAVE_SKEY|CIPF_HAVE_RKEY); if (c->key) NullKey(key); break; case KEY_SEND+KEY_INVAL: c->flags&=~CIPF_HAVE_SKEY; if (c->skey) NullKey(skey); c->timeskey=jiffies+c->tmo_keyxchg; break; case KEY_RECV+KEY_INVAL: c->flags&=~CIPF_HAVE_RKEY; if (c->rkey) NullKey(rkey); c->timerkey=jiffies+c->tmo_keyxchg; break; default: return -EINVAL; } return 0;#undef ExpandUserKey#undef NullKey}static int cipe_alloc_dev(int n);static void cipe_unalloc_dev(int n);static int cipe_owner(struct cipe *c){ struct task_struct *p; pid_t pid=c->owner; tasklist_LOCK(); p=current; do { if (p->pid==pid) { tasklist_UNLOCK(); return pid; } p=next_task(p); } while (p!=current); tasklist_UNLOCK(); return 0;}#define cipe_nowner(n) cipe_owner(&cipe_ctrls[(n)]->cipe)static int cipe_alloc(struct NET_DEVICE *dev, struct siocsifcipall *parm){#ifdef NO_DYNDEV return -ENOSYS;#else int n=parm->num; int e; if (n>=cipe_maxdev) return -EINVAL; if ((e=cipe_alloc_LOCK())) return e; if (n>=0) { if (cipe_ctrls[n]) { if (cipe_ctrls[n]->cipe.sock || (e=cipe_nowner(n))) { printk(KERN_DEBUG DEVNAME ": dev %d busy pid=%d\n", n, e); e=-EBUSY; } else { cipe_ctrls[n]->cipe.owner=current->pid; } } else { e=cipe_alloc_dev(n); } } else { e=-EMFILE; for (n=0; n<cipe_maxdev; ++n) { if (!cipe_ctrls[n]) { e=cipe_alloc_dev(n); break; } if (!cipe_nowner(n)) { cipe_ctrls[n]->cipe.owner=current->pid; e=0; break; } } } if (!e) { parm->num=n; strncpy(parm->name, cipe_ctrls[n]->dev.name, sizeof(parm->name)-1); parm->name[sizeof(parm->name)-1]='\0'; } cipe_alloc_UNLOCK(); return e;#endif}static int cipe_unalloc(struct NET_DEVICE *dev, struct siocsifcipall *parm){#ifdef NO_DYNDEV return -ENOSYS;#else int e; if (parm->num<0 || parm->num>=cipe_maxdev) return -EINVAL; if ((e=cipe_alloc_LOCK())) return e; if (cipe_ctrls[parm->num]->cipe.sock) { e=-EBUSY; } else { if (parm->num>0) cipe_unalloc_dev(parm->num); } cipe_alloc_UNLOCK(); return e;#endif}/*** Device operation handlers ***/int cipe_dev_ioctl(struct NET_DEVICE *dev, struct ifreq *ifr, int cmd){ int e=-ENOTTY;#ifdef LINUX_21 if (!capable(CAP_NET_ADMIN)) return -EPERM;#define doioctl(nam,fun,str) { \ struct str parm; \ dprintk(DEB_CALL, (KERN_INFO "%s: " nam "\n", dev->name)); \ if (copy_from_user((void*)&parm,(void*)ifr->ifr_data, \ sizeof(parm))) { \ e=-EFAULT; goto out; } \ if (parm.magic!=VERSION_MAGIC) { \ printk(KERN_WARNING "%s: ciped version mismatch\n", dev->name); \ e=-EINVAL; goto out; } \ if ((e=fun(dev, &parm))<0) \ goto out; \
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -