우연히 이것이 ip rule add from 0.0.0.0/8 unreachable
네트워크를 깨뜨리는 것을 발견했습니다. 동일한 LAN에서 ping을 실행해도 작동하지 않습니다. 이유를 모르겠습니다.
0.0.0.0/8
IPv4 주소 블록은 예약되어 있으며 실제 IP를 찾기 위해 DHCP 등을 사용하는 시스템에서만 사용할 수 있다는 것을 기억합니다 . 이것은 내 경우가 아니며 모든 호스트가 정적으로 구성됩니다. 주소가 보일 줄은 전혀 예상하지 못했습니다 0.0.0.0
. DHCP를 사용하더라도 이러한 패킷은 현재 LAN으로 제한되며 라우팅되지 않습니다.
그렇다면 이 규칙이 정상적인 트래픽을 방해하는 이유는 무엇입니까?
답변1
소켓이 연결될 때(예:connect(2)
시스템 호출을 사용하여 IPv4 대상으로 다음을 수행할 수 있습니다.
누구나
bind(2)
연결하기 전에 특정 주소로 이동하세요또는 바인딩되지 않음은 바인딩과 동일합니다.INADDR_ANY일명 0.0.0.0은 사용될 실제 소스 주소가 결정될 때까지 자리 표시자로 사용됩니다.
종종 다양한 라우팅 항목이 소스 주소가 0.0.0.0으로 유지될 수 없기 때문에 결국 소스 주소가 무엇인지 결정합니다.소스 코드경로 항목의 매개변수 또는 이 경로에 대해 선택된 인터페이스의 기본 주소입니다.
하지만 추가 라우팅으로 인해규칙( from 0.0.0.0/32 unreachable
동일한 결과가 나올 수도 있습니다.) 테이블에서 초기 경로 조회기본절대 발생하지 않음:
$ ip rule
0: from all lookup local
32765: from 0.0.0.0/8 unreachable
32766: from all lookup main
32767: from all lookup default
라우팅 규칙 순회는 항목 우선 순위 32765에서 중지되며 해당 항목을 찾는 다음 항목에는 도달하지 않습니다.기본라우팅 테이블. 이 라우팅 규칙을 추가하기 전에는 소스 주소가 실제 주소로 업데이트되고 진행 중인 트래픽이 여전히 제대로 작동하므로 바인딩된 소켓 없이 바인딩된 소켓(설정된 연결 포함)만 시작되었습니다.
예를 들어, 시스템 인터페이스의 주소가 192.0.2.2/24라고 가정합니다.이더넷 0, 5555/tcp에서 수신 대기하는 서비스에서 192.0.2.1에 연결을 시도합니다.
socat tcp4:192.0.2.1:5555 -
이제 이 경로 조회가 실패하므로 실패합니다.
$ ip route get to 192.0.2.1
RTNETLINK answers: Network is unreachable
( 와 동일 ip route get from 0.0.0.0 to 192.0.2.1
)
가짜 라우팅 규칙에도 불구하고 먼저 192.0.2.2에 명시적으로 바인딩하면 성공합니다.
socat tcp4:192.0.2.1:5555,bind=192.0.2.2 -
같은 이유로 이 경로 조회는 여전히 성공합니다.
$ ip route get from 192.0.2.2 to 192.0.2.1
192.0.2.1 from 192.0.2.2 dev eth0 uid 1000
cache
이것~에서소스가 추가 라우팅 규칙과 일치하지 않습니다.
가짜 라우팅 규칙이 처음에 존재하지 않으면 첫 번째 예는 성공하고 나중에 추가하면 연결된 소켓은 더 이상 가짜 라우팅 규칙의 영향을 받지 않습니다. 0.0.0.0 주소는 이 연결에 대한 모든 조회에 더 이상 나타나지 않습니다. .
커널 소스에 몇 가지 명확한 답변이 있지만 이를 철저하게 따라가는 것은 내 능력을 약간 벗어났습니다. connect(2)
그렇지 않은 경우에는 다음과 같이 말할 수 있습니다 bind(2)
.
connect(2)
결국 사용될 것이다ip_route_connect()
(예를 들어, 커널에서:전송 제어 프로토콜또는UDP 또는 원시경우...) 0.0.0.0을 와일드카드 소스 주소로 사용하여 경로와 실제 소스를 결정합니다.그런 다음 이전 함수의 결과로 소켓의 소스를 업데이트합니다(전송 제어 프로토콜,UDP 또는 원시...).
하지만 가짜 라우팅 규칙을 추가한 후
ip_route_connect()
결국 다음을 수행하게 됩니다.fib_rules_lookup()
이는 0.0.0.0 소스와 일치합니다.접근할 수 없음규칙이connect(2)
실패합니다.