在学习安全传输平台项目总结了笔记,并分享出来。
10-安全传输平台项目-第06天(密钥协商共享内存-守护进程-脚本)
目录:
一、复习
二、密钥协商共享内存-守护进程-脚本
1、共享内存操作函数接口设计
2、共享内存操作函数实现领读
3、生成密钥-组织密钥结构体信息
4、客户端写密钥信息到共享内存
5、服务器内存释放
6、共享内存补充说明
7、服务器守护进程创建
8、守护进程管理脚本
9、借助信号管理守护进程
10、密钥校验流程分析
一、复习
1、客户端:keymngclient.c—负责业务逻辑;keymngclientop.c—负责功能实现
2、服务器:keymngserver.c—负责业务逻辑;keymngserverop.c—负责功能实现
》密钥协商业务逻辑图:
二、安全传输平台项目——密钥协商共享内存-守护进程-脚本
1、共享内存操作函数接口设计
----共享内存 函数接口。
分析网点密钥信息 元素 --- struct shmNodeInfo{}
shmNodeInfo{ seckey, clientID, serverID, seckeyid, status, time }
模块组织关系:
客户端:
协商密钥成功,写 密钥节点信息 到 共享内存。 密钥校验, 读 取共享内存密钥信息。
服务器:
协商密钥成功,写 密钥节点信息 到 共享内存。 密钥校验, 读 取共享内存密钥信息。
存储:
服务器:struct shmNodeInfo shmInfo[N];
1
:
N
客户端:struct shmNodeInfo shmInfo;
初始化/创建共享内存
int shmInit(int shmkey, int size, int *shmhdle);
写网点信息共享内存
int shmNode_write(int shmhdle, struct shmNodeInfo *pShmNode, int maxnode);
读网点信息共享内存
int shmNode_Read(int shmhdle, struct shmNodeInfo **pShmNode, char *clientID,char *serverID);
2、共享内存操作函数实现领读
》函数封装:shmget()--> myipc_shm.c --> keymng_shmop.c --- keymng_shmop.h
分析了keymng_shmop.h和keymng_shmop.c
>keymng_shmop.h
// keymng_shmop.h#ifndef _KEYMNG_SHMOP_H_
#define _KEYMNG_SHMOP_H_
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
//将网点密钥信息写共享内存, 网点共享内存结构体
typedef struct _NodeSHMInfo
{
int status; //密钥状态 0-有效 1无效
char clientId[12]; //客户端id
char serverId[12]; //服务器端id
int seckeyid; //对称密钥id
unsigned char seckey[128]; //对称密钥 //hash1 hash256 md5
}NodeSHMInfo;
//int KeyMng_ShmInit(int keyid, int keysize, void *shmid )
//打开共享内存 共享内存存在则使用 不存在则创建(此函数并不是初始化)
int KeyMng_ShmInit(int key, int maxnodenum, int *shmhdl);
int KeyMng_ShmWrite(int shmhdl, int maxnodenum, NodeSHMInfo *pNodeInfo);//pNodeInfo是传入参数
int KeyMng_ShmRead(int shmhdl, char *clientId, char *serverId, int maxnodenum, NodeSHMInfo *pNodeInfo);//pNodeInfo是传出参数
#ifdef __cplusplus
}
#endif
#endif
keymng_shmop.h
>keymng_shmop.c
#include <unistd.h>#include <sys/types.h>#include <signal.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include "keymnglog.h"
#include "keymng_shmop.h"
#include "myipc_shm.h"
#include "keymngclientop.h"
//查看共享内存是否存在
//若 存在使用旧
//若 不存在创建
int KeyMng_ShmInit(int key, int maxnodenum, int *shmhdl)
{
int ret = 0;
//打开共享内存
ret = IPC_OpenShm(key, maxnodenum*sizeof(NodeSHMInfo), shmhdl);
if (ret == MYIPC_NotEXISTErr)
{
printf("keymng监测到共享内存不存在 正在创建共享内存...\n");
ret = IPC_CreatShm(key, maxnodenum*sizeof(NodeSHMInfo), shmhdl);
if (ret != 0)
{
printf("keymng创建共享内存 err:%d \n", ret);
return ret;
}
else
{
void *mapaddr = NULL;
printf("keymng创建共享内存 ok...\n");
ret = IPC_MapShm(*shmhdl, (void **) &mapaddr);
if (ret != 0)
{
printf("fun IPC_MapShm() err:%d 清空共享内存失败\n", ret);
return ret;
}
memset(mapaddr, 0, maxnodenum*sizeof(NodeSHMInfo));
IPC_UnMapShm(mapaddr);
printf("keymng清空共享内存ok\n");
}
}
else if (ret == 0)
{
printf("keymng监测到共享内存存在 使用旧的共享内存...\n");
}
else
{
printf("fun IPC_OpenShm() err:%d\n", ret);
}
return ret;
}
//写网点密钥
//若存在 则修改
//若不存在 则找一个空的位置写入
int KeyMng_ShmWrite(int shmhdl, int maxnodenum, NodeSHMInfo *pNodeInfo)
{
int ret = 0, i = 0;
NodeSHMInfo tmpNodeInfo; //空结点
NodeSHMInfo *pNode = NULL;
void *mapaddr = NULL;
memset(&tmpNodeInfo, 0, sizeof(NodeSHMInfo));
//连接共享内存
ret = IPC_MapShm(shmhdl, (void **) &mapaddr);
if (ret != 0)
{
KeyMng_Log(__FILE__, __LINE__,KeyMngLevel[4], ret,"func IPC_MapShm() err");
goto End;
}
//判断传入的网点密钥 是否已经 存在
for (i=0; i<maxnodenum; i++)
{
pNode = mapaddr + sizeof(NodeSHMInfo)*i;
if (strcmp(pNode->clientId, pNodeInfo->clientId) == 0 &&
strcmp(pNode->serverId, pNodeInfo->serverId) == 0 )
{
KeyMng_Log(__FILE__, __LINE__,KeyMngLevel[3], ret,"系统检测到 共享内存中已经存在网点信息cliented:%s serverid%s", pNode->clientId, pNode->serverId);
memcpy(pNode, pNodeInfo, sizeof(NodeSHMInfo));
goto End;
}
}
//若不存在
for (i=0; i<maxnodenum; i++)
{
pNode = mapaddr + sizeof(NodeSHMInfo)*i;
if (memcmp(&tmpNodeInfo, pNode, sizeof(NodeSHMInfo)) == 0 )
{
KeyMng_Log(__FILE__, __LINE__,KeyMngLevel[3], ret,"系统检测到 有一个空的位置 ");
memcpy(pNode, pNodeInfo, sizeof(NodeSHMInfo));
goto End;
}
}
if (i == maxnodenum)
{
ret = 1111;
KeyMng_Log(__FILE__, __LINE__,KeyMngLevel[4], ret,"系统检测到共享内存已满 ");
goto End;
}
End:
IPC_UnMapShm(mapaddr);
return ret;
}
//根据clientid和serverid 去读网点信息
int KeyMng_ShmRead(int shmhdl, char *clientId, char *serverId, int maxnodenum, NodeSHMInfo *pNodeInfo)
{
int ret = 0, i = 0;
NodeSHMInfo tmpNodeInfo; //空结点
NodeSHMInfo *pNode = NULL;
void *mapaddr = NULL;
memset(&tmpNodeInfo, 0, sizeof(NodeSHMInfo));
//连接共享内存
ret = IPC_MapShm(shmhdl, (void **) &mapaddr);
if (ret != 0)
{
KeyMng_Log(__FILE__, __LINE__,KeyMngLevel[4], ret,"func IPC_MapShm() err");
goto End;
}
//遍历网点信息
for (i=0; i<maxnodenum; i++)
{
pNode = mapaddr + sizeof(NodeSHMInfo)*i;
if ( strcmp(pNode->clientId, clientId) == 0 &&
strcmp(pNode->serverId, serverId) == 0 )
{
KeyMng_Log(__FILE__, __LINE__,KeyMngLevel[3], ret,"系统检测到 有一个空的位置 ");
memcpy(pNodeInfo, pNode, sizeof(NodeSHMInfo));
goto End;
}
}
if (i == maxnodenum)
{
ret = 1111;
KeyMng_Log(__FILE__, __LINE__,KeyMngLevel[4], ret,"系统检测到共享内存已满 ");
goto End;
}
End:
IPC_UnMapShm(mapaddr);
return ret;
}
keymng_shmop.c
》网点密钥信息结构体 --- struct shmNodeInfo{}
shmNodeInfo{ seckey, clientID, serverID, seckeyid, status, time }
clientid serverid status seckeyid time seckey
1111 0001 1 100 2017/7/2 a1b2c3
2222 0001 1 101 2017/7/4 abc123
3333 0001 1 102 2017/7/1 ab12c3
4444 0001 1 105 2017/7/3 a1bc23
》存共享内存分析图:
3、生成密钥-组织密钥结构体信息
》生成密钥:
1)借助开源算法 md5 sha1 sha256
2) 自定义算法:
123 abc a1b2c3
abc abc aabbcc
将keymng_shmop.h放入./secmng/inc/目录下,keymng_shmop.c放入./secmng/src/目录下。
>vi keymngclientop.c
1)将头文件"keymng_shmop.h"包含
2)在MngClient_InitInfo中调用KeyMng_ShmInit
3)在MngClient_Agree中组织密钥结构体信息
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>
#include "keymnglog.h"
#include "poolsocket.h"
#include "keymng_msg.h"
#include "keymngclientop.h"
#include "keymng_shmop.h"
int MngClient_InitInfo(MngClient_Info *pCltInfo)
{
int ret = 0;
strcpy(pCltInfo->clientId, "1111");
strcpy(pCltInfo->AuthCode, "1111");
strcpy(pCltInfo->serverId, "0001");
strcpy(pCltInfo->serverip, "127.0.0.1");
pCltInfo->serverport = 8001;
pCltInfo->maxnode = 1;
pCltInfo->shmkey = 0x0011;
pCltInfo->shmhdl = 0;
ret = KeyMng_ShmInit(pCltInfo->shmkey, pCltInfo->maxnode, &pCltInfo->shmhdl);
if (ret != 0) {
printf("---------客户端创建/打开 共享内存失败-----\n");
KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "KeyMng_ShmInit() err:%d", ret);
return 0;
}
return 0;
}
int MngClient_Agree(MngClient_Info *pCltInfo)
{
int i = 0;
int ret = 0;
int time = 3;
int connfd = -1;
// 存放编码 TLV 完成的 req
unsigned char *msgKey_Req_Data = NULL;
int msgKey_Req_DataLen = 0;
// 存放编码 TLV 完成的 res
unsigned char *msgKey_Res_Data = NULL;
int msgKey_Res_DataLen = 0;
MsgKey_Res *pStruct_Res = NULL;
int iType = 0;
// 初始化密钥请求结构体
MsgKey_Req msgKey_req;
msgKey_req.cmdType = KeyMng_NEWorUPDATE;
strcpy(msgKey_req.clientId, pCltInfo->clientId);
strcpy(msgKey_req.AuthCode, pCltInfo->AuthCode);
strcpy(msgKey_req.serverId, pCltInfo->serverId);
// 产生随机数 c: abcdefg s: abcdefg aabbccddeeffgg
for (i = 0; i < 64; i++) {
msgKey_req.r1[i] = 'a' + i;
}
// 编码密钥请求 结构体 req
ret = MsgEncode(&msgKey_req, ID_MsgKey_Req, &msgKey_Req_Data, &msgKey_Req_DataLen);
if (ret != 0) {
KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "func MsgEncode() err:%d", ret);
goto END;
}
// 初始化建立连接函数
ret = sckClient_init();
if (ret != 0) {
KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "func sckClient_init() err:%d", ret);
goto END;
}
// 创建连接。
ret = sckClient_connect(pCltInfo->serverip, pCltInfo->serverport, time, &connfd);
if (ret != 0) {
KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "func sckClient_connect() err:%d", ret);
goto END;
}
// 发送数据 TLV
ret = sckClient_send(connfd, time, msgKey_Req_Data, msgKey_Req_DataLen);
if (ret != 0) {
KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "func sckClient_send() err:%d", ret);
goto END;
}
// ---- 等待服务器回发数据
// 接收数据
ret = sckClient_rev(connfd, time, &msgKey_Res_Data, &msgKey_Res_DataLen);
if (ret != 0) {
KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "func sckClient_rev() err:%d", ret);
goto END;
}
// 解码密钥应答 结构体 res ---> rv r2
ret = MsgDecode(msgKey_Res_Data, msgKey_Res_DataLen, (void **)&pStruct_Res, &iType);
if (ret != 0) {
KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "func MsgDecode() err:%d", ret);
goto END;
}
if (pStruct_Res->rv != 0) {
ret = -1;
goto END;
} else if (pStruct_Res->rv == 0) {
printf("---当前生成的密钥编号为:%d\n", pStruct_Res->seckeyid);
}
// --组织密钥信息结构体
NodeSHMInfo nodeSHMInfo;
// --利用 r1 r2 生成密钥
for (i = 0; i < 64; i++) {
nodeSHMInfo.seckey[2*i] = msgKey_req.r1[i];
nodeSHMInfo.seckey[2*i+1] = pStruct_Res->r2[i];
}
nodeSHMInfo.status = 0; //0-有效 1无效
strcpy(nodeSHMInfo.clientId, msgKey_req.clientId);
strcpy(nodeSHMInfo.serverId, msgKey_req.serverId);
nodeSHMInfo.seckeyid = pStruct_Res->seckeyid;
// --写入共享内存。
END:
if (msgKey_Req_Data != NULL)
MsgMemFree((void **)&msgKey_Req_Data, 0);
if (msgKey_Res_Data != NULL)
MsgMemFree((void **)&msgKey_Res_Data, 0);
if (pStruct_Res != NULL)
MsgMemFree((void **)&pStruct_Res, iType);
return ret;
}
keymngclientop.c
4、客户端写密钥信息到共享内存
>vi keymngclientop.c
在MngClient_Agree中调用写入共享内存的函数KeyMng_ShmWrite
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include "keymnglog.h"
#include "poolsocket.h"
#include "keymng_msg.h"
#include "keymngclientop.h"
#include "keymng_shmop.h"
int MngClient_InitInfo(MngClient_Info *pCltInfo)
{
int ret = 0;
strcpy(pCltInfo->clientId, "1111");
strcpy(pCltInfo->AuthCode, "1111");
strcpy(pCltInfo->serverId, "0001");
strcpy(pCltInfo->serverip, "127.0.0.1");
pCltInfo->serverport = 8001;
pCltInfo->maxnode = 1;
pCltInfo->shmkey = 0x0011;
pCltInfo->shmhdl = 0;
ret = KeyMng_ShmInit(pCltInfo->shmkey, pCltInfo->maxnode, &pCltInfo->shmhdl);
if (ret != 0) {
printf("---------客户端创建/打开 共享内存失败-----\n");
KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "KeyMng_ShmInit() err:%d", ret);
return 0;
}
return 0;
}
int MngClient_Agree(MngClient_Info *pCltInfo)
{
int i = 0;
int ret = 0;
int time = 3;
int connfd = -1;
// 存放编码 TLV 完成的 req
unsigned char *msgKey_Req_Data = NULL;
int msgKey_Req_DataLen = 0;
// 存放编码 TLV 完成的 res
unsigned char *msgKey_Res_Data = NULL;
int msgKey_Res_DataLen = 0;
MsgKey_Res *pStruct_Res = NULL;
int iType = 0;
// 初始化密钥请求结构体
MsgKey_Req msgKey_req;
msgKey_req.cmdType = KeyMng_NEWorUPDATE;
strcpy(msgKey_req.clientId, pCltInfo->clientId);
strcpy(msgKey_req.AuthCode, pCltInfo->AuthCode);
strcpy(msgKey_req.serverId, pCltInfo->serverId);
// 产生随机数 c: abcdefg s: abcdefg aabbccddeeffgg
for (i = 0; i < 64; i++) {
msgKey_req.r1[i] = 'a' + i;
}
// 编码密钥请求 结构体 req
ret = MsgEncode(&msgKey_req, ID_MsgKey_Req, &msgKey_Req_Data, &msgKey_Req_DataLen);
if (ret != 0) {
KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "func MsgEncode() err:%d", ret);
goto END;
}
// 初始化建立连接函数
ret = sckClient_init();
if (ret != 0) {
KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "func sckClient_init() err:%d", ret);
goto END;
}
// 创建连接。
ret = sckClient_connect(pCltInfo->serverip, pCltInfo->serverport, time, &connfd);
if (ret != 0) {
KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "func sckClient_connect() err:%d", ret);
goto END;
}
// 发送数据 TLV
ret = sckClient_send(connfd, time, msgKey_Req_Data, msgKey_Req_DataLen);
if (ret != 0) {
KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "func sckClient_send() err:%d", ret);
goto END;
}
// ---- 等待服务器回发数据
// 接收数据
ret = sckClient_rev(connfd, time, &msgKey_Res_Data, &msgKey_Res_DataLen);
if (ret != 0) {
KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "func sckClient_rev() err:%d", ret);
goto END;
}
// 解码密钥应答 结构体 res ---> rv r2
ret = MsgDecode(msgKey_Res_Data, msgKey_Res_DataLen, (void **)&pStruct_Res, &iType);
if (ret != 0) {
KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "func MsgDecode() err:%d", ret);
goto END;
}
if (pStruct_Res->rv != 0) {
ret = -1;
goto END;
} else if (pStruct_Res->rv == 0) {
printf("---当前生成的密钥编号为:%d\n", pStruct_Res->seckeyid);
}
// --组织密钥信息结构体
NodeSHMInfo nodeSHMInfo;
// --利用 r1 r2 生成密钥
for (i = 0; i < 64; i++) {
nodeSHMInfo.seckey[2*i] = msgKey_req.r1[i];
nodeSHMInfo.seckey[2*i+1] = pStruct_Res->r2[i];
}
nodeSHMInfo.status = 0; //0-有效 1无效
strcpy(nodeSHMInfo.clientId, msgKey_req.clientId);
strcpy(nodeSHMInfo.serverId, msgKey_req.serverId);
nodeSHMInfo.seckeyid = pStruct_Res->seckeyid;
// --写入共享内存。
ret = KeyMng_ShmWrite(pCltInfo->shmhdl, pCltInfo->maxnode, &nodeSHMInfo);
if (ret != 0) {
KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "KeyMng_ShmWrite() err:%d", ret);
goto END;
}
printf("--------------写共享内存完成------\n");
END:
if (msgKey_Req_Data != NULL)
MsgMemFree((void **)&msgKey_Req_Data, 0);
if (msgKey_Res_Data != NULL)
MsgMemFree((void **)&msgKey_Res_Data, 0);
if (pStruct_Res != NULL)
MsgMemFree((void **)&pStruct_Res, iType);
return ret;
}
keymng_shmop.c
>vi makefile
.PHONY:clean allWORKDIR=.VPATH = ./srcCC=gccCFLGS= -Wall -g -I$(WORKDIR)/inc/LIBFLAG = -L$(HOME)/lib BIN = keymngclient keymngserver all:$(BIN) keymngclient:keymngclient.o keymnglog.o keymngclientop.o myipc_shm.o keymng_shmop.o $(CC) $(LIBFLAG) -lpthread -litcastsocket -lmessagereal $^ -o $@ #myipc_shm.o keymng_shmop.o keymng_dbop.o -lclntsh -licdbapi keymngserver:keymngserver.o keymngserverop.o keymnglog.o $(CC) $(LIBFLAG) $^ -o $@ -lpthread -litcastsocket -lmessagereal #testdbapi:testdbapi.o # $(CC) $(LIBFLAG) $^ -o $@ -lpthread -lclntsh -licdbapi %.o:%.c $(CC) $(CFLGS) -c $< -o $@ clean: rm -f *.o $(BIN)
makefile
>make
>./keymngclient
打开另一个终端,执行>./keymngserver,分别查看终端执行情况。
客户端情况:(输入:1):
“Ctrl+c”结束进程后,>ipcs 查看共享内存的创建情况
服务器端情况:
》同理,将服务器添加共享内存:
>vi keymngserverop.c
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include "keymngserverop.h"#include "keymng_msg.h"#include "keymnglog.h"
#include "keymng_shmop.h"
static int seckeyid = 100;
int MngServer_InitInfo(MngServer_Info *svrInfo)
{
int ret = 0;
strcpy(svrInfo->serverId, "0001");
strcpy(svrInfo->dbuse, "SECMNG");
strcpy(svrInfo->dbpasswd, "SECMNG");
strcpy(svrInfo->dbsid, "orcl");
svrInfo->dbpoolnum = 8;
strcpy(svrInfo->serverip, "127.0.0.1");
svrInfo->serverport = 8001;
svrInfo->maxnode = 10;
svrInfo->shmkey = 0x0001;
svrInfo->shmhdl = 0;
ret = KeyMng_ShmInit(svrInfo->shmkey, svrInfo->maxnode, &svrInfo->shmhdl);
if (ret != 0) {
printf("---------服务器创建/打开 共享内存失败-----\n");
KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "服务器 KeyMng_ShmInit() err:%d", ret);
return ret;
}
return 0;
}
int MngServer_Agree(MngServer_Info *svrInfo, MsgKey_Req *msgkeyReq, unsigned char **outData, int *datalen)
{
int ret = 0;
int i = 0;
MsgKey_Res msgKey_Res;
NodeSHMInfo nodeSHMInfo;
// --结合 r1 r2 生成密钥 ---> 成功、失败 rv
if (strcmp(svrInfo->serverId, msgkeyReq->serverId) != 0) {
KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "客户端访问了错误的服务器");
return -1;
}
// 组织 应答结构体 res : rv r2 clientId serverId seckeyid
msgKey_Res.rv = 0; //0 成功 1 失败。
strcpy(msgKey_Res.clientId, msgkeyReq->clientId);
strcpy(msgKey_Res.serverId, msgkeyReq->serverId);
// 生成随机数 r2
for (i = 0; i < 64; i++) {
msgKey_Res.r2[i] = 'a' + i;
}
msgKey_Res.seckeyid = seckeyid++;
// 组织密钥节点信息结构体
for (i = 0; i < 64; i++) {
nodeSHMInfo.seckey[2*i] = msgkeyReq->r1[i];
nodeSHMInfo.seckey[2*i+1] = msgKey_Res.r2[i];
}
nodeSHMInfo.status = 0; //0-有效 1无效
strcpy(nodeSHMInfo.clientId, msgkeyReq->clientId);
strcpy(nodeSHMInfo.serverId, msgkeyReq->serverId);
nodeSHMInfo.seckeyid = msgKey_Res.seckeyid;
// --写入共享内存。
ret = KeyMng_ShmWrite(svrInfo->shmhdl, svrInfo->maxnode, &nodeSHMInfo);
if (ret != 0) {
KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "服务器 KeyMng_ShmWrite() err:%d", ret);
return ret;
}
// --写数据库
// 编码应答报文 传出
ret = MsgEncode(&msgKey_Res, ID_MsgKey_Res, outData, datalen);
if (ret != 0) {
KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "serverAgree MsgEncode() err:%d", ret);
return ret;
}
return 0;
}
int MngServer_Check(MngServer_Info *svrInfo, MsgKey_Req *msgkeyReq, unsigned char **outData, int *datalen)
{
return 0;
}
keymngserverop.c
>vi makefile
.PHONY:clean allWORKDIR=.VPATH = ./srcCC=gccCFLGS= -Wall -g -I$(WORKDIR)/inc/LIBFLAG = -L$(HOME)/libBIN = keymngclient keymngserver all:$(BIN)
keymngclient:keymngclient.o keymnglog.o keymngclientop.o myipc_shm.o keymng_shmop.o
$(CC) $(LIBFLAG) -lpthread -litcastsocket -lmessagereal $^ -o $@
# keymng_dbop.o -lclntsh -licdbapi
keymngserver:keymngserver.o keymngserverop.o keymnglog.o myipc_shm.o keymng_shmop.o
$(CC) $(LIBFLAG) $^ -o $@ -lpthread -litcastsocket -lmessagereal
#testdbapi:testdbapi.o
# $(CC) $(LIBFLAG) $^ -o $@ -lpthread -lclntsh -licdbapi
%.o:%.c
$(CC) $(CFLGS) -c $< -o $@
clean:
rm -f *.o $(BIN)
makefile
5、服务器内存释放
>free(在该释放内存的地方加入 相应创建的函数中寻找释放内存的函数)
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <pthread.h> #include "poolsocket.h" #include "keymngserverop.h"#include "keymng_msg.h"
#include "keymnglog.h"
MngServer_Info serverInfo;
void *start_routine(void * arg)
{
int ret;
int timeout = 3;
int connfd = (int)arg;
unsigned char *out = NULL;
int outlen = 0;
MsgKey_Req *pStruct_req = NULL;
int iType = 0;
unsigned char *res_outData = NULL;
int res_outDataLen = 0;
while (1) {
//服务器端端接受报文
ret = sckServer_rev(connfd, timeout, &out, &outlen);
if (ret == Sck_ErrPeerClosed) {
// 检测到 对端关闭,关闭本端。
printf("----------------ErrPeerClosed 关闭服务器\n");
break;
} else if (ret == Sck_ErrTimeOut) {
if (out != NULL) sck_FreeMem((void **)&out);
continue;
} else if (ret != 0) {
printf("未知错误\n");
break;
}
// 解码客户端 密钥请求报文 ---> cmdType
ret = MsgDecode(out, outlen, (void **)&pStruct_req, &iType);
if (ret != 0) {
KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "MsgDecode() err:%d", ret);
break;
}
switch(pStruct_req->cmdType) {
case KeyMng_NEWorUPDATE:
ret = MngServer_Agree(&serverInfo, pStruct_req, &res_outData, &res_outDataLen);
case KeyMng_Check:
MngServer_Check(&serverInfo, pStruct_req, &res_outData, &res_outDataLen);
/*
case 密钥注销:
mngServer_Agree();
*/
default:
break;
}
if (ret != 0) {
KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "MngServer_Agree() err:%d", ret);
break;
}
//服务器端发送报文
ret = sckServer_send(connfd, timeout, res_outData, res_outDataLen);
if (ret == Sck_ErrPeerClosed) {
// 检测到 对端关闭,关闭本端。
printf("---ErrPeerClosed \n");
break;
} else if (ret == Sck_ErrTimeOut) {
printf("---服务器检测到本端发送数据 超时 \n");
if (out != NULL) sck_FreeMem((void **)&out);
if (pStruct_req != NULL) MsgMemFree((void **)&pStruct_req, iType);
if (res_outData != NULL) MsgMemFree((void **)&res_outData, 0);
continue;
} else if (ret != 0) {
printf("未知错误\n");
break;
}
}
if (out != NULL) sck_FreeMem((void **)&out);
if (pStruct_req != NULL) MsgMemFree((void **)&pStruct_req, iType);
if (res_outData != NULL) MsgMemFree((void **)&res_outData, 0);
sckServer_close(connfd);
return NULL;
}
int main(void)
{
int listenfd;
int ret = 0;
int timeout = 3;
int connfd = -1;
pthread_t pid;
// 服务器信息初始化。
ret = MngServer_InitInfo(&serverInfo);
if (ret != 0) {
KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "MngServer_InitInfo() err:%d", ret);
return ret;
}
//服务器端初始化
ret = sckServer_init(serverInfo.serverport, &listenfd);
if (ret != 0) {
KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "sckServer_init() err:%d", ret);
return ret;
}
while (1) {
ret = sckServer_accept(listenfd, timeout, &connfd);
if (ret == Sck_ErrTimeOut){
KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[2], ret, "---等待客户端连接超时---");
continue;
} else if(ret != 0) {
KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "sckServer_accept() err:%d", ret);
return ret;
}
ret = pthread_create(&pid, NULL, start_routine, (void *)connfd);
}
//服务器端环境释放
sckServer_destroy();
return 0;
}
keymngserver.c
>make
>./keymngclient
打开另一个终端,执行>./keymngserver,分别查看终端执行情况。
客户端情况:(输入:1):
服务器端情况:
打开第三个终端,输入>ipcs,查看共享内存:
6、共享内存补充说明
问题:密钥协商业务逻辑图中两块共享内存是一块吗?有什么关系吗?
分析:服务器和客户端是两个PC,两个共享内存是分别在不同的PC的内核区创建的,图中上边的共享内存(服务器的共享内存)用于app1和keymngserver进行通信,图中下边的的共享内存(客户端的共享内存)用于app2和keymngclient进行通信。而这两个共享内存没有任何关系!
7、服务器守护进程创建
问题:当>./keymngserver 运行时,当前终端,不能输入shell指令,完全被服务器进程占据?
解决:守护进程。
》守护进程创建:
守护进程:
运行于操作系统后台的服务进程。周期性的执行某个任务,或者等待某些事件发生。
不占用控制终端。不随用户的注销而结束、退出。 通常以 d 结尾命名。 daemon
位于一个新会话中。新的进程组。 脱离控制终端。
1. fork 子进程, 父进程exit。
2. 子进程 调用 setsid()创建新会话。 成为会长。进程组组长。 子进程 pid。
3. 修改工作目录位置。防止可执行占用可卸载磁盘空间。 chdir();
4. 设定 创建文件的权限 掩码 umask
5. 关闭/重定向(dup2) 0/1/2 --> /dev/null ---- /dev/zero
6. 守护进程 循环逻辑。
7. 守护进程管理。———— 脚本
>vi keymngserver.c(添加守护进程CREATE_DAEMON)
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <pthread.h> #include "poolsocket.h" #include "keymngserverop.h"#include "keymng_msg.h"#include "keymnglog.h"
MngServer_Info serverInfo;
//注意定义宏的时候最后是一个整体,不能有空格!
#define CREATE_DAEMON if(fork()>0)exit(1);setsid();
void *start_routine(void * arg)
{
int ret;
int timeout = 3;
int connfd = (int)arg;
unsigned char *out = NULL;
int outlen = 0;
MsgKey_Req *pStruct_req = NULL;
int iType = 0;
unsigned char *res_outData = NULL;
int res_outDataLen = 0;
while (1) {
//服务器端端接受报文
ret = sckServer_rev(connfd, timeout, &out, &outlen);
if (ret == Sck_ErrPeerClosed) {
// 检测到 对端关闭,关闭本端。
printf("----------------ErrPeerClosed 关闭服务器\n");
break;
} else if (ret == Sck_ErrTimeOut) {
if (out != NULL) sck_FreeMem((void **)&out);
continue;
} else if (ret != 0) {
printf("未知错误\n");
break;
}
// 解码客户端 密钥请求报文 ---> cmdType
ret = MsgDecode(out, outlen, (void **)&pStruct_req, &iType);
if (ret != 0) {
KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "MsgDecode() err:%d", ret);
break;
}
switch(pStruct_req->cmdType) {
case KeyMng_NEWorUPDATE:
ret = MngServer_Agree(&serverInfo, pStruct_req, &res_outData, &res_outDataLen);
case KeyMng_Check:
MngServer_Check(&serverInfo, pStruct_req, &res_outData, &res_outDataLen);
/*
case 密钥注销:
mngServer_Agree();
*/
default:
break;
}
if (ret != 0) {
KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "MngServer_Agree() err:%d", ret);
break;
}
//服务器端发送报文
ret = sckServer_send(connfd, timeout, res_outData, res_outDataLen);
if (ret == Sck_ErrPeerClosed) {
// 检测到 对端关闭,关闭本端。
printf("---ErrPeerClosed \n");
break;
} else if (ret == Sck_ErrTimeOut) {
printf("---服务器检测到本端发送数据 超时 \n");
if (out != NULL) sck_FreeMem((void **)&out);
if (pStruct_req != NULL) MsgMemFree((void **)&pStruct_req, iType);
if (res_outData != NULL) MsgMemFree((void **)&res_outData, 0);
continue;
} else if (ret != 0) {
printf("未知错误\n");
break;
}
}
if (out != NULL) sck_FreeMem((void **)&out);
if (pStruct_req != NULL) MsgMemFree((void **)&pStruct_req, iType);
if (res_outData != NULL) MsgMemFree((void **)&res_outData, 0);
sckServer_close(connfd);
return NULL;
}
int main(void)
{
int listenfd;
int ret = 0;
int timeout = 3;
int connfd = -1;
pthread_t pid;
CREATE_DAEMON
// 服务器信息初始化。
ret = MngServer_InitInfo(&serverInfo);
if (ret != 0) {
KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "MngServer_InitInfo() err:%d", ret);
return ret;
}
//服务器端初始化
ret = sckServer_init(serverInfo.serverport, &listenfd);
if (ret != 0) {
KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "sckServer_init() err:%d", ret);
return ret;
}
while (1) {
ret = sckServer_accept(listenfd, timeout, &connfd);
if (ret == Sck_ErrTimeOut){
KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[2], ret, "---等待客户端连接超时---");
continue;
} else if(ret != 0) {
KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "sckServer_accept() err:%d", ret);
return ret;
}
ret = pthread_create(&pid, NULL, start_routine, (void *)connfd);
}
//服务器端环境释放
sckServer_destroy();
return 0;
}
keymngserver.c
>make
>./keymngserver
8、守护进程管理脚本
问题抛出:当服务器进程变为守护进程后,无法使用Ctrl+c 结束服务器进程,只能通过>ps aux | grep keymngserver 查到pid,然后 kill -9 pid。但是用户怎么办?用户无法结束服务器进程?
所以,采用脚本。
》shell脚本:
集成 一系列 shell命令。组织到一个文件中。统一运行。
第一行: 指定解析器。 #!/bin/bash /bin/shell
awk 处理列
sed 处理行
在UltraEdit中编辑文件:
>touch myshell
#! /bin/bashls -ldateecho $HOME
>ls -l myshell
>chmod a+x myshell
但是运行脚本,会报错:
分析:错误由于wind和Linux换行不一致造成的:
windows \r\n
---
Linux \n \r --> ^M
解决:
vim --> :set ff=unix(fileformat可以简写为ff)
再次执行>./myshell
但是,在myshell新增加行,设置就失效了,
法一:把set ff=unix写到vim的配置文件vimrc中;
法二:在Linux中写脚本
如何提取pid?如何提取服务器进程?(-u指定用户,awk指定列,$1指定第一列)
>ps -u test04 | grep keymngserver | awk '{print $1}'
》获取 命令结果:(两种方式,常用第二种)
src=$(whoami)
src=`whoami` --> “反引号”
>vi myshell
#! /bin/bashuserN=`whoami`mypid=`ps -u ${userN} | grep keymngserver | awk '{print $1}'`if [ -z ${mypid} ];then echo "The process is not started." exit 1;fikill -9 ${mypid}echo "kill keymngserver successful"
如果启动服务器>./keymngserver,执行>./myshell
9、借助信号管理守护进程
问题抛出:当服务器进程当运行在某处时,执行>./myshell,服务器进程终止,导致可能服务器正和客户端协商,终止了,导致共享内存,堆空间都消失了;服务器里边某些内存没释放,某些进程没有正常终止?
查看kill -l 中这几个信号:
>man sigaction(设置信号捕捉)
>man signal
》加入信号捕捉函数:signal(SIGUSR1, catchSignal);
>vi keymngserver.c
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <pthread.h>#include <signal.h> #include "poolsocket.h" #include "keymngserverop.h"#include "keymng_msg.h"#include "keymnglog.h"
MngServer_Info serverInfo;
int flg = 1;
//注意定义宏的时候最后是一个整体,不能有空格!
#define CREATE_DAEMON if(fork()>0)exit(1);setsid();
void *start_routine(void * arg)
{
int ret;
int timeout = 3;
int connfd = (int)arg;
unsigned char *out = NULL;
int outlen = 0;
MsgKey_Req *pStruct_req = NULL;
int iType = 0;
unsigned char *res_outData = NULL;
int res_outDataLen = 0;
while (1) {
if (flg == 0)
break;
//服务器端端接受报文
ret = sckServer_rev(connfd, timeout, &out, &outlen);
if (ret == Sck_ErrPeerClosed) {
// 检测到 对端关闭,关闭本端。
printf("----------------ErrPeerClosed 关闭服务器\n");
break;
} else if (ret == Sck_ErrTimeOut) {
if (out != NULL) sck_FreeMem((void **)&out);
continue;
} else if (ret != 0) {
printf("未知错误\n");
break;
}
// 解码客户端 密钥请求报文 ---> cmdType
ret = MsgDecode(out, outlen, (void **)&pStruct_req, &iType);
if (ret != 0) {
KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "MsgDecode() err:%d", ret);
break;
}
switch(pStruct_req->cmdType) {
case KeyMng_NEWorUPDATE:
ret = MngServer_Agree(&serverInfo, pStruct_req, &res_outData, &res_outDataLen);
case KeyMng_Check:
MngServer_Check(&serverInfo, pStruct_req, &res_outData, &res_outDataLen);
/*
case 密钥注销:
mngServer_Agree();
*/
default:
break;
}
if (ret != 0) {
KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "MngServer_Agree() err:%d", ret);
break;
}
//服务器端发送报文
ret = sckServer_send(connfd, timeout, res_outData, res_outDataLen);
if (ret == Sck_ErrPeerClosed) {
// 检测到 对端关闭,关闭本端。
printf("---ErrPeerClosed \n");
break;
} else if (ret == Sck_ErrTimeOut) {
printf("---服务器检测到本端发送数据 超时 \n");
if (out != NULL) sck_FreeMem((void **)&out);
if (pStruct_req != NULL) MsgMemFree((void **)&pStruct_req, iType);
if (res_outData != NULL) MsgMemFree((void **)&res_outData, 0);
continue;
} else if (ret != 0) {
printf("未知错误\n");
break;
}
}
if (out != NULL) sck_FreeMem((void **)&out);
if (pStruct_req != NULL) MsgMemFree((void **)&pStruct_req, iType);
if (res_outData != NULL) MsgMemFree((void **)&res_outData, 0);
sckServer_close(connfd);
return NULL;
}
void catchSignal(int signum)
{
flg = 0;
printf(" catch signal %d, process is going to die.\n", signum);
return ;
}
int main(void)
{
int listenfd;
int ret = 0;
int timeout = 3;
int connfd = -1;
pthread_t pid;
CREATE_DAEMON
signal(SIGUSR1, catchSignal);
// 服务器信息初始化。
ret = MngServer_InitInfo(&serverInfo);
if (ret != 0) {
KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "MngServer_InitInfo() err:%d", ret);
return ret;
}
//服务器端初始化
ret = sckServer_init(serverInfo.serverport, &listenfd);
if (ret != 0) {
KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "sckServer_init() err:%d", ret);
return ret;
}
while (1) {
if (flg == 0)
break;
ret = sckServer_accept(listenfd, timeout, &connfd);
if (ret == Sck_ErrTimeOut){
KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[2], ret, "---等待客户端连接超时---");
continue;
} else if(ret != 0) {
KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "sckServer_accept() err:%d", ret);
return ret;
}
ret = pthread_create(&pid, NULL, start_routine, (void *)connfd);
}
//服务器端环境释放
sckServer_destroy();
printf("服务器 优雅退出。\n");
return 0;
}
keymngserver.c
>vi myshell(更改为发送10号信号)
#! /bin/bashuserN=`whoami`mypid=`ps -u ${userN} | grep keymngserver | awk '{print $1}'`if [ -z ${mypid} ];then echo "The process is not started." exit 1;fikill -10 ${mypid}echo "kill keymngserver successful"
myshell
>make
>./keymngserver
打开另一个终端,执行>./myshell,
查看服务器端:
10、密钥校验流程分析
密钥校验:
》服务器:
int MngServer_check() { //读出 密钥请求结构体中 r1[] (10字节的密钥数据) //依据 clientid、serverid 读共享内存 --> seckey 密钥 --> 提取前10字节 --> 比较 //根据比较结果填充 res.rv //组织密钥应答结构体 res 其他成员变量 //编码密钥应答结构体 --> 传出。 }
》客户端:
校验方法:
1. a1b2c3 --> 再加密(非对称加密)--> jqk678
2. 片段校验法: 0-10 密钥信息一致 --> 一致。
int MngServer_check() { //读共享内存 --> seckey 密钥 --> 提取前10字节 --> req.r1[]; //组织密钥请求结构体(校验的事) //编码密钥请求结构体 req //初始化连接 --> listenfd //建立连接 --> connfd //发送请求报文 --> TLV send //接收应答报文 --> fwq TLV res //解析应答报文 --> TLV --> Struct --> rv --> 0 一致 1 不一致。 //给用户返回校验结果。 }
在学习安全传输平台项目总结了笔记,并分享出来。