SSL_connect 在 c++ 中失败但我可以通过 python 连接
我想使用套接字向 api 发送请求。
我知道该服务正在运行,因为 python 中的遗留代码可以正常工作。请参阅下面的摘录:
class SocketConnection:
def __init__(self, payload, host):
self.payload = payload
self.host = host
self.sock = None
self.response_text = {}
self.status_code = None
self.full_resp = ""
def connect(self):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
context = ssl.create_default_context()
sock = context.wrap_socket(sock, server_hostname=self.host)
sock.connect((self.host, 443))
self.sock = sock
def send(self):
self.sock.send(self.payload)
def receive(self):
self.full_resp = self.sock.recv(4096).decode("utf-8")
self.response_text = [self.full_resp]
self.status_code = self.full_resp[9:12]
self.sock.close()
我有以下 C++ 代码,它总是会成功找到它可以连接到的地址,但永远找不到通过 SSL_connect 的地址。 SSL_get_error 返回 1。
array<struct addrinfo*, 2> get_valid_addrinfo(string s) {
struct addrinfo *res;
struct addrinfo hints;
memset(&hints, '\0', sizeof(hints));
hints.ai_socktype = SOCK_STREAM;
hints.ai_family = AF_INET;
hints.ai_flags = AI_ADDRCONFIG;
int e = getaddrinfo(s.c_str(), "https", &hints, &res);
if (e != 0) {
printf("failure %s\n", gai_strerror (e));
assert(-1);
}
int sock = -1;
struct addrinfo *r ;
SSL_CTX * ctx = make_ssl_context();
SSL * ssl;
for (r = res; r != NULL; r = r->ai_next) {
sock = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
if (sock != -1 && connect(sock, r->ai_addr, r->ai_addrlen) == 0) {
free(ssl);
ssl = SSL_new(ctx);
SSL_set_fd(ssl, sock);
if (SSL_connect(ssl) != -1)
break;
}
if (sock != -1) {
close(sock);
sock = -1;
}
}
assert(sock != -1);
close(sock);
free(ssl);
SSL_CTX_free(ctx);
return {res, r};
}
我使用的是 debian 10。
我做错了什么?
I want to send a request to an api using a socket.
I know the service is running as the legacy code in python works. See an excerpt below:
class SocketConnection:
def __init__(self, payload, host):
self.payload = payload
self.host = host
self.sock = None
self.response_text = {}
self.status_code = None
self.full_resp = ""
def connect(self):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
context = ssl.create_default_context()
sock = context.wrap_socket(sock, server_hostname=self.host)
sock.connect((self.host, 443))
self.sock = sock
def send(self):
self.sock.send(self.payload)
def receive(self):
self.full_resp = self.sock.recv(4096).decode("utf-8")
self.response_text = [self.full_resp]
self.status_code = self.full_resp[9:12]
self.sock.close()
I have the following C++ code which will always succeed in finding an address it can connect to, but can never find one that passes SSL_connect. SSL_get_error returns 1.
array<struct addrinfo*, 2> get_valid_addrinfo(string s) {
struct addrinfo *res;
struct addrinfo hints;
memset(&hints, '\0', sizeof(hints));
hints.ai_socktype = SOCK_STREAM;
hints.ai_family = AF_INET;
hints.ai_flags = AI_ADDRCONFIG;
int e = getaddrinfo(s.c_str(), "https", &hints, &res);
if (e != 0) {
printf("failure %s\n", gai_strerror (e));
assert(-1);
}
int sock = -1;
struct addrinfo *r ;
SSL_CTX * ctx = make_ssl_context();
SSL * ssl;
for (r = res; r != NULL; r = r->ai_next) {
sock = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
if (sock != -1 && connect(sock, r->ai_addr, r->ai_addrlen) == 0) {
free(ssl);
ssl = SSL_new(ctx);
SSL_set_fd(ssl, sock);
if (SSL_connect(ssl) != -1)
break;
}
if (sock != -1) {
close(sock);
sock = -1;
}
}
assert(sock != -1);
close(sock);
free(ssl);
SSL_CTX_free(ctx);
return {res, r};
}
I'm on debian 10.
What am I doing wrong?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
在尝试修复代码之前,您应该向其添加一些适当的错误报告,这样您就不会在黑暗中进行尝试。当 OpenSSL 调用失败时,您可以执行以下操作:
然后按照您的意愿报告错误。
我发现
ERR_error_string
返回的字符串特别有用,事实上 OpenSSL 维护着一个称为“错误堆栈”的东西,因此您应该循环ERR_get_error
直到它返回零(或者,如果您只想报告第一个错误,则可以调用ERR_clear_error
,但在继续之前以某种方式清除错误堆栈非常重要)。如果您浏览文档,您可以阅读所有这些内容。我看到 Steffen 刚刚回答了您的其他问题,所以我不需要再写任何内容 :) 但我确实知道像 Cloudflare 这样的云服务提供商需要这个。
Before you try to fix your code, you should add some proper error reporting to it so that you're not shooting in the dark. When an OpenSSL call fails, you can do:
And then report the error however you wish.
I find the string returned by
ERR_error_string
particularly useful, and in fact OpenSSL maintains something called an 'error stack', so you should loop onERR_get_error
until it returns zero (or, if you only want to report the first error, you can callERR_clear_error
instead, but it's important to clear the error stack one way or another before you move on). If you browse the docs, you can read up on all this stuff.And I see that Steffen has just answered your other query, so I don't need to write anything more :) I do know however that cloud service providers like Cloudflare need this.