Mixe for Privacy and Anonymity in the Internet
Public Member Functions | Protected Attributes | Private Member Functions | Private Attributes | Friends
CAMiddleMix Class Reference

#include <CAMiddleMix.hpp>

Inheritance diagram for CAMiddleMix:
[legend]
Collaboration diagram for CAMiddleMix:
[legend]

List of all members.

Public Member Functions

 CAMiddleMix ()
virtual ~CAMiddleMix ()
tMixType getType () const

Protected Attributes

CAQueuem_pQueueSendToMixBefore
CAQueuem_pQueueSendToMixAfter
UINT32 m_u32KeepAliveRecvInterval2
UINT32 m_u32KeepAliveSendInterval2

Private Member Functions

SINT32 loop ()
 Processes Upstream-MixPackets.
SINT32 init ()
SINT32 initOnce ()
SINT32 clean ()
SINT32 connectToNextMix (CASocketAddr *a_pAddrNext)
virtual SINT32 initMixCascadeInfo (DOMElement *&)
 This method is not applicable to middle mixes; it does nothing.
virtual SINT32 processKeyExchange ()
 Processes key exchange with Mix n+1 and Mix n-1.

Private Attributes

CAMuxSocketm_pMuxIn
CAMuxSocketm_pMuxOut
CAASymCipherm_pRSA
volatile bool m_bRun
CAMiddleMixChannelListm_pMiddleMixChannelList

Friends

THREAD_RETURN mm_loopSendToMixBefore (void *)
 DOWNSTREAM (to Client) Take the packets from the Queue and write them to the Socket.
THREAD_RETURN mm_loopSendToMixAfter (void *)
 UPSTREAM (to WEB) Take the packets from the Queue and write them to the Socket.
THREAD_RETURN mm_loopReadFromMixBefore (void *)
THREAD_RETURN mm_loopReadFromMixAfter (void *)
THREAD_RETURN mm_loopDownStream (void *)

Detailed Description

Definition at line 39 of file CAMiddleMix.hpp.


Constructor & Destructor Documentation

Definition at line 47 of file CAMiddleMix.hpp.

References CAMix::m_pInfoService, m_pMiddleMixChannelList, CAMix::m_pMultiSignature, m_pMuxIn, m_pMuxOut, m_pQueueSendToMixAfter, m_pQueueSendToMixBefore, and m_pRSA.

        {
          m_pMiddleMixChannelList=NULL;
          m_pMuxOut=NULL;m_pMuxIn=NULL;m_pRSA=NULL;
          //m_pSignature=NULL;
          m_pMultiSignature=NULL;
          m_pInfoService=NULL;
          m_pQueueSendToMixBefore=m_pQueueSendToMixAfter=NULL;
#ifdef DYNAMIC_MIX
          m_bBreakNeeded = false;
#endif
        }
virtual CAMiddleMix::~CAMiddleMix ( ) [inline, virtual]

Definition at line 59 of file CAMiddleMix.hpp.

References clean().

{clean();};

Here is the call graph for this function:


Member Function Documentation

SINT32 CAMiddleMix::clean ( ) [private, virtual]

Implements CAMix.

Definition at line 1296 of file CAMiddleMix.cpp.

References CAMuxSocket::close(), E_SUCCESS, m_pMiddleMixChannelList, m_pMuxIn, m_pMuxOut, m_pQueueSendToMixAfter, m_pQueueSendToMixBefore, CAMixWithReplayDB::m_pReplayMsgProc, and m_pRSA.

Referenced by ~CAMiddleMix().

{
    delete m_pQueueSendToMixBefore;
    m_pQueueSendToMixBefore=NULL;

    delete m_pQueueSendToMixAfter;
    m_pQueueSendToMixAfter=NULL;

#ifdef REPLAY_DETECTION
    delete m_pReplayMsgProc;
    m_pReplayMsgProc=NULL;
#endif
    if(m_pMuxIn!=NULL)
    {
      m_pMuxIn->close();
      delete m_pMuxIn;
      m_pMuxIn=NULL;
    }

    if(m_pMuxOut!=NULL)
    {
      m_pMuxOut->close();
      delete m_pMuxOut;
      m_pMuxOut=NULL;
    }

    delete m_pRSA;
    m_pRSA=NULL;

    delete m_pMiddleMixChannelList;
    m_pMiddleMixChannelList=NULL;
    return E_SUCCESS;
  }

Here is the call graph for this function:

SINT32 CAMiddleMix::connectToNextMix ( CASocketAddr a_pAddrNext) [private]

Definition at line 1198 of file CAMiddleMix.cpp.

References CAMuxSocket::connect(), E_SUCCESS, E_UNKNOWN, ERR_INTERN_CONNREFUSED, ERR_INTERN_TIMEDOUT, GET_NET_ERROR, GET_NET_ERROR_STR, m_pMuxOut, CAMsg::printMsg(), RETRIES, RETRYTIME, sSleep(), and CASocketAddr::toString().

Referenced by init().

{
#define RETRIES 100
#define RETRYTIME 10
    UINT8 buff[255];
    a_pAddrNext->toString(buff,255);
    CAMsg::printMsg(LOG_INFO,"Try to connect to next Mix on %s ...\n",buff);
    UINT32 i = 0;
    SINT32 err = E_UNKNOWN;
    SINT32 errLast = E_SUCCESS;
    for(i=0; i < RETRIES; i++)
    {
#ifdef DYNAMIC_MIX

      if(m_bBreakNeeded != m_bReconfigured)
      {
        CAMsg::printMsg(LOG_DEBUG, "CAMiddleMix::connectToNextMix - Broken the connect loop!\n");
        break;
      }
#endif
      err = m_pMuxOut->connect(*a_pAddrNext);
      if(err != E_SUCCESS)
      {
        err=GET_NET_ERROR;
#ifdef _DEBUG
        CAMsg::printMsg(LOG_DEBUG,"Con-Error: %i\n",err);
#endif
        if(err!=ERR_INTERN_TIMEDOUT&&err!=ERR_INTERN_CONNREFUSED)
        {
          CAMsg::printMsg(LOG_ERR, "Cannot connect to next Mix on %s. Reason: %s (%i)\n",
            buff, GET_NET_ERROR_STR(err), err);
          break;
        }
          
        if (errLast != err || i % 10 == 0)
        {
          CAMsg::printMsg(LOG_ERR, "Cannot connect to next Mix on %s. Reason: %s (%i). Retrying...\n",
            buff, GET_NET_ERROR_STR(err), err);
          errLast = err;
        }
        else
        {
  #ifdef _DEBUG
          CAMsg::printMsg(LOG_DEBUG,"Cannot connect... retrying\n");
  #endif
        }         
        sSleep(RETRYTIME);
      }
      else
      {
        break;
      }
    }
    return err;
}

Here is the call graph for this function:

tMixType CAMiddleMix::getType ( ) const [inline, virtual]

Implements CAMix.

Definition at line 60 of file CAMiddleMix.hpp.

References CAMix::MIDDLE_MIX.

        {
          return CAMix::MIDDLE_MIX;
        }
SINT32 CAMiddleMix::init ( ) [private, virtual]

Connect to next mix

Implements CAMix.

Definition at line 599 of file CAMiddleMix.cpp.

