详细设计说明书示例_第1页
详细设计说明书示例_第2页
详细设计说明书示例_第3页
详细设计说明书示例_第4页
详细设计说明书示例_第5页
已阅读5页,还剩48页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

编写目的本说明书提供了freeswan各个模块部件的说明,以供编码人员具体实现及今后的维护工作。.总体设计设计原则在确定目标系统的过程中,主要遵循了以下几个原则:目标系统基本上完整地实现 IPSec协议族,完全支持VPN的要求;目标系统的服务器端一定要建立在具有自主版权的内核操作系统之上;目标系统的客户端使用方便、界面友好、配置和管理简单灵活。软件结构该软件由如下几个模块组成:KLIPS模块一一实现对进入或外出IP包的安全处理,如:加密、认证等(运行在内核空间)Pluto模块一一实现IKE协议,完成安全联盟的协商(运行在用户空间)PF_KEY莫块一一实现pfkey2协议,完成上述两个模块间关于 SA的通信.程序描述源代码文件组成本程序由两大模块组成,一部分是 klips,它运行在操作系统内核空间,主要负责安全联盟和密钥的管理工作,以及对数据报的加密、解密的处理工作;一部分是 pluto,它是个运行在用户空间的守护进程, 主要负责安全联盟的协商工作。 下面分别是它们的文件组成:源文件目录| freeswan| klips

libdes|libdes|――pluto|――utilsKLIPS(内核 IPsec)详细设计--――― klips ipsec 的核心实现模块|――net|―― ipsec| ―― 登记模块,并初始化|――ipsec_tunnel. 数据包的处理并发送模块| ―― 数据包接收并处理模块| —— 管理SA的模块|―― sha1实现模块,由改编|―― 实现模块路由表的radix数的实现模块对上个文件的改编实现PF_KEY助议的模块对上个文件的改编|――utils|―― 用户操作eroute 表的模块|―― 用户操作SA库的模块|―― 同上|―― 用户操作虚接口的模块登记及初始化模块概要说明功能proc文件,以便于向内核空间中查询安全联盟和eoute表,以及虚接口的状况;初始化SA数据库(tdb链);初始化SPDBa据库(eroute表);初始化pf_key(PF_KEYg接口);模块所涉及的文件: int ipsec_init(void): int ipsec_tdbinit(void): int ipsec_radijinit(void): intpfkey_init(void)变量说明proc文件结构将下列结构登记到内核系统中,则内核就可以通过proc文件系统向应用程序提供一个安全的界面来存取如 SA、eroute表等资料。structproc_dir_entryipsec_eroute;structproc_dir_entryipsec_spi;structproc_dir_entryipsec_spigrp;structproc_dir_entryipsec_tncfg;structproc_dir_entryipsec_spinew;structproc_dir_entryipsec_klipsdebug;notifier_block结构structnotifier_block结构是在include/linux/里面的:structnotifier_block{int(*notifier_call)(structnotifier_block*self,unsignedlong,void*);structnotifier_block*next;intpriority;};而register_netdevice_notifier函数在net/core/里面,是这样的:intregister_netdevice_notifier(structnotifier_block*nb){returnnotifier_chain_register(&netdev_chain,nb);

而notifier_chain_register函数在include/linux/里面,是这样的:extern__inline__intnotifier_chain_register(structnotifier_block**list,structnotifier_block*n){while(*list){if(n->priority>(*list)->priority)break;list=&((*list)->next);}n->next=*list;*list=n;return0;}显然就是根据每个 block的优先级把这个 block排列在一个 block的链表里面,在notifier_chain_register函数里面我们可以发现这个链表是 netdev_chain。实际上这个链表的作用就是在每个 interface打开,关闭状态改变或者外界调用相应的ioctl的时候通知这个链表上面的所有相关的设备,而每一个协议都调用register_netdevice_notifier注册了一个netdev_notifier的结构体,这样就可以在 interface改变的时候得到通知了(通过调用每个notifier_call函数)。inet_protocol结构structinet_protocolah_protocol={ipsec_rcv, /*AHhandler,定义此协议处理函数 */NULL, /*TUNNELerrorcontrol,错误处理函数 */0, /*next*/IPPROTO_AH,/*protocolID*/0, /*copy*/NULL, /*data*/"AH" /*name*/};copy是ipsec_rcv 函数是用来接收数据的callback copy是用来协议共享的,这个以后再说,data当然就是这个结构体的私有数据了。

同上;structinet_protocolesp_protocolinet_add_protocol函数在net/ipv4/里实现:同上;voidinet_add_protocol(structinet_protocol*prot){unsignedcharhash;structinet_protocol*p2;hash=prot->protocol&(MAX_INET_PROTOS-1);prot->next=inet_protos[hash];inet_protos[hash]=prot;prot->copy=0;p2=(structinet_protocol*)prot->next;while(p2!=NULL){if(p2->protocol==prot->protocol){prot->copy=1;break;}p2=(structinet_protocol*)p2->next;}}hash这个函数是生成了一个 hash表,然后每个 hash表项都是一个链表头,然后通过这个hash表加链表的方式访问每个协议结构体。函数说明登记及初始化模块包括以下一些函数:init_modules(),ipsec_init(),cleanup_module(),ipsec_cleanup()ipsec_eroute_get_info()ipsec_tncfg_get_info(),ipsec_spi_get_info()ipsec_eroute_get_info()ipsec_tncfg_get_info(),ipsec_spi_get_info()ipsec_version_get_info()ipsec_spigrp_get_info(),ipsec_spi_get_new()intinit_module(void)目的: 装载 ipsec时进行登记及初始化工作。TOC\o"1-5"\h\z参数: 无返回值:0 ――初始化成功,非 0值――初始化未成功算法描述: 调用 ipsec_init() 。intcleanup_module(void)目的: 卸载 ipsec 进行清除工作。参数: 无返回值: 0―― 初始化成功,非 0 值――初始化未成功算法描述: 调用 ipsec_cleanup() 。intipsec_int(void)目的: 装载 ipsec时进行登记及初始化工作。。参数: 无返回值: 0―― 初始化成功,非 0值――初始化未成功算法描述:.将定义好的几个 proc_dir_entry结构注册到系统中,如:proc_register(proc_net,&ipsec_eroute);/*PROC_FS_21*/ 或proc_register_dynamic(&proc_net,&ipsec_eroute); 或proc_net_create(“ipsec_eroute”,0,ipsec_eroute_get_info) ;proc_register为系统调用,在 fs/proc/中实现,主要就是在proc_net对应的目录下面生成每个协议的子目录。用户可以通过访问/proc/net目录下面的相应目录得到相关的资料。.调用 ipsec_tdbinit()函数初始化 SA数据库,此函数在文件中实现;.调用ipsec_radijinit()函数初始化SPD数据库,此函数在文件中实现;.调用pfkey_init()函数初始化PFKEY此函数在文件中实现;.调用register_netdevice_notifier(&ipsec_dev_notifier)函数向系统中注册已定义的ipsec_dev_notifier结构,register_netdevice_ntifier()为系统调用;.调用 inet_add_protocol(&esp_protocol)和inet_add_protocol(&ah_protocol)函数向系统中注册ESP协议和AH协议,inet_add_protocol()为系统调用;.调用 ipsec_tunnel_init_devices()函数,登记并初始化ipsec虚接口,此函数定义在文件中。intipsec_cleanup(void)目的:卸载目的:卸载ipsec进行清除工作。返回值:0――清除成功,非 0值――清除未成功算法描述:.调用ipsec_tunnel_cleanup_device(void)函数,清除向系统登记的ipsec虚接口,此函数在中实现;.调用 inet_del_protocol(&ah_protocol)和inet_del_protocol(&esp_protocol)清除掉在系统中注册的 ESP>议和AH协议;.调用系统调用unregister_netdevice_notifier(&ipsec_dev_notifier) 清除掉系统中注册的ipsec_dev_notifier;.调用ipsec_tdbcleanup(0)清除系统中的SA数据库,此函数在中文件实现;.调用ipsec_radijcleanup() 清除系统中的SP啖据库,此函数在文件中实现;.调用 pfkey_cleanup()做pfkey清除工作;.调用系统调用 proc_net_unregister()清除freeswan在系统中登记的各个 proc文件。虚接口模块概要说明功能为了在不改变现有的操作系统的网络协议栈的状况下,更好地将IPsec嵌入,本程序采用了虚接口的概念。实现中,将创建4个ipsec虚接口,可以将虚接口绑定在物理接口上。对于从tcp/udp协议层传下来的数据,将首先查询eroute表,根据eroute表项决定将数据包发往哪一个接口,物理接口与虚接口将被视为一致的。此时,如果数据包发往虚接口,则调用函数进行处理。(该程序类似于网卡驱动程序的编写)构成文件变量说明device结构虚接口定义为structdevice结构,如:staticstructdevicedev_ipsec0={"ipsec0\0", /*name*/0, /*recvmemoryend*/0,/*recvmemorystart*/0,/*memoryend*/0,/*memorystart*/0x0,/*baseI/Oaddress*/0,/*IRQ*/0,0,0,/*flags*/NULL,/*nextdevice*/ipsec_tunnel_probe/*setup*/};ipsecpriv结构structipsecpriv{structsk_buff_headsendq;structdevice*dev;structwait_queue*wait_queue;charlocked;int(*hard_start_xmit)(structsk_buff*skb,structdevice*dev);int(*hard_header)(structsk_buff*skb,structdevice*dev,unsignedshorttype,void*daddr,void*saddr,unsignedlen);ifdefNET_21int(*rebuild_header)(structsk_buff*skb);else/*NET_21*/int(*rebuild_header)(void*buff,structdevice*dev,unsignedlongraddr,structsk_buff*skb);endif/*NET_21*/int(*set_mac_address)(structdevice*dev,void*addr);ifndefNET_21void(*header_cache_bind)(structhh_cache**hhp,structdevice*dev,unsignedshorthtype,__u32daddr);返回值: 返回值: 0 绑定成功,非 0值――绑定未成功endif/*!NET_21*/hh_cache*hh,structdevice*dev,unsignedcharvoid(*header_cache_update)(structhh_cache*hh,structdevice*dev,unsignedcharhaddr);structenet_statistics*(*get_stats)(structdevice*dev);structenet_statisticsmystats;intmtu;/*WhatisthedesiredMTU*/};函数说明intipsec_tunnel_init_devices(void)目的:登记ipsec虚接口。参数: 无返回值: 0―― 登记成功,非 0值――登记未成功算法描述:调用系统调用register_netdev(&dev_ipsec0~3),向系统登记 4个ipsec虚接口。intipsec_tunnel_init(structdevice*dev)目的:初始化ipsec虚接口,完成 device中变量的初始化和系统资源的申请。参数:返回值:0―― 清除成功,非 0值――清除未成功算法描述:.填充 device结构中的几个函数,如:dev->open=ipsec_tunnel_open;dev->stop=ipsec_tunnel_stop;dev->hard_start_xmit =ipsec_tunnel_start_xmit;dev->get_stats=ipsec_tunnel_get_stats;.给 dev配空间,dev->priv=kmalloc(sizeof(structipsecpriv),GFP_KERNEL);.初始化 dev结构:skb_queue_head_init(&dev->buffs[i]);.填充 dev结构的其它值,如:dev->set_mac_address=NULL等等。intipsec_tunnel_attach(structdevice*tndev,structipsecpriv*prv,structdevice*dev)目的:将某个虚接口绑定到指定的物理接口上。算法描述:intipsec_open(structdevice*dev)目的:参数:要open的device返回值: 0 open成功,非0值 open未成功算法描述:此方法在网络设备驱动程序里是网络设备被激活的时候被调用(即设备状态由down->up)。驱动程序作为一个模块被装入:如果虚接口尚未绑定到物理接口,返回错误信息;否则调用MOD_INC_USE_COUNT以防止模块卸载是设备处于打开状态。intipsec_tunnel_start_xmit(structsk_buff*skb,structdevice*dev)目的:假定此函数由dev_queue_xmit()函数调用,主要负责发送从tcp/udp协议层传来的数据包参数: 由dev_queue_xmit()函数填充好的skb,及要发往的网络接口返回值: 0 open成功,非0值 open未成功算法描述:.skb,dev有效吗有效继续,无效返回;prv=dev->priv获取ipsec接口私有数据;若prv为空,返回;获取系列参数:物理接口参数 physdev,physmtu,stats;.如果需要,拷贝skb:IfdefNET_21,thenskb_cloned(skb);.获取Ip头iph,判断该包是否是 IPV4,若不是则丢弃;.计算硬件头长度(hard_header_len);.将ip包的ttl减小,并计算校验和。.填充查找键键值,根据键值查找 eroute表,获取eroute,若找到,取出SA,即outgonging_said;.判断此IP包是否是IKE协商包(UDPport500),若是,则跳出;.进入封装处理大循环(几乎一切处理都由outgoing_said决定,一个 said对应一个或多个tdb(通道描述块),根据每个 tdb对其进行处理):checkforDROPormissingeroutecheckforREJECTeroutecheckforPASSeroutecheckforHOLDeroutecheckforTRAPeroute,signalPF_KEY,swaptoHOLDerouteacquirelockforwalkingtdbchaincalculateheadroomrequiredforchaincheckifSAisinlarval,dropcheckifSAisdead,dropcheckifreplayoverflowed,expireSAcheckiflifetimecountershaveoverflowed,expireSAswitchonprotocoltype,tocalculateheadroomsize.ifESPswitchonprotocoltypetocalculatetailroomsize.alculatemtudiff,sendICMPfragmentneeded.Mark、'note2"ackMSSifdesiredcopyupper(layer2)headertosafetyifitwaspresentcheckifdatafitsinexistingskb,elseexpand.applygroupedtransformsapplydisasterof#ifdefs.switchbyprotocoltype,calculateheadroomforthisstageifESP,thenswitchbyciphergetheadroomifESP,thenswitchbyhashtogettailroomdoublecheck(notinNDEBUG)ifthereisenoughheadroompushthedataaheaddoublecheck(notinNDEBUG)ifthereisenoughtailroomextendthedatabehindseeifpackethasbecometoolong(biggerthan64K)finallymovetheplaintextasappropriateswitchonprotocoltypecase:ESPswitchonciphertype,prepareIVprepareself-describingpaddingswitchonciphertype,doencryptionswitchonciphertype,updateIVswitchonhashtype,doauthenticationcase:AHprepreplayinfo,headroomswitchonhashtype,doauthenticationcase:IPIP,applyencapcase:IPCOMPI.callskb_compressI.dosomedebuggingrecalculateheaderchecksum)lookuperoutebynewouterheader,ifwefoundsomethingandthesrc/dsthavechangedendICMPifpackethasbecometoobigre-applylinklayerheaderiftherewasone.. attempttore-routethepacketdroppacketifnewrouteleadstousagain.. doconnectiontracking. donetfilterlocaloutoutputcallcallip_sendorIP_SENDdependingonkernelversion⑴. 取得一些初始值 ,如dst,src,iphlen,pyldsz,⑵. 接下来是一系列合法性和安全性检查,对不合理部分有两种处理方法:不进行安全处理,直接从物理接口上发送并返回;丢弃数据包,返回。⑶.有eroute吗没有,则从physdev发送数据包并返回,有则继续;⑷. 若指定隧道模式,却找不到spi,不做处理,按 1)发送,返回;⑸. 根据 said取得tdbp链,和sa_len,若tdbp链为空,报错返回;⑹.进入tdb处理循环,求出ipsec处理所需的headroom和tailroom;对tdbp链中每一个 tdb进行如下处理:大量的合法性判断,包括tdb状态是否对,SA是否过时,PFKEYv2处理等;根据tdbp->计算headroom和tailroom。方法是,根据不同而算法不同:IPPROTO_AH:headroom+=sizeof(structah);IPPROTO_ESP:I.tdbp->tdb_encalg(加密算法)ESP_DE:Sheadroom+=sizeof(structesp);ESP_3DES:headroom+=sizeof(structesp);ESP_NUL:Lheadroom+=offsetof(structesp,esp_iv);default:丢弃包。n.tdbp->tdb_autoalg (认证算法)AH_MD5:tailroom+=AHHMAC_HASHLEN;AH_SHA:tailroom+=AHHMAC_HASHLEN;AH_NONE:NOP不处理);default:不对,丢弃包。出.计算:(数据包要是16()字节的倍数,不然加空补齐。tailroom+=((8-((pyldsz+2*sizeof(unsignedchar))%8))%8)+2;IPPROTO_IPIP:headroom+=sizeof(structiphdr);default:出错,丢弃。最后,对链表中每一个 tdb求出的headroom、tailroom求和得出max_headroom、max_tailroom,pyldsz也相应改变(加上 headroom,tailroom)。(Ln1016)⑺.求出tot_headroom,tot_tailroom,mtu_diff;若mtu_diff>0,说明prv->mtu计算不合适,重新计算;⑻. 调整mss;⑼. hard_header_stripped 处理;(Ln1077)⑽.!。原skb空间够用吗不够就重新分配一个 skb并进行extend_copy;. 进入tdb链循环,进行真正的ipsec安全处理。定义变量并赋初值;根据 tdbp->确定headroom,tailroom;与(6)的处理类似。处理skb,移动数据指针(skb_push,skb_put函数);ip头前移;根据不同的协议类型进行不同的处理:switch(tdbp->IPPROTO_ESP:填写espp(spi,rpl,... );求出iv[0],iv[1](初始化向量 );求出idat,ilen(内部数据区域 )要加密的数据地址及长度;求出pad,padlen.(为了认证);(pad前面两个字节分别存放pad长度和前iph->protocol.由tdbp->tdb_encalg决定调用加密算法:ESP_DES:des_cbc_encrypt(idat,idat,ilen,(caddr_t)tdbp->tdb_key_e,(caddr_t)iv,1);ESP_3DES:des_ede3_cbc_encrypt(idat, idat, ilen,(caddr_t)(&((structdes_eks*)(tdbp->tdb_key_e))[0]),(caddr_t)(&((structdes_eks*)(tdbp->tdb_key_e))[1]),(caddr_t)(&((structdes_eks*)(tdbp->tdb_key_e))[2]),(caddr_t)iv,1);由tdbp->tdb_encalg决定如何进行认证:AH_MD:5AH_SHA:IPPROTO_A:H填写ahp;...由tdbp->tdb_encalg决定如何进行认证:AH_MD:5AH_SHA:IPPROTO_IPIP:构造IP头;计算IP头校验,调整 skb内部参数,tdb循环处理;⑫. 取出源、目的地址,再次求er;⑬. 还要继续循环吗!=while(/*((orgdst!=newdst)||(orgsrc!=newsrc))*/(orgedst!=&&&&er);. 硬件头处理;. 求物理接口,寻路由;⑰. 发送。ip_send(skb)intipsec_tunnel_detach(structdevice*dev,structipsecpriv*prv)目的:将某个绑定了的虚接口解除绑定。参数:返回值:0——成功,非0值一一未成功算法描述:将prv的各个值清空intipsec_tunnel_clear(void)目的:清除所有的绑定虚接口。参数: 无返回值: 0——成功,非0值一一未成功算法描述: 将prv的各个值清空intipsec_tunnel_cleanup_devices(void)目的:清除4个注册的ipsec虚接口。参数:无返回值:清除成功,非 0值――清除未成功返回值:算法描述:.调用系统调用 unregister_netdev(&dev_ipsec0~3)清除虚拟接口;.调用系统调用 kfree_s(dev_ipsec0~,sizeof(structipsecpriv)) 释放为虚接口分配的空间。接收处理模块概要说明功能主要负责处理接收到的ipsec数据包。构成文件文件流程如图3-1所示。函数说明intipsec_rcv(structsk_buff*skb,unsighedshortxlen)目的:接收并处理 ipsec数据包。参数:skb-接收到的数据包,xlen-返回值:0――登记成功,非 0值――登记未成功算法描述:. SKB正确性判断(有无数据,头长度等) ;. 如果包被克隆过,对包进行一个留头处理,为后面做准备;. 是AH或ESP格式吗(只支持这两种格式)不是则丢弃包;. 进入解报循环;⑴是ESP包但长度不是4字节的倍数,丢弃。(因ESP包会有补齐验证,见组报)⑵计算ESP或AH头,求出said(spi,proto,等);⑶若为AH头,计算头长度和下一个头;⑷ 为tdb链加锁;⑸取出tdbp(TDB头),若为空,丢弃包;⑹ tdb的状态对吗 larval,dead以及超时(有多种情况)均将丢弃包;⑺根据认证标志 tdbp->tdb_authalg对数据包进行验证;⑻对ESP包进行解密;⑼计算新的IP数据包头;⑽解锁;(中间丢弃包时也先解锁)(11)如果新的数据包还是IPSec包,循环处理;. 对tdb链进行处理;.把解开的包送入IP接收队列。netifrx(skb)。安全联盟的管理模块概要说明功能实现了对 SA数据库的初始化,添加、删除或更新 SA。组成文件,变量说明tdb结构structtdb /*tunneldescriptorblock*/{structtdb *tdb_hnext;/*nextinhashchain*/structtdb *tdb_onext;/*nextinoutput*/structtdb*tdb_inext;/*nextininput(prev!)*/structifnet *tdb_rcvif;/*relatedrcvencapinterface*/structsa_id tdb_said;/*SAID*/__u32 tdb_seq; /*seqnumofmsgthatsetthisSA*/__u32 tdb_pid; /*PIDofprocessthatsetthisSA*/#if1structxformsw*tdb_xform;/*transformationtouse(hostorder)*/caddr_ttdb_xdata;/*transformationdata(opaque)*/#endif__u8 tdb_authalg;/*authalgorithmforthisSA*/__u8 tdb_encalg;/*encalgorithmforthisSA*//*/*proxysockaddr*/u32tdb_alg_errs;/*numberofalgorithmerrors*/u32tdb_auth_errs;/*numberofauthenticationerrors*/u32 tdb_encsize_errs; /*numberofencryptionsizeerrors*/u32 tdb_encpad_errs; /*numberofencryptionsizeerrors*/u32tdb_replaywin_errs;/*numberofpktsequenceerrors*/u8 tdb_replaywin;/*replaywindowsize*/u8 tdb_state;/*stateofSA*/u32 tdb_replaywin_lastseq; /* lastpktsequencenum*/u64 tdb_replaywin_bitmap; /* bitmapofreceivedpkts*/u32 tdb_replaywin_maxdiff; /* maximumpktsequencedifference */u32tdb_flags;/*genericxformflags*/u32tdb_lifetime_allocations_c;/*seerfc2367*/u32tdb_lifetime_allocations_s;u32tdb_lifetime_allocations_h;u64tdb_lifetime_bytes_c;u64tdb_lifetime_bytes_s;u64tdb_lifetime_bytes_h;u64tdb_lifetime_addtime_c;u64tdb_lifetime_addtime_s;u64tdb_lifetime_addtime_h;u64tdb_lifetime_usetime_c;u64tdb_lifetime_usetime_s;u64tdb_lifetime_usetime_h;u64tdb_lifetime_packets_c;u64tdb_lifetime_packets_s;u64tdb_lifetime_packets_h;u64tdb_lifetime_usetime_l;/*lasttimetransformwasused*//*srcsockaddr/*srcsockaddr*//*dstsockaddr*/structsockaddr*tdb_addr_d;structsockaddr*tdb_addr_p;u16tdb_addr_s_size;

u16tdb_addr_d_size;u16tdb_addr_p_size;u16tdb_key_bits_a;/*sizeofauthkeyinbits*/u16 tdb_auth_bits; /*sizeofauthenticatorinbits*/u16tdb_key_bits_e;/*sizeofenckeyinbits*/u16 tdb_iv_bits; /*sizeofIVinbits*/u8tdb_iv_size;u16tdb_key_a_size;u16tdb_key_e_size;caddr_ttdb_key_a;/*authenticationkey*/caddr_ttdb_key_e;/*encryptionkey*/caddr_ttdb_iv;caddr_ttdb_iv;/*InitialisationVector*/__u16tdb_ident_type_s;/*srcidentitytype*/u16tdb_ident_type_d;/*dstidentitytype*/u64tdb_ident_id_s;/*srcidentityid*/u64tdb_ident_id_d;/*dstidentityid*//*srcidentitytype*//*srcidentitytype*//*dstidentitytype*//*srcidentitydata*/__u8 tdb_ident_len_d;caddr_ttdb_ident_data_s;caddr_ttdb_ident_data_d;/*dstidentitydata*/#if0sens#endif};函数说明intipsec_tdbinit(void)目的:初始化tdb链。参数: 无返回值:0――成功,非0值――失败算法描述: 将tdb链清空。inttdb_init(structtdb*tdbp,structencap_msghdr*em)目的:返回值:0――成功,非0值――失败算法描述:intputtdb(structtdb*tdbp)目的:将一个新的tdb块-tdbp加入在tdbh链中参数:tdbp――要添加的tdb块返回值:0―― 成功,非0值――失败算法描述:判断传入的 tdbp是否为空,若为空,返回失败信息;计算根据tdbp->tdb_spi、tdbp->和tdbp->tdb_proto计算出hashval;将tdb链加锁,以免同时有其它存取 tdb链的行为;将tdbp插入tdb链中:tdbp->tdb_hnext=tdbh[hashval];tdbh[hashval]=tdbp;将tdb链解锁。structtdb*gettdb(structsa_id*said)目的:根据给出的said值查找相应的tdb块。参数:said――与要查找的tdb块相应的said值返回值:structtdb――找到的tdb块,NULL――失败算法描述:判断said值是否有效,若为空,返回 NULL;根据said计算hashval;根据hashval值找到所要的tdb块,失败则返回 NULL。intdeltdb(structtdb*tdbp)目的:删除某个指定的tdb块。参数:tdbp――要删除的tdb块返回值:0――成功,非0值――失败算法描述:判断tdbp的有效性,若无效,则返回失败信息;计算hashval值;根据hashval找到tdbp,并删除它,若失败,返回错误。intdeltdbchain(structtdb*tdbp)目的:删除整个tdbp链。参数:tdbp――要删除的tdb链返回值:0――成功,非0值――失败算法描述:判断tdbp是否有效,若无效,返回错误信息;将tdbp移至最后的tdbp->tdb_onext;删除所有的tdb块。intipsec_tdbwipe(structtdb*tdbp)目的:将指定tdb块中的所有值清空。参数:tdbp――要清空的tdb块返回值:0——成功,非0值一一失败算法描述:将所有值置为 NULL。安全策略数据库的管理模块概要说明功能eroute。实现了对SPDeroute。组成文件,变量说明eroutestructeroute{structrjtentryer_rjt;structsa_ider_said;structsockaddr_encaper_eaddr;structsockaddr_encaper_emask;};函数说明intipsec_radijinit(void)目的:初始化radij树参数: 无返回值: 0―― 成功,非0值――失败算法描述:调用rj_init()函数初始化。intipsec_makeroute(structsockaddr_encap*eaddr,structsockaddr_encap*emask,structsa_idsaid)目的:根据said值,生成新的eroute项。参数:eaddr――封装的有效目的地址,emask――封装的目的地址掩码,said――传入的said值返回值:0——成功,非0值一一失败算法描述:分配eroute空间――retrt,并先清0;给retrt赋值:retrt->er_eaddr=*eaddr;retrt->er_emask=*emask;retrt->er_said=said;给eroute表加锁;调用函数rj_addroute(&(retrt->er_eaddr),&(retrt->er_emask),rnh,retrt->,向eroute表中加入新生成的该项;解锁,返回。intipsec_breakroute(structsockaddr_encap*eaddr,structsockaddr_encap*emask)目的:删除指定的route。参数:eaddr――有效目的地址,emask-目的地址的掩码返回值:0――成功,非0值――失败算法描述:锁住eroute表;调用函数rj_delete(eaddr,emask,rnh,&rn)删除这个指定 route;解锁,将该route项清 0,调用系统调用 kfree释放该空间。structeroute*ipsec_findroute(structsockaddr_encap*eaddr)接收并处理 ipsec数据包。参数:eaddr――要查找的route所具有的eaddr值返回值:structeroute――找到的eroute值,NULL――未找到算法描述:调用函数rj_match((caddr_t)eaddr,rnh),根据eaddr查找相应的eroute项;返回找到的eroute项。intipsec_cleareroutes(void)目的:清空eroute表。参数: 无返回值: 0―― 成功,非0值――失败算法描述:首先,锁住 eroute表;调用函数 radijcleartree()函数;解锁,返回。intipsec_radijcleanup(void)目的:参数: 无返回值: 0―― 成功,非0值――失败算法描述:首先,锁住 eroute表;调用函数 radijcleanup()函数;解锁,返回。密钥协商及管理模块概要说明功能前面所描述的KLIPS模块,基本完成了对输入、输出数据包的加密、认证工作,但其前提是处理数据包的SA已经协商完毕,而这个SA的协商工作正是由IKE所负责的。在本程序中,Pluto模块是IKE的一个实现,它可以自动完成两个主机或网关间的安全联盟的协商工作。

源代码组成源代码组成源文件目录Pluto源文件目录|――启动后台进程 pluto的主程序|——监听IKE消息、whack消息和pfkey消息,调用相应处理过程||―― 由server调用,处理 IKE消息|―― 处理IKE消息的头文件,主要定义消息的结构|—— 描述建立ISAKMPS符口IPSECSA的过程|―― state头文件,主要定义 state结构|—— 描述对state的各种操作,为建立SA服务|――connection头文件,定义 connection结构| 描述对connection的各种操作,为建立SA服务|—— 构造和解析SA载荷,为建立SA服务|—— 定义了各种ISAKMP包的消息头格式,以及构造消息头的算法和解析消息头的算法|―― 与建立 SA相关的各种定义|―― 描述对 cookies值的各种操作|――调用加密算法的接口模块|―― ID的表示及操作|―― 处理时间事件|―― 随机数函数模块|―― SHA-1散列函数模块|—— MD嗽列函数模块|—— DSA^名模块|―― 共享密钥的处理模块其它一些函数的定义|――|――|| 由server调用,处理whack消息|――接收ipsecwhack命令,构造相应的whack消息,发送到whackfd,由监听,发到处理|| 由server调用,处理pfkey消息,操作内核中的SAD诉||――日志处理模块|――启动模块概要说明功能启动Pluto后台进程。源代码组成函数说明intmain(intargc,char**argv)目的:分析使用程序的参数,做 pluto进程的初始化工作参数: argcargv返回值: 0―― 成功,非0值――失败算法:分析使用 pluto的命令行参数,并做相应的操作;调用函数 init_log() ,初始化日志;算法:算法:调用函数init_rnd_pool(),初始化随机数池;调用函数init_secret()调用函数init_secret(),生成密钥值;调用函数init_states()调用函数init_states()statetable);3.调用函数 3.调用函数 init_crypto(),做好加密准备;4.调用函数 4.调用函数 init_demux()state_microcode_table;5.调用函数call_server(),启动服务器,监听到来的 ISAKM咆和Whcak信息。intcreate_lock(void)目的:生成一个 lockfile文件,以保证同时只有一个 pluto进程运行参数: 无返回值: 0―― 成功,非0值――失败算法:略intdelete_lock(void)目的:删除 lockfile文件参数: 无返回值: 0―― 成功,非0值――失败算法:略voidexit_pluto(intstatus)目的:以status的状态离开 pluto进程。参数:status―― 0ok1generaldiscomfor10lockfileexists返回值:无算法:略监听模块概要说明功能该模块主要用于监听 SA协商消息一一IKE消息、whack消息和pfkey消息,收到上述几种消息后,再调用相应处理模块。源代码组成文件函数说明voidcall_server(void)目的:监听SA协商消息一一IKE消息、whack消息和pfkey消息,收到上述几种消息后,再调用相应处理模块。参数:无返回值:无算法:调用函数init_pfkeyed(),创建PF_KEY类型的套接口;调用函数init_whackfd(),创建AF_UNIX型套接口,用于通信;进入循环等待,接收到来的消息:如果收到IKE协商消息,调用函数 comm_handle()处理;如果收到whack消息,调用函数whack_handle()处理;如果收到pfkey消息,调用函数 pfkey_handle()处理。voidfind_ifaces(void)目的:参数:无返回值:无staticintinit_pfkeyfd(void)目的:创建PF_KEY®的套接口参数:无返回值:-1――失败,其它――成功算法:调用系统调用socket()创建socket,返回之。staticintinit_whackfd(void)目的:创建AF_UNIX型的套接口。参数:无返回值:-1――失败,其它――成功算法:调用系统调用socket()创建套接口,并用bind()绑定到ctl_addr上,调用系统调用listen()监听。协商安全联盟的模块概要说明功能协商ISAKMPSA和IPSECSA。源代码组成详细说明ISAKMPSA勺建立过程(主模式)消息1:发起方的Cookie值CKY-I、发起方提出的一个或多个对 ISAKMPW息的保护方案staticstf_statusmain_outI1(intwhack_sock,structconnection*c,boolpending_quick,lset_tpolicy,unsignedlongtry)cookie值,和对目的:发起连接 c的SAcookie值,和对ISAKMPW息的保护方案。whack_sock――whack套接口c ―― 这个初始协商消息是为 c这个连接发出的pending_quick——标识在生成ISAKMPSA后,是否需要立即协商 IPSECSApolicy ―― 安全策略try ―― 发起方最多可以重试的协商次数返回值:STF_NO_REPLY--成功;其它一一有错误算法:调用函数new_state(),为这个connection-c构造一个新的state;给这个state结构st的成员变量赋值,其中部分值如下:st->st_connection=c;st->st_try=try; nterface等于NULL返回TRUE;与内核SAD用|擎的交互模块概要说明功能将协商好的SA安装到内核中的SAD驿中,或按照要求从SAD珅删除彳^废的SA,等等。原理是,构造pfkey消息,发送到pfkey套接口,内核的SAD用I擎收到后,解析消息,完成相应操作。(pfkey的详情参见PF_KEY莫块)源代码组成文件函数说明voidpfkey_handle(void)目的: 从读取 pfkeyfd套接口读取 pfkey消息,并分析此消息参数: 无返回值:无算法:调用系统调用read(),从pfkeyfd套接口读取 pfkey消息;调用函数调用函数pfkey_msg_parse()分析收到的消息;算法:算法:调用函数调用函数pfkey_msg_parse()分析收到的消息;算法:算法:ipsec_spi_tget_ipsec_spi(ipsec_spi_tavoid)目的: 生成唯一的 SPI值参数: avoid返回值: ipsec_spi_t算法:略booldo_command(structconnection*c,constchar*verb)目的: 启动_updown脚本,执行其中的防火墙命令规则参数:返回值:算法:boolpfkey_build(interror,constchar*description,constchar*text_said,sturctsadb_ext*extensions[SADB_EXT_MAX+1])目的: 调用其它构造函数,如果构造成功,返回 TRUE失败,在释放extensions的空间返回 FALSE。参数:返回值:TRUE——,FALSE——算法:略boolfinish_pfkey_msg(structsadb_ext*extensions[SADB_EXT_MAX+1],constchar*description,constchar*text_said)目的:结束pfkey消息的构造。参数:extensions[]――description――text_said――返回值:FALSE――失败,TURE――成功构造pfkey消息,构造pfkey消息,若构造失败,返回 FALSE;调用系统调用write(pfkeyfd,pfkey_msg,len),将pfkey消息发送出去如发送失败,则返回 FALSE;调用函数pfkey_extensions_free(extensions)和pfkey_msg_free(&pfkey_msg)释放空间。booldo_eroute(structstate*st,unsignedop,constchar*opnameUNUSED)目的: 根据要建立的一个SA构造一个eroute表项(构造和发送的都是地址消息) 。参数:st――描述一个SA的状态op――UNUSED――返回值:TRUE――成功,FALSE――失败算法:根据st获得SPI值和protocol;调用函数set_text_said(),将计算所得的said放入text_said中;将六个地址转化为结构的变量:、、、、、;调用函数pfkey_extensions_init(extensions),初始化extensions;调用消息构造函数pfkey_build构造消息,并调用finish_pfkey_build()完成构造,把消息发送出去。booldel_spi(ipsec_spi_tspi,intproto,structin_addrsrc,structin_addrdest)目的:删除一个 SA。参数:spi ―― SPI 值proto――协议src ―― 源地址dst ―― 目的地址返回值:TRUE失败成功,返回值:TRUE失败算法:,进行构造消息之前的初始化;调用函数pfkey_extensions_init(extensions),进行构造消息之前的初始化;调用函数set_text_said(),设置text_said值;调用函数pfkey_build(),构造删除一个SA的pfkey消息,调用函数finish_pfkey_build()结束构造,并发送。boolsetup_half_ipsec_sa(structstate*st,boolinbound)目的: 建立半个SA(即,两个网关或主机之间,对于其中某一个来说,数据包进入或出去的所用 SA)参数:st――描述一个 SA的状态INBOUND——表示此SA是进入的还是外出的返回值: TRUE―― 成功,FALSE――失败算法:根据st,调用函数pfkey_build()构造合适的pfkey消息,再调用函数finish_pfkey_build()发送;若此过程中有错误发生,则返回 FALSE,否则,返回 TRUE。boolteardown_half_ipsec_sa(structstate*st,boolinbound)目的:删除半个SA(即,两个网关或主机之间,对于其中某一个来说,数据包进入或出去的所用 SA)参数:st――描述一个 SA的状态INBOUND——表示此SA是进入的还是外出的返回值: TRUE―― 成功,FALSE――失败算法:根据st,取出该SA中设置的spi、proto,调用函数 del_spi删除它。boolcould_eroute(structconnection*c,structconnection*ero)目的:参数:c――描述一个connectionero――

