socat:EXEC 未正确中继

socat:EXEC 未正确中继

我有一个小程序,它首先向用户输出一个字符串,然后接受输入。相反,我希望程序通过从端口发送和接收来工作。为了尝试实现这一点,我运行了命令socat TCP4-LISTEN:1337,reuseaddr,fork EXEC:./program。通过这个命令,我希望能够运行nc 127.0.0.1 1337并期望该程序:

  1. 接收程序发来的消息
  2. 能够提供输入
  3. 失去连接

但是,当使用它运行程序时,socat它会像这样

  1. 提供意见
  2. 从程序收到的消息
  3. 提供另一个输入
  4. 失去了连接

我不明白为什么会发生这种情况。我使用该命令有什么问题吗socat?如果是,请告诉我缺少/错误的内容。

这是程序。

#include <stdio.h>

void vuln(void) {
    printf("Input\n");
    char buffer[256];
    gets(buffer); // potential buffer overflow
}

int main(void) {
    vuln();
    return 0;
}

答案1

在 C 中,printf是缓冲 I/O 库的一部分 - 写入流的数据“缓冲”在内存中(即,不直接写入内核)。

默认情况下,stdout(写入数据的流printf)是行缓冲流,这意味着字节存储在内存缓冲区中,直到将换行符写入流(或者其他一些甚至触发刷新的情况)。

如果标准输出未与终端关联,stdout则为块缓冲流,这意味着字节存储在内存缓冲区中,直到缓冲区满为止。

当您在终端运行程序时,'\n'调用中的 会printf触发刷新(因为它是行缓冲的):

$ ./a.out
Input
whatever-you-type
$

如果将输出重定向到文件,您将看到不同的行为:

Terminal 1               Terminal 2
--------------------     --------------------
$ ./a.out > /tmp/out
                         $ cat /tmp/out
                         $
type-input
$
                         $ cat /tmp/out
                         Input
                         $ 

socat当您在没有 的情况下运行时pts,输出流处于块缓冲模式;当您使用输出流运行它时,pts它处于行缓冲模式。

如果您想覆盖该行为,您有几个选择。您可以调用一个函数来显式地刷新任何缓冲的数据:

printf("Input\n");
fflush(stdout);

或者,您可以在调用之前显式设置输出流的缓冲模式printf

setvbuf(stdout, NULL, _IONBF, 0); // _IONBF = Unbuffered
printf("Input\n");

请参阅罗伯特·洛夫 (Robert Love) 的书的第 3 章Linux系统编程以获得更详细的解释。

相关内容