References CAMuxSocket::accept(), CATargetInterface::cleanAddr(), connectToNextMix(), CASocket::create(), E_SUCCESS, E_UNKNOWN, ev_net_nextConnected, ev_net_prevConnected, ev_net_prevConnectionClosed, CAASymCipher::generateKeyPair(), CAListenerInterface::getAddr(), CATargetInterface::getAddr(), CAMuxSocket::getCASocket(), CACmdLnOptions::getListenerInterface(), CACmdLnOptions::getListenerInterfaceCount(), CALibProxytest::getOptions(), CACmdLnOptions::getTargetInterface(), CACmdLnOptions::getTargetInterfaceCount(), CATargetInterface::getTargetType(), CASocketAddr::getType(), CAListenerInterface::isVirtual(), m_pMiddleMixChannelList, m_pMuxIn, CAMix::m_pMuxInControlChannelDispatcher, m_pMuxOut, m_pQueueSendToMixAfter, m_pQueueSendToMixBefore, CAMixWithReplayDB::m_pReplayDB, CAMixWithReplayDB::m_pReplayMsgProc, m_pRSA, CAMixWithReplayDB::m_u64ReferenceTime, MIXPACKET_SIZE, MONITORING_FIRE_NET_EVENT, CAMsg::printMsg(), processKeyExchange(), readFile(), REPLAY_TIMESTAMP_PROPAGATION_INTERVALL, saveFile(), CASocket::setKeepAlive(), CASocket::setRecvBuff(), CASocket::setSendBuff(), CADatabase::start(), CAReplayCtrlChannelMsgProc::startTimeStampPorpagation(), TARGET_MIX, and CASocketAddr::toString().

  {
#ifdef DYNAMIC_MIX
    m_bBreakNeeded = m_bReconfigured;
#endif

    CAMsg::printMsg(LOG_INFO,"Creating Key...\n");
    m_pRSA=new CAASymCipher();
#ifdef EXPORT_ASYM_PRIVATE_KEY
    if(CALibProxytest::getOptions()->isImportKey())
      {
        UINT32 keyFileBuffLen=8096;
        UINT8* keyFileBuff=new UINT8[keyFileBuffLen];
        CALibProxytest::getOptions()->getEncryptionKeyImportFile(keyFileBuff,keyFileBuffLen);
        UINT8* keyBuff=readFile(keyFileBuff,&keyFileBuffLen);
        m_pRSA->setPrivateKeyAsXML(keyBuff,keyFileBuffLen);
        delete[] keyFileBuff;
        delete[] keyBuff;
      }
    else
#endif
      {
        if(m_pRSA->generateKeyPair(1024)!=E_SUCCESS)
          {
            CAMsg::printMsg(LOG_CRIT,"Could not generate a valid key pair\n");
            return E_UNKNOWN;
          }
      }
#ifdef EXPORT_ASYM_PRIVATE_KEY
    if(CALibProxytest::getOptions()->isExportKey())
      {
        UINT32 keyFileBuffLen=8096;
        UINT8* keyFileBuff=new UINT8[keyFileBuffLen];
        UINT8* keyBuff=new UINT8[keyFileBuffLen];
        CALibProxytest::getOptions()->getEncryptionKeyExportFile(keyFileBuff,keyFileBuffLen);
        m_pRSA->getPrivateKeyAsXML(keyBuff,&keyFileBuffLen);
        saveFile(keyFileBuff,keyBuff,keyFileBuffLen);
        delete[] keyFileBuff;
        delete[] keyBuff;
      }
#endif

    // connect to next mix
    CASocketAddr* pAddrNext=NULL;
    for(UINT32 i=0;i<CALibProxytest::getOptions()->getTargetInterfaceCount();i++)
      {
        CATargetInterface oNextMix;
        CALibProxytest::getOptions()->getTargetInterface(oNextMix,i+1);
        if(oNextMix.getTargetType()==TARGET_MIX)
          {
            pAddrNext=oNextMix.getAddr();
            break;
          }
        oNextMix.cleanAddr();
      }
    if(pAddrNext==NULL)
      {
        CAMsg::printMsg(LOG_CRIT,"No next Mix specified!\n");
        return E_UNKNOWN;
      }

    m_pMuxOut=new CAMuxSocket();

    if(m_pMuxOut->getCASocket()->create(pAddrNext->getType())!=E_SUCCESS)
      {
        CAMsg::printMsg(LOG_CRIT,"Init: Cannot create SOCKET for outgoing connection...\n");
        return E_UNKNOWN;
      }
    m_pMuxOut->getCASocket()->setRecvBuff(50*MIXPACKET_SIZE);
    m_pMuxOut->getCASocket()->setSendBuff(50*MIXPACKET_SIZE);


    CAListenerInterface* pListener=NULL;
    UINT32 interfaces=CALibProxytest::getOptions()->getListenerInterfaceCount();
    for(UINT32 i=1;i<=interfaces;i++)
      {
        pListener=CALibProxytest::getOptions()->getListenerInterface(i);
        if(!pListener->isVirtual())
          break;
        delete pListener;
        pListener=NULL;
      }
    if(pListener==NULL)
      {
        CAMsg::printMsg(LOG_CRIT,"Failed to initialize socket for previous mix! Reason: no usable (non virtual) listener interface found!\n");
        return E_UNKNOWN;
      }
    const CASocketAddr* pAddr=NULL;
    pAddr=pListener->getAddr();
    delete pListener;
    pListener = NULL;

    UINT8 buff[255];
    pAddr->toString(buff,255);
    CAMsg::printMsg(LOG_INFO,"Waiting for connection from previous Mix on %s...\n", buff);

    m_pMuxIn=new CAMuxSocket();
#ifdef DYNAMIC_MIX
    // LERNGRUPPE Do not block if we are currently reconfiguring
    if(m_bBreakNeeded != m_bReconfigured)
    {
      return E_UNKNOWN;
    }
#endif
    SINT32 ret=m_pMuxIn->accept(*pAddr);
    delete pAddr;
    pAddr = NULL;
    if(ret!=E_SUCCESS)
      {
        CAMsg::printMsg(LOG_CRIT,"Error waiting for previous Mix... -- restart!\n");
        return E_UNKNOWN;
      }
    CAMsg::printMsg(LOG_INFO," connected!\n");
    MONITORING_FIRE_NET_EVENT(ev_net_prevConnected);

    m_pMuxIn->getCASocket()->setRecvBuff(50*MIXPACKET_SIZE);
    m_pMuxIn->getCASocket()->setSendBuff(50*MIXPACKET_SIZE);
    m_pMuxIn->getCASocket()->setKeepAlive((UINT32)1800);


    //pAddrNext->toString(buff,255);
    //CAMsg::printMsg(LOG_INFO,"Connecting to next Mix on %s...\n", buff);

    if(connectToNextMix(pAddrNext) != E_SUCCESS)
    {
      delete pAddrNext;
      pAddrNext = NULL;
      MONITORING_FIRE_NET_EVENT(ev_net_prevConnectionClosed);
      CAMsg::printMsg(LOG_DEBUG, "CAMiddleMix::init - Unable to connect to next mix\n");
      return E_UNKNOWN;
    }
    delete pAddrNext;
    pAddrNext = NULL;

//    mSocketGroup.add(muxOut);
    MONITORING_FIRE_NET_EVENT(ev_net_nextConnected);
    CAMsg::printMsg(LOG_INFO," connected!\n");

    m_pMuxOut->getCASocket()->setKeepAlive((UINT32)1800);


      if((ret = processKeyExchange())!=E_SUCCESS)
    {
      CAMsg::printMsg(LOG_CRIT,"Error in proccessKeyExchange()!\n");
        return ret;
    }

    m_pQueueSendToMixBefore=new CAQueue(sizeof(tQueueEntry));
    m_pQueueSendToMixAfter=new CAQueue(sizeof(tQueueEntry));

    m_pMuxInControlChannelDispatcher=new CAControlChannelDispatcher(m_pQueueSendToMixBefore,NULL,0);

#ifdef REPLAY_DETECTION
    m_pReplayDB=new CADatabase();
    m_pReplayDB->start();
    m_pReplayMsgProc=new CAReplayCtrlChannelMsgProc(this);
    m_pReplayMsgProc->startTimeStampPorpagation(REPLAY_TIMESTAMP_PROPAGATION_INTERVALL);
    m_u64ReferenceTime=time(NULL);
#endif
    m_pMiddleMixChannelList=new CAMiddleMixChannelList();

    return E_SUCCESS;
  }

Here is the call graph for this function:

virtual SINT32 CAMiddleMix::initMixCascadeInfo ( DOMElement *&  ) [inline, private, virtual]

This method is not applicable to middle mixes; it does nothing.

Parameters:
dignored
Return values:
E_SUCCESSin any case

Definition at line 85 of file CAMiddleMix.hpp.

References E_SUCCESS.

    {
        return E_SUCCESS;
    }
SINT32 CAMiddleMix::initOnce ( ) [private, virtual]

Reimplemented from CAMix.

Definition at line 48 of file CAMiddleMix.cpp.

References E_SUCCESS, E_UNKNOWN, CACmdLnOptions::getMultiSigner(), CALibProxytest::getOptions(), CAMix::m_pMultiSignature, and CAMsg::printMsg().

  {
    CAMsg::printMsg(LOG_DEBUG,"Starting MiddleMix InitOnce\n");
    //m_pSignature=CALibProxytest::getOptions()->getSignKey();
    m_pMultiSignature=CALibProxytest::getOptions()->getMultiSigner();
    if(m_pMultiSignature==NULL)
      {
        return E_UNKNOWN;
      }
    if(CALibProxytest::getOptions()->getListenerInterfaceCount()<1)
      {
        CAMsg::printMsg(LOG_CRIT,"No ListenerInterfaces specified!\n");
        return E_UNKNOWN;
      }
    return E_SUCCESS;
  }

Here is the call graph for this function:

SINT32 CAMiddleMix::loop ( ) [private, virtual]

Processes Upstream-MixPackets.

Implements CAMix.

Definition at line 1255 of file CAMiddleMix.cpp.

References CASocketGroup::add(), CAMuxSocket::close(), E_UNKNOWN, CAThread::join(), m_bRun, m_pMuxIn, m_pMuxOut, mm_loopReadFromMixAfter, mm_loopReadFromMixBefore, mm_loopSendToMixAfter, mm_loopSendToMixBefore, CAMsg::printMsg(), CAMuxSocket::setCrypt(), CAThread::setMainLoop(), and CAThread::start().

  {

    CASingleSocketGroup oSocketGroup(false);
    oSocketGroup.add(*m_pMuxIn);
    m_pMuxIn->setCrypt(true);
    m_pMuxOut->setCrypt(true);

    m_bRun=true;

    CAThread oThread;
    oThread.setMainLoop(mm_loopReadFromMixAfter);
    oThread.start(this);

    CAThread bThread;
    bThread.setMainLoop(mm_loopSendToMixBefore);
    bThread.start(this);

    CAThread cThread;
    cThread.setMainLoop(mm_loopReadFromMixBefore);
    cThread.start(this);

    CAThread dThread;
    dThread.setMainLoop(mm_loopSendToMixAfter);
    dThread.start(this);

    cThread.join();

    CAMsg::printMsg(LOG_CRIT,"loop(): Preparing for restart...\n");
    m_bRun=false;

    oThread.join();
    bThread.join();
    dThread.join();

    m_pMuxIn->close();
    m_pMuxOut->close();

    CAMsg::printMsg(LOG_CRIT,"loop(): Seems that we are restarting now!!\n");
    return E_UNKNOWN;
  }

Here is the call graph for this function:

SINT32 CAMiddleMix::processKeyExchange ( ) [private, virtual]

Processes key exchange with Mix n+1 and Mix n-1.

  • Step 1: Opens TCP/IP-Connection to Mix n+1.
  • Step 2: Receives info about Mix n+1 .. LastMix as XML struct (see XML struct)
  • Step 3: Verfies signature, generates symetric Keys used for link encryption with Mix
    +1.
  • Step 4: Sends symetric Key to Mix n+1, encrypted with PubKey of Mix n+1 (see XML struct)
  • Step 5: Sends info about Mix n .. LastMix as XML struct (see XML struct)to Mix n-1
  • Step 6: Recevies symetric Key used for link encrpytion with Mix n-1 (see XML struct)
Return values:
E_SUCCESSif KeyExchange with Mix n+1 and Mix n-1 was succesful
E_UNKNOWNotherwise

Getting the KeepAlive Traffice...

Getting and calculating the KeepAlive Traffice...

Implements CAMix.

Definition at line 81 of file CAMiddleMix.cpp.

References CAMix::addMixInfo(), CAMix::appendCompatibilityInfo(), CAMix::appendTermsAndConditionsExtension(), CAMix::checkCompatibility(), createDOMDocument(), createDOMElement(), CABase64::decode(), decodeXMLEncryptedKey(), DOM_Output::dumpToMem(), E_SUCCESS, E_UNKNOWN, CABase64::encode(), encodeXMLEncryptedKey(), equals(), ev_net_keyExchangeNextFailed, ev_net_keyExchangeNextSuccessful, ev_net_keyExchangePrevFailed, ev_net_keyExchangePrevSuccessful, GET_NET_ERROR, GET_NET_ERROR_STR, CAMuxSocket::getCASocket(), getDOMChildByName(), getDOMElementAttribute(), getDOMElementValue(), CACmdLnOptions::getKeepAliveRecvInterval(), CACmdLnOptions::getKeepAliveSendInterval(), CACmdLnOptions::getMixId(), CACmdLnOptions::getNextMixTestCertificate(), CALibProxytest::getOptions(), CACmdLnOptions::getPrevMixTestCertificate(), CAASymCipher::getPublicKeyAsDOMElement(), getRandom(), CACmdLnOptions::getTrustedCertificateStore(), len, CAMix::m_pMultiSignature, m_pMuxIn, m_pMuxOut, m_pRSA, CAMix::m_u32KeepAliveRecvInterval, m_u32KeepAliveRecvInterval2, CAMix::m_u32KeepAliveSendInterval, m_u32KeepAliveSendInterval2, MONITORING_FIRE_NET_EVENT, parseDOMDocument(), CAMsg::printMsg(), CAMuxSocket::receiveFully(), CASocket::send(), setDOMElementAttribute(), setDOMElementValue(), CACmdLnOptions::setNextMixTestCertificate(), CACmdLnOptions::setPrevMixTestCertificate(), CAASymCipher::setPublicKeyAsDOMNode(), CAMuxSocket::setReceiveKey(), CAMuxSocket::setSendKey(), CAMultiSignature::signXML(), CAMix::signXML(), CAMix::termsAndConditionsInfoNode(), CAMix::TIMEOUT_MIX_CONNECTION_ESTABLISHEMENT, CACertStore::verifyMixCert(), CACmdLnOptions::verifyMixCertificates(), and CAMultiSignature::verifyXML().

