【问题标题】:Linux API / library to enumerate all listening ports of a specific IP枚举特定 IP 的所有监听端口的 Linux API/库
【发布时间】:2013-07-02 14:13:48
【问题描述】:

有哪些选项可用于枚举 Linux 上特定 IP 的所有侦听端口?

我正在寻找的函数原型是这样的:

enumerateListeners : IP -> [Port]

内核 API 或 C 库都会很有趣。

【问题讨论】:

    标签: c linux networking kernel port


    【解决方案1】:

    /proc 文件系统是您可以用来获取此信息的内核接口。在/proc/net/tcp/proc/net/tcp6 中特别列出了 TCP 套接字。第二列以 IP:port 对的形式给出本地地址。要选择那些处于 LISTEN 状态的套接字,您必须查看那些在 st(套接字状态)列中具有 0A 的套接字。这是我所拥有的示例:

      sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode                                                     
       0: 00000000:3E81 00000000:0000 0A 00000000:00000000 00:00000000 00000000  1000        0 18064 1 0000000000000000 100 0 0 10 0                     
       1: 00000000:1269 00000000:0000 0A 00000000:00000000 00:00000000 00000000  1000        0 18056 1 0000000000000000 100 0 0 10 0                     
       2: 0100007F:0CEA 00000000:0000 0A 00000000:00000000 00:00000000 00000000   117        0 13084 1 0000000000000000 100 0 0 10 0                     
       3: 00000000:008B 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 9097 1 0000000000000000 100 0 0 10 0                      
       4: 0100007F:0050 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 14349 1 0000000000000000 100 0 0 10 0                     
    

    在 C 中读取这个文件很简单:打开它并用fscanf 浏览它。

    如果有其他方法可以获取此信息,我不知道;这也是netstat 使用的接口,您可以通过strace 轻松验证。

    【讨论】:

    • 我已经按照类似于您的第一个建议的解决方案编写了自己的答案。您介意看看使用sscanf 来解决可能的问题吗?
    • @CetinSert 查看 Linux 内核,http://lxr.linux.no/linux+*/+code=raw_sock_seq_show(抱歉,无法链接,SO 的解析器破坏了 URL)printf() 格式表达式。你应该可以通过scanf() 来扭转它。
    • @FrankH。非常感谢!每个指向其源代码的链接都让我更接近成为内核模块/内核开发人员:)!我想出了一些可行的方法,您可以在下面我自己的答案中看到。
    【解决方案2】:

    更新

    #include <stdio.h>          // printf, fopen, fclose
    #include <stdlib.h>         // free
    #include <arpa/inet.h>      // in_addr*
    
    #define OK(x) ((x) > -1)
    #define LISTENING (0x0A)
    #define port u_int16_t
    
    int listening(in_addr_t addr, port* ports, size_t nPorts) {
    
      char* line = NULL; size_t n = 0;
      u_int32_t locaddr; u_int32_t locport; u_int32_t state; int i = 0;
      FILE* tcp = fopen("/proc/net/tcp", "r");
    
      if   (!OK(getline(&line, &n, tcp))) goto f;
      while (OK(getline(&line, &n, tcp)) && i < nPorts) {
        int r = sscanf(line, "%*d: %8x:%4x %*8x:%*4x %2x", &locaddr, &locport, &state);
        if (r == 3 && addr == locaddr && state == LISTENING) ports[i++] = (port)locport;
      }
    
      f: fclose(tcp); free(line); return i;
    }
    
    int main(int c, char* a[]) {
      struct in_addr ipv4; inet_pton(AF_INET, a[1], &ipv4);     printf("%i = ", ipv4.s_addr);
      char str[512];       inet_ntop(AF_INET, &ipv4, str, 512); printf("%s\n" , str);
    
      port pts[65536]; printf("{ listening: [ "); c = listening(ipv4.s_addr, pts, 65536);
      int i; for (i = 0; i < c; i++) printf("%i, ", pts[i]); printf("] }\n");
    }
    

    【讨论】:

    • 您似乎没有将*line 设置为NULL,因此getline 可能会写入随机内存而不是分配新缓冲区。其余的看起来不错,但有一件事:如果文件格式发生了变化,它可能是通过添加新列来完成的,所以为了未来的安全,最好的办法是在找到所需数据后忽略行尾。跨度>
    • @Joni,已更新为仅显示状态为 0A 的那些,并整合您关于 getline 的建议并尽量减少假设。
    【解决方案3】:

    那么,您是否需要 PortScanner? 我所知道的最好的 PortScanner 是 Nmap

    你可以看看它的源代码,否则编写一个简单函数来枚举为特定IP打开的TCP端口不是一个难题,你可以使用connect 函数与 for 循环一起使用。

    【讨论】:

    • 不,我不是在寻找扫描远程 IP 的东西。而是使用此处提供的 PERL 答案的 C 等效项来枚举本地侦听端口:stackoverflow.com/a/12107348/112882
    猜你喜欢
    • 2011-11-06
    • 1970-01-01
    • 2015-11-28
    • 1970-01-01
    • 2017-03-21
    • 2018-03-18
    • 2011-09-14
    • 2014-06-10
    • 2014-12-18
    相关资源
    最近更新 更多