Exemple #1
0
void LLMNRResponder::_process_packet() {
    if (!_conn || !_conn->next())
        return;

#ifdef LLMNR_DEBUG
    Serial.println("LLMNR: RX'd packet");
#endif

    uint16_t id = _conn_read16();
    uint16_t flags = _conn_read16();
    uint16_t qdcount = _conn_read16();
    uint16_t ancount = _conn_read16();
    uint16_t nscount = _conn_read16();
    uint16_t arcount = _conn_read16();

#ifdef LLMNR_DEBUG
    Serial.print("LLMNR: ID=");
    Serial.println(id, HEX);
    Serial.print("LLMNR: FLAGS=");
    Serial.println(flags, HEX);
    Serial.print("LLMNR: QDCOUNT=");
    Serial.println(qdcount);
    Serial.print("LLMNR: ANCOUNT=");
    Serial.println(ancount);
    Serial.print("LLMNR: NSCOUNT=");
    Serial.println(nscount);
    Serial.print("LLMNR: ARCOUNT=");
    Serial.println(arcount);
#endif

#define BAD_FLAGS (FLAGS_QR | (FLAGS_OP_MASK << FLAGS_OP_SHIFT) | FLAGS_C)
    if (flags & BAD_FLAGS) {
#ifdef LLMNR_DEBUG
        Serial.println("Bad flags");
#endif
        return;
    }

    if (qdcount != 1) {
#ifdef LLMNR_DEBUG
        Serial.println("QDCOUNT != 1");
#endif
        return;
    }

    if (ancount || nscount || arcount) {
#ifdef LLMNR_DEBUG
        Serial.println("AN/NS/AR-COUNT != 0");
#endif
        return;
    }

    uint8_t namelen = _conn_read8();
#ifdef LLMNR_DEBUG
    Serial.print("QNAME len ");
    Serial.println(namelen);
#endif
    if (namelen != _hostname.length()) {
#ifdef LLMNR_DEBUG
        Serial.println("QNAME len mismatch");
#endif
        return;
    }

    char qname[64];
    _conn_readS(qname, namelen);
    _conn_read8();
    qname[namelen] = '\0';
#ifdef LLMNR_DEBUG
    Serial.print("QNAME ");
    Serial.println(qname);
#endif

    if (strcmp(_hostname.c_str(), qname)) {
#ifdef LLMNR_DEBUG
        Serial.println("QNAME mismatch");
#endif
        return;
    }

    uint16_t qtype = _conn_read16();
    uint16_t qclass = _conn_read16();

#ifdef LLMNR_DEBUG
    Serial.print("QTYPE ");
    Serial.print(qtype);
    Serial.print(" QCLASS ");
    Serial.println(qclass);
#endif

    bool have_rr =
        (qtype == 1) && /* A */
        (qclass == 1); /* IN */

    _conn->flush();

#ifdef LLMNR_DEBUG
    Serial.println("Match; responding");
    if (!have_rr)
        Serial.println("(no matching RRs)");
#endif

    ip_addr_t remote_ip;
    remote_ip.addr = _conn->getRemoteAddress();

    struct ip_info ip_info;
    bool match_ap = false;
    if (wifi_get_opmode() & SOFTAP_MODE) {
        wifi_get_ip_info(SOFTAP_IF, &ip_info);
    if (ip_info.ip.addr && ip_addr_netcmp(&remote_ip, &ip_info.ip, &ip_info.netmask))
        match_ap = true;
    }
    if (!match_ap)
        wifi_get_ip_info(STATION_IF, &ip_info);
    uint32_t ip = ip_info.ip.addr;

    // Header
    uint8_t header[] = {
        id >> 8, id & 0xff, // ID
        FLAGS_QR >> 8, 0, // FLAGS
        0, 1, // QDCOUNT
        0, !!have_rr, // ANCOUNT
        0, 0, // NSCOUNT
        0, 0, // ARCOUNT
    };
    _conn->append(reinterpret_cast<const char*>(header), sizeof(header));
    // Question
    _conn->append(reinterpret_cast<const char*>(&namelen), 1);
    _conn->append(qname, namelen);
    uint8_t q[] = {
        0, // Name terminator
        0, 1, // TYPE (A)
        0, 1, // CLASS (IN)
    };
    _conn->append(reinterpret_cast<const char*>(q), sizeof(q));
    // Answer, if we have one
    if (have_rr) {
        _conn->append(reinterpret_cast<const char*>(&namelen), 1);
        _conn->append(qname, namelen);
        uint8_t rr[] = {
            0, // Name terminator
            0, 1, // TYPE (A)
            0, 1, // CLASS (IN)
            0, 0, 0, 30, // TTL (30 seconds)
            0, 4, // RDLENGTH
            ip & 0xff, (ip >> 8) & 0xff, (ip >> 16) & 0xff, (ip >> 24) & 0xff, // RDATA
        };
        _conn->append(reinterpret_cast<const char*>(rr), sizeof(rr));
    }
    _conn->setMulticastInterface(remote_ip);
    _conn->send(&remote_ip, _conn->getRemotePort());
}
Exemple #2
0
void MDNSResponder::_parsePacket(){
  int i;
  char tmp;
  bool serviceParsed = false;
  bool protoParsed = false;
  bool localParsed = false;

  char hostName[255];
  uint8_t hostNameLen;

  char serviceName[32];
  uint8_t serviceNameLen;
  uint16_t servicePort = 0;

  char protoName[32];
  protoName[0] = 0;
  uint8_t protoNameLen = 0;

  uint16_t packetHeader[6];

  for(i=0; i<6; i++) packetHeader[i] = _conn_read16();

  if ((packetHeader[1] & 0x8000) != 0) { // Read answers
#ifdef MDNS_DEBUG_RX
    Serial.printf("Reading answers RX: REQ, ID:%u, Q:%u, A:%u, NS:%u, ADD:%u\n", packetHeader[0], packetHeader[2], packetHeader[3], packetHeader[4], packetHeader[5]);
#endif

    if (!_waitingForAnswers) {
#ifdef MDNS_DEBUG_RX
      Serial.println("Not expecting any answers right now, returning");
#endif
      _conn->flush();
      return;
    }

    int numAnswers = packetHeader[3];
    // Assume that the PTR answer always comes first and that it is always accompanied by a TXT, SRV and A answer in the same packet.
    if (numAnswers != 4) {
#ifdef MDNS_DEBUG_RX
      Serial.println("Expected a packet with 4 answers, returning");
#endif
      _conn->flush();
      return;
    }
    
    uint8_t tmp8;
    uint16_t answerPort = 0;
    uint8_t answerIp[4] = { 0,0,0,0 };
    char answerHostName[255];
    bool serviceMatch = false;
    MDNSAnswer *answer;
    uint8_t partsCollected = 0;

    // Clear answer list
    if (_newQuery) {
      int numAnswers = _getNumAnswers();
      for (int n = numAnswers - 1; n >= 0; n--) {
        answer = _getAnswerFromIdx(n);
        os_free(answer->hostname);
        os_free(answer);
        answer = 0;
      }
      _answers = 0;
      _newQuery = false;
    }

    while (numAnswers--) {
      // Read name
      do {
        tmp8 = _conn_read8();
        if (tmp8 & 0xC0) { // Compressed pointer (not supported)
          tmp8 = _conn_read8();
          break;
        }
        if (tmp8 == 0x00) { // Énd of name
          break;
        }
        _conn_readS(serviceName, tmp8);
        serviceName[tmp8] = '\0';
#ifdef MDNS_DEBUG_RX
        Serial.printf(" %d ", tmp8);
        for (int n = 0; n < tmp8; n++) {
          Serial.printf("%02x ", serviceName[n]);
        }
        Serial.println();
#endif
        if (serviceName[0] == '_') {
          if (strcmp(&serviceName[1], _query->_service) == 0) {
            serviceMatch = true;
#ifdef MDNS_DEBUG_RX
            Serial.printf("found matching service: %s\n", _query->_service);
#endif
          }
        }
      } while (true);

      uint16_t answerType = _conn_read16(); // Read type
      uint16_t answerClass = _conn_read16(); // Read class
      uint32_t answerTtl = _conn_read32(); // Read ttl
      uint16_t answerRdlength = _conn_read16(); // Read rdlength

#ifdef MDNS_DEBUG_RX
      Serial.printf("type: %04x rdlength: %d\n", answerType, answerRdlength);
#endif

      if (answerType == MDNS_TYPE_PTR) {
        partsCollected |= 0x01;
        _conn_readS(hostName, answerRdlength); // Read rdata
#ifdef MDNS_DEBUG_RX
        for (int n = 0; n < answerRdlength; n++) {
          Serial.printf("%02x ", hostName[n]);
        }
        Serial.println();
#endif
      }

      if (answerType == MDNS_TYPE_TXT) {
        partsCollected |= 0x02;
        _conn_readS(hostName, answerRdlength); // Read rdata
#ifdef MDNS_DEBUG_RX
        for (int n = 0; n < answerRdlength; n++) {
          Serial.printf("%02x ", hostName[n]);
        }
        Serial.println();
#endif
      }

      if (answerType == MDNS_TYPE_SRV) {
        partsCollected |= 0x04;
        uint16_t answerPrio = _conn_read16(); // Read priority
        uint16_t answerWeight = _conn_read16(); // Read weight
        answerPort = _conn_read16(); // Read port

        // Read hostname
        tmp8 = _conn_read8();
        if (tmp8 & 0xC0) { // Compressed pointer (not supported)
          Serial.println("Skipping compressed pointer");
          tmp8 = _conn_read8();
        }
        else {
          _conn_readS(answerHostName, tmp8);
          answerHostName[tmp8] = '\0';
#ifdef MDNS_DEBUG_RX
          Serial.printf(" %d ", tmp8);
          for (int n = 0; n < tmp8; n++) {
            Serial.printf("%02x ", answerHostName[n]);
          }
          Serial.printf("\n%s\n", answerHostName);
#endif
          if (answerRdlength - (6 + 1 + tmp8) > 0) { // Skip any remaining rdata
            _conn_readS(hostName, answerRdlength - (6 + 1 + tmp8));
          }
        }
      }

      if (answerType == MDNS_TYPE_A) {
        partsCollected |= 0x08;
        for (int i = 0; i < 4; i++) {
          answerIp[i] = _conn_read8();
        }
      }

      if ((partsCollected == 0x0F) && serviceMatch) {
#ifdef MDNS_DEBUG_RX
        Serial.println("All answers parsed, adding to _answers list..");
#endif
        // Add new answer to answer list
        if (_answers == 0) {
          _answers = (struct MDNSAnswer*)(os_malloc(sizeof(struct MDNSAnswer)));
          answer = _answers;
        }
        else {
          answer = _answers;
          while (answer->next != 0) {
            answer = _answers->next;
          }
          answer->next = (struct MDNSAnswer*)(os_malloc(sizeof(struct MDNSAnswer)));
          answer = answer->next;
        }
        answer->next = 0;
        answer->hostname = 0;

        // Populate new answer
        answer->port = answerPort;
        for (int i = 0; i < 4; i++) {
          answer->ip[i] = answerIp[i];
        }
        answer->hostname = (char *)os_malloc(strlen(answerHostName) + 1);
        os_strcpy(answer->hostname, answerHostName);
      }
    }
    
    _conn->flush();
    return;
  }

  // PARSE REQUEST NAME

  hostNameLen = _conn_read8();
  _conn_readS(hostName, hostNameLen);
  hostName[hostNameLen] = '\0';

  if(hostName[0] == '_'){
    serviceParsed = true;
    memcpy(serviceName, hostName+1, hostNameLen);
    serviceNameLen = hostNameLen-1;
    hostNameLen = 0;
  }

  if(hostNameLen > 0 && !_hostName.equals(hostName) && !_instanceName.equals(hostName)){
#ifdef MDNS_DEBUG_ERR
    Serial.printf("ERR_NO_HOST: %s\n", hostName);
    Serial.printf("hostname: %s\n", _hostName.c_str() );
    Serial.printf("instance: %s\n", _instanceName.c_str() );
#endif
    _conn->flush();
    return;
  }

  if(!serviceParsed){
    serviceNameLen = _conn_read8();
    _conn_readS(serviceName, serviceNameLen);
    serviceName[serviceNameLen] = '\0';

    if(serviceName[0] == '_'){
      memmove(serviceName, serviceName+1, serviceNameLen);
      serviceNameLen--;
      serviceParsed = true;
    } else if(serviceNameLen == 5 && strcmp("local", serviceName) == 0){
      tmp = _conn_read8();
      if(tmp == 0){
        serviceParsed = true;
        serviceNameLen = 0;
        protoParsed = true;
        protoNameLen = 0;
        localParsed = true;
      } else {
#ifdef MDNS_DEBUG_ERR
        Serial.printf("ERR_FQDN: %s\n", serviceName);
#endif
        _conn->flush();
        return;
      }
    } else {
#ifdef MDNS_DEBUG_ERR
      Serial.printf("ERR_SERVICE: %s\n", serviceName);
#endif
      _conn->flush();
      return;
    }
  }

  if(!protoParsed){
    protoNameLen = _conn_read8();
    _conn_readS(protoName, protoNameLen);
    protoName[protoNameLen] = '\0';
    if(protoNameLen == 4 && protoName[0] == '_'){
      memmove(protoName, protoName+1, protoNameLen);
      protoNameLen--;
      protoParsed = true;
    } else if(strcmp("services", serviceName) == 0 && strcmp("_dns-sd", protoName) == 0){
      _conn->flush();
      advertiseServices();
      return;
    } else {
#ifdef MDNS_DEBUG_ERR
      Serial.printf("ERR_PROTO: %s\n", protoName);
#endif
      _conn->flush();
      return;
    }
  }

  if(!localParsed){
    char localName[32];
    uint8_t localNameLen = _conn_read8();
    _conn_readS(localName, localNameLen);
    localName[localNameLen] = '\0';
    tmp = _conn_read8();
    if(localNameLen == 5 && strcmp("local", localName) == 0 && tmp == 0){
      localParsed = true;
    } else {
#ifdef MDNS_DEBUG_ERR
      Serial.printf("ERR_FQDN: %s\n", localName);
#endif
      _conn->flush();
      return;
    }
  }

  if(serviceNameLen > 0 && protoNameLen > 0){
    servicePort = _getServicePort(serviceName, protoName);
    if(servicePort == 0){
#ifdef MDNS_DEBUG_ERR
      Serial.printf("ERR_NO_SERVICE: %s\n", serviceName);
#endif
      _conn->flush();
      return;
    }
  } else if(serviceNameLen > 0 || protoNameLen > 0){
#ifdef MDNS_DEBUG_ERR
    Serial.printf("ERR_SERVICE_PROTO: %s\n", serviceName);
#endif
    _conn->flush();
    return;
  }

  // RESPOND

#ifdef MDNS_DEBUG_RX
  Serial.printf("RX: REQ, ID:%u, Q:%u, A:%u, NS:%u, ADD:%u\n", packetHeader[0], packetHeader[2], packetHeader[3], packetHeader[4], packetHeader[5]);
#endif

  uint16_t currentType;
  uint16_t currentClass;

  int numQuestions = packetHeader[2];
  if(numQuestions > 4) numQuestions = 4;
  uint16_t questions[4];
  int question = 0;

  while(numQuestions--){
    currentType = _conn_read16();
    if(currentType & MDNS_NAME_REF){ //new header handle it better!
      currentType = _conn_read16();
    }
    currentClass = _conn_read16();
    if(currentClass & MDNS_CLASS_IN) questions[question++] = currentType;

    if(numQuestions > 0){
      if(_conn_read16() != 0xC00C){//new question but for another host/service
        _conn->flush();
        numQuestions = 0;
      }
    }

#ifdef MDNS_DEBUG_RX
    Serial.printf("REQ: ");
    if(hostNameLen > 0) Serial.printf("%s.", hostName);
    if(serviceNameLen > 0) Serial.printf("_%s.", serviceName);
    if(protoNameLen > 0) Serial.printf("_%s.", protoName);
    Serial.printf("local. ");

    if(currentType == MDNS_TYPE_AAAA) Serial.printf("  AAAA ");
    else if(currentType == MDNS_TYPE_A) Serial.printf("  A ");
    else if(currentType == MDNS_TYPE_PTR) Serial.printf("  PTR ");
    else if(currentType == MDNS_TYPE_SRV) Serial.printf("  SRV ");
    else if(currentType == MDNS_TYPE_TXT) Serial.printf("  TXT ");
    else Serial.printf("  0x%04X ", currentType);

    if(currentClass == MDNS_CLASS_IN) Serial.printf("  IN ");
    else if(currentClass == MDNS_CLASS_IN_FLUSH_CACHE) Serial.printf("  IN[F] ");
    else Serial.printf("  0x%04X ", currentClass);

    Serial.printf("\n");
#endif
  }
  uint8_t responseMask = 0;
  for(i=0;i<question;i++){
    if(questions[i] == MDNS_TYPE_A) responseMask |= 0x1;
    else if(questions[i] == MDNS_TYPE_SRV) responseMask |= 0x3;
    else if(questions[i] == MDNS_TYPE_TXT) responseMask |= 0x4;
    else if(questions[i] == MDNS_TYPE_PTR) responseMask |= 0xF;
  }

  return _reply(responseMask, serviceName, protoName, servicePort);
}
Exemple #3
0
void MDNSResponder::_parsePacket(){
  int i;
  char tmp;
  bool serviceParsed = false;
  bool protoParsed = false;
  bool localParsed = false;

  char hostName[255];
  uint8_t hostNameLen;

  char serviceName[32];
  uint8_t serviceNameLen;
  uint16_t servicePort;

  char protoName[32];
  uint8_t protoNameLen;

  uint16_t packetHeader[6];

  for(i=0; i<6; i++) packetHeader[i] = _conn_read16();

  if((packetHeader[1] & 0x8000) != 0){ //not parsing responses yet
    _conn->flush();
    return;
  }

  // PARSE REQUEST NAME

  hostNameLen = _conn_read8();
  _conn_readS(hostName, hostNameLen);
  hostName[hostNameLen] = '\0';

  if(hostName[0] == '_'){
    serviceParsed = true;
    memcpy(serviceName, hostName+1, hostNameLen);
    serviceNameLen = hostNameLen-1;
    hostNameLen = 0;
  }

  if(hostNameLen > 0 && strcmp(_hostName, hostName) != 0){
#ifdef MDNS_DEBUG_ERR
    os_printf("ERR_NO_HOST: %s\n", hostName);
#endif
    _conn->flush();
    return;
  }

  if(!serviceParsed){
    serviceNameLen = _conn_read8();
    _conn_readS(serviceName, serviceNameLen);
    serviceName[serviceNameLen] = '\0';

    if(serviceName[0] == '_'){
      memcpy(serviceName, serviceName+1, serviceNameLen);
      serviceNameLen--;
      serviceParsed = true;
    } else if(serviceNameLen == 5 && strcmp("local", serviceName) == 0){
      tmp = _conn_read8();
      if(tmp == 0){
        serviceParsed = true;
        serviceNameLen = 0;
        protoParsed = true;
        protoNameLen = 0;
        localParsed = true;
      } else {
#ifdef MDNS_DEBUG_ERR
        os_printf("ERR_FQDN: %s\n", serviceName);
#endif
        _conn->flush();
        return;
      }
    } else {
#ifdef MDNS_DEBUG_ERR
      os_printf("ERR_SERVICE: %s\n", serviceName);
#endif
      _conn->flush();
      return;
    }
  }

  if(!protoParsed){
    protoNameLen = _conn_read8();
    _conn_readS(protoName, protoNameLen);
    protoName[protoNameLen] = '\0';
    if(protoNameLen == 4 && protoName[0] == '_'){
      memcpy(protoName, protoName+1, protoNameLen);
      protoNameLen--;
      protoParsed = true;
    } else {
#ifdef MDNS_DEBUG_ERR
      os_printf("ERR_PROTO: %s\n", protoName);
#endif
      _conn->flush();
      return;
    }
  }

  if(!localParsed){
    char localName[32];
    uint8_t localNameLen = _conn_read8();
    _conn_readS(localName, localNameLen);
    localName[localNameLen] = '\0';
    tmp = _conn_read8();
    if(localNameLen == 5 && strcmp("local", localName) == 0 && tmp == 0){
      localParsed = true;
    } else {
#ifdef MDNS_DEBUG_ERR
      os_printf("ERR_FQDN: %s\n", localName);
#endif
      _conn->flush();
      return;
    }
  }

  if(serviceNameLen > 0 && protoNameLen > 0){
    servicePort = _getServicePort(serviceName, protoName);
    if(servicePort == 0){
#ifdef MDNS_DEBUG_ERR
      os_printf("ERR_NO_SERVICE: %s\n", serviceName);
#endif
      _conn->flush();
      return;
    }
  } else if(serviceNameLen > 0 || protoNameLen > 0){
#ifdef MDNS_DEBUG_ERR
    os_printf("ERR_SERVICE_PROTO: %s\n", serviceName);
#endif
    _conn->flush();
    return;
  }

  // RESPOND

#ifdef MDNS_DEBUG_RX
  os_printf("RX: REQ, ID:%u, Q:%u, A:%u, NS:%u, ADD:%u\n", packetHeader[0], packetHeader[2], packetHeader[3], packetHeader[4], packetHeader[5]);
#endif

  uint16_t currentType;
  uint16_t currentClass;

  int numQuestions = packetHeader[2];
  if(numQuestions > 4) numQuestions = 4;
  uint16_t questions[4];
  int question = 0;

  while(numQuestions--){
    currentType = _conn_read16();
    if(currentType & MDNS_NAME_REF){ //new header handle it better!
      currentType = _conn_read16();
    }
    currentClass = _conn_read16();
    if(currentClass & MDNS_CLASS_IN) questions[question++] = currentType;

    if(numQuestions > 0){
      if(_conn_read16() != 0xC00C){//new question but for another host/service
        _conn->flush();
        numQuestions = 0;
      }
    }

#ifdef MDNS_DEBUG_RX
    os_printf("REQ: ");
    if(hostNameLen > 0) os_printf("%s.", hostName);
    if(serviceNameLen > 0) os_printf("_%s.", serviceName);
    if(protoNameLen > 0) os_printf("_%s.", protoName);
    os_printf("local. ");

    if(currentType == MDNS_TYPE_AAAA) os_printf("  AAAA ");
    else if(currentType == MDNS_TYPE_A) os_printf("  A ");
    else if(currentType == MDNS_TYPE_PTR) os_printf("  PTR ");
    else if(currentType == MDNS_TYPE_SRV) os_printf("  SRV ");
    else if(currentType == MDNS_TYPE_TXT) os_printf("  TXT ");
    else os_printf("  0x%04X ", currentType);

    if(currentClass == MDNS_CLASS_IN) os_printf("  IN ");
    else if(currentClass == MDNS_CLASS_IN_FLUSH_CACHE) os_printf("  IN[F] ");
    else os_printf("  0x%04X ", currentClass);

    os_printf("\n");
#endif
  }
  uint8_t responseMask = 0;
  for(i=0;i<question;i++){
    if(questions[i] == MDNS_TYPE_A) responseMask |= 0x1;
    else if(questions[i] == MDNS_TYPE_SRV) responseMask |= 0x3;
    else if(questions[i] == MDNS_TYPE_TXT) responseMask |= 0x4;
    else if(questions[i] == MDNS_TYPE_PTR) responseMask |= 0xF;
  }

  return _reply(responseMask, (serviceName), (protoName), servicePort);
}