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

下载本文档

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

文档简介

1引言1.1编写目的本说明书提供了freeswan各个模块部件的说明,以供编码人员具体实现及今后的维护工作。2总体设计2.1设计原则在确定目标系统的过程中,主要遵循了以下几个原则:u 目标系统基本上完整地实现IPSec协议族,完全支持VPN的要求;u 目标系统的服务器端一定要建立在具有自主版权的内核操作系统之上;u 目标系统的客户端使用方便、界面友好、配置和管理简单灵活。2.2 软件结构该软件由如下几个模块组成:u KLIPS模块 实现对进入或外出IP包的安全处理,如:加密、认证等(运行在内核空间)u Pluto模块 实现IKE协议,完成安全联盟的协商(运行在用户空间)u PF_KEY模块 实现pfkey2协议,完成上述两个模块间关于SA的通信3程序描述3.1源代码文件组成本程序由两大模块组成,一部分是klips,它运行在操作系统内核空间,主要负责安全联盟和密钥的管理工作,以及对数据报的加密、解密的处理工作;一部分是pluto,它是一个运行在用户空间的守护进程,主要负责安全联盟的协商工作。下面分别是它们的文件组成:源文件目录|freeswan|klips|libdes|pluto|utils3.2 KLIPS(内核IPsec)详细设计klipsipsec的核心实现模块|net|ipsec|ipsec_init.c登记模块,并初始化|ipsec_tunnel.数据包的处理并发送模块|ipsec_rcv.c数据包接收并处理模块|ipsec_xform.c管理SA的模块|ipsec_sha1.csha1实现模块,由sha1.c改编|ipsec_md5c.cmd5.c实现模块|ipcomp.c|radij.c路由表的radix数的实现模块|ipsec_radij.c对上个文件的改编|pfkey_v2.c实现PF_KEY2协议的模块|pfkey_v2_parser.c对上个文件的改编|sysctl_net_ipsec.c|utils|eroute.c用户操作eroute表的模块|spi.c用户操作SA库的模块|spigrp.c同上|tncfg.c用户操作虚接口的模块|klipsdebug.c3.2.1登记及初始化模块概要说明.1功能向内核系统登记几个proc文件,以便于向内核空间中查询安全联盟和eoute表,以及虚接口的状况;初始化SA数据库(tdb链);初始化SPDB数据库(eroute表);初始化pf_key(PF_KEY套接口);.2模块所涉及的文件ipsec_init.c:int ipsec_init(void)ipsec_xform.c:int ipsec_tdbinit(void)ipsec_radij.c:int ipsec_radijinit(void)pfkey_v2.c: int pfkey_init(void)变量说明.1 proc文件结构将下列结构登记到内核系统中,则内核就可以通过proc文件系统向应用程序提供一个安全的界面来存取如SA、eroute表等资料。struct proc_dir_entry ipsec_eroute ;struct proc_dir_entry ipsec_spi ;struct proc_dir_entry ipsec_spigrp ;struct proc_dir_entry ipsec_tncfg ;struct proc_dir_entry ipsec_spinew ;struct proc_dir_entry ipsec_klipsdebug ;.2 notifier_block结构struct notifier_block结构是在include/linux/notifier.h里面的:struct notifier_blockint (*notifier_call)(struct notifier_block *self, unsigned long, void *);struct notifier_block *next;int priority;而register_netdevice_notifier函数在net/core/dev.c里面,是这样的:int register_netdevice_notifier(struct notifier_block *nb)return notifier_chain_register(&netdev_chain, nb);而notifier_chain_register函数在include/linux/notifier.h里面,是这样的:extern _inline_ int notifier_chain_register(struct notifier_block *list, struct notifier_block *n)while(*list)if(n-priority (*list)-priority)break;list= &(*list)-next);n-next = *list;*list=n;return 0;显然就是根据每个block的优先级把这个block排列在一个block的链表里面,在notifier_chain_register函数里面我们可以发现这个链表是netdev_chain。实际上这个链表的作用就是在每个interface打开,关闭状态改变或者外界调用相应的ioctl的时候通知这个链表上面的所有相关的设备,而每一个协议都调用register_netdevice_notifier注册了一个netdev_notifier的结构体,这样就可以在interface改变的时候得到通知了(通过调用每个notifier_call函数)。.3 inet_protocol结构struct inet_protocol ah_protocol =ipsec_rcv,/* AH handler ,定义此协议处理函数*/NULL,/* TUNNEL error control,错误处理函数 */0,/* next */IPPROTO_AH,/* protocol ID */0,/* copy */NULL,/* data */AH/* name */;ipsec_rcv函数是用来接收数据的callback函数,第二个是错误处理函数,其它的copy是用来协议共享的,这个以后再说,data当然就是这个结构体的私有数据了。struct inet_protocol esp_protocol 同上;inet_add_protocol函数在net/ipv4/protocol.c里实现:void inet_add_protocol(struct inet_protocol *prot)unsigned char hash;struct inet_protocol *p2;hash = prot-protocol & (MAX_INET_PROTOS - 1);prot -next = inet_protoshash;inet_protoshash = prot;prot-copy = 0;p2 = (struct inet_protocol *) prot-next;while(p2 != NULL) if (p2-protocol = prot-protocol) prot-copy = 1;break;p2 = (struct inet_protocol *) p2-next;这个函数是生成了一个hash表,然后每个hash表项都是一个链表头,然后通过这个hash表加链表的方式访问每个协议结构体。函数说明登记及初始化模块包括以下一些函数:init_modules(),ipsec_init(),cleanup_module(),ipsec_cleanup(),ipsec_eroute_get_info(),ipsec_spi_get_info(),ipsec_spigrp_get_info(),ipsec_tncfg_get_info(),ipsec_version_get_info(),ipsec_spi_get_new().1int init_module(void)目的:装载ipsec时进行登记及初始化工作。参数:无返回值:0初始化成功,非0值 初始化未成功算法描述:调用ipsec_init()。.2int cleanup_module(void)目的:卸载ipsec进行清除工作。 参数:无返回值:0 初始化成功,非0值初始化未成功算法描述:调用ipsec_cleanup()。.3int ipsec_int(void)目的:装载ipsec时进行登记及初始化工作。 参数:无返回值:0 初始化成功,非0值初始化未成功算法描述:1将定义好的几个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/root.c中实现,主要就是在proc_net对应的目录下面生成每个协议的子目录。用户可以通过访问/proc/net目录下面的相应目录得到相关的资料。2调用ipsec_tdbinit()函数初始化SA数据库,此函数在ipsec_tdb.c文件中实现;3调用ipsec_radijinit()函数初始化SPD数据库,此函数在ipsec_radij.c文件中实现;4调用pfkey_init()函数初始化PFKEY,此函数在pfkey_v2.c文件中实现;5调用register_netdevice_notifier(&ipsec_dev_notifier)函数向系统中注册已定义的ipsec_dev_notifier结构,register_netdevice_ntifier()为系统调用;6调用inet_add_protocol(&esp_protocol)和inet_add_protocol(&ah_protocol)函数向系统中注册ESP协议和AH协议,inet_add_protocol()为系统调用;7调用ipsec_tunnel_init_devices()函数,登记并初始化ipsec虚接口,此函数定义在ipsec_tunnel.c文件中。.4int ipsec_cleanup(void)目的:卸载ipsec进行清除工作。 参数:无返回值:0 清除成功,非0值清除未成功算法描述:1调用ipsec_tunnel_cleanup_device(void)函数,清除向系统登记的ipsec虚接口,此函数在ipsec_xform.c中实现;2调用inet_del_protocol(&ah_protocol)和inet_del_protocol(&esp_protocol)清除掉在系统中注册的ESP协议和AH协议;3调用系统调用unregister_netdevice_notifier(&ipsec_dev_notifier)清除掉系统中注册的ipsec_dev_notifier;4调用ipsec_tdbcleanup(0)清除系统中的SA数据库,此函数在ipsec_tdb.c中文件实现;5调用ipsec_radijcleanup()清除系统中的SPD数据库,此函数在ipsec_radij.c文件中实现;6调用pfkey_cleanup()做pfkey清除工作;7调用系统调用proc_net_unregister()清除freeswan在系统中登记的各个proc文件。3.2.2虚接口模块概要说明.1功能为了在不改变现有的操作系统的网络协议栈的状况下,更好地将IPsec嵌入,本程序采用了虚接口的概念。实现中,将创建4个ipsec虚接口,可以将虚接口绑定在物理接口上。对于从tcp/udp协议层传下来的数据,将首先查询eroute表,根据eroute表项决定将数据包发往哪一个接口,物理接口与虚接口将被视为一致的。此时,如果数据包发往虚接口,则调用函数进行处理。(该程序类似于网卡驱动程序的编写).2构成文件ipsec_tunnel.c变量说明.1 device结构虚接口定义为struct device结构,如:static struct device dev_ipsec0 = ipsec00 ,/* name */0,/* recv memory end */0,/* recv memory start */0,/* memory end */0,/* memory start */0x0,/* base I/O address */0,/* IRQ */0, 0, 0,/* flags */NULL,/* next device */ipsec_tunnel_probe/* setup */; .2ipsecpriv结构struct ipsecprivstruct sk_buff_head sendq;struct device *dev;struct wait_queue *wait_queue;char locked;int (*hard_start_xmit) (struct sk_buff *skb, struct device *dev);int (*hard_header) (struct sk_buff *skb,struct device *dev,unsigned short type,void *daddr,void *saddr,unsigned len);#ifdef NET_21int (*rebuild_header)(struct sk_buff *skb);#else /* NET_21 */int (*rebuild_header)(void *buff, struct device *dev,unsigned long raddr, struct sk_buff *skb);#endif /* NET_21 */int (*set_mac_address)(struct device *dev, void *addr);#ifndef NET_21void (*header_cache_bind)(struct hh_cache *hhp, struct device *dev,unsigned short htype, _u32 daddr);#endif /* !NET_21 */void (*header_cache_update)(struct hh_cache *hh, struct device *dev, unsigned char * haddr);struct enet_statistics *(*get_stats)(struct device *dev);struct enet_statistics mystats;int mtu;/* What is the desired MTU? */;函数说明.1int ipsec_tunnel_init_devices(void)目的:登记ipsec虚接口。 参数:无返回值:0 登记成功,非0值登记未成功算法描述:调用系统调用register_netdev(&dev_ipsec03),向系统登记4个ipsec虚接口。.2int ipsec_tunnel_init(struct device *dev)目的:初始化ipsec虚接口,完成device中变量的初始化和系统资源的申请。参数:返回值:0 清除成功,非0值清除未成功算法描述:1填充device结构中的几个函数,如:a) dev-open= ipsec_tunnel_open;b) dev-stop= ipsec_tunnel_stop;c) dev-hard_start_xmit= ipsec_tunnel_start_xmit;d) dev-get_stats= ipsec_tunnel_get_stats;2给dev配空间,dev-priv = kmalloc(sizeof(struct ipsecpriv),GFP_KERNEL);3初始化dev结构:skb_queue_head_init(&dev-buffsi);4填充dev结构的其它值,如:dev-set_mac_address = NULL等等。.3int ipsec_tunnel_attach (struct device* tndev, struct ipsecpriv* prv,struct device *dev)目的:将某个虚接口绑定到指定的物理接口上。参数:返回值:0 绑定成功,非0值绑定未成功算法描述:.4int ipsec_open(struct device *dev)目的:参数:要open的device返回值:0 open成功,非0值open未成功算法描述:此方法在网络设备驱动程序里是网络设备被激活的时候被调用(即设备状态由down-up)。驱动程序作为一个模块被装入:如果虚接口尚未绑定到物理接口,返回错误信息;否则调用MOD_INC_USE_COUNT宏,以防止模块卸载是设备处于打开状态。.5int ipsec_tunnel_start_xmit(struct sk_buff *skb,struct device *dev)目的:假定此函数由dev_queue_xmit()函数调用,主要负责发送从tcp/udp协议层传来的数据包参数:由dev_queue_xmit()函数填充好的skb,及要发往的网络接口返回值:0 open成功,非0值open未成功算法描述:1 skb, dev 有效吗? 有效继续,无效返回;prv = dev-priv 获取ipsec接口私有数据;若prv为空,返回;获取系列参数:物理接口参数physdev, physmtu, stats;2 如果需要,拷贝skb:Ifdef NET_21, then skb_cloned(skb);3 获取Ip头iph,判断该包是否是IPV4,若不是则丢弃;4 计算硬件头长度(hard_header_len);5 将ip包的ttl减小,并计算校验和。6 填充查找键键值,根据键值查找eroute表,获取eroute,若找到,取出SA,即outgonging_said;7 判断此IP包是否是IKE协商包(UDP port 500),若是,则跳出;8 进入封装处理大循环(几乎一切处理都由outgoing_said决定,一个said对应一个或多个tdb(通道描述块),根据每个tdb对其进行处理):(1) check for DROP or missing eroute (2) check for REJECT eroute(3) check for PASS eroute(4) check for HOLD eroute(5) check for TRAP eroute, signal PF_KEY, swap to HOLD eroute(6) acquire lock for walking tdb chain(7) calculate headroom required for chain1) check if SA is in larval, drop 2) check if SA is dead, drop 3) check if replay overflowed, expire SA 4) check if lifetime counters have overflowed, expire SA 5) switch on protocol type, to calculate headroom size. I. if ESP switch on protocol type to calculate tailroom size. (8) alculate mtudiff, send ICMP fragment needed. Mark note2 (9) ack MSS if desired (10) copy upper (layer 2) header to safety if it was present (11) check if data fits in existing skb, else expand. (12) apply grouped transforms 1) apply disaster of #ifdefs. 2) switch by protocol type, calculate headroom for this stage I. if ESP, then switch by cipher get headroom II. if ESP, then switch by hash to get tailroom 3) double check (not in NDEBUG) if there is enough headroom 4) push the data ahead 5) double check (not in NDEBUG) if there is enough tailroom 6) extend the data behind 7) see if packet has become too long (bigger than 64K) 8) finally move the plaintext as appropriate 9) switch on protocol type 10) case: ESP I. switch on cipher type, prepare IV II. prepare self-describing padding III. switch on cipher type, do encryption IV. switch on cipher type, update IV V. switch on hash type, do authentication 11) case: AH I. prep replay info, headroom II. switch on hash type, do authentication 12) case: IPIP, apply encap 13) case: IPCOMP I. call skb_compress II. do some debugging 14) recalculate header checksum lookup eroute by new outer header, if we found something and the src/dst have changed 9 end ICMP if packet has become too big 10 re-apply link layer header if there was one. 11 attempt to re-route the packet 12 drop packet if new route leads to us again. 13 do connection tracking 14 do netfilter localout output call 15 call ip_send or IP_SEND depending on kernel version 取得一些初始值, 如dst, src, iphlen, pyldsz, 接下来是一系列合法性和安全性检查,对不合理部分有两种处理方法:1) 不进行安全处理,直接从物理接口上发送并返回;2) 丢弃数据包,返回。 有eroute吗? 没有,则从physdev发送数据包并返回,有则继续; 若指定隧道模式,却找不到spi,不做处理,按1)发送,返回; 根据said取得tdbp链,和sa_len,若tdbp链为空,报错返回; 进入tdb处理循环,求出ipsec处理所需的headroom和tailroom;对tdbp链中每一个tdb进行如下处理: 大量的合法性判断,包括tdb状态是否对,SA是否过时,PFKEYv2处理等; 根据tdbp-tdb_to计算headroom和tailroom。方法是,根据tdb_to不同而算法不同:IPPROTO_AH: headroom += sizeof(struct ah);IPPROTO_ESP:.tdbp-tdb_encalg(加密算法)ESP_DES: headroom += sizeof(struct esp);ESP_3DES: headroom += sizeof(struct esp);ESP_NULL: headroom += offsetof(struct esp, esp_iv); ?default: 丢弃包。.tdbp-tdb_autoalg(认证算法)AH_MD5: tailroom += AHHMAC_HASHLEN;AH_SHA: tailroom += AHHMAC_HASHLEN;AH_NONE: NOP(不处理);default: 不对,丢弃包。.计算:(数据包要是16(?)字节的倍数,不然加空补齐。tailroom += (8 - (pyldsz + 2 * sizeof(unsigned char) % 8) % 8) + 2;IPPROTO_IPIP: headroom += sizeof(struct iphdr);default: 出错,丢弃。最后,对链表中每一个tdb求出的headroom、tailroom求和得出max_headroom、max_tailroom,pyldsz也相应改变(加上headroom, tailroom)。(Ln 1016) 求出tot_headroom, tot_tailroom, mtu_diff;若mtu_diff0,说明prv-mtu计算不合适,重新计算; 调整mss; hard_header_stripped处理;(Ln 1077) !。原skb空间够用吗?不够就重新分配一个skb并进行extend_copy; 进入tdb链循环,进行真正的ipsec安全处理。 定义变量并赋初值; 根据tdbp-tdb_to确定headroom, tailroom;与(6)的处理类似。 处理skb,移动数据指针( skb_push, skb_put 函数); ip头前移; 根据不同的协议类型进行不同的处理:switch(tdbp-tdb_to)IPPROTO_ESP: 填写espp (spi, rpl,. );求出iv0, iv1 (初始化向量?);求出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)(&(struct des_eks*)(tdbp-tdb_key_e)0),(caddr_t)(&(struct des_eks*)(tdbp-tdb_key_e)1),(caddr_t)(&(struct des_eks*)(tdbp-tdb_key_e)2),(caddr_t)iv, 1);由tdbp-tdb_encalg决定如何进行认证:AH_MD5:AH_SHA:IPPROTO_AH: 填写ahp;.由tdbp-tdb_encalg决定如何进行认证:AH_MD5:AH_SHA:IPPROTO_IPIP: 构造IP头; 计算IP头校验,调整skb内部参数,tdb循环处理; 取出源、目的地址,再次求er; 还要继续循环吗? while(/*(orgdst != newdst) | (orgsrc != newsrc)*/(orgedst != outgoing_said.dst.s_addr) &outgoing_said.dst.s_addr &er); 硬件头处理; 求物理接口,寻路由; 发送。ip_send(skb).6int ipsec_tunnel_detach(struct device *dev,struct ipsecpriv *prv)目的:将某个绑定了的虚接口解除绑定。参数:返回值:0 成功,非0值未成功算法描述:将prv的各个值清空.7int ipsec_tunnel_clear(void)目的:清除所有的绑定虚接口。参数:无返回值:0 成功,非0值未成功算法描述:将prv的各个值清空.8int ipsec_tunnel_cleanup_devices(void)目的:清除4个注册的ipsec虚接口。参数:无返回值:0 清除成功,非0值清除未成功算法描述:1调用系统调用unregister_netdev(&dev_ipsec03)清除虚拟接口;2调用系统调用kfree_s(dev_ipsec03.priv,sizeof(struct ipsecpriv)释放为虚接口分配的空间。3.2.3接收处理模块概要说明.1功能主要负责处理接收到的ipsec数据包。.2构成文件ipsec_rcv.c文件.3 流程如图31所示。函数说明.1int ipsec_rcv(struct sk_buff *skb,unsighed short xlen)目的:接收并处理ipsec数据包。参数:skb 接收到的数据包,xlen ?返回值:0 登记成功,非0值登记未成功算法描述:1 SKB正确性判断(有无数据,头长度等);2 如果包被克隆过,对包进行一个留头处理,为后面做准备;3 是AH或ESP格式吗(只支持这两种格式)?不是则丢弃包;4 进入解报循环; 是ESP包但长度不是4字节的倍数,丢弃。(因ESP包会有补齐验证,见组报); 计算ESP或AH头,求出said (spi, proto, 等); 若为AH头,计算头长度和下一个头; 为tdb链加锁; 取出tdbp(TDB头),若为空,丢弃包; tdb的状态对吗? larval, dead 以及超时(有多种情况)均将丢弃包; 根据认证标志tdbp-tdb_authalg对数据包进行验证; 对ESP包进行解密; 计算新的IP数据包头; 解锁; (中间丢弃包时也先解锁) 如果新的数据包还是IPSec包,循环处理;5 对tdb链进行处理;6 把解开的包送入IP接收队列。 netifrx(skb)。3.2.4安全联盟的管理模块概要说明.1功能实现了对SA数据库的初始化,添加、删除或更新SA。.2组成文件ipsec_tdb.h,ipsec_tdb.c变量说明.1 tdb结构struct tdb/* tunnel descriptor block */struct tdb*tdb_hnext;/* next in hash chain */struct tdb*tdb_onext;/* next in output */struct tdb*tdb_inext;/* next in input (prev!) */struct ifnet*tdb_rcvif;/* related rcv encap interface */struct sa_idtdb_said;/* SA ID */_u32tdb_seq;/* seq num of msg that set this SA */_u32tdb_pid;/* PID of process that set this SA */#if 1struct xformsw*tdb_xform;/* transformation to use (host order)*/caddr_ttdb_xdata;/* transformation data (opaque) */#endif_u8tdb_authalg;/* auth algorithm for this SA */_u8tdb_encalg;/* enc algorithm for this SA */_u32tdb_alg_errs;/* number of algorithm errors */_u32tdb_auth_errs;/* number of authentication errors */_u32tdb_encsize_errs;/* number of encryption size errors */_u32tdb_encpad_errs;/* number of encryption size errors */_u32tdb_replaywin_errs;/* number of pkt sequence errors */_u8tdb_replaywin;/* replay window size */_u8tdb_state;/* state of SA */_u32tdb_replaywin_lastseq;/* last pkt sequence num */_u64tdb_replaywin_bitmap;/* bitmap of received pkts */_u32tdb_replaywin_maxdiff;/* maximum pkt sequence difference */_u32tdb_flags;/* generic xform flags */_u32tdb_lifetime_allocations_c;/* see rfc2367 */_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;/* last time transform was used */struct sockaddr*tdb_addr_s;/* src sockaddr */struct sockaddr*tdb_addr_d;/* dst sockaddr */struct sockaddr*tdb_addr_p;/* proxy sockaddr */_u16tdb_addr_s_size;_u16tdb_addr_d_size;_u16tdb_addr_p_size;_u16tdb_key_bits_a;/* size of authkey in bits */_u16tdb_auth_bits;/* size of authenticator in bits */_u16tdb_key_bits_e;/* size of enckey in bits */_u16tdb_iv_bits;/* size of IV in bits */_u8tdb_iv_size;_u16tdb_key_a_size;_u16tdb_key_e_size;caddr_ttdb_key_a;/* authentication key */caddr_ttdb_key_e;/* encryption key */caddr_ttdb_iv;/* Initialisation Vector */_u16tdb_ident_type_s;/* src identity type */_u16tdb_ident_type_d;/* dst identity type */_u64tdb_ident_id_s;/* src identity id */_u64tdb_ident_id_d;/* dst identity id */_u8tdb_ident_len_s;/* src identity type */_u8td

温馨提示

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

评论

0/150

提交评论