IPv6 连接突然消失

IPv6 连接突然消失

在下面指定的环境中,IPv4 像猫一样呼噜呼噜地叫,但 IPv6 会在短时间后消失 - 也就是说,即使主机也无法通过 Docker 网络通过 IPv6 到达其容器。我是否遗漏了什么?

编辑#1

用全局变量替换了 64:ff9b::,但问题仍然存在。主机失去了与直接连接的 Docker 容器的 IPv6(而非 IPv4)连接。首先是“无到主机的路由”,然后是超时。

剧本.yml

---
- hosts: all
  become: yes
  become_method: sudo
  tasks:
  - import_tasks: tasks/firewall.yml
  - import_tasks: tasks/router.yml
  - import_tasks: tasks/docker.yml
  - name: /usr/local/docker-services
    file:
      path: /usr/local/docker-services
      owner: root
      group: root
      mode: '0700'
      state: directory
  - name: nginx-site.conf
    copy:
      dest: /usr/local/docker-services/nginx-site.conf
      owner: root
      group: root
      mode: '0666'
      src: files/nginx-site.conf
  - name: docker-compose.yml
    copy:
      dest: /usr/local/docker-services/docker-compose.yml
      owner: root
      group: root
      mode: '0666'
      content: |
        version: '2.4'
        networks:
          ext-nginx:
            internal: true
            enable_ipv6: true
            driver_opts:
              com.docker.network.bridge.name: docker1
            ipam:
              config:
              - subnet: 192.168.234.0/30
                gateway: 192.168.234.1
              - subnet: 64:ff9b::192.168.234.0/126
                gateway: 64:ff9b::192.168.234.1
        services:
          nginx:
            container_name: nginx
            image: nginx
            restart: always
            logging:
              options:
                labels: container
            labels:
              container: nginx
            networks:
              ext-nginx:
                ipv4_address: 192.168.234.2
                ipv6_address: 64:ff9b::192.168.234.2
                priority: 1
            volumes:
            - type: bind
              source: /usr/local/docker-services/nginx-site.conf
              target: /etc/nginx/conf.d/default.conf
              read_only: true
    register: docker_compose_yml
  - name: docker-compose.service
    copy:
      dest: /etc/systemd/system/docker-compose.service
      owner: root
      group: root
      mode: '0644'
      src: files/docker-compose.service
    register: docker_compose_service
  - name: systemctl daemon-reload
    when: docker_compose_service.changed
    systemd:
      daemon_reload: yes
  - name: systemctl stop docker-compose.service
    when: >-
      docker_compose_service.changed
      or docker_compose_yml.changed
    service:
      name: docker-compose
      state: stopped
  - name: systemctl start docker-compose.service
    service:
      name: docker-compose
      state: started
      enabled: yes

任务/防火墙.yml

---
- name: Firewall rules applicator
  apt:
    name: iptables-persistent
- name: Firewall rules file
  loop: [4, 6]
  copy:
    dest: '/etc/iptables/rules.v{{ item }}'
    owner: root
    group: root
    mode: '0644'
    src: 'files/firewall/rules.v{{ item }}'
  register: firewall_file
- name: Apply firewall rules
  when: 'firewall_file.results[0].changed or firewall_file.results[1].changed'
  service:
    name: netfilter-persistent
    state: restarted

任务/路由器.yml

---
- name: net.ipv4.ip_forward
  sysctl:
    name: net.ipv4.ip_forward
    value: '1'
- name: net.ipv6.conf.all.forwarding
  sysctl:
    name: net.ipv6.conf.all.forwarding
    value: '1'

任务/docker.yml

---
- name: apt-transport-https
  apt:
    name: apt-transport-https
- name: Docker apt key
  apt_key:
    url: https://download.docker.com/linux/debian/gpg
- name: Docker apt repo
  apt_repository:
    filename: docker
    repo: >
      deb https://download.docker.com/linux/debian
      {{ ansible_lsb.codename }} stable
- name: /etc/docker
  file:
    path: /etc/docker
    owner: root
    group: root
    mode: '0755'
    state: directory
- name: /etc/docker/daemon.json
  copy:
    dest: /etc/docker/daemon.json
    owner: root
    group: root
    mode: '0644'
    content: '{"iptables":false}'
- name: Docker
  apt:
    name: docker-ce
- name: Docker compose
  apt:
    name: docker-compose