Referenced by init().

  {
    UINT8* recvBuff=NULL;
    UINT32 len;
    SINT32 ret;

    if((ret = m_pMuxOut->receiveFully((UINT8*)&len, sizeof(len), TIMEOUT_MIX_CONNECTION_ESTABLISHEMENT)) != E_SUCCESS)
    {
      if (ret != E_UNKNOWN)
      {
        CAMsg::printMsg(LOG_INFO,"Error receiving Key Info length from next Mix. Reason: '%s' (%i)\n",
          GET_NET_ERROR_STR(GET_NET_ERROR), GET_NET_ERROR);
      }
      else
      {
        CAMsg::printMsg(LOG_INFO,"Error receiving Key Info length from next Mix.");
      }
      MONITORING_FIRE_NET_EVENT(ev_net_keyExchangeNextFailed);
      return E_UNKNOWN;
    }
    len=ntohl(len);   
    CAMsg::printMsg(LOG_INFO,"Received Key Info length %u\n",len);
    
    if (len > 100000)
    {
      CAMsg::printMsg(LOG_WARNING,"Unrealistic length for key info: %u We might not be able to get a connection.\n",len);
    }
    
    recvBuff=new UINT8[len+1]; //for the \0 at the end
    if(recvBuff==NULL)
      return E_UNKNOWN;
    if((ret = m_pMuxOut->receiveFully(recvBuff,len, TIMEOUT_MIX_CONNECTION_ESTABLISHEMENT)) != E_SUCCESS)
    {
      if (ret != E_UNKNOWN)
      {
        CAMsg::printMsg(LOG_INFO,"Error receiving Key Info from next Mix. Reason: '%s' (%i)\n",
          GET_NET_ERROR_STR(GET_NET_ERROR), GET_NET_ERROR);
      }
      else
      {
        CAMsg::printMsg(LOG_INFO,"Error receiving Key Info from next Mix.");
      }
      MONITORING_FIRE_NET_EVENT(ev_net_keyExchangeNextFailed);
      delete []recvBuff;
      recvBuff = NULL;
      return E_UNKNOWN;
    }
    recvBuff[len]=0; //make a string
    CAMsg::printMsg(LOG_INFO,"Received Key Info...\n");
    CAMsg::printMsg(LOG_INFO,"%s\n",recvBuff);

    //Parsing KeyInfo received from Mix n+1
    XERCES_CPP_NAMESPACE::DOMDocument* doc=parseDOMDocument(recvBuff,len);
    delete []recvBuff;
    recvBuff = NULL;
    if(doc==NULL)
      {
        CAMsg::printMsg(LOG_INFO,"Error parsing Key Info from next Mix!\n");
        MONITORING_FIRE_NET_EVENT(ev_net_keyExchangeNextFailed);
        return E_UNKNOWN;
      }

    DOMElement* root=doc->getDocumentElement();

    //Finding first <Mix> entry and sending symetric key...
    bool bFoundNextMix=false;
    DOMNode* child=root->getFirstChild();
    SINT32 result;
    SINT32 resultCompatibility = E_SUCCESS;
    while(child!=NULL)
      {
        if(equals(child->getNodeName(),"Mix"))
          {
            //verify certificate from next mix if enabled
            if(CALibProxytest::getOptions()->verifyMixCertificates())
            {
              CACertificate* nextMixCert = CALibProxytest::getOptions()->getTrustedCertificateStore()->verifyMixCert(child);
              if(nextMixCert != NULL)
              {
                CAMsg::printMsg(LOG_DEBUG, "Next mix certificate was verified by a trusted root CA.\n");
                CALibProxytest::getOptions()->setNextMixTestCertificate(nextMixCert);
              }
              else
              {
                CAMsg::printMsg(LOG_ERR, "Could not verify certificate received from next mix!\n");
                return E_UNKNOWN;
              }
            }
            //check Signature....
            //CASignature oSig;
            CACertificate* nextCert=CALibProxytest::getOptions()->getNextMixTestCertificate();
            //oSig.setVerifyKey(nextCert);
            ret = CAMultiSignature::verifyXML(child, nextCert);
            //ret=oSig.verifyXML(child,NULL);
            delete nextCert;
            nextCert = NULL;
            if(ret!=E_SUCCESS)
              {
                MONITORING_FIRE_NET_EVENT(ev_net_keyExchangeNextFailed);
                //CAMsg::printMsg(LOG_CRIT,"Could not verify the symmetric key from next mix! The operator of the next mix has to send you his current mix certificate, and you will have to import it in your configuration. Alternatively, you might import the proper root certification authority for verifying the certificate.\n");
                CAMsg::printMsg(LOG_CRIT,"Could not verify the symmetric key from next mix! The operator of the next mix has to send you his current mix certificate, and you will have to import it in your configuration.\n");
                return E_UNKNOWN;
              }
            
            if (resultCompatibility == E_SUCCESS)
            {
              resultCompatibility = checkCompatibility(child, "next");
            }

            //extracting Nonce and computing Hash of them
            DOMElement* elemNonce;
            getDOMChildByName(child,"Nonce",elemNonce,false);
            UINT32 lenNonce=1024;
            UINT8 arNonce[1024];
            UINT32 tmpLen=1024;
            if(elemNonce==NULL)
              {
                MONITORING_FIRE_NET_EVENT(ev_net_keyExchangeNextFailed);
                CAMsg::printMsg(LOG_INFO,"No nonce found in Key Info from next Mix!\n");
                if (doc != NULL)
                {
                  doc->release();
                  doc = NULL;
                }
                return E_UNKNOWN;
              }
            getDOMElementValue(elemNonce,arNonce,&lenNonce);
            CABase64::decode(arNonce,lenNonce,arNonce,&tmpLen);
            lenNonce=tmpLen;
            tmpLen=1024;
            CABase64::encode(SHA1(arNonce,lenNonce,NULL),SHA_DIGEST_LENGTH,
                                  arNonce,&tmpLen);
            arNonce[tmpLen]=0;

            //Extracting PubKey of Mix n+1, generating SymKey for link encryption
            //with Mix n+1, encrypt and send them
            DOMNode* rsaKey=child->getFirstChild();
            CAASymCipher oRSA;
            oRSA.setPublicKeyAsDOMNode(rsaKey);
            UINT8 key[64];
            getRandom(key,64);
            XERCES_CPP_NAMESPACE::DOMDocument* docSymKey=createDOMDocument();
            DOMElement* elemRoot=NULL;
            encodeXMLEncryptedKey(key,64,elemRoot,docSymKey,&oRSA);
            docSymKey->appendChild(elemRoot);

            appendCompatibilityInfo(elemRoot);

            DOMElement* elemNonceHash=createDOMElement(docSymKey,"Nonce");
            setDOMElementValue(elemNonceHash,arNonce);
            elemRoot->appendChild(elemNonceHash);

            DOMElement *elemKeepAlive;
            DOMElement *elemKeepAliveSendInterval;
            DOMElement *elemKeepAliveRecvInterval;
            getDOMChildByName(child,"KeepAlive",elemKeepAlive,false);
            getDOMChildByName(elemKeepAlive,"SendInterval",elemKeepAliveSendInterval,false);
            getDOMChildByName(elemKeepAlive,"ReceiveInterval",elemKeepAliveRecvInterval,false);
            UINT32 tmpSendInterval,tmpRecvInterval;
            getDOMElementValue(elemKeepAliveSendInterval,tmpSendInterval,0xFFFFFFFF); //if now send interval was given set it to "infinite"
            getDOMElementValue(elemKeepAliveRecvInterval,tmpRecvInterval,0xFFFFFFFF); //if no recv interval was given --> set it to "infinite"
            CAMsg::printMsg(LOG_DEBUG,"KeepAlive-Traffic: Getting offer -- SendInterval %u -- ReceiveInterval %u\n",tmpSendInterval,tmpRecvInterval);
            // Add Info about KeepAlive traffic
            UINT32 u32KeepAliveSendInterval=CALibProxytest::getOptions()->getKeepAliveSendInterval();
            UINT32 u32KeepAliveRecvInterval=CALibProxytest::getOptions()->getKeepAliveRecvInterval();
            elemKeepAlive=createDOMElement(docSymKey,"KeepAlive");
            elemKeepAliveSendInterval=createDOMElement(docSymKey,"SendInterval");
            elemKeepAliveRecvInterval=createDOMElement(docSymKey,"ReceiveInterval");
            elemKeepAlive->appendChild(elemKeepAliveSendInterval);
            elemKeepAlive->appendChild(elemKeepAliveRecvInterval);
            setDOMElementValue(elemKeepAliveSendInterval,u32KeepAliveSendInterval);
            setDOMElementValue(elemKeepAliveRecvInterval,u32KeepAliveRecvInterval);
            elemRoot->appendChild(elemKeepAlive);
            CAMsg::printMsg(LOG_DEBUG,"KeepAlive-Traffic: Offering -- SendInterval %u -- Receive Interval %u\n",u32KeepAliveSendInterval,u32KeepAliveRecvInterval);
            m_u32KeepAliveSendInterval2=max(u32KeepAliveSendInterval,tmpRecvInterval);
            if(m_u32KeepAliveSendInterval>10000)
              m_u32KeepAliveSendInterval2-=10000; //make the send interval a little bit smaller than the related receive intervall
            m_u32KeepAliveRecvInterval2=max(u32KeepAliveRecvInterval,tmpSendInterval);
            
            m_u32KeepAliveSendInterval2 = u32KeepAliveSendInterval;
            if (m_u32KeepAliveSendInterval2 > tmpRecvInterval - 10000)
              m_u32KeepAliveSendInterval2-=10000; //make the send interval a little bit smaller than the related receive interval
            m_u32KeepAliveRecvInterval2=max(u32KeepAliveRecvInterval,tmpSendInterval);
            if (m_u32KeepAliveRecvInterval2 - 10000 < tmpSendInterval)
            {
              m_u32KeepAliveRecvInterval2 += 10000;
            }
            
            CAMsg::printMsg(LOG_DEBUG,"KeepAlive-Traffic: Calculated -- SendInterval %u -- Receive Interval %u\n",m_u32KeepAliveSendInterval2,m_u32KeepAliveRecvInterval2);

            //m_pSignature->signXML(elemRoot);
            m_pMultiSignature->signXML(elemRoot, true);
            m_pMuxOut->setSendKey(key,32);
            m_pMuxOut->setReceiveKey(key+32,32);
            UINT32 outlen=0;
            UINT8* out=DOM_Output::dumpToMem(docSymKey,&outlen);
            CAMsg::printMsg(LOG_DEBUG,"send length %u\n", outlen);
            UINT32 size=htonl(outlen);
            m_pMuxOut->getCASocket()->send((UINT8*)&size, sizeof(size));
            m_pMuxOut->getCASocket()->send(out, outlen);
            if (docSymKey != NULL)
            {
              docSymKey->release();
              docSymKey = NULL;
            }
            delete[] out;
            out = NULL;
            bFoundNextMix=true;
            break;
          }
        child=child->getNextSibling();
      }
      
      
    if(!bFoundNextMix)
      {
        CAMsg::printMsg(LOG_INFO,"Error -- no Key Info found for next Mix!\n");
        MONITORING_FIRE_NET_EVENT(ev_net_keyExchangeNextFailed);
        if (doc != NULL)
        {
          doc->release();
          doc = NULL;
        }
        return E_UNKNOWN;
      }
    // -----------------------------------------
    // ---- Start exchange with Mix n-1 --------
    // -----------------------------------------
    //Inserting own (key) info
    UINT32 count=0;
    if(getDOMElementAttribute(root,"count",count)!=E_SUCCESS)
      {
        MONITORING_FIRE_NET_EVENT(ev_net_keyExchangeNextFailed);
        if (doc != NULL)
        {
          doc->release();
          doc = NULL;
        }
        return E_UNKNOWN;
      }
    count++;
    setDOMElementAttribute(root,"count",count);

    addMixInfo(root, true);
    DOMElement* mixNode;
    getDOMChildByName(root, "Mix", mixNode, false);


    UINT8 tmpBuff[50];
    CALibProxytest::getOptions()->getMixId(tmpBuff,50); //the mix id...
    setDOMElementAttribute(mixNode,"id",tmpBuff);
    //Supported Mix Protocol -->currently "0.3"
    DOMElement* elemMixProtocolVersion=createDOMElement(doc,"MixProtocolVersion");
    mixNode->appendChild(elemMixProtocolVersion);
    setDOMElementValue(elemMixProtocolVersion,(UINT8*)"0.3");

    DOMElement* elemKey=NULL;
    m_pRSA->getPublicKeyAsDOMElement(elemKey,doc); //the key
    mixNode->appendChild(elemKey);

    appendCompatibilityInfo(mixNode);

    //inserting Nonce
    DOMElement* elemNonce=createDOMElement(doc,"Nonce");
    UINT8 arNonce[16];
    getRandom(arNonce,16);
    UINT32 tmpLen=50;
    CABase64::encode(arNonce,16,tmpBuff,&tmpLen);
    tmpBuff[tmpLen]=0;
    setDOMElementValue(elemNonce,tmpBuff);
    mixNode->appendChild(elemNonce);

// Add Info about KeepAlive traffic
    DOMElement* elemKeepAlive;
    UINT32 u32KeepAliveSendInterval=CALibProxytest::getOptions()->getKeepAliveSendInterval();
    UINT32 u32KeepAliveRecvInterval=CALibProxytest::getOptions()->getKeepAliveRecvInterval();
    elemKeepAlive=createDOMElement(doc,"KeepAlive");
    DOMElement* elemKeepAliveSendInterval;
    DOMElement* elemKeepAliveRecvInterval;
    elemKeepAliveSendInterval=createDOMElement(doc,"SendInterval");
    elemKeepAliveRecvInterval=createDOMElement(doc,"ReceiveInterval");
    elemKeepAlive->appendChild(elemKeepAliveSendInterval);
    elemKeepAlive->appendChild(elemKeepAliveRecvInterval);
    setDOMElementValue(elemKeepAliveSendInterval,u32KeepAliveSendInterval);
    setDOMElementValue(elemKeepAliveRecvInterval,u32KeepAliveRecvInterval);
    mixNode->appendChild(elemKeepAlive);
    CAMsg::printMsg(LOG_DEBUG,"KeepAlive-Traffic: Offering -- SendInterval %u -- Receive Interval %u\n",u32KeepAliveSendInterval,u32KeepAliveRecvInterval);

    /* append the terms and conditions, if there are any, to the KeyInfo
     * Extensions, (nodes that can be removed from the KeyInfo without
     * destroying the signature of the "Mix"-node).
     */
    if(CALibProxytest::getOptions()->getTermsAndConditions() != NULL)
    {
      appendTermsAndConditionsExtension(doc, root);
      mixNode->appendChild(termsAndConditionsInfoNode(doc));
    }

    // create signature
    if(signXML(mixNode)!=E_SUCCESS)
    {
      CAMsg::printMsg(LOG_DEBUG,"Could not sign KeyInfo send to users...\n");
    }



    //UINT8* out=new UINT8[0xFFFF];
    //memset(out, 0, (sizeof(UINT8)*0xFFFF));
    UINT32 outlen = 0;
    UINT8* out = DOM_Output::dumpToMem(doc, &outlen);
#ifdef _DEBUG
    CAMsg::printMsg(LOG_DEBUG,"New Key Info size: %u\n", outlen);
#endif
    len = htonl(outlen);
    //memcpy(out,&len, sizeof(len));

    m_pMuxIn->getCASocket()->send((UINT8*) &len, sizeof(len));

    ret=m_pMuxIn->getCASocket()->send(out, outlen);
    delete[] out;
    out = NULL;
    if( (ret < 0) || (ret != (SINT32)outlen) )
    {
      CAMsg::printMsg(LOG_DEBUG,"Error sending new New Key Info\n");
      MONITORING_FIRE_NET_EVENT(ev_net_keyExchangeNextFailed);
      if (doc != NULL)
      {
        doc->release();
        doc = NULL;
      }
      return E_UNKNOWN;
    }
    MONITORING_FIRE_NET_EVENT(ev_net_keyExchangeNextSuccessful);
    CAMsg::printMsg(LOG_DEBUG,"Sending new key info succeeded\n");
    
    CAMsg::printMsg(LOG_INFO,"Waiting for length of symmetric key from previous Mix...\n");
    //Now receiving the symmetric key form Mix n-1
    if((ret = m_pMuxIn->receiveFully((UINT8*) &len, sizeof(len), TIMEOUT_MIX_CONNECTION_ESTABLISHEMENT)) != E_SUCCESS)
    {
      if (ret != E_UNKNOWN)
      {
        CAMsg::printMsg(LOG_CRIT,"Error receiving symmetric key info length from the previous mix! Reason: '%s' (%i)\n",
          GET_NET_ERROR_STR(GET_NET_ERROR), GET_NET_ERROR);
      }
      else
      {
        CAMsg::printMsg(LOG_CRIT,"Error receiving symmetric key info length from the previous mix!");
      }
      return E_UNKNOWN;
    }
    
    len = ntohl(len);
    
    if (len > 100000)
    {
      CAMsg::printMsg(LOG_WARNING,"Unrealistic length for key info: %u We might not be able to get a connection.\n",len);
    }
    
    
    recvBuff = new UINT8[len+1]; //for \0 at the end
    
    if((ret = m_pMuxIn->receiveFully(recvBuff, len, TIMEOUT_MIX_CONNECTION_ESTABLISHEMENT)) != E_SUCCESS)
    //if((recLen = m_pMuxIn->getCASocket()->receive(recvBuff, len)) != len)
    {   
      MONITORING_FIRE_NET_EVENT(ev_net_keyExchangePrevFailed);
      if (ret != E_UNKNOWN)
      {
        CAMsg::printMsg(LOG_ERR,"Socket error occurred while receiving the symmetric key from the previous mix! Reason: '%s' (%i) The previous mix might be unable to verify our Mix certificate(s) and therefore closed the connection. Please ask the operator for the log, and exchange your certificates if necessary.\n",
            GET_NET_ERROR_STR(GET_NET_ERROR), GET_NET_ERROR);
      }
      else
      {
        CAMsg::printMsg(LOG_ERR,"Socket error occurred while receiving the symmetric key from the previous mix! The previous mix might be unable to verify our Mix certificate(s) and therefore closed the connection. Please ask the operator for the log, and exchange your certificates if necessary.\n");
      }
      delete []recvBuff;
      recvBuff = NULL;
      if (doc != NULL)
      {
        doc->release();
        doc = NULL;
      }
      return E_UNKNOWN;
    }
    recvBuff[len]=0;
    CAMsg::printMsg(LOG_INFO,"Symmetric Key Info received is:\n");
    CAMsg::printMsg(LOG_INFO,"%s\n",(char*)recvBuff);
    //Parsing doc received
    doc=parseDOMDocument(recvBuff, len);
    delete[] recvBuff;
    recvBuff = NULL;
    if(doc==NULL)
    {
      MONITORING_FIRE_NET_EVENT(ev_net_keyExchangePrevFailed);
      CAMsg::printMsg(LOG_INFO,"Error parsing Key Info from previous Mix!\n");
      return E_UNKNOWN;
    }
    DOMElement* elemRoot=doc->getDocumentElement();
    //verify certificate from previous mix if enabled
    if(CALibProxytest::getOptions()->verifyMixCertificates())
    {
      CACertificate* prevMixCert = CALibProxytest::getOptions()->getTrustedCertificateStore()->verifyMixCert(elemRoot);
      if(prevMixCert != NULL)
      {
        CAMsg::printMsg(LOG_DEBUG, "Previous mix certificate was verified by a trusted root CA.\n");
        CALibProxytest::getOptions()->setPrevMixTestCertificate(prevMixCert);
      }
      else
      {
        CAMsg::printMsg(LOG_ERR, "Could not verify certificate received from previous mix!\n");
        return E_UNKNOWN;
      }
    }
    //verify signature
    //CASignature oSig;
    CACertificate* pCert=CALibProxytest::getOptions()->getPrevMixTestCertificate();
    //oSig.setVerifyKey(pCert);
    result = CAMultiSignature::verifyXML(elemRoot, pCert);
    delete pCert;
    pCert = NULL;
    //if(oSig.verifyXML(elemRoot)!=E_SUCCESS)
    if(result != E_SUCCESS)
    {
      MONITORING_FIRE_NET_EVENT(ev_net_keyExchangePrevFailed);
      //CAMsg::printMsg(LOG_CRIT,"Could not verify the symmetric key from previous mix! The operator of the previous mix has to send you his current mix certificate, and you will have to import it in your configuration. Alternatively, you might import the proper root certification authority for verifying the certificate.\n");
      CAMsg::printMsg(LOG_CRIT,"Could not verify the symmetric key from previous mix! The operator of the previous mix has to send you his current mix certificate, and you will have to import it in your configuration.\n");
      if (doc != NULL)
      {
        doc->release();
        doc = NULL;
      }
      return E_UNKNOWN;
    }

      
      
     if (resultCompatibility != E_SUCCESS ||
      (resultCompatibility = checkCompatibility(elemRoot, "previous")) != E_SUCCESS)
     {
        if (doc != NULL)
        {
          doc->release();
          doc = NULL;
        }
        return resultCompatibility;
      }

    //Verifying nonce
    elemNonce=NULL;
    getDOMChildByName(elemRoot,"Nonce",elemNonce,false);
    tmpLen=50;
    memset(tmpBuff,0,tmpLen);
    if(elemNonce==NULL||getDOMElementValue(elemNonce,tmpBuff,&tmpLen)!=E_SUCCESS||
      CABase64::decode(tmpBuff,tmpLen,tmpBuff,&tmpLen)!=E_SUCCESS||
      tmpLen!=SHA_DIGEST_LENGTH ||
      memcmp(SHA1(arNonce,16,NULL),tmpBuff,SHA_DIGEST_LENGTH)!=0
      )
    {
      MONITORING_FIRE_NET_EVENT(ev_net_keyExchangePrevFailed);
      CAMsg::printMsg(LOG_CRIT,"Could not verify the Nonce from previous mix!\n");
      if (doc != NULL)
      {
        doc->release();
        doc = NULL;
      }
      return E_UNKNOWN;
    }
    CAMsg::printMsg(LOG_INFO,"Verified the symmetric key of the previous mix!\n");

    UINT8 key[150];
    UINT32 keySize=150;

    ret=decodeXMLEncryptedKey(key,&keySize,elemRoot,m_pRSA);
    if(ret!=E_SUCCESS||keySize!=64)
    {
      MONITORING_FIRE_NET_EVENT(ev_net_keyExchangePrevFailed);
      CAMsg::printMsg(LOG_CRIT,"Could not set the symmetric key from previous mix to be used by the MuxSocket!\n");
      if (doc != NULL)
      {
        doc->release();
        doc = NULL;
      }
      return E_UNKNOWN;
    }
    MONITORING_FIRE_NET_EVENT(ev_net_keyExchangePrevSuccessful);
    m_pMuxIn->setReceiveKey(key,32);
    m_pMuxIn->setSendKey(key+32,32);

    elemKeepAlive=NULL;
    elemKeepAliveSendInterval=NULL;
    elemKeepAliveRecvInterval=NULL;
    getDOMChildByName(elemRoot,"KeepAlive",elemKeepAlive);
    getDOMChildByName(elemKeepAlive,"SendInterval",elemKeepAliveSendInterval);
    getDOMChildByName(elemKeepAlive,"ReceiveInterval",elemKeepAliveRecvInterval);
    UINT32 tmpSendInterval,tmpRecvInterval;
    getDOMElementValue(elemKeepAliveSendInterval,tmpSendInterval,0xFFFFFFFF); //if no send interval was given set it to "infinite"
    getDOMElementValue(elemKeepAliveRecvInterval,tmpRecvInterval,0xFFFFFFFF); //if no recv interval was given --> set it to "infinite"
    CAMsg::printMsg(LOG_DEBUG,"KeepAlive-Traffic: Getting offer -- SendInterval %u -- Receive Interval %u\n",tmpSendInterval,tmpRecvInterval);
    m_u32KeepAliveSendInterval = u32KeepAliveSendInterval;
    if (m_u32KeepAliveSendInterval > tmpRecvInterval - 10000)
      m_u32KeepAliveSendInterval-=10000; //make the send interval a little bit smaller than the related receive interval
    m_u32KeepAliveRecvInterval=max(u32KeepAliveRecvInterval,tmpSendInterval);
    if (m_u32KeepAliveRecvInterval - 10000 < tmpSendInterval)
    {
      m_u32KeepAliveRecvInterval += 10000;
    }
    CAMsg::printMsg(LOG_DEBUG,"KeepAlive-Traffic: Calculated -- SendInterval %u -- Receive Interval %u\n",m_u32KeepAliveSendInterval,m_u32KeepAliveRecvInterval);

    if (doc != NULL)
    {
      doc->release();
      doc = NULL;
    }

    return E_SUCCESS;
  }

