Tuyến mặc định IPv6 biến mất sau khi bật chuyển tiếp trên Linux
Bật chuyển tiếp IPv6 khiến nhân bỏ qua router advertisements trên uplink, và tuyến mặc định đã học hết hạn. Sửa bằng accept_ra.
Tôi đặt net.ipv6.conf.all.forwarding=1 trên một cổng Debian để nó có thể chuyển tiếp lưu lượng của các máy khách VPN, và khoảng nửa giờ sau máy không còn tuyến mặc định IPv6 nào. Router thượng nguồn vẫn sống, hàng xóm link-local vẫn trả lời, và uplink vẫn giữ địa chỉ toàn cầu của nó. Thứ đã dừng lại là việc nhân tiếp tục chấp nhận router advertisements trên giao diện đó. Tuyến không biến mất khi tôi gõ sysctl; nó biến mất khi thời hạn của tuyến mặc định học được từ RA hết và không có gì làm mới nó.
Thoạt nhìn không có gì hỏng. Việc chuyển tiếp hoạt động, các máy khách vẫn đi qua trong khi tuyến cũ còn trong bộ nhớ đệm, và sự cố đến muộn hơn thay đổi đã gây ra nó. Chính độ trễ đó khiến người ta đổ lỗi cho phía thượng nguồn hoặc cho một quy tắc tường lửa chưa từng tham gia.
Đọc bảng tuyến trước khi chạm vào bất kỳ sysctl nào
Bắt đầu bằng ip -6 route show default và đọc các thuộc tính, không chỉ cổng. Một tuyến mặc định học được từ RA được đánh dấu proto ra, mang theo ưu tiên và hiển thị đếm ngược expires. Một tuyến bạn thêm bằng tay không có cả hai, và sự khác biệt đó cho bạn biết cơ chế nào sở hữu tuyến.
$ ip -6 route show default
default via fe80::1 dev eth0 proto ra metric 1024 expires 1432sec hoplimit 64 pref mediumSau đó xem địa chỉ: ip -6 addr show dev eth0. Một địa chỉ toàn cầu có thời hạn ưu tiên và hợp lệ tính bằng giờ sẽ sống lâu hơn một tuyến mặc định có thời hạn router tính bằng phút. Có địa chỉ mà thiếu tuyến mặc định là dấu hiệu của một vấn đề quảng cáo. Nếu cả địa chỉ cũng thiếu, trước hết phải lần theo liên kết, thông tin tiền tố hoặc việc phát hiện địa chỉ trùng.
Vì sao chuyển tiếp tắt xử lý RA
RA là một gói ICMPv6 loại 134, được gửi từ nguồn link-local với giới hạn bước nhảy 255. Trước khi dùng nó, nhân kiểm tra accept_ra của giao diện. Giá trị mặc định là 1, và 1 không có nghĩa là có. Nó có nghĩa là: chỉ chấp nhận khi máy này không chuyển tiếp. Đặt forwarding=1 thì điều kiện đó không thỏa, nên quảng cáo bị bỏ trước khi bất kỳ tiền tố hoặc router mặc định nào trong đó được xét đến.
Có ba giá trị, và chỉ giá trị thứ ba sống sót qua chuyển tiếp:
accept_ra | forwarding=0 | forwarding=1 |
|---|---|---|
| 0 | ignored | ignored |
| 1 (default) | accepted | ignored |
| 2 | accepted | accepted |
Hai cờ khác quyết định thứ thực sự được cài. accept_ra_defrtr kiểm soát việc router mặc định trong quảng cáo có trở thành tuyến hay không, và accept_ra_pinfo kiểm soát việc thông tin tiền tố có được dùng để cấu hình địa chỉ hay không. Tắt accept_ra_defrtr là cách thông thường để giữ địa chỉ SLAAC trên một máy chuyển tiếp mà không học tuyến mặc định. Đó là một đòn bẩy khác với accept_ra, và là thứ bạn dùng khi muốn có địa chỉ nhưng không muốn có tuyến. Tài liệu tham chiếu IP sysctl của nhân liệt kê cả ba.
Xác nhận bằng ba lệnh
Đầu tiên, đọc giá trị đang chạy thay vì tập tin bạn nghĩ là đã nạp:
sysctl net.ipv6.conf.eth0.forwarding net.ipv6.conf.all.forwarding \
net.ipv6.conf.eth0.accept_ra net.ipv6.conf.eth0.accept_ra_defrtrThứ hai, chứng minh rằng quảng cáo vẫn đến. Lọc theo byte loại ICMPv6 là đủ, và nó tránh cho bạn phải đọc một bức tường lưu lượng phát hiện hàng xóm:
tcpdump -ni eth0 'icmp6 and ip6[40] == 134'Nếu không thấy gì trong vài phút, accept_ra không phải vấn đề của bạn. Phía thượng nguồn đã ngừng quảng cáo, có gì đó trên đường đi lọc ICMPv6, hoặc giao diện đó thật sự không nằm trên phân đoạn bạn nghĩ. Thứ ba, tự yêu cầu một quảng cáo và đọc các trường của nó:
rdisc6 eth0rdisc6 có trong gói ndisc6 trên Debian và Ubuntu. Trong đầu ra, hãy xem thời hạn router và ưu tiên trước khi thay đổi bất cứ điều gì khác. Một quảng cáo có thời hạn router bằng 0 là chỉ thị gỡ router mặc định, và không giá trị accept_ra nào biến nó thành tuyến dùng được. Đây cũng là cách bạn bắt được một CPE thượng nguồn ở chế độ cầu nối vốn chia tiền tố nhưng không bao giờ tự nhận là router.
Biến uplink thành giao diện duy nhất cho phép
Nếu phía thượng nguồn phải là router mặc định, hãy chấp nhận quảng cáo ở đó bất chấp chuyển tiếp, và không ở nơi nào khác:
# /etc/sysctl.d/60-ipv6-router.conf
net.ipv6.conf.all.forwarding = 1
net.ipv6.conf.eth0.accept_ra = 2
net.ipv6.conf.eth0.accept_ra_defrtr = 1Việc giới hạn phạm vi quan trọng vì chuyển tiếp IPv6 trong Linux là một công tắc toàn cục, không phải một công tắc cho mỗi liên kết. Ghi 1 vào net.ipv6.conf.wg0.forwarding rồi đọc net.ipv6.conf.all.forwarding: giá trị toàn cục đảo lại và mọi giao diện bắt đầu chuyển tiếp. Bạn không thể vừa là router trên đường hầm vừa là máy chủ thường trên LAN. Thứ bạn giới hạn được là việc chấp nhận. Giữ accept_ra=2 trên uplink và để các giao diện đường hầm và LAN ở 1 hoặc 0, để một quảng cáo lạc đường đến qua đường hầm không thể cài tuyến mặc định trỏ vào trong đó.
sysctl -w tạm thời sẽ không sống qua lần khởi động lại kế tiếp, và cả systemd-networkd lẫn NetworkManager đều ghi các giá trị này từ cấu hình riêng của chúng. Trong networkd, đặt IPv6Forwarding=yes và IPv6AcceptRA=yes trong tập tin .network của uplink; networkd ghi nhận IPv6Forwarding là toàn cục vì cùng lý do phía nhân. Với NetworkManager, ipv6.method=auto trên uplink là thứ điều khiển giá trị accept_ra, nên hãy đọc lại sysctl sau nmcli connection up thay vì tin vào lần kiểm tra đầu tiên.
Phương án tĩnh, ip -6 route add default via fe80::1 dev eth0, thực sự hoạt động, và đó là câu trả lời hợp lý khi router thượng nguồn có địa chỉ link-local ổn định. Hãy rõ ràng về những gì bạn đánh đổi. Tuyến mặc định tĩnh không bao giờ được làm mới và không bao giờ bị thu hồi, nên nó tiếp tục trỏ tới một hàng xóm đã chết sau khi phía thượng nguồn được thay. Tuyến RA hỏng một cách an toàn; tuyến tĩnh hỏng một cách âm thầm.
Kiểm tra gói được chuyển tiếp, không phải gói của chính cổng
Ping của chính cổng có thể thành công trên một tuyến mà không máy khách nào dùng được, và cũng có thể thành công vì cổng là nguồn. Hãy kiểm tra từ một máy khách đã kết nối, rồi hỏi cổng xem nó sẽ làm gì cho địa chỉ của máy khách đó:
# on the VPN client
ping -6 -c 3 2001:4860:4860::8888
# on the gateway, using a client address
ip -6 route get 2001:4860:4860::8888 from fd42:20::2Sau đó chờ một thời hạn router và xem lại. Trạng thái ổn định bạn muốn là một tuyến mặc định được đánh dấu proto ra với giá trị expires liên tục được đặt lại, cộng với all.forwarding=1. Nếu expires chỉ đếm ngược, quảng cáo vẫn đang bị bỏ ở đâu đó, và thủ phạm thường là một trình quản lý mạng ghi đè accept_ra sau khi sysctl lúc khởi động đã chạy.
Trước khi kết thúc, hãy xác nhận bốn điều: tuyến mặc định là proto ra và đang được làm mới, accept_ra=2 chỉ áp dụng cho uplink, chuyển tiếp vẫn là 1 sau khi khởi động lại và sau khi khởi động lại trình quản lý, và chính máy khách chứ không phải cổng hoàn tất một ping IPv6. Nếu máy khách vẫn thất bại với tuyến lành mạnh, nghi phạm tiếp theo là đường về hoặc một tường lửa thượng nguồn, không phải quảng cáo.