• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Делюсь опытом Если при отправке e-mail через WiFiClientSecure часто наступает wdt.reset...

Paul_B

Member
В файле WiFiClientSecure.cpp необходимо произвести изменения:
1. _timeout = 5000 (вместо 15000) в двух местах (может это и не надо, а установить client.setTimeout(5000), но у меня это не приносило плоды, возможно из-за ошибки, изложенной в п.2)
2. заменить функцию
Код:
int WiFiClientSecure::connect(const char* name, uint16_t port)
{
    IPAddress remote_addr;
    if (!WiFi.hostByName(name, remote_addr, _timeout)) {
        return 0;
    }
    if (!WiFiClient::connect(remote_addr, port)) {
        return 0;
    }
    return _connectSSL(name);
}
Там, в отличие от WiFiclient.cpp стояло if (!WiFi.hostByName(name, remote_addr)) поэтому часто были зависания тут и перезагрузка по wdt.reset
3. В файлах WiFiclient.cpp и WiFiClientSecure.cpp заменить yield() на delay(1);

Полностью модифицированный файл прилагаю.
Заменяется по пути C:\DOCUMENTS AND SETTINGS\USER\APPDATA\LOCAL\ARDUINO15\PACKAGES\ESP8266\HARDWARE\ESP8266\2.4.2\LIBRARIES\ESP8266WIFI\SRC\WiFiClientSecure.cpp

Сами функции, реализующие отправку e-mail вот:
Код:
#include <WiFiClientSecure.h>
#include <base64.h>

//#define NDEBUG

uint16_t smtpPort = 465;
char* Mail_Message=NULL;
char* Mail_Subj=NULL;
char* smtpUser=NULL;
char* smtpHost=NULL;
char* smtpPass=NULL;
char* mailTo=NULL;


static inline bool checkResponse(const String& response, int16_t code) {
  return response.startsWith(String(code) + ' ');
}

static bool checkResponse(const String& response, int16_t code, const String& errorMsg) {
  bool result = checkResponse(response, code);

  if (! result) {
    Serial.print(errorMsg);
    Serial.print(F(": \""));
    if (response.endsWith(F("\r\n")))
      Serial.print(response.substring(0, response.length() - 2));
    else
      Serial.print(response);
    Serial.println(F("\"!"));
  }

  return result;
}

static String getLine(WiFiClient& client) {
  String result;

  if (client.connected())
    result = client.readStringUntil('\n');
//#ifndef NDEBUG
//  Serial.print(F("<<"));
//  Serial.println(result);
//#endif

  return result;
}

static void sendLine(WiFiClient& client, const String& str) {
//#ifndef NDEBUG
//  Serial.print(F(">>"));
//  Serial.println(str);
//#endif
  if (client.connected())
    client.println(str);
}

static String sendCommand(WiFiClient& client, const String& str) {
  sendLine(client, str);
  client.flush();

  return getLine(client);
}               

bool sendMail(char* smtpHost, uint16_t smtpPort, char* smtpUser, char* smtpPassword, char* mailTo, char* mailSubject, const String& mailMessage) {
  WiFiClientSecure client;
  String str;

// client.setTimeout(2000); // 15 sec. read timeout

  Serial.print(F("Connecting to "));
  Serial.println(smtpHost);
  yield();
  if (! client.connect(smtpHost, smtpPort)) {
    Serial.println(F("Connection failed!"));
    return false;
  }
  Serial.println(F("Connected OK..."));

  str = getLine(client);
  if (! checkResponse(str, 220, F("SMTP connection error")))
    return false;
  str = sendCommand(client, F("HELO esp8266.local"));
  if (! checkResponse(str, 250, F("SMTP HELO error")))
    return false;
  if (String(smtpPassword).length()) {
    str = sendCommand(client, F("AUTH LOGIN"));
    if (! checkResponse(str, 334, F("SMTP AUTH error")))
      return false;
    str = sendCommand(client, base64::encode(smtpUser));
    if (! checkResponse(str, 334, F("SMTP AUTH USER error")))
      return false;
    str = sendCommand(client, base64::encode(smtpPassword));
    if (! checkResponse(str, 235, F("SMTP AUTH PASS error")))
      return false;
  }
  str = F("MAIL FROM: <");
  str += smtpUser;
  str += '>';
  str = sendCommand(client, str);
  if (! checkResponse(str, 250, F("SMTP MAIL FROM error")))
    return false;
  str = F("RCPT TO: <");
  str += mailTo;
  str += '>';
  str = sendCommand(client, str);
  if (! checkResponse(str, 250, F("SMTP RCPT TO error")))
    return false;
  str = sendCommand(client, F("DATA"));
  if (! checkResponse(str, 354, F("SMTP DATA error")))
    return false;
  str = F("Subject: =?utf-8?B?");
  str += base64::encode(mailSubject);
  str += F("=?=");
  sendLine(client, str);
  sendLine(client, F("MIME-Version: 1.0"));
  sendLine(client, F("Content-type: text/plain; charset=utf-8"));
  str = F("From: <");
  str += smtpUser;
  str += '>';
  sendLine(client, str);
  str = F("To: <");
  str += mailTo;
  str += '>';
  sendLine(client, str);
  sendLine(client, "");
  sendLine(client, mailMessage);
  str = sendCommand(client, F("\r\n."));
  if (! checkResponse(str, 250, F("SMTP send error")))
    return false;
  sendCommand(client, F("QUIT"));
  Serial.println(F("Connect END..."));

  client.stop();

  return true;
}
вызов: sendMail(smtpHost, smtpPort, smtpUser, smtpPass, mailTo, Mail_Subj, Mail_Message)
Например:
Код:
String smtpHost = "smtp.mail.ru";
uint16_t smtpPort = 465;
String smtpUser = "12345@mail.ru";
String smtpPass = "12345pass";
String mailTo = "54321@yandex.ru";
Это проще вставить в проект, чем подключать библиотеки.

Работает на mail.ru yandex.ru и gmail.com
 

Вложения

Последнее редактирование:

Paul_B

Member
Если раньше при отправке ~50 обязательно происходила перезагрузка на этапе коннектинга к хосту, то сейчас уже работает 3 часа, отправлено более 150 сообщений и все ОК.
 

Алексей.

Active member
При DNS атаке, атакуемому на запрос разрешении доменного имени приходит ip адрес атакующего, атакуемый устанавливает, как он считает, защищенное соединение с хостом, получает цепочку сертификатов заканчивающуюся корневым сертификатом.
Атакующий присылает свой самодельный корневой сертификат.
Используя WiFiClientSecure можно проверить заранее известный fingerprint или установить доверенный CA и не доверять сертификату полученному от атакующего.
Драматизм ситуации в том, что корневые сертификаты иногда тухнут. Вопрос как обеспечить на есп обновление корневых сертификатов или fingerprint-ов.
 
Сверху Снизу