Here is the call graph for this function:


Friends And Related Function Documentation

THREAD_RETURN mm_loopDownStream ( void *  ) [friend]
THREAD_RETURN mm_loopReadFromMixAfter ( void *  param) [friend]

Definition at line 1059 of file CAMiddleMix.cpp.

Referenced by loop().

  {
    CAMiddleMix* pMix=(CAMiddleMix*)param;
    HCHANNEL channelIn;
    CASymCipher* pCipher;

    tPoolEntry* pPoolEntry=new tPoolEntry;
    MIXPACKET* pMixPacket=&pPoolEntry->packet;

    SINT32 ret;
    CASingleSocketGroup oSocketGroup(false);
    oSocketGroup.add(*(pMix->m_pMuxOut));

    CAQueue* pQueue=pMix->m_pQueueSendToMixBefore;

#ifdef USE_POOL
    CAPool* pPool=new CAPool(MIX_POOL_SIZE);
#endif
    while(pMix->m_bRun)
      {
        if(pQueue->getSize()>MAX_READ_FROM_NEXT_MIX_QUEUE_SIZE)
        {
#ifdef DEBUG
          CAMsg::printMsg(LOG_DEBUG,"CAMiddleMix::Queue next is full!\n");
#endif
          msSleep(200);
          continue;
        }
        #ifndef USE_POOL
          ret=oSocketGroup.select(1000);
        #else
          ret=oSocketGroup.select(MIX_POOL_TIMEOUT);
        #endif
        if(ret!=1)
          {
            if(ret==E_TIMEDOUT)
              {
                #ifndef USE_POOL
                  continue;
                #else
                  pMixPacket->channel=DUMMY_CHANNEL;
                  pMixPacket->flags=CHANNEL_DUMMY;
                  getRandom(pMixPacket->data,DATA_SIZE);
                  pPool->pool(pPoolEntry);
                  if(pMix->m_pMuxIn->send(pMixPacket)==SOCKET_ERROR)
                    pMix->m_bRun=false;
                #endif
              }
            else
            {
              CAMsg::printMsg(LOG_CRIT,"loopReadFromMixAfter -- Error on select() while waiting for data from next mix -- goto ERR!\n");
              pMix->m_bRun=false;
              MONITORING_FIRE_NET_EVENT(ev_net_nextConnectionClosed);
            }
          }
        else
          {

            ret=pMix->m_pMuxOut->receive(pMixPacket);
            if ((ret!=SOCKET_ERROR)&&(pMixPacket->flags & ~CHANNEL_ALLOWED_FLAGS))
              {
                CAMsg::printMsg(LOG_INFO,"loopReadFromMixAfter -- received a packet with invalid flags: %0X .  Removing them.\n",(pMixPacket->flags & ~CHANNEL_ALLOWED_FLAGS));
                pMixPacket->flags&=CHANNEL_ALLOWED_FLAGS;
              }
            if(ret==SOCKET_ERROR)
              {
                CAMsg::printMsg(LOG_CRIT,"loopReadFromMixAfter -- Error while receiving data from next mix. Reason: %s (%i)\n",
                  GET_NET_ERROR_STR(GET_NET_ERROR), GET_NET_ERROR);
                pMix->m_bRun=false;
                MONITORING_FIRE_NET_EVENT(ev_net_nextConnectionClosed);
              }
            #ifdef USE_POOL
            else if(pMixPacket->channel==DUMMY_CHANNEL)
              {
                pMixPacket->flags=CHANNEL_DUMMY;
                getRandom(pMixPacket->data,DATA_SIZE);
                pPool->pool(pPoolEntry);
                if(pMix->m_pMuxIn->send(pMixPacket)==SOCKET_ERROR)
                  pMix->m_bRun=false;
              }
            #endif
            #ifdef REPLAY_DETECTION
            else if(pMixPacket->channel==REPLAY_CONTROL_CHANNEL_ID)
              {
                pQueue->add(pPoolEntry,sizeof(tPoolEntry));
              }
            #endif
            else if(pMix->m_pMiddleMixChannelList->getOutToIn(&channelIn,pMixPacket->channel,&pCipher)==E_SUCCESS)
              {//connection found
#ifdef LOG_CRIME
                HCHANNEL channelOut = pMixPacket->channel;
#endif
                pMixPacket->channel=channelIn;
#ifdef LOG_CRIME
                if((pMixPacket->flags&CHANNEL_SIG_CRIME)==CHANNEL_SIG_CRIME)
                  {
                    getRandom(pMixPacket->data,DATA_SIZE);
                    //Log in and out channel number, to allow
                    CAMsg::printMsg(LOG_CRIT,"Detecting crime activity - previous mix channel: %u, "
                        "next mix channel: %u\n", channelIn, channelOut);
                  }
                else
#endif
                pCipher->crypt2(pMixPacket->data,pMixPacket->data,DATA_SIZE);
                pCipher->unlock();
                #ifdef USE_POOL
                  pPool->pool(pPoolEntry);
                #endif
                if((pMixPacket->flags&CHANNEL_CLOSE)!=0)
                  {//Channel close received -->remove channel form channellist
                    pMix->m_pMiddleMixChannelList->remove(channelIn);
                  }
                pQueue->add(pPoolEntry,sizeof(tPoolEntry));
              }
          }
      }

    CAMsg::printMsg(LOG_CRIT,"loopReadFromMixAfter -- Exiting clean ups...\n");
    pMix->m_bRun=false;
    UINT8 b[sizeof(tQueueEntry)+1];
    /* write bytes to the send queues to accelerate loop()-joins for the send threads*/
    if(pMix->m_pQueueSendToMixBefore!=NULL)
    {
      pMix->m_pQueueSendToMixBefore->add(b,sizeof(tQueueEntry)+1);
    }
    if(pMix->m_pQueueSendToMixAfter!=NULL)
    {
      pMix->m_pQueueSendToMixAfter->add(b,sizeof(tQueueEntry)+1);
    }
    delete pPoolEntry;
    pPoolEntry = NULL;
    #ifdef USE_POOL
      delete pPool;
      pPool = NULL;
    #endif
    CAMsg::printMsg(LOG_CRIT,"loopReadFromMixAfter -- Now Exiting!\n");
    THREAD_RETURN_SUCCESS;
  }
