#include "common.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define MAXSTRLEN (1024) static void common_Log(FILE *pLog, const char *csFmtStr, va_list va_args); static void common_DoExit(int iExitCode); static void common_SigpipeHandle(int x); /*function to wait for a specific FILE to be ready for reading*/ ERROR_STATUS COMMON_ReadWaitFile(FILE *phF) { int iFDNum=fileno(phF); return COMMON_ReadWaitFD(iFDNum); } /*function to wait for a specific File Descriptor (file, socket, pipe) to be ready for reading*/ ERROR_STATUS COMMON_ReadWaitFD(int iFD) { int iStatus; fd_set fds_r,fds_w,fds_ex; FD_ZERO(&fds_r); FD_ZERO(&fds_w); FD_ZERO(&fds_ex); FD_SET(iFD,&fds_r); iStatus=select(iFD+1,&fds_r,&fds_w,&fds_ex,NULL); if(iStatus>0) { /*more one file ready (i.e. should only be one)*/ iStatus=SUCCESS; } else { /*something gone wrond or we are interrupted*/ iStatus=ERROR_INTERRUPT; } return iStatus; } // Function to read a proxy list from file and populate array of proxies // Each proxy should be a separate line containing the url only // e.g.: //127.0.0.1:8423 //127.0.0.1:8424 //127.0.0.1:4433 ERROR_STATUS COMMON_ReadProxyListFile(SSL *ptSSL, const char *sFilename){ FILE *phF; // pointer to file unsigned int uiCount = 0; // simple counters char acLine [128]; // maximum size of line to read from SPP_PROXY *patNewProxiesList=NULL; if(ptSSL==NULL || sFilename==NULL) { return INVALID_POINTER; } // Open file for reading phF = fopen(sFilename,"r"); // Check for errors while opening file if( phF == NULL ){ return FILE_NOT_READABLE; } uiCount=0; // Read file line-by-line while ( fgets ( acLine, sizeof(acLine), phF ) != NULL ) { // Remove trailing newline (NOTE: strtoK is not thread safe) strtok(acLine, "\n"); if(strlen(acLine)<=2) continue; //ignore blank lines COMMON_AppendProxy(ptSSL,acLine); /*TODO - log the proxy creation properly*/ COMMON_Log(stdout,"Proxy(%2u): %s\n",uiCount,acLine); } // Close file fclose(phF); return SUCCESS; } ERROR_STATUS COMMON_InitProxySet(SSL *ptSSL) { while(ptSSL->proxies_len>0) { ptSSL->proxies_len--; OPENSSL_free(ptSSL->proxies[ptSSL->proxies_len]); } ptSSL->proxies_len=0; memset(ptSSL->proxies,0,sizeof(ptSSL->proxies)); return SUCCESS; } ERROR_STATUS COMMON_InitMulticontextSet(SSL *ptSSL) { while(ptSSL->slices_len>0) { ptSSL->slices_len--; OPENSSL_free(ptSSL->slices[ptSSL->slices_len]); } ptSSL->slices_len=0; memset(ptSSL->slices,0,sizeof(ptSSL->slices)); return SUCCESS; } ERROR_STATUS COMMON_AppendProxy(SSL *ptSSL, const char *psProxyURL) { char *psProxyUrlCpy=NULL; if(ptSSL->proxies_len>=(sizeof(ptSSL->proxies)/sizeof(ptSSL->proxies[0]))) return ARRAY_OVERFLOW; /*SPP_generate_proxy will generate something with the string provide * but there is no guarantee that it will be sensible if * invalid data is passed in*/ psProxyUrlCpy=strdup(psProxyURL); ptSSL->proxies[ptSSL->proxies_len] = SPP_generate_proxy(ptSSL, psProxyUrlCpy); (ptSSL->proxies_len)++; return SUCCESS; } ERROR_STATUS COMMON_SetServer(SSL *ptSSL, const char *psURL) { char *psUrlCpy=NULL; psUrlCpy=strdup(psURL); ptSSL->spp_server_address = psUrlCpy; return SUCCESS; } ERROR_STATUS COMMON_AppendContext(SSL *ptSSL, const char *psContextDesc) { char *psContextDescCpy=NULL; if(ptSSL->slices_len>=(sizeof(ptSSL->slices)/sizeof(ptSSL->slices[0]))) return ARRAY_OVERFLOW; psContextDescCpy=strdup(psContextDesc); ptSSL->slices[ptSSL->slices_len] = SPP_generate_slice(ptSSL, psContextDescCpy); ptSSL->slices_len++; return SUCCESS; } ERROR_STATUS COMMON_SetProxyAccessPermissionByID(SSL *ptSSL, int iSliceID, int iMiddleboxNum, int bGrantRead, int bGrantWrite) { int *read_slices; size_t *read_slice_len; int *write_slices; size_t *write_slice_len; int reads_insert_index, write_insert_index; int x,y,z; if(ptSSL->proxies_len<=iMiddleboxNum) return ARRAY_OVERFLOW; read_slices=ptSSL->proxies[iMiddleboxNum]->read_slice_ids; read_slice_len=&(ptSSL->proxies[iMiddleboxNum]->read_slice_ids_len); write_slices=ptSSL->proxies[iMiddleboxNum]->write_slice_ids; write_slice_len=&(ptSSL->proxies[iMiddleboxNum]->write_slice_ids_len); /*handle empty case specially*/ if(*read_slice_len==0 && bGrantRead) { read_slices[0]=iSliceID; (*read_slice_len)++; } if(*write_slice_len==0 && bGrantWrite) { write_slices[0]=iSliceID; (*write_slice_len)++; } /*if we have just inserted the first record, this loop will * terminate on first iteration*/ x=0;y=*read_slice_len; while(y>x+1) { z=(x+y)/2; if(read_slices[z]>iSliceID) y=z; else x=z; } if(bGrantRead) { if(read_slices[x]!=iSliceID) { if(*read_slice_len>y) { /*we have higher number slices to move up*/ memmove(&read_slices[x+1],&read_slices[x],(*read_slice_len-y)*sizeof(*read_slices)); } read_slices[x+1]=iSliceID; (*read_slice_len)++; } /*else we are re-granted an already granted access - NOP*/ } else { /*we are removing the permission if it is granted*/ if(read_slices[x]==iSliceID) { if(*read_slice_len>y) { /*we have higher number slices to move up*/ memmove(&read_slices[x],&read_slices[x+1],(*read_slice_len-y)*sizeof(*read_slices)); } (*read_slice_len)--; } /*else we removing a non-existent permission - NOP*/ } x=0;y=*write_slice_len; while(y>x+1) { z=(x+y)/2; if(write_slices[z]>iSliceID) y=z; else x=z; } if(bGrantWrite) { if(write_slices[x]!=iSliceID) { if(*write_slice_len>y) { /*we have higher number slices to move up*/ memmove(&write_slices[x+1],&write_slices[x],(*write_slice_len-y)*sizeof(*write_slices)); } write_slices[x+1]=iSliceID; (*write_slice_len)++; } /*else we are re-granted an already granted access - NOP*/ } else { /*we are removing the permission if it is granted*/ if(write_slices[x]==iSliceID) { if(*write_slice_len>y) { /*we have higher number slices to move up*/ memmove(&write_slices[x],&write_slices[x+1],(*write_slice_len-y)*sizeof(*write_slices)); } (*write_slice_len)--; } /*else we removing a non-existent permission - NOP*/ } return SUCCESS; } ERROR_STATUS COMMON_TcpConnect(int *piSocket, const char *sHost, int iPort){ struct hostent *hp; struct sockaddr_in addr; int iOne=1; // Resolve host if(!(hp = gethostbyname(sHost))) return NETWORK_CONNECT_FAIL; memset(&addr, 0, sizeof(addr)); addr.sin_addr = *(struct in_addr*) hp->h_addr_list[0]; addr.sin_family = AF_INET; addr.sin_port = htons(iPort); if((*piSocket=socket(AF_INET,SOCK_STREAM, IPPROTO_TCP))<0){ return NETWORK_CONNECT_FAIL; } /*I'm copying this option below*/ //set_nagle(*piSocket, 1); setsockopt(*piSocket, IPPROTO_TCP, TCP_NODELAY, (char*)&iOne, sizeof(int)); if(connect(*piSocket,(struct sockaddr *)&addr, sizeof(addr))<0){ return NETWORK_CONNECT_FAIL; } return SUCCESS; } void COMMON_LogErrorAndExit(int iExitCode, FILE *pLog, const char *csFmtStr, ...) { va_list va_args; va_start(va_args,csFmtStr); common_Log(pLog, csFmtStr,va_args); va_end(va_args); common_DoExit(iExitCode); } void COMMON_CheckLogErrorAndExit(int iExitCode, FILE *pLog, const char *csFmtStr, ...) { va_list va_args; if(iExitCode!=0) { va_start(va_args,csFmtStr); common_Log(pLog, csFmtStr,va_args); va_end(va_args); common_DoExit(iExitCode); } } void COMMON_Log(FILE *pLog, const char *csFmtStr, ...) { va_list va_args; va_start(va_args,csFmtStr); common_Log(pLog, csFmtStr,va_args); va_end(va_args); } void COMMON_CheckLog(int iExitCode, FILE *pLog, const char *csFmtStr, ...) { va_list va_args; if(iExitCode!=0) { va_start(va_args,csFmtStr); common_Log(pLog, csFmtStr,va_args); va_end(va_args); } } char *gsPassword=NULL; static int password_cb(char *buf,int num, int rwflag,void *userdata) { if(gsPassword==NULL) return 0; if(num=ID_MIDDLEBOX_MIN && iID<=ID_MIDDLEBOX_MAX) { meth = SPP_proxy_method(); } else { return INTEGER_OUT_OF_RANGE; } ctx = SSL_CTX_new(meth); /* Specify the cipher suites that may be used. */ if (!SSL_CTX_set_cipher_list(ctx, "DHE-RSA-AES128-SHA256")) { return ERROR_IN_LIBRARY_CALL; } /* Load the CAs*/ if(!(SSL_CTX_load_verify_locations(ctx, sCAKeysFile,NULL))) return FILE_NOT_READABLE; /* Load our certificate*/ if(!(SSL_CTX_use_certificate_chain_file(ctx, sMyKeyfile))) return FILE_NOT_READABLE; /*set the routine to handle passing in the passowrd for our private key*/ if(gsPassword!=NULL) { free(gsPassword); gsPassword=NULL; } if(sMyPassword!=NULL){ gsPassword=strdup(sMyPassword); } SSL_CTX_set_default_passwd_cb(ctx, password_cb); /*load our private key*/ if(!(SSL_CTX_use_PrivateKey_file(ctx, sMyKeyfile,SSL_FILETYPE_PEM))) return FILE_NOT_READABLE; *pptCtx=ctx; return SUCCESS; } void COMMON_DestroyCtx(SSL_CTX *ptCtx) { if(gsPassword!=NULL) { free(gsPassword); gsPassword=NULL; SSL_CTX_free(ptCtx); } } static void common_Log(FILE *pLog, const char *csFmtStr, va_list va_args) { assert(pLog!=NULL); assert(csFmtStr!=NULL); assert(strnlen(csFmtStr,MAXSTRLEN)