iptables는 tun 인터페이스의 패킷을 기록하지 않습니다.

iptables는 tun 인터페이스의 패킷을 기록하지 않습니다.

Ubuntu 22.04에는 다음 iptables규칙이 설정되어 있습니다.

iptables -I OUTPUT -d 192.168.0.0/16 -j LOG --log-prefix "CHECK1 "
iptables -I FORWARD -d 192.168.0.0/16 -j LOG --log-prefix "CHECK2 "

설정이 올바른지 확인하기 위해 192.168.0.0/16브라우저에서 website.com(서브넷에 있음)으로 이동하여 CHECK1메시지가 표시되는 것을 확인했습니다 /var/log/kern.log.

tun그런 다음 IP 주소가 있는 인터페이스를 생성 172.30.0.1하고 그 인터페이스에서 손으로 만든 TCP-SYN 패킷을 보내는 C 프로그램을 실행했습니다 . 이 패킷의 소스 주소는 172.30.0.1이고 대상 주소는 192.168.255.8(website.com 주소)입니다. Wireshark에 나타납니다. 그러나 에는 해당 로그 메시지가 없습니다 /var/log/kern.log.

이 패킷은 어떻게 됐나요?

이것은 iptables-save:

*filter
:INPUT ACCEPT [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
:DOCKER - [0:0]
:DOCKER-ISOLATION-STAGE-1 - [0:0]
:DOCKER-ISOLATION-STAGE-2 - [0:0]
:DOCKER-USER - [0:0]
-A FORWARD -d 192.168.0.0/16 -j LOG --log-prefix "CHECK2 "
-A FORWARD -j DOCKER-USER
-A FORWARD -j DOCKER-ISOLATION-STAGE-1
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o docker0 -j DOCKER
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT
-A FORWARD -i docker0 -o docker0 -j ACCEPT
-A OUTPUT -d 192.168.0.0/16 -j LOG --log-prefix "CHECK1 "
-A DOCKER-ISOLATION-STAGE-1 -i docker0 ! -o docker0 -j DOCKER-ISOLATION-STAGE-2
-A DOCKER-ISOLATION-STAGE-1 -j RETURN
-A DOCKER-ISOLATION-STAGE-2 -o docker0 -j DROP
-A DOCKER-ISOLATION-STAGE-2 -j RETURN
-A DOCKER-USER -j RETURN
COMMIT
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
:DOCKER - [0:0]
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
-A OUTPUT ! -D 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
-A DOCKER -i docker0 -j RETURN
COMMIT

C 코드는 다음과 같습니다(간결성을 위해 오류 검사는 생략했습니다).

#include <arpa/inet.h>
#include <fcntl.h>
#include <linux/if.h>
#include <linux/if_tun.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

static int
tunAlloc(void)
{
    int fd;
    struct ifreq ifr = {.ifr_name = "tun0", .ifr_flags = IFF_TUN | IFF_NO_PI};

    fd = open("/dev/net/tun", O_RDWR);
    ioctl(fd, TUNSETIFF, (void*)&ifr);
    ioctl(fd, TUNSETOWNER, geteuid());
    return fd;
}

static void
bringInterfaceUp(void)
{
    int sock;
    struct sockaddr_in addr = {.sin_family = AF_INET};
    struct ifreq ifr = {.ifr_name = "tun0"};

    inet_aton("172.30.0.1", &addr.sin_addr);
    memcpy(&ifr.ifr_addr, &addr, sizeof(struct sockaddr));

    sock = socket(AF_INET, SOCK_DGRAM, 0);
    ioctl(sock, SIOCSIFADDR, &ifr);
    ioctl(sock, SIOCGIFFLAGS, &ifr);
    ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
    ioctl(sock, SIOCSIFFLAGS, &ifr);
    close(sock);
}

static void
emitPacket(int tap_fd)
{
    unsigned char packet[] = {0x45, 0x00, 0x00, 0x3c, 0xd8, 0x6f, 0x40, 0x00, 0x3f, 0x06, 0x08, 0x91,
                              172,  30,   0,    1,    192,  168,  255,  8,    0xa2, 0x9a, 0x27, 0x11,
                              0x80, 0x0b, 0x63, 0x79, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, 0xfa, 0xf0,
                              0x89, 0xd8, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a,
                              0x5b, 0x76, 0x5f, 0xd4, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x07};

    write(tap_fd, packet, sizeof(packet));
}

int
main()
{
    int tap_fd;

    tap_fd = tunAlloc();
    bringInterfaceUp();
    emitPacket(tap_fd);
    close(tap_fd);

    return 0;
}

답변1

샘플 코드를 사용하면 설명하는 것과 동일한 문제가 나타납니다.

"샤오바오, 어디야?"푸워루)는 다음을 실행할 때 패킷이 신비롭게 사라지는 것처럼 보일 때 훌륭한 진단 도구입니다.

docker run --privileged --rm -t --pid=host \
  -v /sys/kernel/debug/:/sys/kernel/debug/ \
  cilium/pwru --filter-port 10001

코드에서 패킷을 내보내면 다음이 표시됩니다.

0xffff8cd640b80500      5     [sendpacket]        netif_receive_skb
0xffff8cd640b80500      5     [sendpacket]   skb_defer_rx_timestamp
0xffff8cd640b80500      5     [sendpacket]      __netif_receive_skb
0xffff8cd640b80500      5     [sendpacket] __netif_receive_skb_one_core
0xffff8cd640b80500      5     [sendpacket]                   ip_rcv
0xffff8cd640b80500      5     [sendpacket]              ip_rcv_core
0xffff8cd640b80500      5     [sendpacket] kfree_skb_reason(SKB_DROP_REASON_IP_CSUM)
0xffff8cd640b80500      5     [sendpacket]   skb_release_head_state
0xffff8cd640b80500      5     [sendpacket]               sock_wfree
0xffff8cd640b80500      5     [sendpacket]         skb_release_data
0xffff8cd640b80500      5     [sendpacket]            skb_free_head
0xffff8cd640b80500      5     [sendpacket]             kfree_skbmem

