基於openswan klips的IPsec實現分析(七)內核SADB維護(1)
轉載請註明出處:http://blog.csdn.net/rosetta
上一節講了應用層pluto是如何構造SADB消息發送給內核的,這節將講內核對SADB的維護,所有SA處理函數都在指針數組msg_parsers[]中。
SADB(SA Database)即SA數據庫,一般聽到數據庫三字就會想到衆所周知的Mysql、Oracle等,但klips對於SA的維護使用的數據庫其實就是一個哈希表ipsec_sadb_hash[](以下稱sa哈希表),其每一個成員都是structipsec_sa結構,定義在ipsec_sa.c裏:
struct ipsec_sa *ipsec_sadb_hash[SADB_HASHMOD];
結構體struct ipsec_sa成員比較多就不給出了。
三元組said (spi,目的地址,協議),用以唯一標識SA
typedefstruct { /* to identify an SA, weneed: */
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;
隧道協商成功後最終形成的三元組例子比如:
[email protected]和ah0x235cc2d7@192.168.2.3
spi:0x1002,0x235cc2d7
協議:tun(ESP或AH),AH
目的地址:192.168.2.1, 192.168.2.3
通過said查找SA.
structipsec_sa *
ipsec_sa_getbyid(ip_said*said)
{
int hashval;
struct ipsec_sa *ips;
char sa[SATOT_BUF];
size_t sa_len;
if(said == NULL) {
KLIPS_PRINT(debug_xform,
"klips_error:ipsec_sa_getbyid: "
"null pointer passed in!\n");
return NULL;
}
sa_len = satot(said, 0, sa, sizeof(sa));//通過said獲取以上三元組例子的長度,只爲調試使用。
hashval = IPS_HASH(said);
KLIPS_PRINT(debug_xform,
"klips_debug:ipsec_sa_getbyid: "
"linked entry in ipsec_sa table forhash=%d of SA:%s requested.\n",
hashval,
sa_len ? sa : " (error)");
if((ips = ipsec_sadb_hash[hashval]) ==NULL) {//sa哈希表中無此sa節點,出錯。
KLIPS_PRINT(debug_xform,
"klips_debug:ipsec_sa_getbyid: "
"no entries in ipsec_sa table forhash=%d of SA:%s.\n",
hashval,
sa_len ? sa : " (error)");
return NULL;
}
for (; ips; ips = ips->ips_hnext) {//循環sa哈希表中獲取到的一個節點,匹配三元組。
if ((ips->ips_said.spi ==said->spi) &&
(ips->ips_said.dst.u.v4.sin_addr.s_addr== said->dst.u.v4.sin_addr.s_addr) &&
(ips->ips_said.proto == said->proto)){
atomic_inc(&ips->ips_refcount);
return ips; //成功匹配,返回。
}
}
KLIPS_PRINT(debug_xform,
"klips_debug:ipsec_sa_getbyid: "
"no entry in linked list for hash=%dof SA:%s.\n",
hashval,
sa_len ? sa : " (error)");
return NULL;
}
內核增加SA
int ipsec_sa_add(structipsec_sa *ips)
{
int error = 0;
unsigned int hashval;
if(ips == NULL) {
KLIPS_PRINT(debug_xform,
"klips_error:ipsec_sa_add:"
"null pointer passedin!\n");
return -ENODATA;
}
hashval = IPS_HASH(&ips->ips_said);//通過said計算HASH值。
atomic_inc(&ips->ips_refcount);//原子增加此sa被引用的次數
spin_lock_bh(&tdb_lock);//操作哈希數據自旋鎖
ips->ips_hnext = ipsec_sadb_hash[hashval];
ipsec_sadb_hash[hashval] = ips;//增加sa完成。
spin_unlock_bh(&tdb_lock);
return error;
}
內核刪除SA
/*
Theipsec_sa table better be locked before it is handed in, or races might happen
*/
int
ipsec_sa_del(struct ipsec_sa *ips)
{
unsignedint hashval;
structipsec_sa *ipstp;
charsa[SATOT_BUF];
size_tsa_len;
if(ips== NULL) {
KLIPS_PRINT(debug_xform,
"klips_error:ipsec_sa_del: "
"null pointer passed in!\n");
return-ENODATA;
}
sa_len= satot(&ips->ips_said, 0, sa, sizeof(sa));
if(ips->ips_inext|| ips->ips_onext) {
KLIPS_PRINT(debug_xform,
"klips_error:ipsec_sa_del: "
"SA:%s still linked!\n",
sa_len ? sa : " (error)");
return-EMLINK;
}
hashval= IPS_HASH(&ips->ips_said);
KLIPS_PRINT(debug_xform,
"klips_debug:ipsec_sa_del: "
"deleting SA:%s, hashval=%d.\n",
sa_len ? sa : " (error)",
hashval);
if(ipsec_sadb_hash[hashval]== NULL) {
KLIPS_PRINT(debug_xform,
"klips_debug:ipsec_sa_del: "
"no entries in ipsec_sa table forhash=%d of SA:%s.\n",
hashval,
sa_len ? sa : " (error)");
return-ENOENT;
}
if(ips == ipsec_sadb_hash[hashval]) {//僅從哈希表中移除,具體的釋放內存操作會在ipsec_sa_free()函數中進行,都是一些kfree操作,不做具體分析。
ipsec_sadb_hash[hashval]= ipsec_sadb_hash[hashval]->ips_hnext;
ips->ips_hnext= NULL;
atomic_dec(&ips->ips_refcount);//
KLIPS_PRINT(debug_xform,
"klips_debug:ipsec_sa_del: "
"successfully deleted first ipsec_sain chain.\n");
return0;
}else {
for(ipstp = ipsec_sadb_hash[hashval];
ipstp;
ipstp = ipstp->ips_hnext) {
if(ipstp->ips_hnext == ips) {
ipstp->ips_hnext= ips->ips_hnext;
ips->ips_hnext= NULL;
atomic_dec(&ips->ips_refcount);
KLIPS_PRINT(debug_xform,
"klips_debug:ipsec_sa_del: "
"successfully deleted link in ipsec_sachain.\n");
return0;
}
}
}
KLIPS_PRINT(debug_xform,
"klips_debug:ipsec_sa_del: "
"no entries in linked list for hash=%dof SA:%s.\n",
hashval,
sa_len ? sa : " (error)");
return-ENOENT;
}