THREAD_RETURN mm_loopReadFromMixBefore ( void *  param) [friend]

Definition at line 888 of file CAMiddleMix.cpp.

Referenced by loop().

  {
    CAMiddleMix* pMix=(CAMiddleMix*)param;
    HCHANNEL channelOut = 0, channelIn = 0;
    tPoolEntry* pPoolEntry=new tPoolEntry;
    MIXPACKET* pMixPacket=&pPoolEntry->packet;

    CAQueue* pQueue=pMix->m_pQueueSendToMixAfter;

    CASymCipher* pCipher;
    SINT32 ret;
    UINT8* tmpRSABuff=new UINT8[RSA_SIZE];
    UINT32 rsaOutLen=RSA_SIZE;
    CASingleSocketGroup oSocketGroup(false);
    oSocketGroup.add(*(pMix->m_pMuxIn));

    #ifdef USE_POOL
      CAPool* pPool=new CAPool(MIX_POOL_SIZE);
    #endif

    while(pMix->m_bRun)
      {
        if(pQueue->getSize()>MAX_READ_FROM_PREV_MIX_QUEUE_SIZE)
        {
#ifdef DEBUG
          CAMsg::printMsg(LOG_DEBUG,"CAFirstMix::Queue prev is full!\n");
#endif
          msSleep(200);
          continue;
        }
        #ifndef USE_POOL
          ret=oSocketGroup.select(1000);
        #else
          ret=oSocketGroup.select(MIX_POOL_TIMEOUT);
        #endif
        if(ret!=1)
          {
            if(ret==E_TIMEDOUT)
              {
                #ifndef USE_POOL
                  continue;
                #else
                  pMixPacket->channel=DUMMY_CHANNEL;
                  pMixPacket->flags=CHANNEL_DUMMY;
                  getRandom(pMixPacket->data,DATA_SIZE);
                  pPool->pool(pPoolEntry);
                  if(m_pMuxOut->send(pMixPacket)==SOCKET_ERROR)
                    pMix->m_bRun=false;
                #endif
              }
            else
              {
                CAMsg::printMsg(LOG_CRIT,"loopUpStream -- Fehler bei select() -- goto ERR!\n");
                pMix->m_bRun=false;
                MONITORING_FIRE_NET_EVENT(ev_net_prevConnectionClosed);
              }
          }
        else
          {
            ret=pMix->m_pMuxIn->receive(pMixPacket);

            if ((ret!=SOCKET_ERROR)&&(pMixPacket->flags & ~CHANNEL_ALLOWED_FLAGS))
            {
              CAMsg::printMsg(LOG_INFO,"loopUpStream received a packet with invalid flags: %0X .  Removing them.\n",(pMixPacket->flags & ~CHANNEL_ALLOWED_FLAGS));
              pMixPacket->flags&=CHANNEL_ALLOWED_FLAGS;
            }

            if(ret==SOCKET_ERROR)
            {

              CAMsg::printMsg(LOG_CRIT,"Fehler beim Empfangen -- Exiting!\n");
              pMix->m_bRun=false;
              MONITORING_FIRE_NET_EVENT(ev_net_prevConnectionClosed);
            }
            #ifdef USE_POOL
            else if(pMixPacket->channel==DUMMY_CHANNEL)
            {
              pMixPacket->flags=CHANNEL_DUMMY;
              getRandom(pMixPacket->data,DATA_SIZE);
              pPool->pool(pPoolEntry);
              if(pMix->m_pMuxOut->send(pMixPacket)==SOCKET_ERROR)
                pMix->m_bRun=false;
            }
            #endif

            else //receive successful
            {
              channelIn = pMixPacket->channel;
              if(pMix->m_pMiddleMixChannelList->getInToOut(pMixPacket->channel,&channelOut,&pCipher)!=E_SUCCESS)
              {//new connection ?
                if(pMixPacket->flags & CHANNEL_OPEN) //if not channel-open flag set -->drop this packet
                {
                  #ifdef _DEBUG
                    CAMsg::printMsg(LOG_DEBUG,"New Connection from previous Mix!\n");
                  #endif
                  pMix->m_pRSA->decryptOAEP(pMixPacket->data,tmpRSABuff,&rsaOutLen);
                  #ifdef REPLAY_DETECTION
                    // replace time(NULL) with the real timestamp ()
                    // packet-timestamp + m_u64ReferenceTime
                    UINT32 stamp=((UINT32)(tmpRSABuff[13]<<16)+(UINT32)(tmpRSABuff[14]<<8)+(UINT32)(tmpRSABuff[15]))*REPLAY_BASE;
                    if(pMix->m_pReplayDB->insert(tmpRSABuff,stamp+pMix->m_u64ReferenceTime)!=E_SUCCESS)
//                      if(pMix->m_pReplayDB->insert(tmpRSABuff,time(NULL))!=E_SUCCESS)
                      {
                        CAMsg::printMsg(LOG_INFO,"Replay: Duplicate packet ignored.\n");
                        continue;
                      }
                  #endif

                  pCipher=new CASymCipher();
                  pCipher->setKeys(tmpRSABuff,MIDDLE_MIX_SIZE_OF_SYMMETRIC_KEYS);
                  pCipher->crypt1(pMixPacket->data+RSA_SIZE,
                        pMixPacket->data+rsaOutLen-MIDDLE_MIX_SIZE_OF_SYMMETRIC_KEYS,
                        DATA_SIZE-RSA_SIZE);
                  memcpy(pMixPacket->data,tmpRSABuff+MIDDLE_MIX_SIZE_OF_SYMMETRIC_KEYS,rsaOutLen-MIDDLE_MIX_SIZE_OF_SYMMETRIC_KEYS);
                  getRandom(pMixPacket->data+DATA_SIZE-MIDDLE_MIX_SIZE_OF_SYMMETRIC_KEYS-MIDDLE_MIX_ASYM_PADDING_SIZE,MIDDLE_MIX_SIZE_OF_SYMMETRIC_KEYS+MIDDLE_MIX_ASYM_PADDING_SIZE);
                  pMix->m_pMiddleMixChannelList->add(pMixPacket->channel,pCipher,&channelOut);
                  pMixPacket->channel=channelOut;
                  #ifdef USE_POOL
                    pPool->pool(pPoolEntry);
                  #endif
                  #ifdef LOG_CRIME
                  crimeSurveillanceUpstream(pMixPacket, channelIn);
                  #endif
                  pQueue->add(pPoolEntry,sizeof(tPoolEntry));
                }
              }
              else
              {//established connection
                pCipher->crypt1(pMixPacket->data,pMixPacket->data,DATA_SIZE);
                pCipher->unlock();
                #ifdef USE_POOL
                  pPool->pool(pPoolEntry);
                #endif
                if((pMixPacket->flags&CHANNEL_CLOSE)!=0)
                {//Channel close received -->remove channel form channellist
                  pMix->m_pMiddleMixChannelList->remove(pMixPacket->channel);
                }
                pMixPacket->channel=channelOut;
                #ifdef LOG_CRIME
                crimeSurveillanceUpstream(pMixPacket, channelIn);
                #endif
                pQueue->add(pPoolEntry,sizeof(tPoolEntry));
              }
            }
          }
      }

    CAMsg::printMsg(LOG_CRIT,"loopReadFromMixBefore -- Exiting clean ups...\n");
    pMix->m_bRun=false;
    UINT8 b[sizeof(tQueueEntry)+1];
    /* write bytes to the send queues to accelerate loop()-joins for the send threads*/
    if(pMix->m_pQueueSendToMixBefore!=NULL)
    {
      pMix->m_pQueueSendToMixBefore->add(b,sizeof(tQueueEntry)+1);
    }
    if(pMix->m_pQueueSendToMixAfter!=NULL)
    {
      pMix->m_pQueueSendToMixAfter->add(b,sizeof(tQueueEntry)+1);
    }
    delete tmpRSABuff;
    tmpRSABuff = NULL;
    delete pPoolEntry;
    pPoolEntry = NULL;
    #ifdef USE_POOL
      delete pPool;
      pPool = NULL;
    #endif
    CAMsg::printMsg(LOG_CRIT,"loopReadFromMixBefore -- Now Exiting!\n");
    THREAD_RETURN_SUCCESS;
  }
