2

我正在尝试与 SMTP 服务器进行简单连接(需要身份验证)。我使用 SSL(C 中的 OpenSSL 库)在端口 587 上连接到 smtp.live.com。

我首先使用 socket() 函数初始化我的套接字,然后使用 connect() 连接到服务器。然后我启动 SSL 通道,然后尝试登录。

这是我的外壳上的输出:

server : 220 BLU0-SMTP261.phx.gbl Microsoft ESMTP MAIL Service, Version: 6.0.3790.4675     ready at  Sat, 9 Mar 2013 07:25:17 -0800 

EHLO [127.0.0.1]
server : 250-BLU0-SMTP261.phx.gbl Hello [163.5.221.45]
250-TURN
250-SIZE 41943040
250-ETRN
250-PIPELINING
250-DSN
250-ENHANCEDSTATUSCODES
250-8bitmime
250-BINARYMIME
250-CHUNKING
250-VRFY
250-TLS
250-STARTTLS
250 OK

STARTTLS
server : 220 2.0.0 SMTP server ready

EHLO [127.0.0.1]
server : 250-BLU0-SMTP261.phx.gbl Hello [163.5.221.45]
250-TURN
250-SIZE 41943040
250-ETRN
250-PIPELINING
250-DSN
250-ENHANCEDSTATUSCODES
250-8bitmime
250-BINARYMIME
250-CHUNKING
250-VRFY
250-AUTH LOGIN PLAIN
250 OK

AUTH LOGIN
server : 334 VXNlcm5hbWU6

Y2hlcmGhvdXXXXXXXXXXXuY29tXHJcbg0K
serveur : 
U2hsYWXXXXXXXXXXXwblxyXG4NCg0K
server : 

如您所见,用户名和密码均采用 base64 编码(不带 \r\n)。我不明白为什么服务器不回答任何事情......(我试图在读取套接字之前放置一个 sleep() ,但我得到了相同的结果)

连接服务器的代码:

static int              _connect_IPV4(int socket, struct hostent *host)
{
  struct sockaddr_in    addr;

  addr.sin_port = htons(587);
  addr.sin_family = AF_INET;
  addr.sin_addr = *(struct in_addr *)host->h_addr;
  bzero(&addr.sin_zero, 8);
  if (connect(socket, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) == -1)
    printf("%s\n", strerror(errno));
  else
    return (socket);
}

启动 SSL 的代码:

static void     _launch_ssl(int socket)
{
  read_socket(socket);
  write_socket(socket, "EHLO [127.0.0.1]\r\n");
  read_socket(socket);
  write_socket(socket, "STARTTLS\r\n");
  read_socket(socket);
}

连接 SSL 的代码:

connection      *ssl_connect()
{
  connection    *c;

  c = malloc(sizeof(connection));
  c->ssl_handle = NULL;
  c->ssl_context = NULL;
  c->socket = connect_TCP_IP();
  _launch_ssl(c->socket);
  if (c->socket != -1)
    {
      SSL_load_error_strings();
      SSL_library_init();

      SSL_CTX_new(SSLv23_client_method());
      SSL_new(c->ssl_context);
      SSL_set_fd(c->ssl_handle, c->socket);
      SSL_connect(c->ssl_handle);
    }
  return (c);
}

主要的 :

int             main()
{
  connection    *c;

  c = ssl_connect();
  ssl_write_socket(c, "EHLO [127.0.0.1]\r\n");
  ssl_read_socket(c);
  ssl_write_socket(c, "AUTH LOGIN\r\n");
  ssl_read_socket(c);
  ssl_write_socket(c, "Y2hlcmNoZXN0b3lhQGhvdG1haWwuY29tXHJcbg0K");
  printf("\n");
  ssl_read_socket(c);
  ssl_write_socket(c, "U2hsYWdldHRvUHIwblxyXG4NCg0K");
  printf("\n");
  ssl_read_socket(c);
}
4

1 回答 1

1

首先,我希望您打算改进您的客户端,以便它真正对服务器发送的内容做出反应。例如,看起来在您的_launch_ssl函数中,您实际上并没有检查服务器的回复,EHLO以确保STARTTLS在您尝试使用它之前将其作为选项提供。该函数的伪代码应该是:

  1. 发送 EHLO(最好不要使用 [127.0.0.1] 之类的无意义的东西!)
  2. 检查服务器的回复
  3. 如果 STARTTLS 不在提供的选项中,则保释
  4. 如果 STARTTLS 是提供的选项之一,请发送 STARTTLS 并继续。

同样,在 中main(),您需要检查EHLO服务器是否实际响应了 250,然后检查AUTH服务器是否实际响应了 334。

否则,问题似乎是您\r\n在回复后没有发送。换句话说:

ssl_write_socket(c, "Y2hlcmNoZXN0b3lhQGhvdG1haWwuY29tXHJcbg0K");

应该:

ssl_write_socket(c, "Y2hlcmNoZXN0b3lhQGhvdG1haWwuY29tXHJcbg0K\r\n");

此外,您的 base64 字符串包含嵌入\\r\\n\r\n字符串中的(反斜杠 + 'r' + 反斜杠 + 'n' + CR + LF) ,就好像它们是用户名的一部分一样。假设这是错误的,那么实际上,您的代码可能实际上应该是:\\r\\n\r\n

ssl_write_socket(c, "Y2hlcmNoZXN0b3lhQGhvdG1haWwuY29t\r\n");
于 2013-03-09T16:17:35.410 回答