一、我们用应对HTTP的策略来应对HTTPS一定是行不通的,HTTPS除了与服务器进行基本的连接以后,还需要与服务器进行一个安全认证,只连接不认证是无法获取到资源的。认证基于连接,先连接再认证。
二、OPEN_SEEL库
1、我们需要第三方OPEN_SEEL库来帮助我们认证。
openssl安装
sudo apt-get install libssl-doc #openssl文档
sudo apt-get install libssl-dev #openssl库
2、使用openssl编译时需要链接库
gcc *.c -I../include -lssl -lcrypto -o app
3、头文件
#include <openssl/ssl.h>
#include <openssl/err.h>
4、相关接口
SSL * sslsocket; //安全套接字 可以简单理解为webfd的升级版
SSL_CTX * sslctx; //安全认证上下文(保存了安全认证过程)
先创建上下文信息,然后用上下文去生成安全套接字。
SSL_load_error_strings(); //初始化加载openssl错误处理函数
SSL_library_init(); //初始化openssl库
OpenSSL_add_ssl_algorithms(); //初始化散列函数 (初始化加密方式)
SSL_CTX * sslctx = SSL_CTX_new(版本信息); //new安全认证上下文
版本信息 = SSLv23_method();(有很多,这只是其中之一)
SSL * sslsocket = SSL_new(sslctx) //使用认证上下文信息创建安全套接字
SSL_set_fd(sslsocket , webfd); //用已连接成功的webfd对sslsocket进行服务端关联设置,让sslsocket可以访问服务端
SSL_connect(sslsocket) //与https服务端完成安全认证 , 认证成功可以交互数据
//SSL提供了读写模块,加密解密读写
SSL_read(SSL * sslsocket , cosnt char * buffer , ssize_t rsize);
SSL_write(SSL * sslsocket , char * buffer , ssize_t wsize);
RETURN VALUE: 成功返回读到的数据量, 读取完毕返回0 , 失败返回-1。
5、改造下载模块,区分HTTP和HTTPS
//下载模块,发送请求,接收并处理响应 , 如果ssl为NULL表示http交互方式,否则https交互方式 。
int spider_response_download(int , char * , url_t * , ssl_t *);
#include<SPIDER.h>
int spider_response_download(int webfd , const char* req_head , url_t* node , ssl_t* ssl)
{
char buffer[8192];
char res_head[4096];
int rsize;
char *pos = NULL;
int fd;
bzero(buffer,sizeof(buffer));
bzero(res_head,sizeof(res_head));
if(!ssl)
{
send(webfd,req_head,strlen(req_head),0);
printf("[5] HTTP Request_head Send To Webserver Successfully...\n");
rsize = recv(webfd,buffer,sizeof(buffer),0);
if((pos = strstr(buffer,"\r\n\r\n")) == NULL)
{
printf("spider_response_download strstr not found..\n");
return -1;
}
snprintf(res_head,pos - buffer + 4,"%s",buffer);
printf("[6] HTTP Get Response Head Successfully :\n%s",res_head);
fd = open(node->save_file,O_RDWR|O_CREAT,0775);
write(fd,pos + 4,rsize - (pos - buffer + 4));
while((rsize = recv(webfd,buffer,sizeof(buffer),0)) > 0){
write(fd,buffer,rsize);
bzero(buffer,sizeof(buffer));
}
printf("[7] HTTP Download Successfully...\n");
return 0;
}
else
{
SSL_write(ssl->sslsocket,req_head,strlen(req_head));
printf("[5] HTTPS Request_head Send To Webserver Successfully...\n");
rsize = SSL_read(ssl->sslsocket,buffer,sizeof(buffer));
if((pos = strstr(buffer,"\r\n\r\n")) == NULL)
{
printf("spider_response_download strstr not found..\n");
return -1;
}
snprintf(res_head,pos - buffer + 4,"%s",buffer);
printf("[6] HTTPS Get Response Head Successfully :\n%s",res_head);
fd = open(node->save_file,O_RDWR|O_CREAT,0775);
write(fd,pos + 4,rsize - (pos - buffer + 4));
while((rsize = SSL_read(ssl->sslsocket,buffer,sizeof(buffer))) > 0)
{
write(fd,buffer,rsize);
bzero(buffer,sizeof(buffer));
}
printf("[7] HTTPS Download Successfully...\n");
free(ssl);
ssl = NULL;
return 0;
}
close(fd);
close(webfd);
return -1;
}
6、添加安全认证模块
typedef struct{
SSL * sslsocket; //安全套接字
SSL_CTX * sslctx; //安全认证上下文
}ssl_t;
//安全认证过程 基于连接
ssl_t * spider_openssl_create(int);
#include<SPIDER.h>
ssl_t* spider_openssl_create(int webfd)
{
ssl_t *ssl = NULL;
if((ssl = (ssl_t*)malloc(sizeof(ssl_t)))== NULL) //申请空间
{
perror("openssl_create malloc ssl error");
return NULL;
}
SSL_load_error_strings();
SSL_library_init();
OpenSSL_add_ssl_algorithms();
ssl->sslctx = SSL_CTX_new(SSLv23_method()); //生成安全认证上下文
ssl->sslsocket = SSL_new(ssl->sslctx); //生成安全套接字
SSL_set_fd(ssl->sslsocket,webfd); //与连接好的webfd进行关联
SSL_connect(ssl->sslsocket); //安全认证
printf("------openssl connect succefffully!------\n");
return ssl;
}
其余模块没有发生改动,不再赘述。
7、主函数
#include<SPIDER.h>
int main()
{
const char *turl ="https://seopic.699pic.com/photo/40202/3604.jpg_wh1200.jpg";
url_t node;
char req_head[4096];
ssl_t* ssl = NULL;
strcpy(node.alpha_url,turl);
int webfd = spider_net_init();
spider_analytical_url(&node);
spider_connect_webserver(webfd,&node);
spider_create_request_head(req_head,&node);
if(node.http_type)
ssl = spider_openssl_create(webfd);
spider_response_download(webfd , req_head, &node,ssl);
return 0;
}
注:编译时切记链入库,否则会提醒缺少库,或者不识别函数。