返回值:TRUE算法:返回值:TRUE算法:成功,FALSE失败boolinstall_inbound_ipsec_sa(structstate*st)目的:安装 SA,仅被被响应方使用,响应方接着会用install_ipsec_sa来安装outbound的SA;而发起方使用install_ipsec_sa来安装inbound和outbound的SA。参数:st――描述一个SA的状态返回值: TRUE―― 成功,FALSE――失败算法:如果对方的client有固定的IP地址,检查我们是否有一条达到那里的路由,这条路由与现在的相矛盾(不知道这样说对不对);如果有,则删除之;调用函数could_eroute(c,route_owner(c,TRUE)),检查我们是否有 eroute表项,如果没有,返回 FALSE;调用函数route_connection(c,FALSE),检查我们是否可以将外出的数据包路由到某个ipsec虚接口。事实上,这只检查了我们的peer不在他的子网中,或者如果他在,我们使用UDP500端口的IKE消息,使得它不被处理;调用函数setup_half_ipsec_sa(st),建立进入的 SA。boolinstall_ipsec_sa(structstate*st,boolinbound_alse)目的:安装 SA。参数:st――描述一个SA的状态inbound_also 标识这个SA是inbound,或outbound返回值: TRUE―― 成功,FALSE――失败算法:调用函数 route_owner(c,TRUE) ,查找是谁拥有这个 eroute;调用函数 could_eroute(c,ero) ,;调用函数route_connection(c, TRUE),检查我们是否可以将外出的数据包路由到某个ipsec虚接口;调用函数setup_half_ipsec_sa(),根据inbound_also,建立进入的或外出的 SA;如果建立成功,如果c->eroute_owner为SOS_NOBOD,Y则调用函数do_eroute(…,"add")添力口eroute表项,再调用函数 do_command()启动脚本;如果不是SOS_NOBODYU调用do_eroute(…,”replace")更新eroute表项。booldelete_ipsec_sa(structstate*st,boolinbound_only)目的:安装SA。参数:st――描述一个 SA的状态inbound_only――是否只删inbound的SA返回值:TRUE――成功,FALSE――失败算法:如果inbound_only为TRUE则调用函数teardown_haf_ipsec_sa()删除半个SA如果inbound_only为FALSE,判断是否c->eroute_owner==st->st_serialno,如果相等,调用函数do_command(••,"down”)启动脚本关闭,及调用do_eroute(…,”delete”)删除eroute;如果上述步骤成功,再调用teardown_half_ipsec_sa()删除 SA。PF_KEY模块概要说明PF_KEY是一种新型的协、议族,由 PF_ROUTE行生而来。在协议族中,PF_KEY被定义为15。目前,实现所依据的时 PF_KEY勺第二个版本。密钥管理进程可以使用它与操作系统中的“keyengine”或安全联盟数据库(SADB通信,并使用PF_INET通过网络与远程密钥管理进程进行通信。密钥管理进程与 PF_KEY勺关系如图所示:TOC\o"1-5"\h\z+ +|KeyMgmtDaemon|+ +| || | Applications=====[PF_KEY]====[PF_INET]==========================| | OSKernel+ ++ +|KeyEngine||TCP/IP,||orSADB|---|includingIPsec|+ +| |+ +|+ +|Network||Interface|+ +Figure1:RelationshipofKeyMgmttoPF_KEY该模块大致由四部分组成:――PF_KEYv2KeymanagementAPIdomainsocketI/F――PF_KEYv2KeymanagementAPImessageparser提供了一个可用于 IPsec密钥管理函数库(keymanagementAPI)。――PF_KEYv2KeymanagementAPImessageparser――实现用户层与核心之间对于密钥协商的交互处理功能实现pfkey_v2协议族,用于密钥协商进程 pluto与内核的管理SADB的进程间通信。组成文件PF_KEY的消息机制PF_KEYt一套独特的消息行为,不像其他大多数BSDsocket采用的bind()、connect。、accept()、listen()等操作来实现通信。正常情况下,正确格式的消息发给内核,内核将应答消息返回到PF_KEYsocket中。如果内核检测到错误,错误标识会随应答消息一起被发送出去。PF_KEYt如下几种消息行为:SADB_REGISTE捕息:进程向内核注册一个socket以便能够从内核获得新的SA消息格式为:<base>,即只包含消息基本头。内核将发送SADB_REGISTERW息进行应答,格式为:<base,supported>,supported扩展表明内核所支持的验证算法和密钥算法。SADB_ACQUIRE息:这个消息是由内核发出的,可以用于两种情况:⑴.内核向密钥管理进程申请创建一个 SA。消息格式为:<base,address,proposal>,其中,proposal扩展给出了SA的几种提案,即采用什么协议( AH或ESP)、采用什么验证方法和加密方法等;扩展数据中还可包含的选项有:Identity扩展,Sensitivity扩展。但,密钥管理进程并不向内核发送 SADB_ACQUIRE答消息。⑵.当密钥协商过程失败后,内核通过发送 SADB_ACQUIRE息来通知密钥管理进程。消息格式为:<base>,即只包含一个消息基本头,其中,消息错误号代表了错误的原因。密钥管理进程不向内核发送SADB_ACQUIRE答消息。SADB_GETSP|肖息:密钥管理进程向内核申请一个 SPI。消息格式为:<base,address,SPIrange>,SPIrange扩展指出了所申请的 SPI的范围。内核发送 SADB_GETSPI应答消息,格式为:<base,SA(*),address>,其中,SA(*)表示SA扩展的各个字段,除了扩展长度、扩展类型和SPI外,其余字段应设为0被忽略掉。SADB_UPDATE息:密钥管理进程请求内核更新(或)增加一条 SA记录,该消息随SADB_GETSP|肖息一起使用。消息格式为:<base,SA,address,key>,扩展数据中还可包含的选项有:lifetime扩展、identity扩展、sensitivity扩展。内核发送SADB_UPDATE答消息,格式为:<base,SA,address>,或者还包含与请求消息相应的扩展数据。SADB_AD消息:在手工配置密钥或知道SPI的情况下,无须先使用GETSPI消息而直接申请内核更新(或增加)一条SA记录。消息格式与SADB_UPDATE息相同。内核发送的SADB_AD应答消息与SADB_UPDATE答消息相同。SADB_DELETEi息:密钥管理进程请求内核删除一条 SA记录。消息格式为:<base,SA(*),address>

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论