Linux

IPv6 連接突然消失

  • February 2, 2020

在下面指定的環境中,IPv4 像貓一樣發出咕嚕聲,但 IPv6 會在短時間內消失——即即使主機也無法通過 Docker 網路通過 IPv6 訪問其容器。我錯過了什麼?

編輯#1

替換 64:ff9b:: w/ 全域,但問題仍然存在。主機失去了與直接連接的 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

任務/firewall.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

文件/防火牆/rules.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

文件/防火牆/rules.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

我的猜測是您的 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 數據包並將回複數據包標記為ESTABLISHEDRELATED。我的建議是在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

引用自:https://serverfault.com/questions/1000367