이는 패킷에 잘못된 체크섬이 포함되어 있어 패킷이 삭제되었음을 나타냅니다.

Wireshark를 사용하여 패킷 캡처를 확인하면 올바른 체크섬이 표시됩니다. 이러한 문제를 해결하면 다음을 수행할 수 있습니다.

    static void emitPacket(int tap_fd) {
    │ unsigned char packet[] = {
    │   │ 0x45, 0x00, 0x00, 0x3c, 0xd8, 0x6f, 0x40, 0x00, 0x3f, 0x06, 0xf7, 0x7b,
    │   │ 172,  30,   0,    1,    192,  168,  255,  8,    0xa2, 0x9a, 0x27, 0x11,
    │   │ 0x80, 0x0b, 0x63, 0x79, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, 0xfa, 0xf0,
    │   │ 0x78, 0xc3, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a,
    │   │ 0x5b, 0x76, 0x5f, 0xd4, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x07};
    │ write(tap_fd, packet, sizeof(packet));
    }

그러나 이는 라우팅 논리에서 실패합니다.

0xffff8cd8bca97100      0     [sendpacket]        netif_receive_skb
0xffff8cd8bca97100      0     [sendpacket]   skb_defer_rx_timestamp
0xffff8cd8bca97100      0     [sendpacket]      __netif_receive_skb
0xffff8cd8bca97100      0     [sendpacket] __netif_receive_skb_one_core
0xffff8cd8bca97100      0     [sendpacket]                   ip_rcv
0xffff8cd8bca97100      0     [sendpacket]              ip_rcv_core
0xffff8cd8bca97100      0     [sendpacket]               sock_wfree
0xffff8cd8bca97100      0     [sendpacket]             nf_hook_slow
0xffff8cd8bca97100      0     [sendpacket]              nf_checksum
0xffff8cd8bca97100      0     [sendpacket]           nf_ip_checksum
0xffff8cd8bca97100      0     [sendpacket]  __skb_checksum_complete
0xffff8cd8bca97100      0     [sendpacket]       tcp_v4_early_demux
0xffff8cd8bca97100      0     [sendpacket]     ip_route_input_noref
0xffff8cd8bca97100      0     [sendpacket]      ip_route_input_slow
0xffff8cd8bca97100      0     [sendpacket]      fib_validate_source
0xffff8cd8bca97100      0     [sendpacket]    __fib_validate_source
0xffff8cd8bca97100      0     [sendpacket] ip_handle_martian_source
0xffff8cd8bca97101      0     [sendpacket] kfree_skb_reason(SKB_DROP_REASON_NOT_SPECIFIED)
0xffff8cd8bca97100      0     [sendpacket]   skb_release_head_state
0xffff8cd8bca97100      0     [sendpacket]         skb_release_data
0xffff8cd8bca97100      0     [sendpacket]            skb_free_head
0xffff8cd8bca97100      0     [sendpacket]             kfree_skbmem

log_martians실제로 시스템에서 이 기능을 활성화 하면 다음이 표시됩니다.

Feb 14 12:14:03 madhatter kernel: IPv4: martian source 192.168.255.8 from
172.30.0.1, on dev tun0

...우리는 얻었습니다저것이 주소와 동일한 주소를 가진 인터페이스로 들어오는 패킷이 있기 때문에 오류가 발생합니다. 이는 문제입니다(우리는 이에 올바르게 응답할 수 없습니다).

tun0(a) 패킷과 다른 주소를 설정하고 (b) /24넷마스크를 사용하여 적절한 네트워크에 대한 자동 경로를 얻도록 코드를 수정하는 경우:

static void bringInterfaceUp(void) {
  int sock;
  struct sockaddr_in addr = {.sin_family = AF_INET};
  struct ifreq ifr = {.ifr_name = "tun0"};

  inet_aton("172.30.0.10", &addr.sin_addr);
  memcpy(&ifr.ifr_addr, &addr, sizeof(struct sockaddr));
  sock = socket(AF_INET, SOCK_DGRAM, 0);
  must(ioctl(sock, SIOCSIFADDR, &ifr));

  /*
  I don't know if this is entirely kosher -- it's the result of a quick
  glance over the netdevice(7) man page -- but it seems to work.
  */
  inet_aton("255.255.255.0", &addr.sin_addr);
  memcpy(&ifr.ifr_addr, &addr, sizeof(struct sockaddr));
  must(ioctl(sock, SIOCSIFNETMASK, &ifr));

  must(ioctl(sock, SIOCGIFFLAGS, &ifr));
  ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
  must(ioctl(sock, SIOCSIFFLAGS, &ifr));
  close(sock);
}

이제 패킷이 다음에서 전송되는 것을 볼 수 있습니다 eth0.

$ sudo tcpdump -i any -nn port 10001
tcpdump: data link type LINUX_SLL2
dropped privs to tcpdump
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
12:33:26.877514 tun0  In  IP 172.30.0.1.41626 > 192.168.255.8.10001: Flags [S], seq 2148230009, win 64240, options [mss 1460,sackOK,TS val 1534484436 ecr 0,nop,wscale 7], length 0
12:33:26.877536 eth0  Out IP 172.30.0.1.41626 > 192.168.255.8.10001: Flags [S], seq 2148230009, win 64240, options [mss 1460,sackOK,TS val 1534484436 ecr 0,nop,wscale 7], length 0

관련 정보