• https下载图片


    OpenSSL用法示例

    OpenSSL源码安装

    对于ubuntu,懒得编译源码可以直接安装

    sudo apt-get install libssl–dev

      /usr/include/openssl/ssl.h

    CMakeLists中添加  

    link_libraries(ssl crypto)

    apt-get安装不需要再制定libssl.a, libcrypto.a的路径了, 就像用libc标准库一样。源码安装要指定-L/path/to/libssl.a或者-L/path/to/libssl.so , -lssl。客户端不需要生成证书。

    sale.txt

    1. GET /uploadfile/photo/20231022/37cac8bc693780b740b4e659846689cd.jpg HTTP/1.1
    2. Accept: image/jpeg,image/avif,image/webp,image/apng,*/*
    3. Accept-Encoding: gzip, deflate
    4. Accept-Language: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7,ja;q=0.6
    5. Connection: keep-alive
    6. Host: img.sx2737.com
    7. Upgrade-Insecure-Requests: 1
    8. User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36

    * main.c

    1. #include
    2. /* ... */
    3. #include "https.h"
    4. static int get_host_ip(char ip[], char hostname[]) {
    5. struct ipv4head ipv4List;
    6. struct ipv4_entry *n1;
    7. int count = 0;
    8. /* get ip by Gateway 10.0.0.1 */
    9. bcl_dns_query(&ipv4List, hostname, "10.0.0.1");
    10. while(!TAILQ_EMPTY(&ipv4List)) {
    11. n1 = TAILQ_FIRST(&ipv4List);
    12. TAILQ_REMOVE(&ipv4List, n1, entries);
    13. printf("ip=%s\n", n1->data);
    14. strncpy(ip, n1->data, 16);
    15. free(n1);
    16. count += 1;
    17. }
    18. return count;
    19. }
    20. int main(int argc, char *argv[]) {
    21. char path_dst[256];
    22. char path_src[256];
    23. char hostname[32] = {'\0'};
    24. char ip[16] = {'\0'};
    25. int sockfd = -1;
    26. bclerrinit();
    27. strcpy(path_src, "/mnt/e/CLionProjects/arp/fap30/input/sale.txt");
    28. strcpy(path_dst, "/mnt/e/CLionProjects/arp/fap30/print/sale.jpg");
    29. strcpy(hostname, "img.sx2737.com"); /* octipus.net, www.google.co.il */
    30. get_host_ip(ip, hostname);
    31. printf("path_dst=%s\n", path_dst);
    32. if (E_FAIL == https_get_body(ip,path_src, path_dst)) {
    33. bclerrlog(E_SOCKFD_RECV, _FL_, "https_get_body(%s,%s,%s)",ip,path_src,path_dst);
    34. return E_FAIL;
    35. }
    36. bclerrend();
    37. return E_OK;
    38. }

    网关直接固定写的10.0.0.1, 需要改。或者再实现一个拿到网关Gateway IP地址的函数 查DNS

    DNS没做缓存,简化版测试查询DNS发UDP包。 一个域名对应多个ip,也不知道多少个ip,用的/usr/include/x86_64-linux-gnu/sys/queue.h  参照下面的bcl_udp.h

    #include

    * https.h

    1. #ifndef ARP_TEST_HTTPS_H
    2. #define ARP_TEST_HTTPS_H
    3. #include /* SSL_Library_init() */
    4. #include
    5. int https_get_body(char *ip, char *in_path, char *out_path);
    6. #endif //ARP_TEST_HTTPS_H

    * https.c

    1. /*
    2. * @ref: https://aticleworld.com/ssl-server-client-using-openssl-in-c/
    3. * sudo apt-get install libssl–dev
    4. * -L/path/to/ssl_dir -lssl -lcrypto
    5. */
    6. #include /* memset */
    7. /* ... */
    8. #include "https.h"
    9. extern unsigned int ip2int(const char *ip);
    10. static SSL_CTX *InitCTX(void) {
    11. SSL_METHOD *method;
    12. SSL_CTX *ctx;
    13. OpenSSL_add_all_algorithms(); /* Load cryptos, et.al. */
    14. SSL_load_error_strings(); /* Bring in and register error messages */
    15. method = TLSv1_2_client_method(); /* Create new client-method instance */
    16. ctx = SSL_CTX_new(method); /* Create new context */
    17. if ( ctx == NULL ) {
    18. ERR_print_errors_fp(stderr);
    19. abort();
    20. }
    21. return ctx;
    22. }
    23. ssize_t send_from_file_ssl(SSL *ssl, char *path) {
    24. byte_t *buf = NULL;
    25. size_t isz = 0;
    26. ssize_t outBytes;
    27. buf = file_get_contents(path, &isz);
    28. outBytes = SSL_write(ssl, buf, isz);
    29. /* bcl_xxd(buf, isz); */
    30. free(buf);
    31. return outBytes;
    32. }
    33. int https_get_body(char *ip, char *in_path, char *out_path) {
    34. SSL_CTX *ctx = NULL;
    35. SSL *ssl;
    36. int bytes;
    37. #define HTTPS_BUFF_SIZE 4096
    38. char buf[HTTPS_BUFF_SIZE];
    39. int sockfd = -1;
    40. FILE *out = NULL;
    41. SSL_library_init();
    42. ctx = InitCTX();
    43. ssl = SSL_new(ctx); /* create new SSL connection state */
    44. sockfd = bcl_tcp_connector(ip2int(ip), 443);
    45. SSL_set_fd(ssl, sockfd); /* attach the socket descriptor */
    46. if ( SSL_connect(ssl) < 0 ) { /* perform the connection */
    47. ERR_print_errors_fp(stderr);
    48. return E_FAIL;
    49. }
    50. send_from_file_ssl(ssl, in_path);
    51. bytes = SSL_read(ssl, buf, HTTPS_BUFF_SIZE);
    52. /* Dump HTTP header */
    53. bcl_xxd(buf, bytes);
    54. out = fopen(out_path, "w");
    55. if (NULL == out) {
    56. bclerreg(E_OSCALL, _FL_, "fopen(%s)", out_path);
    57. return E_FAIL;
    58. }
    59. while (0<(bytes = SSL_read(ssl, buf, HTTPS_BUFF_SIZE))) {
    60. fwrite(buf, 1, bytes, out);
    61. memset(buf, 0, bytes);
    62. }
    63. fclose(out);
    64. bcl_closesock(sockfd);
    65. SSL_free(ssl);
    66. SSL_CTX_free(ctx);
    67. return E_OK;
    68. }

    先准备ssl需要的库, SSL_Libary_init(), 创建SSL_CTX *ctx对象   

    封装socket fd为SSL *, 操作SSL *取代 int fd。SSL_read替换recv, SSL_write替换send

    close(fd)关闭socket fd。用完SSL_free(ssl),  释放https链接。销毁SSL_CTX *ctx对象 

    SSL_read第0次调用拿到http header,再调用得到的是http body。不需要手动解析http \r\n 0x0d 0x0a, 也省了很多麻烦。

    1. int bcl_tcp_connector(u_int32_t _addr, u_int16_t _port) {
    2. struct sockaddr_in saddr;
    3. int sock;
    4. int ret;
    5. for (;;) {
    6. sock = socket(AF_INET, SOCK_STREAM, 0);
    7. if (sock <0) {
    8. /* ... */
    9. return E_FAIL;
    10. }
    11. memset(&saddr, 0x00, sizeof (saddr));
    12. saddr.sin_family = AF_INET;
    13. saddr.sin_addr.s_addr = _addr;
    14. saddr.sin_port = htons(_port);
    15. ret = connect(sock, (struct sockaddr *)&saddr, sizeof(saddr));
    16. if (ret >= 0) {
    17. return sock;
    18. }
    19. /* ERROR connect */
    20. if (errno == EINTR) {
    21. bcl_closesock(sock);
    22. continue;
    23. }
    24. char ip[16];
    25. bcl_int2ip(ip, _addr);
    26. bclerreg(E_OSCALL, _FL_, "Error connect %s:%d", ip, _port);
    27. return E_FAIL;
    28. }
    29. }

    创建socket fd,调用connect,常规方法。 

    bcl_xxd函数hexdump调试用

    1. uint8_t arc_xxd(byte *s, uint8_t len, void *param);
    2. void bcl_xxd(const void *s, size_t len)
    3. {
    4. uint16_t line = 0;
    5. byte *t = (byte *)s;
    6. uint8_t b;
    7. size_t left = len;
    8. for (; ;) {
    9. if (left > 16) {
    10. b = arc_xxd(t, 16, &line);
    11. } else {
    12. b = arc_xxd(t, left, &line);
    13. }
    14. if (b < 1) {break;}
    15. left -= b;
    16. if (left <= 0) {break;}
    17. t += b;
    18. }
    19. }
    20. uint8_t arc_xxd(byte *s, uint8_t len, void *param)
    21. {
    22. uint8_t i;
    23. uint16_t *line = (uint16_t *)param;
    24. fprintf(stdout, "%08x:", *line << 4);
    25. for (i = 0; i+2 < len; i+=2) {
    26. fprintf(stdout, " %02x%02x", s[i], s[i+1]);
    27. }
    28. if (i fprintf(stdout, " %02x", s[i]); i+= 1;}
    29. if (i fprintf(stdout, "%02x", s[i]); i+=1;}
    30. if (i < 16 && 0x00 != (i & 0x01)) { fputs(" ", stdout); i+=1;}
    31. for (; i <16; i+= 2) {
    32. fputs(" ", stdout); /* space * 5 */
    33. }
    34. fputs(" ", stdout);
    35. for (i = 0; i
    36. if (s[i] <0x20 || s[i] > 0x7e) {
    37. fputc('.', stdout);
    38. } else {
    39. fputc(s[i], stdout);
    40. }
    41. }
    42. fputs("\r\n", stdout);
    43. *line += 1;
    44. return i;
    45. }

    * bcl_udp.h

    1. #ifndef ERRLOG_BCL_UDP_H
    2. #define ERRLOG_BCL_UDP_H
    3. #include
    4. typedef union {
    5. unsigned char c[4];
    6. unsigned int addr;
    7. } IPv4_t;
    8. void IPv4_toString(char *s, IPv4_t ipv4);
    9. /* in_addr_t */ unsigned int ip2int(const char *ip);
    10. struct ipv4_entry {
    11. char data[16];
    12. TAILQ_ENTRY(ipv4_entry) entries;
    13. };
    14. TAILQ_HEAD(ipv4head, ipv4_entry);
    15. int bcl_dns_query(struct ipv4head *head, char *host_name, const char *dns_ip);
    16. #endif //ERRLOG_BCL_UDP_H

    * bcl_udp.c

    1. #ifdef __cplusplus
    2. extern "C" {
    3. #endif
    4. #include /* bzero */
    5. #include /* inet_addr */
    6. #include /* close */
    7. #include /* strcat, memset */
    8. #include /* getenv(), rand() */
    9. #include "bcl_udp.h"
    10. #include "arclog.h"
    11. #include "bcl_socket.h"
    12. #define PRIVATE static
    13. unsigned int /* in_addr_t */ip2int(const char *ip) {
    14. IPv4_t un;
    15. int i, j;
    16. un.c[0] = un.c[1] = un.c[2] = un.c[3] = 0;
    17. for (i = 0, j = 0; i < 16 && ip[i] != '\0'; i++) {
    18. if (0x30 <= ip[i] && ip[i] < 0x3a) { /* '0','9' */
    19. un.c[j] *= 10;
    20. un.c[j] += ip[i] - 0x30;
    21. } else if (ip[i] == 0x2e) { /* '.' */
    22. j += 1;
    23. }
    24. }
    25. return un.addr;
    26. }
    27. typedef struct {
    28. u_short transId; /* 0xb6f6 */
    29. u_short flags; /* 0x0100 Standard query */
    30. u_short questions; /* 0x0001 */
    31. u_char rss[6]; /* 00 00 00 00 00 00 */
    32. } DnsHdr_t;
    33. #define HOST_LEN 64
    34. typedef struct {
    35. u_char name[2]; /* ptr */
    36. u_short type; /* 0x0005 alias */
    37. u_short in; /* 0x0001 */
    38. u_int32_t ttl; /* 81, 1min21s */
    39. u_short dataLen; /* 0x0017, 23 */
    40. char cname[HOST_LEN]; /* 3www31633com8163jiasu3com */
    41. } __attribute__((packed)) DnsAnswer_t;
    42. /**
    43. * @ref: https://www.linuxquestions.org/questions/linux-networking-3/dns-packet-structure-289886/
    44. * @param name "p3-sign.douyinpic.com"
    45. * @param entry "7p3-sign9douyinpic3com"
    46. * @return
    47. */
    48. PRIVATE char *dns_entry(char *entry, const char *name) {
    49. const char *p = name;
    50. char *q = entry;
    51. int8_t len;
    52. while ('\0' != *p) {
    53. len = 0;
    54. for (; *p && *p != '.'; p++) {
    55. len += 1;
    56. }
    57. *q++ = len;
    58. memcpy(q, p - len, len);
    59. q += len;
    60. p++;
    61. }
    62. return q;
    63. }
    64. #define SWAP(a, b, type) do { type _t = a; a = b; b = _t;} while(0);
    65. #define REVERSE(a, b, type) do { \
    66. type *p = a, *q = b; \
    67. type t; \
    68. if (p > q) { SWAP(p, q, type *);} \
    69. for (; p < q; p++, q--) { \
    70. t = *p; \
    71. *p = *q; \
    72. *q = t; \
    73. } \
    74. } while (0);
    75. void IPv4_toString(char *s, IPv4_t ipv4) {
    76. int i;
    77. char *t;
    78. #ifdef __ORDER_LITTLE_ENDIAN__
    79. for (i = 0; i < 4; i++) {
    80. #else
    81. for (i = 3; 0 <= i; i--) {
    82. #endif
    83. t = s;
    84. while (ipv4.c[i]) {
    85. *s++ = ipv4.c[i] % 10 + 0x30;
    86. ipv4.c[i] /= 10;
    87. }
    88. REVERSE(s-1, t, char);
    89. *s++ = '.';
    90. }
    91. *(s-1) = '\0';
    92. }
    93. int bcl_dns_query(struct ipv4head *head, char *host_name, const char *dns_ip) {
    94. int sockfd;
    95. char buf[1024] = {'\0'};
    96. struct sockaddr_in dest_addr;
    97. DnsHdr_t header;
    98. char *p = NULL;
    99. off_t queryLen;
    100. DnsAnswer_t ans;
    101. IPv4_t ipv4;
    102. struct ipv4_entry *n1 = NULL;
    103. sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    104. if (sockfd < 0) {
    105. bclerreg(E_OSCALL, _FL_, "socket() UDP");
    106. return E_FAIL;
    107. }
    108. /* DNS address */
    109. memset(&dest_addr, 0, sizeof(struct sockaddr_in));
    110. dest_addr.sin_family = AF_INET;
    111. dest_addr.sin_addr.s_addr = ip2int(dns_ip);
    112. dest_addr.sin_port = htons(53); /* DNS port 53 */
    113. if (connect(sockfd, (const struct sockaddr *) &dest_addr, sizeof(dest_addr)) < 0) {
    114. bclerreg(E_OSCALL, _FL_, "connect()");
    115. return E_FAIL;
    116. }
    117. /* DNS query packet */
    118. header.transId = (u_short) rand();
    119. header.flags = htons(0x0100);
    120. header.questions = htons(0x0001);
    121. memset(header.rss, 0, sizeof(header.rss));
    122. memcpy(buf, &header, sizeof(header));
    123. p = buf + sizeof(header);
    124. /* queries: p3-sign.douyinpic.com */
    125. p = dns_entry(p, host_name);
    126. *p++ = '\0';
    127. /* type A, class IN */
    128. *p++ = 0x00; *p++ = 0x01;
    129. *p++ = 0x00; *p++ = 0x01;
    130. queryLen = p - buf;
    131. if (send(sockfd, buf, queryLen, 0) < 0) {
    132. bclerreg(E_OSCALL, _FL_, "send()");
    133. return E_FAIL;
    134. }
    135. memset(buf, 0, 1024);
    136. if (recv(sockfd, buf, 1024, 0) < 1) {
    137. bclerreg(E_OSCALL, _FL_, "recv()");
    138. return E_FAIL;
    139. }
    140. p = buf + queryLen;
    141. /* Answers: buf + queryLen */
    142. TAILQ_INIT(head);
    143. while (*p != 0x00) {
    144. /* bcl_xxd(p, 0xa0); */
    145. if (*(u_char *)p == 0xc0) {
    146. /* c0 0c, c0 14 */
    147. ans.dataLen = ntohs(((DnsAnswer_t *)p)->dataLen);
    148. }
    149. #if DEBUG
    150. printf("dataLen=%d\n", ans.dataLen);
    151. bcl_xxd(((DnsAnswer_t *)p)->cname, ans.dataLen);
    152. #endif
    153. if (4 == ans.dataLen) { /* IPv4 */
    154. memcpy(&ipv4, &((DnsAnswer_t *)p)->cname, 4);
    155. n1 = (struct ipv4_entry *)malloc(sizeof(struct ipv4_entry));
    156. IPv4_toString(n1->data, ipv4);
    157. TAILQ_INSERT_TAIL(head, n1, entries);
    158. }
    159. p += sizeof(DnsAnswer_t) - HOST_LEN + ans.dataLen;
    160. }
    161. return E_OK;
    162. }
    163. #ifdef __cplusplus
    164. };
    165. #endif

    查询DNS以上

    C:\Windows\system32\wsl.exe --distribution Ubuntu --exec /bin/bash -c "export ESWTDIR=/mnt/e/CLionProjects/arp && export FAPWORKDIR=/mnt/e/CLionProjects/arp/fap30 && cd /mnt/e/CLionProjects/arp/fap30 && /mnt/e/CLionProjects/arp/cmake-build-debug/arp_test ./input/banner.txt banner_3.jpg"
    ip=61.164.142.245
    ip=115.231.71.216
    path_dst=/mnt/e/CLionProjects/arp/fap30/print/sale.jpg
    00000000: 4854 5450 2f31 2e31 2032 3030 204f 4b0d  HTTP/1.1 200 OK.
    00000010: 0a4c 6173 742d 4d6f 6469 6669 6564 3a20  .Last-Modified:
    00000020: 5375 6e2c 2032 3220 4f63 7420 3230 3233  Sun, 22 Oct 2023
    00000030: 2030 383a 3036 3a30 3320 474d 540d 0a45   08:06:03 GMT..E
    00000040: 7461 673a 2022 3336 3333 3661 6665 3533  tag: "36336afe53
    00000050: 3039 6561 3933 6163 6633 3930 6162 3934  09ea93acf390ab94
    00000060: 3637 6132 6634 220d 0a43 6f6e 7465 6e74  67a2f4"..Content
    00000070: 2d54 7970 653a 2069 6d61 6765 2f6a 7065  -Type: image/jpe
    00000080: 670d 0a44 6174 653a 2053 756e 2c20 3232  g..Date: Sun, 22
    00000090: 204f 6374 2032 3032 3320 3038 3a30 363a   Oct 2023 08:06:
    000000a0: 3034 2047 4d54 0d0a 5365 7276 6572 3a20  04 GMT..Server:
    000000b0: 7465 6e63 656e 742d 636f 730d 0a78 2d63  tencent-cos..x-c
    000000c0: 6f73 2d68 6173 682d 6372 6336 3465 636d  os-hash-crc64ecm
    000000d0: 613a 2031 3534 3631 3131 3537 3934 3831  a: 1546111579481
    000000e0: 3535 3537 3339 340d 0a78 2d63 6f73 2d72  5557394..x-cos-r
    000000f0: 6571 7565 7374 2d69 643a 204e 6a55 7a4e  equest-id: NjUzN
    00000100: 4751 335a 574e 664e 5755 7a4e 6a51 774d  GQ3ZWNfNWUzNjQwM
    00000110: 474a 664d 5745 305a 4446 664f 5459 314f  GJfMWE0ZDFfOTY1O
    00000120: 4442 6b4e 673d 3d0d 0a43 6f6e 7465 6e74  DBkNg==..Content
    00000130: 2d4c 656e 6774 683a 2032 3237 3938 0d0a  -Length: 22798..
    00000140: 4163 6365 7074 2d52 616e 6765 733a 2062  Accept-Ranges: b
    00000150: 7974 6573 0d0a 582d 4e57 532d 4c4f 472d  ytes..X-NWS-LOG-
    00000160: 5555 4944 3a20 3735 3537 3138 3835 3632  UUID: 7557188562
    00000170: 3130 3431 3837 3231 320d 0a43 6f6e 6e65  104187212..Conne
    00000180: 6374 696f 6e3a 206b 6565 702d 616c 6976  ction: keep-aliv
    00000190: 650d 0a58 2d43 6163 6865 2d4c 6f6f 6b75  e..X-Cache-Looku
    000001a0: 703a 2043 6163 6865 2048 6974 0d0a 0d0a  p: Cache Hit....

    Process finished with exit code 0

    查看下载 E:\CLionProjects\arp\fap30\print\sale.jpg

    对于http响应body,有的返回是gzip压缩,要用zlib库解压。分段的内容要解析

    1. /** @ref: https://www.iteye.com/blog/dbscx-830644 */
    2. char *http_chunked_parse(char *s, u_int16_t *len) {
    3. int i;
    4. /* 0x1000 == 4096 */
    5. *len = 0;
    6. for (i = 0; i < 4; i++) {
    7. if (s[i] == 0x0d && s[i+1] == 0x0a) {
    8. break;
    9. }
    10. /* 32 63 31 0d 0a <=> "3c1\r\n"(LEN=0x2c1, Dec:705) */
    11. *len *= 16;
    12. if (0x30<=s[i] && s[i] < 0x40) {
    13. *len += s[i] - 0x30;
    14. } else if (0x61 <= s[i] && s[i] < 0x67) {
    15. *len += s[i] - 0x61 + 10;
    16. }
    17. }
    18. if (s[i] == 0x0d && s[i+1] == 0x0a) {
    19. s = &s[i] + 2;
    20. }
    21. return s;
    22. }

    0d 0a 30 0d 0a 0d 0a 结束

    SO2 Lab 10 - Networking

  • 相关阅读:
    微服务(四)——zookeeper入门&api实践
    Docker学习笔记 - 极简极入门级
    C++ 编写时间类Time
    [开学季]ChatPaper全流程教程
    零知识证明在隐私保护和身份验证中的应用
    【聊天系统的优化】RPC方式的优化
    力扣面试经典100题
    10个有趣的Python高级脚本,建议收藏 ~
    uniapp运动课程健身打卡系统微信小程序
    MD5加密解密网站测试,MD5加密还安全吗?
  • 原文地址:https://blog.csdn.net/fareast_mzh/article/details/134044691