THREAD_RETURN mm_loopSendToMixAfter ( void *  param) [friend]

UPSTREAM (to WEB) Take the packets from the Queue and write them to the Socket.

Definition at line 765 of file CAMiddleMix.cpp.

Referenced by loop().

  {
    INIT_STACK;
    BEGIN_STACK("CAFirstMix::fm_loopSendToMixAfter");

    CAMiddleMix* pMiddleMix=(CAMiddleMix*)param;
    CAQueue* pQueue=((CAMiddleMix*)param)->m_pQueueSendToMixAfter;
    CAMuxSocket* pMuxSocket=pMiddleMix->m_pMuxOut;

    UINT32 len;
    SINT32 ret;
    tPoolEntry* pPoolEntry=new tPoolEntry;
    MIXPACKET* pMixPacket=&pPoolEntry->packet;
    UINT32 u32KeepAliveSendInterval=pMiddleMix->m_u32KeepAliveSendInterval2;
    while(pMiddleMix->m_bRun)
      {
        len=sizeof(tPoolEntry);
        ret=pQueue->getOrWait((UINT8*)pPoolEntry,&len,u32KeepAliveSendInterval);
        if(!(pMiddleMix->m_bRun))
        {
          CAMsg::printMsg(LOG_INFO,"SendToMixAfter thread: was interrupted.\n");
          MONITORING_FIRE_NET_EVENT(ev_net_nextConnectionClosed);
          break;
        }
        if(ret==E_TIMEDOUT)
          {//send a dummy as keep-alive-traffic
            pMixPacket->flags=CHANNEL_DUMMY;
            pMixPacket->channel=DUMMY_CHANNEL;
            getRandom(pMixPacket->data,DATA_SIZE);
          }
        else if(ret!=E_SUCCESS||len!=sizeof(tQueueEntry))
          {
            MONITORING_FIRE_NET_EVENT(ev_net_nextConnectionClosed);
            CAMsg::printMsg(LOG_ERR,"CAFirstMix::lm_loopSendToMixAfter - Error in dequeueing MixPaket\n");
            CAMsg::printMsg(LOG_ERR,"ret=%i len=%i\n",ret,len);
            break;
          }
        if((pMuxSocket->send(pMixPacket)!=MIXPACKET_SIZE))
          {
            MONITORING_FIRE_NET_EVENT(ev_net_nextConnectionClosed);
            CAMsg::printMsg(LOG_ERR,"CAFirstMix::lm_loopSendToMixAfter - Error in sending MixPaket\n");
            break;
          }
#ifdef LOG_PACKET_TIMES
        if(!isZero64(pPoolEntry->timestamp_proccessing_start))
          {
            getcurrentTimeMicros(pPoolEntry->timestamp_proccessing_end);
            pFirstMix->m_pLogPacketStats->addToTimeingStats(*pPoolEntry,pMixPacket->flags,true);
          }
#endif
      }
    pMiddleMix->m_bRun = false;
    delete pPoolEntry;
    pPoolEntry = NULL;
    FINISH_STACK("CAFirstMix::fm_loopSendToMixAfter");

    CAMsg::printMsg(LOG_DEBUG,"Exiting Thread SendToMixAfter\n");
    THREAD_RETURN_SUCCESS;
  }
