TCP接続が来たらすぐにクローズするだけのSocketプログラム

IPv4 と IPv6 の両方でTCP 接続を待ち受けつつ、接続が来たらすぐに FIN でクローズするだけのプログラムを書きました。

 1#include <netdb.h>
 2#include <stdio.h>
 3#include <stdlib.h>
 4#include <string.h>
 5#include <unistd.h>
 6#include <arpa/inet.h>
 7#include <sys/socket.h>
 8#include <sys/types.h>
 9#include <sys/wait.h>
10
11int main(int argc, char const *argv[]) {
12    int port = 80;
13    if (argc > 1) {
14        port = atoi(argv[1]);
15    }
16
17    int sockfd;
18    if ((sockfd = socket(AF_INET6, SOCK_STREAM, 0)) == -1) {
19        perror("socket error");
20        return 1;
21    }
22
23    int opt = 1;
24    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1) {
25        perror("setsockopt error");
26        return 1;
27    }
28
29    struct sockaddr_in6 sockaddr;
30    memset(&sockaddr, 0, sizeof(sockaddr));
31    sockaddr.sin6_family = AF_INET6;
32    sockaddr.sin6_addr = in6addr_any;
33    sockaddr.sin6_port = htons(port);
34
35    if (bind(sockfd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) == -1) {
36        perror("bind error");
37        return 1;
38    }
39
40    if (listen(sockfd, SOMAXCONN) == -1) {
41        perror("listen error");
42        return 1;
43    }
44
45    while (1) {
46        int sock;
47        struct sockaddr_in client;
48        int client_len = sizeof(client);
49
50        if ((sock = accept(sockfd, (struct sockaddr *)&client, (socklen_t *)&client_len)) == -1) {
51            perror("accept error");
52            continue;
53        }
54
55        close(sock);
56    }
57
58    close(sockfd);
59
60    return 0;
61}

複数の TCP 接続要求がシーケンシャルに処理されたり、複数のポートで仕掛けるには別プロセスとして起動する必要があったりしますが、スレッドや fork を使うほどでもないかなと…。

本当はプログラムを書かずに iptables などで実現したかったのですが、TCP 接続をいったん確立したうえでクローズ (FIN or RST) する良い方法が思いつきませんでした。 何らかの TCP サーバが必要になるのは良いとして、ハンドシェイク後に何らかのパケットが来ないと REJECT できないし、REJECT したとしてもその TCP サーバとしては TCP 接続がある状態になってしまうので。 bind や listen だけして accept しないものがあれば良かったのですが。