• 本地库覆盖glibc的API


    本地库覆盖glibc的getifaddrs

    基本原理:(原理类似libSegFault.so这个库)

    使用linux的环境变量“LD_PRELOAD”来提前载入一个库,然后这个库里面的同名API就可以覆盖后续的共享库的API了(glibc里面的若链接的API是可以被覆盖的)。如我们在自己的共享库中重写一个API

    int getifaddrs (struct ifaddrs **ifap);

    主要修改代码点:

    1. 在一个新的共享库里重写/覆盖getifaddrs(), 生产一个共享库libovfuns.so,把它拷贝到/opt/lib里面。主要修改点事去掉原有glibc里__netlink_assert_response(...)的abort处理,同时是在系统的文件里面记录一条异常log:(/opt/log/overwirte_fun.log)

      1. static void __netlink_assert_response (int fd, ssize_t result)
      2. {
      3. if (result < 0)
      4. {
      5. /* Check if the error is unexpected. */
      6. bool terminate = false;
      7. int error_code = errno;
      8. int family = get_address_family (fd);
      9. if (family != AF_NETLINK)
      10. /* If the address family does not match (or getsockname
      11. failed), report the original error. */
      12. terminate = true;
      13. else if (error_code == EBADF
      14. || error_code == ENOTCONN
      15. || error_code == ENOTSOCK
      16. || error_code == ECONNREFUSED)
      17. /* These errors indicate that the descriptor is not a
      18. connected socket. */
      19. terminate = true;
      20. else if (error_code == EAGAIN || error_code == EWOULDBLOCK)
      21. {
      22. /* The kernel might return EAGAIN for other reasons than a
      23. non-blocking socket. But if the socket is not blocking,
      24. it is not ours, so report the error. */
      25. int mode = fcntl (fd, F_GETFL, 0);
      26. if (mode < 0 || (mode & O_NONBLOCK) != 0)
      27. terminate = true;
      28. }
      29. printf("[%s %d]\n", __func__, __LINE__);
      30. if (terminate)
      31. {
      32. char message[200];
      33. if (family < 0)
      34. snprintf (message, sizeof (message),
      35. "Inovance overwrite: Unexpected error %d on netlink descriptor %d",
      36. error_code, fd);
      37. else
      38. snprintf (message, sizeof (message),
      39. "Inovance overwrite: Unexpected error %d on netlink descriptor %d"
      40. " (address family %d)",
      41. error_code, fd, family);
      42. //just use the log message replace the "__libc_fatal"
      43. // __libc_fatal (message);
      44. overwrite_fun_log("getifaddrs", message);
      45. }
      46. else
      47. /* Restore orignal errno value. */
      48. set_errno (error_code);
      49. }
      50. else if (result < sizeof (struct nlmsghdr))
      51. {
      52. char message[200];
      53. int family = get_address_family (fd);
      54. if (family < 0)
      55. snprintf (message, sizeof (message),
      56. "Inovance overwrite: Unexpected netlink response of size %zd"
      57. " on descriptor %d",
      58. result, fd);
      59. else
      60. snprintf (message, sizeof (message),
      61. "Inovance overwrite: Unexpected netlink response of size %zd"
      62. " on descriptor %d (address family %d)",
      63. result, fd, family);
      64. //just use the log message replace the "__libc_fatal"
      65. // __libc_fatal (message);
      66. overwrite_fun_log("getifaddrs", message);
      67. }
      68. }

    2. 修改test启动的服务脚本:在原有服务脚本里面增加如下行,用于设置环境变量Environment="LD_PRELOAD=/opt/runtime/libovfuns.so"

      1. root@xxx:# cat /lib/systemd/system/test.service
      2. [Unit]
      3. Description=Inovance CoDeSys Control Progres
      4. Wants=inovance-daemon.service
      5. After=inovance-daemon.service
      6. [Service]
      7. Type=simple
      8. Environment="LD_PRELOAD=/opt/lib/libovfuns.so"
      9. PIDFile=/run/test.pid
      10. ExecStartPre=/bin/sleep 5
      11. ExecStart=/opt/xxx/test
      12. StandardOutput=null
      13. StandardError=null
      14. #Restart=always
      15. #RestartSec=1
      16. #StartLimitInterval=0
      17. [Install]
      18. WantedBy=multi-user.target

    3. 下面是测试代码,编译时使用gcc -L/opt/runtime/ -I./lib -lovfuns -o test test.c

    4. 生产test测试程序

      1. #define _GNU_SOURCE /* To get defns of NI_MAXSERV and NI_MAXHOST */
      2. #include <arpa/inet.h>
      3. #include <sys/socket.h>
      4. #include <netdb.h>
      5. #include "my_ifaddrs.h"
      6. #include <stdio.h>
      7. #include <stdlib.h>
      8. #include <unistd.h>
      9. #include <linux/if_link.h>
      10. int main(int argc, char *argv[])
      11. {
      12. struct ifaddrs *ifaddr, *ifa;
      13. int family, s, n;
      14. char host[NI_MAXHOST];
      15. if (getifaddrs(&ifaddr) == -1) {
      16. perror("getifaddrs");
      17. exit(EXIT_FAILURE);
      18. }
      19. /* Walk through linked list, maintaining head pointer so we
      20. can free list later */
      21. for (ifa = ifaddr, n = 0; ifa != NULL; ifa = ifa->ifa_next, n++) {
      22. if (ifa->ifa_addr == NULL)
      23. continue;
      24. family = ifa->ifa_addr->sa_family;
      25. /* Display interface name and family (including symbolic
      26. form of the latter for the common families) */
      27. printf("%-8s %s (%d)\n",
      28. ifa->ifa_name,
      29. (family == AF_PACKET) ? "AF_PACKET" :
      30. (family == AF_INET) ? "AF_INET" :
      31. (family == AF_INET6) ? "AF_INET6" : "???",
      32. family);
      33. /* For an AF_INET* interface address, display the address */
      34. if (family == AF_INET || family == AF_INET6) {
      35. s = getnameinfo(ifa->ifa_addr,
      36. (family == AF_INET) ? sizeof(struct sockaddr_in) :
      37. sizeof(struct sockaddr_in6),
      38. host, NI_MAXHOST,
      39. NULL, 0, NI_NUMERICHOST);
      40. if (s != 0) {
      41. printf("getnameinfo() failed: %s\n", gai_strerror(s));
      42. exit(EXIT_FAILURE);
      43. }
      44. printf("\t\taddress: <%s>\n", host);
      45. } else if (family == AF_PACKET && ifa->ifa_data != NULL) {
      46. struct rtnl_link_stats *stats = ifa->ifa_data;
      47. printf("\t\ttx_packets = %10u; rx_packets = %10u\n"
      48. "\t\ttx_bytes = %10u; rx_bytes = %10u\n",
      49. stats->tx_packets, stats->rx_packets,
      50. stats->tx_bytes, stats->rx_bytes);
      51. }
      52. }
      53. freeifaddrs(ifaddr);
      54. exit(EXIT_SUCCESS);
      55. }

      测试添加和不添加环境量,程序使用的API是不同的,具体测试log如下所示:

      不添加环境变量,程序使用原始API

      root@xxx:# ./test

      lo AF_PACKET (17)

      tx_packets = 65; rx_packets = 65

      tx_bytes = 3180; rx_bytes = 3180

      enp1s0 AF_PACKET (17)

      tx_packets = 686; rx_packets = 3008

      tx_bytes = 50762; rx_bytes = 192738

      enp2s0 AF_PACKET (17)

      tx_packets = 118; rx_packets = 204

      tx_bytes = 19366; rx_bytes = 22391

      enp3s0 AF_PACKET (17)

      tx_packets = 0; rx_packets = 0

      tx_bytes = 0; rx_bytes = 0

      enp4s0 AF_PACKET (17)

      tx_packets = 0; rx_packets = 16

      tx_bytes = 0; rx_bytes = 960

      tunl0 AF_PACKET (17)

      tx_packets = 0; rx_packets = 0

      tx_bytes = 0; rx_bytes = 0

      tap0 AF_PACKET (17)

      tx_packets = 0; rx_packets = 0

      tx_bytes = 0; rx_bytes = 0

      tap1 AF_PACKET (17)

      tx_packets = 0; rx_packets = 0

      tx_bytes = 0; rx_bytes = 0

      lo AF_INET (2)

      address: <127.0.0.1>

      enp1s0 AF_INET (2)

      address: <10.61.64.75>

      enp2s0 AF_INET (2)

      address: <192.168.2.88>

      添加环境变量,程序使用新的API

      root@xxx:# env LD_PRELOAD=/opt/runtime/libovfuns.so ./test

      [__netlink_request 601] <------这个log是新的API里面的

      [__netlink_request 604]

      [__netlink_request 601]

      [__netlink_request 604]

      [__netlink_request 601]

      [__netlink_request 604]

      [__netlink_request 601]

      [__netlink_request 604]

      [__netlink_request 601]

      [__netlink_request 604]

      lo AF_PACKET (17)

      tx_packets = 107; rx_packets = 107

      tx_bytes = 5196; rx_bytes = 5196

      enp1s0 AF_PACKET (17)

      tx_packets = 1138; rx_packets = 4968

      tx_bytes = 83894; rx_bytes = 316171

      enp2s0 AF_PACKET (17)

      tx_packets = 160; rx_packets = 251

      tx_bytes = 23366; rx_bytes = 26263

      enp3s0 AF_PACKET (17)

      tx_packets = 0; rx_packets = 0

      tx_bytes = 0; rx_bytes = 0

      enp4s0 AF_PACKET (17)

      tx_packets = 0; rx_packets = 24

      tx_bytes = 0; rx_bytes = 1440

      tunl0 AF_PACKET (17)

      tx_packets = 0; rx_packets = 0

      tx_bytes = 0; rx_bytes = 0

      tap0 AF_PACKET (17)

      tx_packets = 0; rx_packets = 0

      tx_bytes = 0; rx_bytes = 0

      tap1 AF_PACKET (17)

      tx_packets = 0; rx_packets = 0

      tx_bytes = 0; rx_bytes = 0

      lo AF_INET (2)

      address: <127.0.0.1>

      enp1s0 AF_INET (2)

      address: <10.61.64.75>

      enp2s0 AF_INET (2)

      address: <192.168.2.88>

  • 相关阅读:
    C++教程笔记链接推荐
    什么是线段树?
    壳聚糖-卵清蛋白|Chitosan-Ovalbumin|卵清蛋白-PEG-壳聚糖
    微擎模块 名片小程序 1.7.9 小程序前端+后端有加密,优化代码,新增付费发布幻灯片
    linux - 疑难问题解决
    面试官:实际工作中哪里用到了自定义注解?
    软件工程导论---概述软件工程
    科研宝典·工具篇 | CiteSpace: 科学文献分析
    这种测试用例编写方法,你怕是都没用过...
    NLP_情感分类_数据清洗
  • 原文地址:https://blog.csdn.net/paky_du/article/details/127808596