THREAD_RETURN mm_loopSendToMixBefore ( void *  param) [friend]

DOWNSTREAM (to Client) Take the packets from the Queue and write them to the Socket.

Definition at line 826 of file CAMiddleMix.cpp.

Referenced by loop().

  {
    INIT_STACK;
    BEGIN_STACK("CAFirstMix::fm_loopSendToMixBefore");

    CAMiddleMix* pMiddleMix=(CAMiddleMix*)param;
    CAQueue* pQueue=((CAMiddleMix*)param)->m_pQueueSendToMixBefore;
    CAMuxSocket* pMuxSocket=pMiddleMix->m_pMuxIn;

    UINT32 len;
    SINT32 ret;
    tPoolEntry* pPoolEntry=new tPoolEntry;
    MIXPACKET* pMixPacket=&pPoolEntry->packet;
    UINT32 u32KeepAliveSendInterval=pMiddleMix->m_u32KeepAliveSendInterval;
    while(pMiddleMix->m_bRun)
      {
        len=sizeof(tPoolEntry);
        ret=pQueue->getOrWait((UINT8*)pPoolEntry,&len,u32KeepAliveSendInterval);
        if(!(pMiddleMix->m_bRun))
        {
          CAMsg::printMsg(LOG_INFO,"SendToMixBefore thread: was interrupted.\n");
          break;
        }
        if(ret==E_TIMEDOUT)
          {//send a dummy as keep-alive-traffic
            pMixPacket->flags=CHANNEL_DUMMY;
            pMixPacket->channel=DUMMY_CHANNEL;
            getRandom(pMixPacket->data,DATA_SIZE);
          }
        else if(ret!=E_SUCCESS||len!=sizeof(tQueueEntry))
          {
            MONITORING_FIRE_NET_EVENT(ev_net_prevConnectionClosed);
            CAMsg::printMsg(LOG_ERR,"CAFirstMix::lm_loopSendToMixBefore - Error in dequeueing MixPaket\n");
            CAMsg::printMsg(LOG_ERR,"ret=%i len=%i\n",ret,len);
            break;
          }
        if((pMuxSocket->send(pMixPacket)!=MIXPACKET_SIZE))
          {
            MONITORING_FIRE_NET_EVENT(ev_net_prevConnectionClosed);
            CAMsg::printMsg(LOG_ERR,"CAFirstMix::lm_loopSendToMixBefore - Error in sending MixPaket\n");
            break;
          }
#ifdef LOG_PACKET_TIMES
        if(!isZero64(pPoolEntry->timestamp_proccessing_start))
          {
            getcurrentTimeMicros(pPoolEntry->timestamp_proccessing_end);
            pFirstMix->m_pLogPacketStats->addToTimeingStats(*pPoolEntry,pMixPacket->flags,true);
          }
#endif
      }
    pMiddleMix->m_bRun = false;
    delete pPoolEntry;
    pPoolEntry = NULL;
    FINISH_STACK("CAFirstMix::fm_loopSendToMixBefore");

    CAMsg::printMsg(LOG_DEBUG,"Exiting Thread SendToMixBefore\n");
    THREAD_RETURN_SUCCESS;
  }

Member Data Documentation

volatile bool CAMiddleMix::m_bRun [private]

Definition at line 106 of file CAMiddleMix.hpp.

Referenced by processKeyExchange().

Definition at line 107 of file CAMiddleMix.hpp.

Referenced by mm_loopSendToMixAfter(), and processKeyExchange().


The documentation for this class was generated from the following files: