本文档的Copyleft归yfydz所有,使用GPL发布,可以自由拷贝,转载,转载时请保持文档的完整性,
5. 系统一些主要数据结构
5.1 SA ID
/* linux/include/openswan.h */
// IP地址结构
typedef struct {
// V4和V6地址的联合
union {
struct sockaddr_in v4;
struct sockaddr_in6 v6;
} u;
} ip_address;
// 子网结构
typedef struct {
// 地址
ip_address addr;
// 掩码位数
int maskbits;
} ip_subnet;
/* and the SA ID stuff */
#ifdef __KERNEL__
typedef __u32 ipsec_spi_t;
#else
typedef u_int32_t ipsec_spi_t;
#endif
// 包含3项: 目的地址, SPI和协议
typedef struct { /* to identify an SA, we need: */
ip_address dst; /* A. destination host */
ipsec_spi_t spi; /* B. 32-bit SPI, assigned by dest. host */
# define SPI_PASS 256 /* magic values... */
# define SPI_DROP 257 /* ...for use... */
# define SPI_REJECT 258 /* ...with SA_INT */
# define SPI_HOLD 259
# define SPI_TRAP 260
# define SPI_TRAPSUBNET 261
int proto; /* C. protocol */
# define SA_ESP 50 /* IPPROTO_ESP */
# define SA_AH 51 /* IPPROTO_AH */
# define SA_IPIP 4 /* IPPROTO_IPIP */
# define SA_COMP 108 /* IPPROTO_COMP */
# define SA_INT 61 /* IANA reserved for internal use */
} ip_said;
5.2 连接(connection)
连接用于描述建立IPSec通道的连接信息, 参数直接的配置文件中配置, 连接可以是静态的, 也就是
两端地址等信息都是固定; 也可以是动态的, 也就是连接一方可以先不固定地址, 这时的连接只相当
于一个模板, 只有当真正有连接建立时再建立具体的连接实例。
/* programs/pluto/connection.h */
struct connection {
// 连接名称
char *name;
// 策略
lset_t policy;
// IKE生命期
time_t sa_ike_life_seconds;
// IPSEC连接生命期
time_t sa_ipsec_life_seconds;
// 重协商间隔时间
time_t sa_rekey_margin;
//
unsigned long sa_rekey_fuzz;
// 重协商尝试次数
unsigned long sa_keying_tries;
/* RFC 3706 DPD */
// DPD检查间隔时间
time_t dpd_delay; /* time between checks */
// DPD判断对方死亡时间,dpd_delay*dpd_tries
time_t dpd_timeout; /* time after which we are dead */
// DPD对方死亡后判断操作
enum dpd_action dpd_action; /* what to do when we die */
// 强制使用UDP封装(NAT穿越)
bool forceencaps; /* always use NAT-T encap */
// 日志文件名称
char *log_file_name; /* name of log file */
// 日志文件流指针
FILE *log_file; /* possibly open FILE */
CIRCLEQ_ENTRY(connection) log_link; /* linked list of open conns {} */
// 日志文件是否错误
bool log_file_err; /* only bitch once */
// 安全策略路由
struct spd_route spd;
/* internal fields: */
// 实例序号, 有的连接是那种动态通配连接,开始时并没有明确的IP地址,只有连接时才建立实例
unsigned long instance_serial;
// 策略优先权
policy_prio_t prio;
// 实例初始化正确标志
bool instance_initiation_ok; /* this is an instance of a policy that mandates
initiate */
// 连接类型
enum connection_kind kind;
// 网卡
const struct iface_port *interface; /* filled in iff oriented */
// 是否已经初始化标志
bool initiated;
// 与连接相关的状态的序列号
so_serial_t /* state object serial number */
newest_isakmp_sa,
newest_ipsec_sa;
#ifdef DEBUG
lset_t extra_debugging;
#endif
/* note: if the client is the gateway, the following must be equal */
// 地址协议族:V4, V6
sa_family_t addr_family; /* between gateways */
// 通道内封装的地址的协议族
sa_family_t tunnel_addr_family; /* between clients */
// 下一策略
struct connection *policy_next; /* if multiple policies,
next one to apply */
// 网关信息指针
struct gw_info *gw_info;
// ESP使用算法名称
char *alg_esp; /* string the admin provided */
// IKE使用算法名称
char *alg_ike; /* ditto. may be NULL */
// ESP算法信息
struct alg_info_esp *alg_info_esp;
// IKE算法信息
struct alg_info_ike *alg_info_ike;
// 主机对
struct host_pair *host_pair;
// 主机对链表
struct connection *hp_next; /* host pair list link */
// 下一个连接
struct connection *ac_next; /* all connections list link */
// 证书信息
generalName_t *requested_ca; /* collected certificate requests */
#ifdef XAUTH_USEPAM
// PAM认证句柄
pam_handle_t *pamh; /* PAM handle for that connection */
#endif
};
// 安全策略路由结构
struct spd_route {
// 链表下一项
struct spd_route *next;
// 本地和对方的端点信息
struct end this;
struct end that;
// 所有者
so_serial_t eroute_owner;
// 路由状态类型
enum routing_t routing; /* level of routing in place */
// 请求ID
uint32_t reqid;
};
// 端点结构
struct end {
// 端点ID值,可为地址,也可以是一个字符串
struct id id;
// 端点地址, 下一跳(网关)地址, 源地址
ip_address
host_addr,
host_nexthop,
host_srcip;
// 内部子网
ip_subnet client;
// 一些标志
// 从DNS服务器获取key
bool key_from_DNS_on_demand;
// 存在子网
bool has_client;
// 有通配子网
bool has_client_wildcard;
// 有通配端口
bool has_port_wildcard;
// 有通配ID
bool has_id_wildcards;
// 启动停止命令文件
char *updown;
// IKE端口
u_int16_t host_port; /* where the IKE port is */
// 指定了IKE端口
bool host_port_specific; /* if TRUE, then IKE ports are tested for*/
// 端口
u_int16_t port; /* port number, if per-port keying. */
// 协议
u_int8_t protocol; /* protocol number, if per-per keying. */
// 证书
cert_t cert; /* end certificate */
// CA的名称
chunk_t ca; /* CA distinguished name */
// 属性表
struct ietfAttrList *groups;/* access control groups */
// smartcard
smartcard_t *sc; /* smartcard reader and key info */
#ifdef VIRTUAL_IP
// 虚拟IP(一般用于×××客户端)
struct virtual_t *virt;
#endif
// 是XAUTH的服务器端
bool xauth_server;
// 是XAUTH的客户端
bool xauth_client;
// 是设置配置的服务器端, 可向客户端提供虚拟IP,DNS,WINS等参数
bool modecfg_server; /* Give local addresses to tunnel's end */
// 是设置配置的客户端
bool modecfg_client; /* request address for local end */
// 发送证书类型
enum certpolicy sendcert; /* whether or not to send the certificate */
};
// ID结构
struct id {
// 类型
int kind; /* ID_* value */
// 地址
ip_address ip_addr; /* ID_IPV4_ADDR, ID_IPV6_ADDR */
// ID名称
chunk_t name; /* ID_FQDN, ID_USER_FQDN (with @) */
/* ID_KEY_ID, ID_DER_ASN_DN */
};
5.2 状态(state)
状态是用于描述连接建立过程中的各种中间阶段,
/* programs/pluto/state.h */
/* state object: record the state of a (possibly nascent) SA
*
* Invariants (violated only during short transitions):
* - each state object will be in statetable exactly once.
* - each state object will always have a pending event.
* This prevents leaks.
*/
struct state
{
// 状态序号
so_serial_t st_serialno; /*serial number (for seniority) */
// 父状态序号
so_serial_t st_clonedfrom; /* serial number of parent */
// 状态使用数
int st_usage;
// 相关的连接指针
struct connection *st_connection; /* connection for this SA */
// 与whack通信的接口描述符
int st_whack_sock; /* fd for our Whack TCP socket.
* Single copy: close when
* freeing struct.
*/
// 缓期的消息摘要
struct msg_digest *st_suspended_md; /* suspended state-transition */
// Oakley(主模式)转换属性参数
struct oakley_trans_attrs st_oakley;
// AH协议信息
struct ipsec_proto_info st_ah;
// ESP协议信息
struct ipsec_proto_info st_esp;
// IP压缩协议信息
struct ipsec_proto_info st_ipcomp;
#ifdef KLIPS
// 进入方向的SPI
ipsec_spi_t st_tunnel_in_spi; /* KLUDGE */
// 发出方向的SPI
ipsec_spi_t st_tunnel_out_spi; /* KLUDGE */
#endif
// 阶段2中使用的oakley组
const struct oakley_group_desc *st_pfs_group; /*group for Phase 2 PFS */
// DOI解释域
u_int32_t st_doi; /* Domain of Interpretation */
// 状况
u_int32_t st_situation;
// IPSEC SA策略
lset_t st_policy; /* policy for IPsec SA */
// 对端地址
ip_address st_remoteaddr; /* where to send packets to */
// 对端的端口
u_int16_t st_remoteport; /* host byte order */
// 网卡
const struct iface_port *st_interface; /* where to send from */
// 本地地址和端口
ip_address st_localaddr; /* where to send them from */
u_int16_t st_localport;
// 消息ID
msgid_t st_msgid; /* MSG-ID from header. Network Order! */
// 消息ID
msgid_t st_msgid_phase15; /* msgid for phase 1.5 */
msgid_t st_msgid_phase15b; /* msgid for phase 1.5 */
/* only for a state representing an ISAKMP SA */
// 使用的消息ID链表
struct msgid_list *st_used_msgids; /* used-up msgids */
/* symmetric stuff */
/* initiator stuff */
// 发起方公共值
chunk_t st_gi; /* Initiator public value */
// 发起方cookie
u_int8_t st_icookie[COOKIE_SIZE];/* Initiator Cookie */
// 发起方时间
chunk_t st_ni; /* Ni nonce */
/* responder stuff */
// 接收方公共值
chunk_t st_gr; /* Responder public value */
// 接收方cookie
u_int8_t st_rcookie[COOKIE_SIZE];/* Responder Cookie */
// 接收方时间
chunk_t st_nr; /* Nr nonce */
/* my stuff */
// 发送的包数
chunk_t st_tpacket; /* Transmitted packet */
/* Phase 2 ID payload info about my user */
// 本地定义的协议和端口信息
u_int8_t st_myuserprotoid; /* IDcx.protoid */
u_int16_t st_myuserport;
/* his stuff */
// 接收的包数
chunk_t st_rpacket; /* Received packet */
/* Phase 2 ID payload info about peer's user */
// 对方的协议和端口信息
u_int8_t st_peeruserprotoid; /* IDcx.protoid */
u_int16_t st_peeruserport;
/* end of symmetric stuff */
// 使用的密钥数
u_int8_t st_sec_in_use; /* bool: does st_sec hold a value */
// 本地秘密
MP_INT st_sec; /* Our local secret value */
// 本地秘密的备份
chunk_t st_sec_chunk; /* copy of above */
// 共享密钥
chunk_t st_shared; /* Derived shared secret
* Note: during Quick Mode,
* presence indicates PFS
* selected.
*/
// 优先权
enum crypto_importance st_import; /* relative priority of crypto
* operations
*/
/* In a Phase 1 state, preserve peer's public key after authentication */
// 对方的公钥
struct pubkey *st_peer_pubkey;
// 状态类型
enum state_kind st_state; /* State of exchange */
// 重发数量
u_int8_t st_retransmit; /* Number of retransmits */
// 重协商尝试次数
unsigned long st_try; /* number of times rekeying attempted */
/* 0 means the only time */
// 有效时间
time_t st_margin; /* life after EVENT_SA_REPLACE */
// 输出包数统计
unsigned long st_outbound_count; /* traffic through eroute */
// 已经持续时间
time_t st_outbound_time; /* time of last change to
st_outbound_count */
// 是否需要加密
bool st_calculating; /* set to TRUE, if we are performing
cryptographic
* operations on this state at this time
*/
// 阶段1的发起方进行哈希的SA载荷
chunk_t st_p1isa; /* Phase 1 initiator SA (Payload) for
HASH */
// KEY ID
chunk_t st_skeyid; /* Key material */
chunk_t st_skeyid_d; /* KM for non-ISAKMP key derivation */
chunk_t st_skeyid_a; /* KM for ISAKMP authentication */
chunk_t st_skeyid_e; /* KM for ISAKMP encryption */
// 加密用的初始化向量
u_char st_iv[MAX_DIGEST_LEN]; /* IV for encryption */
// 老的初始化向量
u_char st_old_iv[MAX_DIGEST_LEN]; /* IV for encryption */
u_char st_new_iv[MAX_DIGEST_LEN];
// 阶段1的初始化向量
u_char st_ph1_iv[MAX_DIGEST_LEN]; /* IV at end if phase 1 */
// 各种初始化向量长度
unsigned int st_iv_len;
unsigned int st_old_iv_len;
unsigned int st_new_iv_len;
unsigned int st_ph1_iv_len;
// 加密密钥
chunk_t st_enc_key; /* Oakley Encryption key *
// 事件
struct event *st_event; /* backpointer for certain events */
// 状态链表的下一项和前一项
struct state *st_hashchain_next; /* Next in list */
struct state *st_hashchain_prev; /* Previous in list */
// 内部参数
struct {
// 接收到的错误数据包数
unsigned int st_malformed_received;
// 发送的错误数据包数
unsigned int st_malformed_sent;
// XAUTH客户端认证结束
bool st_xauth_client_done;
// XAUTH客户端认证尝试次数
int st_xauth_client_attempt;
// 模式配置服务器端处理结束
bool st_modecfg_server_done;
// 配置参数已经设置标志
bool st_modecfg_vars_set;
// 已经获得证书请求标志
bool st_got_certrequest;
// 模式配置启动标志
bool st_modecfg_started;
// 密钥ID已经计算标志
bool st_skeyid_calculated;
// 对方支持DPD标志
bool st_dpd; /* Peer supports DPD */
// 本地是否使用DPD标志
bool st_dpd_local; /* If we want DPD on this conn */
// 是否已经在日志中记录了算法标志
bool st_logged_p1algos; /* if we have logged algos */
// NAT穿越参数
u_int32_t st_nat_traversal; /* bit field of permitted
* methods. If non-zero, then
* NAT-T has been detected, and
* should be used. */
// NAT前的地址
ip_address st_nat_oa;
// NAT后的地址
ip_address st_natd;
} hidden_variables; /* internal state that
* should get copied by god
* Eistein would be proud
*/
// XAUTH用户名
unsigned char *st_xauth_username;
/* RFC 3706 Dead Peer Detection */
// 上次DPD时间
time_t st_last_dpd; /* Time of last DPD transmit */
// DPD包序号
u_int32_t st_dpd_seqno; /* Next R_U_THERE to send */
// 期待的DPD包序号
u_int32_t st_dpd_expectseqno; /* Next R_U_THERE_ACK to receive */
// 对方的DPD序号
u_int32_t st_dpd_peerseqno; /* global variables */
// DPD事件
struct event *st_dpd_event; /* backpointer for DPD events */
// 看到的提供者ID
u_int32_t st_seen_vendorid; /* Bit field about recognized Vendor ID */
// 不同IPSEC实现互连时的一些错误信息
struct isakmp_quirks quirks; /* work arounds for faults in other
* products */
};
/* Oakley (Phase 1 / Main Mode) transform and attributes
* This is a flattened/decoded version of what is represented
* in the Transaction Payload.
* Names are chosen to match corresponding names in state.
*/
// Oakley(第一阶段/主模式)转换和属性结构
struct oakley_trans_attrs {
// 加密算法
u_int16_t encrypt; /* Encryption algorithm */
// 密钥长度
u_int16_t enckeylen; /* encryption key len (bits) */
// 加密算法描述结构
const struct encrypt_desc *encrypter; /* package of encryption routines */
// 哈希算法
oakley_hash_t hash; /* Hash algorithm */
// 哈希算法描述结构
const struct hash_desc *hasher; /* package of hashing routines */
// 认证算法
oakley_auth_t auth; /* Authentication method */
#ifdef XAUTH
// XAUTH认证
u_int16_t xauth; /* did we negotiate Extended Authentication? */
#endif
// Oakley组描述结构
const struct oakley_group_desc *group; /* Oakley group */
// 生存期, 时间限制
time_t life_seconds; /* When this SA expires (seconds) */
// 生存期, 数据量限制
u_int32_t life_kilobytes; /* When this SA is exhausted (kilobytes) */
#if 0 /* not yet */
// 伪随机函数算法
u_int16_t prf; /* Pseudo Random Function */
#endif
};
/* IPsec (Phase 2 / Quick Mode) transform and attributes
* This is a flattened/decoded version of what is represented
* by a Transaction Payload. There may be one for AH, one
* for ESP, and a funny one for IPCOMP.
*/
// IPSEC(第2阶段/快速模式)转换和属性结构
struct ipsec_trans_attrs {
// 转换ID
u_int8_t transid; /* transform id */
// SPI
ipsec_spi_t spi; /* his SPI */
// 生存期, 时间限制
time_t life_seconds; /* When this SA expires */
// 生存期, 数据量限制
u_int32_t life_kilobytes; /* When this SA expires */
// 封装类型
u_int16_t encapsulation;
// 认证类型
ipsec_auth_t auth;
// 密钥长度
u_int16_t key_len;
// 密钥计算轮数
u_int16_t key_rounds;
#if 0 /* not implemented yet */
u_int16_t cmprs_dict_sz;
u_int32_t cmprs_alg;
#endif
};
/* IPsec per protocol state information */
// IPSEC协议信息
struct ipsec_proto_info {
// 是否提供标志
bool present; /* was this transform specified? */
// IPSEC(第2阶段/快速模式)转换和属性结构
struct ipsec_trans_attrs attrs;
// 本地SPI
ipsec_spi_t our_spi;
// 密钥长度
u_int16_t keymat_len; /* same for both */
// 本地密钥
u_char *our_keymat;
// 对方密钥
u_char *peer_keymat;
};
// 事件结构
struct event
{
// 事件事件
time_t ev_time;
// 事件类型
enum event_type ev_type; /* Event type */
// 事件相关的状态结构
struct state *ev_state; /* Pointer to relevant state (if any) */
// 事件链表的下一项
struct event *ev_next; /* Pointer to next event */
};
5.4 内核接口相关结构
/* programs/pluto/kernel.h */
// pfkey协议信息
struct pfkey_proto_info {
// 协议
int proto;
// 封装类型
int encapsulation;
// 请求ID
unsigned reqid;
};
// 内核SA结构
struct kernel_sa {
// 源地址
const ip_address *src;
// 目的地址
const ip_address *dst;
// 源子网
const ip_subnet *src_client;
// 目的子网
const ip_subnet *dst_client;
// SPI
ipsec_spi_t spi;
// 协议
unsigned proto;
// SA类型
unsigned satype;
// 回放窗口
unsigned replay_window;
// 请求ID
unsigned reqid;
// 认证算法
unsigned authalg;
// 认证算法密钥长度
unsigned authkeylen;
// 认证密钥
char *authkey;
// 加密算法
unsigned encalg;
// 加密算法密钥长度
unsigned enckeylen;
// 加密密钥
char *enckey;
// 封装
int encapsulation;
#ifdef NAT_TRAVERSAL
// NAT穿越的源端口,目的端口
u_int16_t natt_sport, natt_dport;
// ID和类型
u_int8_t transid, natt_type;
// NAT转换前原地址
ip_address *natt_oa;
#endif
// SA ID
const char *text_said;
};
// 内核操作结构
struct kernel_ops {
// 枚举类型
enum {
// 内核不支持
KERNEL_TYPE_NONE,
// 内核使用KLIPS实现IPSEC
KERNEL_TYPE_KLIPS,
// 内核使用自带的native ipsec
KERNEL_TYPE_LINUX,
} type;
// 操作名称
const char *opname;
// 是否存在进入方向的加密路由
bool inbound_eroute;
// 使用有策略生存期限制
bool policy_lifetime;
// 回放窗口
int replay_window;
int *async_fdp;
// 初始化
void (*init)(void);
// 登记
void (*pfkey_register)(void);
// 登记回应
void (*pfkey_register_response)(const struct sadb_msg *msg);
// 队列处理
void (*process_queue)(void);
// 处理消息
void (*process_msg)(void);
// 原始加密路由处理
bool (*raw_eroute)(const ip_address *this_host,
const ip_subnet *this_client,
const ip_address *that_host,
const ip_subnet *that_client,
ipsec_spi_t spi,
unsigned int proto,
unsigned int transport_proto,
unsigned int satype,
const struct pfkey_proto_info *proto_info,
time_t use_lifetime,
unsigned int op,
const char *text_said);
// 增加SA
bool (*add_sa)(const struct kernel_sa *sa, bool replace);
bool (*grp_sa)(const struct kernel_sa *sa_outer,
const struct kernel_sa *sa_inner);
// 删除SA
bool (*del_sa)(const struct kernel_sa *sa);
// 获取SPI
ipsec_spi_t (*get_spi)(const ip_address *src,
const ip_address *dst,
int proto,
bool tunnel_mode,
unsigned reqid,
ipsec_spi_t min,
ipsec_spi_t max,
const char *text_said);
// 执行建立连接命令
bool (*docommand)(struct connection *c
, struct spd_route *sr
, const char *verb
, struct state *st);
};
/* information from /proc/net/ipsec_eroute */
// 加密路由信息
struct eroute_info {
// 包数
unsigned long count;
// 本地子网
ip_subnet ours;
// 对方子网
ip_subnet his;
// 目的地址
ip_address dst;
// SA ID
ip_said said;
// 传输协议
int transport_proto;
// 链表下一项
struct eroute_info *next;
};
5.5 密钥结构
/* programs/pluto/keys.h */
// RSA公钥
struct RSA_public_key
{
// 密钥ID
char keyid[KEYID_BUF]; /* see ipsec_keyblobtoid(3) */
/* length of modulus n in octets: [RSA_MIN_OCTETS, RSA_MAX_OCTETS] */
// 长度
unsigned k;
/* public: */
// 公钥参数
MP_INT
n, /* modulus: p * q */
e; /* exponent: relatively prime to (p-1) * (q-1) [probably small] */
};
// RSA私钥
struct RSA_private_key {
// 公钥结构, 因为私钥和公钥是对称的, 基本描述结构也相同
struct RSA_public_key pub; /* must be at start for RSA_show_public_key */
// 私钥相关参数, 主要是一些内部私有数据
MP_INT
d, /* private exponent: (e^-1) mod ((p-1) * (q-1)) */
/* help for Chinese Remainder Theorem speedup: */
p, /* first secret prime */
q, /* second secret prime */
dP, /* first factor's exponent: (e^-1) mod (p-1) == d mod (p-1) */
dQ, /* second factor's exponent: (e^-1) mod (q-1) == d mod (q-1) */
qInv; /* (q^-1) mod p */
};
/* public key machinery */
// 公开密钥结构
struct pubkey {
// ID结构
struct id id;
// 使用数
unsigned refcnt; /* reference counted! */
// 认证层次
enum dns_auth_level dns_auth_level;
// DNS签名
char *dns_sig;
// 相关时间: 安装时间, 上次尝试时间, 上次工作时间, 到期时间
time_t installed_time
, last_tried_time
, last_worked_time
, until_time;
// 发布者
chunk_t issuer;
// 公开密钥算法类型
enum pubkey_alg alg;
// 公开密钥算法联合
union {
// 目前只支持RSA这种公开密钥算法
struct RSA_public_key rsa;
} u;
};
// 公开密钥链表结构
struct pubkey_list {
struct pubkey *key;
struct pubkey_list *next;
};
...... 待续 ......