文件/防火墙/规则.v4

*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -d 127.0.0.0/8 ! -i lo -j DROP
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
-A FORWARD -o docker1 -d 192.168.234.2/32 -p tcp -m tcp --dport 80 -j ACCEPT
-A FORWARD -i docker1 -o eth0 -j ACCEPT
-A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
COMMIT

*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
-A PREROUTING -i eth0 -d 78.47.124.58 -p tcp -m tcp --dport 80 -j DNAT --to 192.168.234.2
-A POSTROUTING -o eth0 ! -s 78.47.124.58 -j MASQUERADE
COMMIT

文件/防火墙/规则.v6

*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -d ::1/128 ! -i lo -j DROP
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
-A FORWARD -o docker1 -d 64:ff9b::192.168.234.2 -p tcp -m tcp --dport 80 -j ACCEPT
-A FORWARD -i docker1 -o eth0 -j ACCEPT
-A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
COMMIT

*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
-A PREROUTING -i eth0 -d 2a01:4f8:c0c:3bc1::/64 -p tcp -m tcp --dport 80 -j DNAT --to 64:ff9b::192.168.234.2
-A POSTROUTING -o eth0 ! -s 2a01:4f8:c0c:3bc1::/64 -j MASQUERADE
COMMIT

文件/nginx-site.conf

server {
    listen       80;
    listen       [::]:80;
    server_name  localhost;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

文件/docker-compose.service

[Unit]
Requires=docker.service

[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/usr/local/docker-services
ExecStart=/usr/bin/docker-compose up -d --force-recreate
ExecStop=/usr/bin/docker-compose down

[Install]
WantedBy=multi-user.target

答案1

我猜你的 IPv6 防火墙规则正在阻止NDP(邻居发现协议)数据包,从而阻止您的主机正确解析容器的链路层地址。

在 IPv4 堆栈中,链路层(以太网)地址的解析由ARP(地址解析协议),它使用链路层地址作为数据包目的地。当主机发出 ARP 请求或未经请求的 ARP 通告时,这些数据包将直接转发到广播链路层地址(FF:FF:FF:FF:FF:FF以太网协议中),因此不受过滤iptables

在 IPv6 堆栈中,链路层地址的解析由 NDP(邻居发现协议)处理。与 ARP 不同,NDP 数据包实际上是转发到 IPv6 地址的 ICMPv6 数据包,因此需要进行ip6tables过滤。

我相信,根据我的经验和Arch Linux Wiki 文章,CONNTRACK 模块不是为了跟踪 ICMPv6 NDP 数据包并将回复数据包标记为已确立的或者有关的files/firewall/rules.v6。我的建议是在文件中明确允许此类流量:

(新规则)

-A INPUT -i docker1 -p ipv6-icmp -m icmp6 --icmpv6-type 133 -m comment --comment router-solicitation -j ACCEPT
-A INPUT -i eth0 -p ipv6-icmp -m icmp6 --icmpv6-type 134 -m comment --comment router-advertisement -j ACCEPT
-A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type 135 -m comment --comment neighbor-solicitation -j ACCEPT
-A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type 136 -m comment --comment neighbor-advertisement -j ACCEPT

(完整文件)

*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -d ::1/128 ! -i lo -j DROP
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
-A INPUT -i docker1 -p ipv6-icmp -m icmp6 --icmpv6-type 133 -m comment --comment router-solicitation -j ACCEPT
-A INPUT -i eth0 -p ipv6-icmp -m icmp6 --icmpv6-type 134 -m comment --comment router-advertisement -j ACCEPT
-A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type 135 -m comment --comment neighbor-solicitation -j ACCEPT
-A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type 136 -m comment --comment neighbor-advertisement -j ACCEPT
-A FORWARD -o docker1 -d 64:ff9b::192.168.234.2 -p tcp -m tcp --dport 80 -j ACCEPT
-A FORWARD -i docker1 -o eth0 -j ACCEPT
-A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
COMMIT

*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
-A PREROUTING -i eth0 -d 2a01:4f8:c0c:3bc1::/64 -p tcp -m tcp --dport 80 -j DNAT --to 64:ff9b::192.168.234.2
-A POSTROUTING -o eth0 ! -s 2a01:4f8:c0c:3bc1::/64 -j MASQUERADE
COMMIT

相关内容