No.3ベストアンサー
- 回答日時:
SSL以前の問題ですね。
> while (1) {
> char buf[1024] = {0};
> if (SSL_read(ssl, buf, sizeof(buf)-1) <= 0)
> break;
> res += buf;
> }
よくこれでブロックしないですね。
SSL_readでタイムアウトして切断されるまで待たされて、タイムアウトした所でSSL_read < 0となってループを抜ける事になりそうですが。
このコードだと、POP3Sではなく普通にread/writeを使ってPOP3を話すプログラムを書いても動かないと思います。
もし、「ブロック???」と思うなら、次のページでも読んでみると良いでしょう。
http://msdn.microsoft.com/ja-jp/library/3tbz7kf5 …
まず、ブロッキングで書くとしたら、サーバーから返ってくる文字列をちゃんと確認して、CRLF (\r\n)が来ていた場合はループから抜けるようにしましょう。
例えばこんな感じ?
size_t crlf_pos;
while (1) {
char buf2[1024] = {0};
if ((crlf_pos = res.find("\r\n")) != string::npos || SSL_read(ssl, buf2, sizeof(buf2)-1) <= 0)
break;
res += buf2;
}
cout << res.substr(0, crlf_pos) << endl;
res.erase(0, crlf_pos + 2); // 2 = sizeof(CRLF)
あと、POP3の資料といえばこの2つですよね。
http://tools.ietf.org/html/rfc2595
http://tools.ietf.org/html/rfc1939
RFC2595はPOP3をどうやってSSLと一緒に使うかの解説で、#1さんの回答にあったSTLSが説明されています。RFC1939はPOP3そのものの解説です。
あと、SSLで安全な通信がしたかったら、certificateをセットして、CRLかOCSPかをチェックしてください。なりすまし対策がないSSLは見掛け倒しです。暗号化通信をしているかもしれませんが、誰と暗号化通信をしているかはわかりません。
#2の回答についてコメントです
> WSAAsyncSelect()でメッセージで通知して貰うようにして組んだことはありますが、
> FD_READで受信した後でSSL_read()しても何も読めない。という状況になったことはあります。
もしノンブロッキングなソケットが裏にあるとしたら、SSL_ERROR_WANT_READ / SSL_ERROR_WANT_WRITE をちゃんとハンドリングしないとダメですね。
http://www.openssl.org/docs/ssl/SSL_read.html
selectで読めると言われても、SSLのレベルでデータが読めるまでには何度も read/write を繰り返さないといけないことがありますので。
この回答への補足
ありがとうございます。
なんとか、サーバーとの通信が出来ました。
サーバからのレスポンス
+OK Gpop ready for requests from 203.138.226.165 yw8pf6263343pac.0
サーバからのレスポンス
+OK send PASS
サーバからのレスポンス
-ERR [AUTH] Username and password not accepted.
これは、USER と PASS が合っていないのでそうなっています。
Welcom まで来ました。
とりあえず修正したコードは以下のものです。
// SSLtest.cpp : コンソール アプリケーションのエントリ ポイントを定義します。
//
#include "stdafx.h"
#include <iostream>
#include <string>
#include <winsock2.h>
#include <conio.h>
#include <ctype.h>
#include "openssl\ssl.h"
#include "openssl\crypto.h"
#include "openssl\err.h"
#include "openssl\rand.h"
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "libeay32.lib")
#pragma comment(lib, "ssleay32.lib")
int main(void) {
WSADATA wsaData;
struct sockaddr_in server;
SOCKET sock;
std::string req; // リクエスト
std::string res; // レスポンス
std::string host_url = "pop.googlemail.com";
req = "";
SSL *ssl;
SSL_CTX *ctx;
// Winsockの設定
WSAStartup(MAKEWORD(2, 0), &wsaData);
sock = socket(AF_INET, SOCK_STREAM, 0);
server.sin_family = AF_INET;
server.sin_port = htons(995);
server.sin_addr.S_un.S_addr = inet_addr(host_url.c_str());
if (server.sin_addr.S_un.S_addr == 0xffffffff) {
struct hostent *host;
unsigned int **addrptr;
host = gethostbyname(host_url.c_str());
if (host == NULL) {
return 1;
}
addrptr = (unsigned int **)host->h_addr_list;
while (*addrptr != NULL) {
server.sin_addr.S_un.S_addr = *(*addrptr);
if (connect(sock, (struct sockaddr *)&server, sizeof(server)) == 0) {
break;
}
}
if (*addrptr == NULL) {
return 1;
}
}
else {
if (connect(sock, (struct sockaddr *)&server, sizeof(server)) != 0)
return 1;
}
SSL_load_error_strings();
SSL_library_init();
ctx = SSL_CTX_new(TLSv1_method());
if (ctx == NULL) {
return 1;
}
ssl = SSL_new(ctx);
if (ssl == NULL) {
return 1;
}
if (SSL_set_fd(ssl, sock) == 0) {
return 1;
}
RAND_poll();
while (RAND_status() == 0) {
unsigned short rand_ret = rand() % 65536;
RAND_seed(&rand_ret, sizeof(rand_ret));
}
if (SSL_connect(ssl) != 1) {
ERR_print_errors_fp(stderr);
return 1;
}
SSL_write(ssl, req.c_str(), req.length());
std::cout << "サーバからのレスポンス" << std::endl;
size_t crlf_pos;
while (1) {
char buf2[1024] = {0};
if ((crlf_pos = res.find("\r\n")) != std::string::npos || SSL_read(ssl, buf2, sizeof(buf2)-1) <= 0)
break;
res += buf2;
}
std::cout << res.substr(0, crlf_pos) << std::endl;
res.erase(0, crlf_pos + 2); // 2 = sizeof(CRLF)
std::cout << res << std::endl;
req = "USER ***********\r\n";
res = "";
SSL_write(ssl, req.c_str(), req.length());
std::cout << "サーバからのレスポンス" << std::endl;
while (1) {
char buf2[1024] = {0};
if ((crlf_pos = res.find("\r\n")) != std::string::npos || SSL_read(ssl, buf2, sizeof(buf2)-1) <= 0)
break;
res += buf2;
}
std::cout << res.substr(0, crlf_pos) << std::endl;
res.erase(0, crlf_pos + 2); // 2 = sizeof(CRLF)
std::cout << res << std::endl;
res = "";
req = "PASS *********\r\n";
SSL_write(ssl, req.c_str(), req.length());
std::cout << "サーバからのレスポンス" << std::endl;
while (1) {
char buf2[1024] = {0};
if ((crlf_pos = res.find("\r\n")) != std::string::npos || SSL_read(ssl, buf2, sizeof(buf2)-1) <= 0)
break;
res += buf2;
}
std::cout << res.substr(0, crlf_pos) << std::endl;
res.erase(0, crlf_pos + 2); // 2 = sizeof(CRLF)
std::cout << res << std::endl;
SSL_shutdown(ssl);
SSL_free(ssl);
SSL_CTX_free(ctx);
ERR_free_strings();
closesocket(sock);
WSACleanup();
return 0;
}
ありがとうございました。
ありがとうございました。
LIST も確認できました。
// SSLtest.cpp : コンソール アプリケーションのエントリ ポイントを定義します。
//
#include "stdafx.h"
#include <iostream>
#include <string>
#include <winsock2.h>
#include <conio.h>
#include <ctype.h>
#include "openssl\ssl.h"
#include "openssl\crypto.h"
#include "openssl\err.h"
#include "openssl\rand.h"
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "libeay32.lib")
#pragma comment(lib, "ssleay32.lib")
int main(void) {
WSADATA wsaData;
struct sockaddr_in server;
SOCKET sock;
std::string req; // リクエスト
std::string res; // レスポンス
std::string host_url = "pop.googlemail.com";
req = "";
SSL *ssl;
SSL_CTX *ctx;
// Winsockの設定
WSAStartup(MAKEWORD(2, 0), &wsaData);
sock = socket(AF_INET, SOCK_STREAM, 0);
server.sin_family = AF_INET;
server.sin_port = htons(995);
server.sin_addr.S_un.S_addr = inet_addr(host_url.c_str());
if (server.sin_addr.S_un.S_addr == 0xffffffff) {
struct hostent *host;
unsigned int **addrptr;
host = gethostbyname(host_url.c_str());
if (host == NULL) {
return 1;
}
addrptr = (unsigned int **)host->h_addr_list;
while (*addrptr != NULL) {
server.sin_addr.S_un.S_addr = *(*addrptr);
if (connect(sock, (struct sockaddr *)&server, sizeof(server)) == 0) {
break;
}
}
if (*addrptr == NULL) {
return 1;
}
}
else {
if (connect(sock, (struct sockaddr *)&server, sizeof(server)) != 0)
return 1;
}
SSL_load_error_strings();
SSL_library_init();
ctx = SSL_CTX_new(TLSv1_method());
if (ctx == NULL) {
return 1;
}
ssl = SSL_new(ctx);
if (ssl == NULL) {
return 1;
}
if (SSL_set_fd(ssl, sock) == 0) {
return 1;
}
RAND_poll();
while (RAND_status() == 0) {
unsigned short rand_ret = rand() % 65536;
RAND_seed(&rand_ret, sizeof(rand_ret));
}
if (SSL_connect(ssl) != 1) {
ERR_print_errors_fp(stderr);
return 1;
}
SSL_write(ssl, req.c_str(), req.length());
std::cout << "サーバからのレスポンス" << std::endl;
size_t crlf_pos;
while (1) {
char buf2[1024] = {0};
if ((crlf_pos = res.find("\r\n")) != std::string::npos || SSL_read(ssl, buf2, sizeof(buf2)-1) <= 0)
break;
res += buf2;
}
std::cout << res.substr(0, crlf_pos) << std::endl;
res.erase(0, crlf_pos + 2); // 2 = sizeof(CRLF)
std::cout << res << std::endl;
req = "USER ******\r\n";
res = "";
SSL_write(ssl, req.c_str(), req.length());
std::cout << "サーバからのレスポンス" << std::endl;
while (1) {
char buf2[1024] = {0};
if ((crlf_pos = res.find("\r\n")) != std::string::npos || SSL_read(ssl, buf2, sizeof(buf2)-1) <= 0)
break;
res += buf2;
}
std::cout << res.substr(0, crlf_pos) << std::endl;
res.erase(0, crlf_pos + 2); // 2 = sizeof(CRLF)
std::cout << res << std::endl;
res = "";
req = "PASS *******\r\n";
SSL_write(ssl, req.c_str(), req.length());
std::cout << "サーバからのレスポンス" << std::endl;
while (1) {
char buf2[1024] = {0};
if ((crlf_pos = res.find("\r\n")) != std::string::npos || SSL_read(ssl, buf2, sizeof(buf2)-1) <= 0)
break;
res += buf2;
}
std::cout << res.substr(0, crlf_pos) << std::endl;
res.erase(0, crlf_pos + 2); // 2 = sizeof(CRLF)
std::cout << res << std::endl;
res = "";
req = "LIST\r\n";
SSL_write(ssl, req.c_str(), req.length());
std::cout << "サーバからのレスポンス" << std::endl;
while (1) {
char buf2[1024] = {0};
if ((crlf_pos = res.find("\r\n")) != std::string::npos || SSL_read(ssl, buf2, sizeof(buf2)-1) <= 0)
break;
res += buf2;
}
std::cout << res.substr(0, crlf_pos) << std::endl;
res.erase(0, crlf_pos + 2); // 2 = sizeof(CRLF)
std::cout << res << std::endl;
SSL_shutdown(ssl);
SSL_free(ssl);
SSL_CTX_free(ctx);
ERR_free_strings();
closesocket(sock);
WSACleanup();
return 0;
}
No.2
- 回答日時:
>と同じことを、SSL_write と SSL_read を使ってやりたいのですがうまく出来ません。
send()とrecv()をSSL_write()とSSL_read()に置き換えるだけなんですけどね。
# もちろんその前にSSL接続に必要な準備とかありますが。
んで……ブロッキングモードでやっているんでしょうか?
ノンブロッキングモードでやっているんでしょうか?
WSAAsyncSelect()でメッセージで通知して貰うようにして組んだことはありますが、
FD_READで受信した後でSSL_read()しても何も読めない。という状況になったことはあります。
おそらく、受信した生パケットがSSLの電文を複合するのにサイズが足りなかった…のかも知れませんが。
普通にrecv()で戻り値が0なら切断された…という処理をすることになりますが…
SSL接続時の場合だとFD_READの後で読み出せるだけのデータが無いとか、SSLネゴシエーションのパケットを受信した為SSL_read()ではまだデータが無い。とかいうことも。
この回答への補足
ネットで探したものをテストしています。
// SSLtest.cpp : コンソール アプリケーションのエントリ ポイントを定義します。
//
#include "stdafx.h"
#include <iostream>
#include <string>
#include <winsock2.h>
#include <conio.h>
#include <ctype.h>
#include "openssl\ssl.h"
#include "openssl\crypto.h"
#include "openssl\err.h"
#include "openssl\rand.h"
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "libeay32.lib")
#pragma comment(lib, "ssleay32.lib")
int main(void) {
WSADATA wsaData;
struct sockaddr_in server;
SOCKET sock;
std::string req; // リクエスト
std::string res; // レスポンス
std::string host_url = "pop.googlemail.com";
req = "USER *****\r\n\r\n";
SSL *ssl;
SSL_CTX *ctx;
// Winsockの設定
WSAStartup(MAKEWORD(2, 0), &wsaData);
sock = socket(AF_INET, SOCK_STREAM, 0);
server.sin_family = AF_INET;
server.sin_port = htons(995);
server.sin_addr.S_un.S_addr = inet_addr(host_url.c_str());
if (server.sin_addr.S_un.S_addr == 0xffffffff) {
struct hostent *host;
unsigned int **addrptr;
host = gethostbyname(host_url.c_str());
if (host == NULL) {
return 1;
}
addrptr = (unsigned int **)host->h_addr_list;
while (*addrptr != NULL) {
server.sin_addr.S_un.S_addr = *(*addrptr);
if (connect(sock, (struct sockaddr *)&server, sizeof(server)) == 0) {
break;
}
}
if (*addrptr == NULL) {
return 1;
}
}
else {
if (connect(sock, (struct sockaddr *)&server, sizeof(server)) != 0)
return 1;
}
SSL_load_error_strings();
SSL_library_init();
ctx = SSL_CTX_new(TLSv1_method());
if (ctx == NULL) {
return 1;
}
ssl = SSL_new(ctx);
if (ssl == NULL) {
return 1;
}
if (SSL_set_fd(ssl, sock) == 0) {
return 1;
}
RAND_poll();
while (RAND_status() == 0) {
unsigned short rand_ret = rand() % 65536;
RAND_seed(&rand_ret, sizeof(rand_ret));
}
if (SSL_connect(ssl) != 1) {
ERR_print_errors_fp(stderr);
return 1;
}
SSL_write(ssl, req.c_str(), req.length());
std::cout << "サーバからのレスポンス" << std::endl;
while (1) {
char buf[1024] = {0};
if (SSL_read(ssl, buf, sizeof(buf)-1) <= 0)
break;
res += buf;
}
std::cout << res << std::endl;
res = "";
req = "PASS ******\r\n\r\n";
SSL_write(ssl, req.c_str(), req.length());
std::cout << "サーバからのレスポンス" << std::endl;
while (1) {
char buf2[1024] = {0};
if (SSL_read(ssl, buf2, sizeof(buf2)-1) <= 0)
break;
res += buf2;
}
std::cout << res << std::endl;
SSL_shutdown(ssl);
SSL_free(ssl);
SSL_CTX_free(ctx);
ERR_free_strings();
closesocket(sock);
WSACleanup();
return 0;
}
No.1
- 回答日時:
>POP3S での、サーバーとのやりとりについて
>解説してある資料を探しています。
POP3S用の特別なコマンドがあるワケではないので…探してもないんじゃないですかね?
・接続用の標準ポート番号が異なる。
・SSLで通信路が保護される。
だけで後の手順は通常のPOP3と一緒だったかと。
平文で接続して、途中からSSL通信に移行する。
とかいう場合はその限りではありませんが。
http://salt.iajapan.org/wpmu/anti_spam/admin/tec …
のSTLSコマンドとか。
コマンドラインでの操作
openssl s_client -connect pop.gmail.com:995
CONNECTED(00000003)
[※SSL接続の出力は省略]
---
+OK Gpop ready for requests from xxx.xx.xx.xxx x20xx1401750xxx
USER [俺のid]
+OK send PASS
PASS [俺のpass]
+OK Welcome.
LIST
+OK 5 messages (24576 bytes)
1 4699
2 4315
3 6260
と同じことを、SSL_write と SSL_read を使ってやりたいのですがうまく出来ません。
+OK Gpop ready for requests from xxx.xx.xx.xxx x20xx1401750xxx
のあと、動かなくなります。
出来ましたらアドバイスお願いいたします。
参考:
http://d.hatena.ne.jp/inuz/20070502/p1
http://www-cms.phys.s.u-tokyo.ac.jp/~naoki/CIPIN …
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- その他(ソフトウェア) PC上のOutlookでIMAPアクセス時の送信が出来ない。Android上では問題なし。 2 2022/09/28 11:22
- Gmail GmailでのPOPメールの保存先はどこなのか 3 2022/06/09 02:06
- サーバー active directory のユーザをローカルで使いたい 1 2023/07/22 07:40
- サーバー 接続・ログインはできているのにメールが送信できない 2 2022/06/27 15:03
- その他(メールソフト・メールサービス) 詐欺メールの量が酷い 3 2022/05/19 12:36
- サーバー メールサーバーについて詳しい方、メールサーバーの管理業務経験のある方、教えてください。 3 2022/11/12 18:24
- UNIX・Linux いつの間にか自宅サーバーが見れなくなっていた時のトラブルシューティング手順をご教示ください 4 2023/02/15 21:01
- Gmail 【お助け!】サーバーからのメール送信でGmailに送信されない問題について 1 2023/06/20 22:03
- Gmail SPFレコードとDNSサーバーについて、gmailを設定できるかどうか 2 2023/06/10 23:55
- Gmail 秀丸メール、2台のPCにセットしてあります。gmailのついて質問です。 1 2022/07/25 08:01
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
エクセル VBA でのCOMポート...
-
TCP/IP通信時のサーバーからの受信
-
Winsockで接続待ちタイムアウト...
-
ソケット通信 同じポート番号...
-
C#とTCP/IPを利用したサーバー...
-
相手のIPアドレスを取得する方法
-
ソケットプログラミングに関す...
-
VB6‥ソケットについて
-
ソケットのrecvの戻り値が0
-
ソケットのクローズについて
-
SIPがNATを越えられない理由
-
Javaプログラム同士のプロセス...
-
UdpClient 送信元のIPアドレ...
-
vbでの232c接続プログラムについて
-
VB6のwinsockでconnectできない
-
空きポートの取得方法
-
Linuxのsocket接続でacceptでき...
-
UDP通信におけるbind関数について
-
Winsockプログラムの初歩的質問...
-
どうか、POSTでのファイル転送...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
TCP/IP通信時のサーバーからの受信
-
recv関数でフリーズしてしまう
-
Winsockで接続待ちタイムアウト...
-
UDP通信におけるbind関数について
-
エクセル VBA でのCOMポート...
-
Socket通信の0バイト受信について
-
VB6のwinsockでconnectできない
-
ソケットのrecvの戻り値が0
-
ソケットを用いた1対多通信につ...
-
UdpClient 送信元のIPアドレ...
-
ソケットでクライアントのipア...
-
UDP通信する時に、相手にどうや...
-
ソケット通信 同じポート番号...
-
同じLAN内パソコンのIPアドレス...
-
Connectエラーが出てしまう・・...
-
ソケットのクローズについて
-
CreateFile関数でCOMポートが開...
-
異なる言語間でのソケット通信...
-
C言語でHTTP1.1のキープアライ...
-
送信したデータの一部が文字化...
おすすめ情報