1: 
   2: 
   3: /**********************
   4: *                     *
   5: *  COMPILER INCLUDES  *
   6: *                     *
   7: **********************/
   8: 
   9: 
  10: /*********************
  11: *                    *
  12: *  PROJECT INCLUDES  *
  13: *                    *
  14: *********************/
  15: 
  16: 
  17: #include "mind.h" 
  18: #include "dnspacket.h" 
  19: #include "rdata_a.h" 
  20: #include "rdata_name.h" 
  21: #include "resolver.h" 
  22: #include "rrfactory.h" 
  23: #include "watchptr.h" 
  24: #include "wwwi/singleton.h" 
  25: 
  26: 
  27: using std::auto_ptr;
  28: using std::memset;
  29: using WWWI::IPDump;
  30: using WWWI::GetSingleton;
  31: 
  32: 
  33: /************************
  34: *                       *
  35: *  RESOLVERCONSTRUCTOR  *
  36: *                       *
  37: ************************/
  38: 
  39: 
  40: Resolver::Resolver() {
  41:   m_cap = GetSingleton<RRCache>();
  42:   m_usID = 0;
  43: }
  44: 
  45: 
  46: /**************************
  47: *                         *
  48: *  METHOD QUERYAUTHORITY  *
  49: *                         *
  50: **************************/
  51: 
  52: 
  53: ResponsePtr Resolver::QueryAuthority(QuestionConstPtr ci_qnp, DNSSocketPtr i_dspAuthority, IPAddress i_ipAuthority) {
  54:   DNSPacketPtr dppServer;
  55:   unsigned short usID;
  56:   SockAddrIn *sipAuthority;
  57:   LogHandle lh(LF_RESOLVER,LY_DEBUG);
  58: 
  59:   lh << "resolv qauth start " << ci_qnp << endl; lh();
  60: 
  61:   sipAuthority = new SockAddrIn;
  62:   memset(sipAuthority,0,sizeof(SockAddrIn));
  63:   sipAuthority->sin_addr.s_addr = i_ipAuthority;
  64:   sipAuthority->sin_port = htons(53);
  65:   sipAuthority->sin_family = AF_INET;
  66: 
  67:   usID = m_usID++;
  68:   dppServer = new DNSPacket(sipAuthority,usID,ci_qnp);
  69:   i_dspAuthority->SendPacket(dppServer);
  70:   SoftDelete(dppServer);
  71: 
  72:   dppServer = i_dspAuthority->RecvPacketTimed(1000);
  73:   if (dppServer==NULL) { 
  74:     lh << "resolv qauth timeout " << ci_qnp << endl;
  75:     return NULL;
  76:   }
  77:   if (dppServer->TestID(usID)==false) {
  78:     lh << "resolv qauth xtalk " << ci_qnp << endl;
  79:     SoftDelete(dppServer);
  80:     return NULL;
  81:   }
  82: 
  83:   RequestPtr rqp = NULL;
  84:   ResponsePtr rsp = NULL;
  85:   WatchPtr<RequestPtr> watch_rqp(rqp);
  86:   WatchPtr<ResponsePtr> watch_rsp(rsp);
  87:   dppServer->Parse(usID,rqp,rsp);
  88:   SoftDelete(dppServer);
  89: 
  90:   if ((rqp->GetOpcode()!=OPCODE_QUERY)||
  91:       (rqp->GetQuestionCount()!=1)||
  92:       (rsp==NULL)) {
  93:     lh << "resolv qauth gibberish " << ci_qnp << endl;
  94:     return NULL;
  95:   }
  96: 
  97:   lh << "resolv qauth done " << ci_qnp << endl;
  98:   watch_rsp.Release();
  99:   return rsp;
 100: }
 101:     
 102: 
 103: /***************************
 104: *                          *
 105: *  METHODS QUERYRECURSIVE  *
 106: *                          *
 107: ***************************/
 108: 
 109: 
 110: ResponsePtr Resolver::QueryRecursive(const char *i_strName, RRType i_ty, RRClass i_cl, unsigned i_uSteps) {
 111:   QuestionPtr qnp = new Question(i_strName,i_ty,i_cl);
 112:   ResponsePtr rsp = this->QueryRecursive(qnp,i_uSteps);
 113:   return rsp;
 114: }
 115: 
 116: 
 117: ResponsePtr Resolver::QueryRecursive(QuestionConstPtr ci_qnp,unsigned i_uSteps) {
 118:   ResponsePtr rsp;
 119:   auto_ptr<DNSSocket> dsuUpstream(new DNSSocket(INADDR_ANY,0));
 120:   bool bCached;
 121: 
 122:   if (i_uSteps==0) return new Response(RCODE_SERVFAIL);
 123: 
 124:   // Try the cache first.
 125:   rsp = m_cap->Get(ci_qnp);
 126:   bCached = (rsp!=NULL);
 127: 
 128:   while(bCached==false) {
 129:     RRListPtr rlpAuthority;
 130: 
 131:     rlpAuthority = m_cap->GetBestAuthority(ci_qnp->GetName());
 132: 
 133:     while(i_uSteps>0) {
 134:       i_uSteps--;
 135:       RRList::iterator rrpi;
 136:       IPAddress ipAuthority;
 137: 
 138:       if (rlpAuthority->size()==0) return new Response(RCODE_SERVFAIL);
 139:       rrpi = rlpAuthority->GetRandomRR();
 140:       ipAuthority = SimpleResolve((*rrpi)->GetRData()->As<RDataName>()->GetRDName(),i_uSteps);
 141:       if (ipAuthority==(IPAddress)-1) {
 142:         SoftDelete(*rrpi);
 143:         rlpAuthority->erase(rrpi);
 144:         continue;
 145:       }
 146:       rsp = this->QueryAuthority(ci_qnp,dsuUpstream.get(),ipAuthority);
 147:       if (rsp==NULL) continue;
 148:       if (rsp->GetRCode()==RCODE_SERVFAIL) {
 149:         SoftDelete(*rrpi);
 150:         rlpAuthority->erase(rrpi);
 151:         continue;
 152:       }
 153:       if ((rsp->GetANCount()==0)&&(rsp->GetNSCount()==0)) {
 154:         SoftDelete(*rrpi);
 155:         rlpAuthority->erase(rrpi);
 156:         continue;
 157:       }
 158:       break;
 159:     }
 160:     SoftDelete(rlpAuthority);
 161:     if ((i_uSteps==0)&&(rsp==NULL)) return new Response(RCODE_SERVFAIL);
 162: 
 163:     if (rsp->GetRCode()!=RCODE_NOERROR) break;
 164:     if (rsp->GetAA()==true) break;
 165:     if (rsp->GetANCount()==0) {
 166:       m_cap->Add(rsp);
 167:       SoftDelete(rsp);
 168:       continue;
 169:     }
 170:     break;
 171:   }
 172: 
 173:   // Add to cache, then check to see if our answer is really a CNAME.
 174:   if (rsp!=NULL) {
 175:     if (bCached==false) {
 176:       if ((rsp->GetAA()==true)&&(rsp->GetTC()==false)) m_cap->Add(rsp);
 177:     }
 178:     if (rsp->GetANList()->HasQuestionMatch(ci_qnp)==false) {
 179:       if (rsp->GetANCount()==1) {
 180:         RRPtr rrp = *rsp->GetANList()->begin();
 181:         if (rrp->IsTypeClass(TY_CNAME,ci_qnp->GetClass())==true) {
 182:           QuestionPtr qnpCName = new Question(*ci_qnp,rrp->GetRData()->As<RDataName>()->GetRDName());
 183:           ResponsePtr rspCName = this->QueryRecursive(qnpCName,i_uSteps-1);
 184:           SoftDelete(qnpCName);
 185:           if (rspCName!=NULL) {
 186:             rrp = RRFactory::NewRR(rrp);
 187:             rspCName->AddAN(rrp);
 188:             SoftDelete(rsp);
 189:             rsp = rspCName;
 190:           }
 191:         }
 192:       }
 193:     }
 194:   }
 195: 
 196:   return rsp;
 197: }
 198: 
 199: 
 200: /**************************
 201: *                         *
 202: *  METHODS SIMPLERESOLVE  *
 203: *                         *
 204: **************************/
 205: 
 206: 
 207: IPAddress Resolver::SimpleResolve(const char *ci_strName, unsigned i_uSteps) {
 208:   IPAddress ipOut = inet_addr(ci_strName);
 209:   if (ipOut==(IPAddress)-1) { 
 210:     LabelListPtr llp = new LabelList(ci_strName);
 211:     ipOut = this->SimpleResolve(llp,i_uSteps);
 212:     SoftDelete(llp);
 213:   } else {
 214:     LogHandle lh(LF_RESOLVER,LY_DEBUG);
 215:     lh << "resolv simple fast " << ci_strName << " is ";
 216:     IPDump(lh,ipOut);
 217:   }
 218:   return ipOut;
 219: }
 220: 
 221: 
 222: inline IPAddress Resolver::SimpleResolve(LabelListConstPtr ci_llpName, unsigned i_uSteps) {
 223:   RRListPtr rlp;
 224:   IPAddress  ipOut;
 225:   LogHandle lh(LF_RESOLVER,LY_DEBUG);
 226: 
 227:   if (i_uSteps==0) return (IPAddress)-1;
 228: 
 229:   lh << "resolv simple start " << ci_llpName << endl; lh();
 230: 
 231:   rlp = m_cap->GetSimple(ci_llpName,TY_A,CL_IN);
 232: 
 233:   if (rlp == NULL) {
 234:     QuestionPtr qnp;
 235:     ResponsePtr rsp;
 236:     LabelListPtr llp;
 237: 
 238:     llp = new LabelList(*ci_llpName);
 239:     qnp = new Question(llp,TY_A,CL_IN);
 240:     rsp = this->QueryRecursive(qnp,i_uSteps);
 241:     if (rsp==NULL) goto srFailed;
 242:     rlp = rsp->RemoveANList();
 243:     SoftDelete(rsp);
 244:     SoftDelete(qnp);
 245:     if (rlp->size()==0) goto srFailed;
 246:   }
 247:   assert(rlp->size()>0);
 248:   ipOut = (*rlp->GetRandomRR())->GetRData()->As<RDataA>()->GetRDAddress();
 249:   SoftDelete(rlp);
 250: 
 251:   lh << "resolv simple done " << ci_llpName << " is ";
 252:   IPDump(lh,ipOut);
 253:   lh();
 254:   return ipOut;
 255: 
 256: srFailed:
 257:   lh << "resolv simple fail " << ci_llpName << endl; lh();
 258:   return (IPAddress)-1;
 259: }
 260: 
 261: 
 262: