@@ -58,6 +58,10 @@ static __attribute__((__used__)) const char * GIT_VERSION_UNKNOWN = NULL;
}
# endif
# define INTERCEPT_RET_CODE_OK (APP_STATE_DROPPKT | APP_STATE_KILL_FOLLOW | APP_STATE_GIVEME)
# define INTERCEPT_RET_CODE_FAIL (APP_STATE_FAWPKT | APP_STATE_KILL_FOLLOW | APP_STATE_DROPME)
# define INTERCEPT_RET_CODE_BYPASS (APP_STATE_FAWPKT | APP_STATE_KILL_FOLLOW | APP_STATE_GIVEME)
# define INTERCEPT_RET_CODE_NEED_NEXT (APP_STATE_DROPPKT | APP_STATE_GIVEME)
struct kni_handle * g_kni_handle = NULL ;
struct kni_field_stat_handle * g_kni_fs_handle = NULL ;
@@ -655,13 +659,10 @@ error_out:
return NULL ;
}
static char * add_cmsg_to_packet ( struct pme_info * pmeinfo , struct streaminfo * stream , struct pkt_info * pktinfo , int * len ) {
//tcp option: kind 88, len 4, control_info_len
void * logger = g_kni_handle - > local_logger ;
char * new_pkt = ( char * ) ALLOC ( struct wrapped_packet , 1 ) ;
static int rebuild_packet_to_add_tcp_option ( struct pme_info * pmeinfo , struct pkt_info * pktinfo , char * new_pkt ) {
//char *new_pkt = (char*)ALLOC(struct wrapped_packet, 1);
int offset = 0 ;
//iphdr
KNI_LOG_DEBUG ( logger , " Kni add cmsg to packet malloc buffer size:%d " , sizeof ( struct wrapped_packet ) ) ;
if ( pmeinfo - > addr_type = = ADDR_TYPE_IPV6 ) {
memcpy ( new_pkt , ( void * ) pktinfo - > iphdr . v6 , pktinfo - > iphdr_len ) ;
}
@@ -686,18 +687,10 @@ static char* add_cmsg_to_packet(struct pme_info *pmeinfo, struct streaminfo *str
//data
memcpy ( new_pkt + offset , ( void * ) pktinfo - > data , pktinfo - > data_len ) ;
offset + = pktinfo - > data_len ;
//kni_cmsg_serialize_header
uint16_t header_len = 0 ;
unsigned char * header = kni_cmsg_serialize_header_new ( pmeinfo , stream , pktinfo , & header_len ) ;
if ( header = = NULL ) {
KNI_LOG_ERROR ( logger , " Kni add cmsg to packet: serialize_header failed " ) ;
goto error_out ;
}
memcpy ( new_pkt + offset , ( void * ) header , header_len ) ;
offset + = header_len ;
KNI_LOG_DEBUG ( logger , " Kni add cmsg to packet:offset=%d,header_len=%d, tcp_data_len=%d " , offset , header_len , pktinfo - > data_len ) ;
FREE ( & header ) ;
//ipv6
return offset ;
}
static void set_new_packet_checksum ( struct pme_info * pmeinfo , struct pkt_info * pktinfo , char * new_pkt , int offset ) {
if ( pmeinfo - > addr_type = = ADDR_TYPE_IPV6 ) {
kni_ipv6_header_parse ( ( void * ) new_pkt , pktinfo ) ;
pktinfo - > iphdr . v6 - > ip6_ctlun . ip6_un1 . ip6_un1_plen = htons ( offset - sizeof ( ip6_hdr ) ) ;
@@ -712,9 +705,33 @@ static char* add_cmsg_to_packet(struct pme_info *pmeinfo, struct streaminfo *str
iphdr - > check = 0 ;
iphdr - > check = kni_ip_checksum ( ( void * ) iphdr , pktinfo - > iphdr_len ) ;
//tcphdr: checkdum
struct tcphdr * tcphdr = ( struct tcphdr * ) ( new_pkt + pktinfo - > iphdr_len ) ;
tcphdr - > check = 0 ;
tcphdr - > check = kni_tcp_checksum ( ( void * ) tcphdr , offset - pktinfo - > iphdr_len , iphdr - > saddr , iphdr - > daddr ) ;
}
}
static char * add_cmsg_to_packet ( struct pme_info * pmeinfo , struct streaminfo * stream , struct pkt_info * pktinfo , int * len ) {
//tcp option: kind 88, len 4, control_info_len
void * logger = g_kni_handle - > local_logger ;
char * new_pkt = ( char * ) ALLOC ( struct wrapped_packet , 1 ) ;
int offset = 0 ;
//iphdr
KNI_LOG_DEBUG ( logger , " Kni add cmsg to packet malloc buffer size:%d " , sizeof ( struct wrapped_packet ) ) ;
offset = rebuild_packet_to_add_tcp_option ( pmeinfo , pktinfo , new_pkt ) ;
uint16_t header_len = 0 ;
unsigned char * header = kni_cmsg_serialize_header_new ( pmeinfo , stream , pktinfo , & header_len ) ;
if ( header = = NULL ) {
KNI_LOG_ERROR ( logger , " Kni add cmsg to packet: serialize_header failed " ) ;
goto error_out ;
}
memcpy ( new_pkt + offset , ( void * ) header , header_len ) ;
offset + = header_len ;
KNI_LOG_DEBUG ( logger , " Kni add cmsg to packet:offset=%d,header_len=%d, tcp_data_len=%d " , offset , header_len , pktinfo - > data_len ) ;
FREE ( & header ) ;
//ipv6
set_new_packet_checksum ( pmeinfo , pktinfo , new_pkt , offset ) ;
* len = offset ;
return new_pkt ;
@@ -1200,19 +1217,16 @@ static void set_timestamp_depend_first_data(struct streaminfo *stream, struct pm
}
}
static int first_data _intercept( struct streaminfo * stream , struct pme_info * pmeinfo , struct pkt_info * pktinfo , int thread_seq ) {
static int is_stream_can _intercept( struct streaminfo * stream , struct pme_info * pmeinfo , struct pkt_info * pktinfo , int thread_seq ) {
FS_operate ( g_kni_fs_handle - > handle , g_kni_fs_handle - > fields [ KNI_FIELD_INTCP_READY_STM ] , 0 , FS_OP_ADD , 1 ) ;
//FS_operate(g_kni_fs_handle->handle, g_kni_fs_handle->fields[KNI_FIELD_INTCP_READY_BYTE], 0, FS_OP_ADD, pktinfo->ip_totlen);
void * logger = g_kni_handle - > local_logger ;
char * buff = NULL ;
int ret , len ;
int ret ;
//intercept_error: TCP CTEAT LINK NOT BYSYN or TCP_CREATE_LINK_MODE error
unsigned char intercept_stream_link_mode ;
int intercept_stream_link_mode_len = sizeof ( unsigned char ) ;
unsigned short stream_tunnel_type = STREAM_TUNNLE_NON ;
int stream_tunnel_type_len = sizeof ( unsigned short ) ;
int has_dup_traffic ;
int have_dup_pkt_len = sizeof ( has_dup_traffic ) ;
ret = MESA_get_stream_opt ( stream , MSO_TCP_CREATE_LINK_MODE , ( void * ) & intercept_stream_link_mode , & intercept_stream_link_mode_len ) ;
if ( ret = = 0 ) {
if ( intercept_stream_link_mode ! = TCP_CTEAT_LINK_BYSYN ) {
@@ -1228,7 +1242,6 @@ static int first_data_intercept(struct streaminfo *stream, struct pme_info *pmei
FS_operate ( g_kni_fs_handle - > handle , g_kni_fs_handle - > fields [ KNI_FIELD_INTCPERR_GET_LINK_MODE_ERR ] , 0 , FS_OP_ADD , 1 ) ;
goto error_out ;
}
ret = MESA_get_stream_opt ( stream , MSO_STREAM_TUNNEL_TYPE , ( void * ) & stream_tunnel_type , & stream_tunnel_type_len ) ;
if ( ret = = 0 ) {
if ( stream_tunnel_type ! = STREAM_TUNNLE_NON ) {
@@ -1295,6 +1308,19 @@ static int first_data_intercept(struct streaminfo *stream, struct pme_info *pmei
FS_operate ( g_kni_fs_handle - > handle , g_kni_fs_handle - > fields [ KNI_FIELD_INTCPERR_NO_TFE ] , 0 , FS_OP_ADD , 1 ) ;
goto error_out ;
}
return INTERCEPT_RET_CODE_OK ;
error_out :
return INTERCEPT_RET_CODE_FAIL ;
}
static int first_data_intercept ( struct streaminfo * stream , struct pme_info * pmeinfo , struct pkt_info * pktinfo , int thread_seq ) {
FS_operate ( g_kni_fs_handle - > handle , g_kni_fs_handle - > fields [ KNI_FIELD_INTCP_READY_STM ] , 0 , FS_OP_ADD , 1 ) ;
//FS_operate(g_kni_fs_handle->handle, g_kni_fs_handle->fields[KNI_FIELD_INTCP_READY_BYTE], 0, FS_OP_ADD, pktinfo->ip_totlen);
void * logger = g_kni_handle - > local_logger ;
char * buff = NULL ;
int ret , len ;
int has_dup_traffic ;
int have_dup_pkt_len = sizeof ( has_dup_traffic ) ;
//dup_traffic_check
if ( g_kni_handle - > dup_traffic_switch = = 1 ) {
@@ -1339,7 +1365,7 @@ static int first_data_intercept(struct streaminfo *stream, struct pme_info *pmei
{
KNI_LOG_DEBUG ( g_kni_handle - > local_logger , " Proxy-tcp-option: bypass Duplicated Packet first data, streamid = %d " , pmeinfo - > stream_traceid ) ;
FS_operate ( g_kni_fs_handle - > handle , g_kni_fs_handle - > fields [ KNI_FIELD_INTCPERR_DUP_TRAFFIC ] , 0 , FS_OP_ADD , 1 ) ;
return APP_STATE_FAWPKT | APP_STATE_KILL_FOLLOW | APP_STATE_DROPME ;
goto error_out ;
}
}
@@ -1380,7 +1406,8 @@ static int first_data_intercept(struct streaminfo *stream, struct pme_info *pmei
}
}
}
return APP_STATE_FAWPKT | APP_STATE_KILL_FOLLOW | APP_STATE_GIVEME ;
return INTERCEPT_RET_CODE_BYPASS ;
//return APP_STATE_FAWPKT | APP_STATE_KILL_FOLLOW | APP_STATE_GIVEME;
}
}
@@ -1446,13 +1473,15 @@ static int first_data_intercept(struct streaminfo *stream, struct pme_info *pmei
KNI_LOG_DEBUG ( logger , " stream has dup traffic, traceid = %s " , pmeinfo - > stream_traceid ) ;
}
FREE ( & buff ) ;
return APP_STATE_DROPPKT | APP_STATE_KILL_FOLLOW | APP_STATE_GIVEME ;
return INTERCEPT_RET_CODE_OK ;
//return APP_STATE_DROPPKT | APP_STATE_KILL_FOLLOW | APP_STATE_GIVEME;
error_out :
if ( buff ! = NULL ) {
FREE ( & buff ) ;
}
return APP_STATE_FAWPKT | APP_STATE_KILL_FOLLOW | APP_STATE_DROPME ;
return INTERCEPT_RET_CODE_FAIL ;
//return APP_STATE_FAWPKT | APP_STATE_KILL_FOLLOW | APP_STATE_DROPME;
}
static int dabloom_search ( struct pkt_info * pktinfo , int thread_seq ) {
@@ -1503,6 +1532,7 @@ char* kni_maat_action_trans(enum kni_action action){
char next_data_intercept ( struct pme_info * pmeinfo , const void * a_packet , struct pkt_info * pktinfo , int thread_seq ) {
//return value 0
//FS_operate(g_kni_fs_handle->handle, g_kni_fs_handle->fields[KNI_FIELD_INTCP_READY_BYTE], 0, FS_OP_ADD, pktinfo->ip_totlen);
int ret , len ;
void * logger = g_kni_handle - > local_logger ;
@@ -1510,7 +1540,8 @@ char next_data_intercept(struct pme_info *pmeinfo, const void *a_packet, struct
struct ip6_hdr * ipv6_hdr = NULL ;
if ( pktinfo - > parse_failed = = 1 ) {
KNI_LOG_ERROR ( logger , " next_data_intercept: invalid ip header, drop pkt and not send to tfe " ) ;
return APP_STATE_DROPPKT | APP_STATE_KILL_FOLLOW | APP_STATE_GIVEME ;
return INTERCEPT_RET_CODE_OK ;
//return APP_STATE_DROPPKT | APP_STATE_KILL_FOLLOW | APP_STATE_GIVEME;
}
//search dabloom
if ( g_kni_handle - > dup_traffic_switch = = 1 ) {
@@ -1519,12 +1550,14 @@ char next_data_intercept(struct pme_info *pmeinfo, const void *a_packet, struct
if ( g_kni_handle - > pxy_tcp_option_enable = = 1 )
{
if ( pmeinfo - > pxy_tcp_option . bypass_duplicated_packet = = 1 ) { //Bypass Duplicated Packet
return APP_STATE_FAWPKT | APP_STATE_KILL_FOLLOW | APP_STATE_GIVEME ;
return INTERCEPT_RET_CODE_BYPASS ;
//return APP_STATE_FAWPKT | APP_STATE_KILL_FOLLOW | APP_STATE_GIVEME;
}
}
ret = dabloom_search ( pktinfo , thread_seq ) ;
if ( ret = = 1 ) {
return APP_STATE_FAWPKT | APP_STATE_KILL_FOLLOW | APP_STATE_GIVEME ;
return INTERCEPT_RET_CODE_BYPASS ;
//return APP_STATE_FAWPKT | APP_STATE_KILL_FOLLOW | APP_STATE_GIVEME;
}
}
}
@@ -1539,12 +1572,14 @@ char next_data_intercept(struct pme_info *pmeinfo, const void *a_packet, struct
if ( pktinfo - > ip_totlen > KNI_DEFAULT_MTU ) {
KNI_LOG_DEBUG ( logger , " Next data packet exceed MTU(1500), stream traceid = %s, stream addr = %s " ,
pmeinfo - > stream_traceid , pmeinfo - > stream_addr ) ;
return APP_STATE_DROPPKT | APP_STATE_KILL_FOLLOW | APP_STATE_GIVEME ;
return INTERCEPT_RET_CODE_OK ;
//return APP_STATE_DROPPKT | APP_STATE_KILL_FOLLOW | APP_STATE_GIVEME;
}
if ( g_kni_handle - > ssl_dynamic_bypass_enable = = 1 ) {
if ( pmeinfo - > is_dynamic_bypass ) {
next_data_ssl_dynamic_bypass ( pktinfo ) ;
return APP_STATE_FAWPKT | APP_STATE_KILL_FOLLOW | APP_STATE_GIVEME ;
return INTERCEPT_RET_CODE_BYPASS ;
//return APP_STATE_FAWPKT | APP_STATE_KILL_FOLLOW | APP_STATE_GIVEME;
}
}
@@ -1554,19 +1589,25 @@ char next_data_intercept(struct pme_info *pmeinfo, const void *a_packet, struct
pmeinfo - > tfe_id , pmeinfo - > stream_traceid , pmeinfo - > stream_addr ) ;
FS_operate ( g_kni_fs_handle - > handle , g_kni_fs_handle - > fields [ KNI_FIELD_INTCPERR_SENDTO_TFE_FAIL ] , 0 , FS_OP_ADD , 1 ) ;
}
KNI_LOG_INFO ( logger , " Success at send continue packet to tfe%d, stream traceid = %s, stream addr = %s " ,
pmeinfo - > tfe_id , pmeinfo - > stream_traceid , pmeinfo - > stream_addr ) ;
//else{
// FS_operate(g_kni_fs_handle->handle, g_kni_fs_handle->fields[KNI_FIELD_INTCP_BYTE], 0, FS_OP_ADD, pktinfo->ip_totlen);
//}
return APP_STATE_DROPPKT | APP_STATE_KILL_FOLLOW | APP_STATE_GIVEME ;
return INTERCEPT_RET_CODE_OK ;
//return APP_STATE_DROPPKT | APP_STATE_KILL_FOLLOW | APP_STATE_GIVEME;
}
char first_data_process ( struct streaminfo * stream , struct pme_info * pmeinfo , struct pkt_info * pktinfo , int thread_seq ) {
//first data packet, get action
void read_stream_intercept_status ( struct streaminfo * stream , struct pme_info * pmeinfo , int thread_seq )
{
void * logger = g_kni_handle - > local_logger ;
int maat_hit = 0 ;
int ret = 0 ;
struct identify_info _identify_info ;
ret = tsg_pull_policy_result ( stream , PULL_KNI_RESULT , & ( pmeinfo - > maat_result ) , 1 , & _identify_info ) ;
pmeinfo - > check_data_packets_num + + ;
//ret == 0, bypass and dropme
if ( ret = = 0 ) {
pmeinfo - > action = KNI_ACTION_NONE ;
@@ -1590,25 +1631,89 @@ char first_data_process(struct streaminfo *stream, struct pme_info *pmeinfo, str
KNI_LOG_INFO ( logger , " intercept_policy_scan: %s, %s, maat_hit = %d, policy_id = %d, action = %d(%s), stream traceid = %s " ,
pmeinfo - > stream_addr , ( char * ) & ( pmeinfo - > domain ) , maat_hit , pmeinfo - > policy_id , pmeinfo - > action , action_str , pmeinfo - > stream_traceid ) ;
}
switch ( pmeinfo - > action ) {
case KNI_ACTION_INTERCEPT :
pmeinfo - > ssl_intercept_state = 1 ;
//only action = intercept, need sendlog
pmeinfo - > tld_handle = TLD_create ( - 1 ) ;
if ( g_kni_handle - > pxy_tcp_option_enable = = 1 )
{
KNI_LOG_DEBUG ( logger , " Proxy-tcp-option: before scan status:%d ( 1 is has been scanned, other value not scan),stream traceid = %s " , pmeinfo - > pxy_tcp_option_is_scan , pmeinfo - > stream_traceid ) ;
if ( pmeinfo - > pxy_tcp_option_is_scan ! = 1 )
{
pxy_tcp_option_get_param ( g_tsg_maat_feather , ( const struct streaminfo * ) stream , pmeinfo , logger ) ;
pmeinfo - > pxy_tcp_option_is_scan = 1 ;
}
char deal_chello_frag ( struct streaminfo * stream , struct pme_info * pmeinfo , int thread_seq )
{
void * logger = g_kni_handle - > local_logger ;
int ret = 0 ;
struct ssl_frag_chello * ssl_frag_chell_0 = ssl_frag_chello_get0 ( stream ) ;
if ( ssl_frag_chell_0 - > p_sz > 0 ) {
for ( int i = 0 ; i < ( int ) ssl_frag_chell_0 - > p_sz ; i + + ) {
struct detain_pkt * packet = ssl_frag_chell_0 - > p [ i ] ;
int len_rawpkt ;
void * rawpkt = ( void * ) MESA_detain_rawpkt_data_get0 ( stream , packet , & len_rawpkt ) ;
struct pkt_info rawpkt_info ;
memset ( & rawpkt_info , 0 , sizeof ( rawpkt_info ) ) ;
wrapped_kni_header_parse ( rawpkt , pmeinfo , & rawpkt_info ) ;
KNI_LOG_DEBUG ( logger , " Deal chello frags list[%d], stream traceid: %s, seq: %u, tcp_data_len: %d " , i , pmeinfo - > stream_traceid , ntohl ( rawpkt_info . tcphdr - > seq ) , rawpkt_info . data_len ) ;
if ( i = = 0 ) {
ret = first_data_intercept ( stream , pmeinfo , & rawpkt_info , thread_seq ) ;
// usleep(5000);
if ( ret = = INTERCEPT_RET_CODE_FAIL ) {
break ;
}
} else {
char * new_pkt = ( char * ) ALLOC ( struct wrapped_packet , 1 ) ;
int offset = 0 ;
offset = rebuild_packet_to_add_tcp_option ( pmeinfo , & rawpkt_info , new_pkt ) ;
set_new_packet_checksum ( pmeinfo , & rawpkt_info , new_pkt , offset ) ;
ret = next_data_intercept ( pmeinfo , ( void * ) new_pkt , & rawpkt_info , thread_seq ) ;
free ( new_pkt ) ;
}
return first_data_intercept ( stream , pmeinfo , pktinfo , thread_seq ) ;
default :
//action != intercept, bypass and dropme
return APP_STATE_FAWPKT | APP_STATE_DROPME ;
}
}
ssl_frag_chello_free ( stream ) ;
return ret ;
}
char first_data_process ( struct streaminfo * stream , struct pme_info * pmeinfo , const void * a_packet , struct pkt_info * pktinfo , int thread_seq ) {
//first data packet, get action
void * logger = g_kni_handle - > local_logger ;
read_stream_intercept_status ( stream , pmeinfo , thread_seq ) ;
if ( pmeinfo - > check_data_packets_num = = 1 )
{
int ret = is_stream_can_intercept ( stream , pmeinfo , pktinfo , thread_seq ) ;
if ( ret = = INTERCEPT_RET_CODE_FAIL ) {
return INTERCEPT_RET_CODE_FAIL ;
}
}
if ( pmeinfo - > action ! = KNI_ACTION_INTERCEPT & & pmeinfo - > check_data_packets_num < g_kni_handle - > reassembled_packets_num )
return INTERCEPT_RET_CODE_NEED_NEXT ;
if ( pmeinfo - > action = = KNI_ACTION_INTERCEPT ) {
pmeinfo - > ssl_intercept_state = 1 ;
//only action = intercept, need sendlog
pmeinfo - > tld_handle = TLD_create ( - 1 ) ;
if ( g_kni_handle - > pxy_tcp_option_enable = = 1 )
{
KNI_LOG_DEBUG ( logger , " Proxy-tcp-option: before scan status:%d ( 1 is has been scanned, other value not scan),stream traceid = %s " , pmeinfo - > pxy_tcp_option_is_scan , pmeinfo - > stream_traceid ) ;
if ( pmeinfo - > pxy_tcp_option_is_scan ! = 1 )
{
pxy_tcp_option_get_param ( g_tsg_maat_feather , ( const struct streaminfo * ) stream , pmeinfo , logger ) ;
pmeinfo - > pxy_tcp_option_is_scan = 1 ;
}
}
struct ssl_frag_chello * ssl_frag_chell_0 = ssl_frag_chello_get0 ( stream ) ;
if ( ssl_frag_chell_0 & & ssl_frag_chell_0 - > p_sz > 0 )
{
KNI_LOG_DEBUG ( logger , " ssl_frag chello: packet num: %d, stream traceid = %s, data packet number: %d " , ssl_frag_chell_0 - > p_sz , pmeinfo - > stream_traceid , pmeinfo - > check_data_packets_num ) ;
return deal_chello_frag ( stream , pmeinfo , thread_seq ) ;
// ret = next_data_intercept(pmeinfo, a_packet, pktinfo, thread_seq);
}
else {
return first_data_intercept ( stream , pmeinfo , pktinfo , thread_seq ) ;
}
}
return APP_STATE_FAWPKT | APP_STATE_DROPME ;
}
void dup_traffic_detect ( struct pme_info * pmeinfo , struct pkt_info * pktinfo ) {
@@ -1679,7 +1784,7 @@ static char data_opstate(struct streaminfo *stream, struct pme_info *pmeinfo, co
}
//first data
if ( stream - > ptcpdetail - > datalen > 0 ) {
return first_data_process ( stream , pmeinfo , & pktinfo , thread_seq ) ;
return first_data_process ( stream , pmeinfo , a_packet , & pktinfo , thread_seq ) ;
}
//before first data, may be dup_syn, syn/ack, dup_syn/ack
if ( pktinfo . parse_failed ! = 0 ) {
@@ -2504,6 +2609,7 @@ extern "C" int kni_init(){
printf ( " MESA_prof_load: log_level not set, profile = %s, section = %s " , profile , section ) ;
goto error_out ;
}
local_logger = MESA_create_runtime_log_handle ( log_path , log_level ) ;
if ( unlikely ( local_logger = = NULL ) ) {
printf ( " Failed at create logger: %s " , log_path ) ;
@@ -2514,7 +2620,7 @@ extern "C" int kni_init(){
//kni_git_log
KNI_LOG_ERROR ( local_logger , " ----------kni version = %s----------- " , kni_git_verison ) ;
MESA_load_profile_int_def ( profile , section , " reassembled_packets_num " , & ( g_kni_handle - > reassembled_packets_num ) , 2 ) ;
char deploy_mode [ KNI_SYMBOL_MAX ] ;
ret = MESA_load_profile_string_def ( profile , section , " deploy_mode " , deploy_mode , sizeof ( deploy_mode ) , " normal " ) ;
g_kni_handle - > deploy_mode = KNI_DEPLOY_MODE_NORMAL ;
@@ -2707,6 +2813,7 @@ extern "C" int kni_init(){
FREE ( & cmsg_receiver_args ) ;
goto error_out ;
}
return 0 ;
error_out :