간단히 말해서:입장0.0.0.0
:port
(예: ) (내부적으로) (포트 번호는 어디에 있습니까?) curl http://0.0.0.0:443
로 리디렉션됩니다 (예: 이전 명령 과 동일 ).127.0.0.1:port
port
curl
curl http://127.0.0.1:443
왜이런 일이 일어날까요?어떻게연결을 차단 0.0.0.0
하시겠습니까?
업데이트 2:Linux 커널(버전 6.0.9)을 패치하여 이를 방지하는 방법을 찾았습니다.
--- .orig/usr/src/linux/net/ipv4/route.c
+++ /usr/src/linux/net/ipv4/route.c
@@ -2740,14 +2740,17 @@ struct rtable *ip_route_output_key_hash_
}
if (!fl4->daddr) {
- fl4->daddr = fl4->saddr;
+ rth = ERR_PTR(-ENETUNREACH);
+ goto out;
+ /* commenting out the rest:
+ fl4->daddr = fl4->saddr; // if you did specify src address and dest is 0.0.0.0 then set dest=src addr
if (!fl4->daddr)
- fl4->daddr = fl4->saddr = htonl(INADDR_LOOPBACK);
+ fl4->daddr = fl4->saddr = htonl(INADDR_LOOPBACK); // if you didn't specify source address and dest address is 0.0.0.0 then make them both 127.0.0.1
dev_out = net->loopback_dev;
fl4->flowi4_oif = LOOPBACK_IFINDEX;
res->type = RTN_LOCAL;
flags |= RTCF_LOCAL;
- goto make_route;
+ goto make_route; END of COMMENTed out block */
}
err = fib_lookup(net, fl4, res, 0);
결과: IP 0.0.0.0으로 전송된 패킷은 어디로 가나요? :
$ ip route get 0.0.0.0
RTNETLINK answers: Network is unreachable
...그들은하지 않습니다!
클라이언트는 127.1.2.18:5000에서 0.0.0.0:80으로 연결을 시도합니다.
$ nc -n -s 127.1.2.18 -p 5000 -vvvvvvvv -- 0.0.0.0 80
(UNKNOWN) [0.0.0.0] 80 (http) : Network is unreachable
sent 0, rcvd 0
(커널 패치를 적용하지 않은 경우 위 클라이언트가 성공적으로 연결되려면 다음과 같은 서버가 필요합니다: (루트로, bash에서) while true; do nc -n -l -p 80 -s 127.1.2.18 -vvvvvvvv -- 127.1.2.18 5000; echo "------------------$(date)";sleep 1; done
)
수정됨 ping
(즉, ping
대상 주소가 0.0.0.0일 때 대상 주소를 소스 주소와 동일하게 설정하지 않음, 즉 // special case for 0 dst address
아래에 표시된 2줄을 주석 처리함)여기):
$ ping -c1 0.0.0.0
ping: connect: Network is unreachable
즉각적인. 그러나 소스 주소를 지정하는 경우 완료하려면 시간 초과(10초)가 필요합니다.
$ ping -I 127.1.2.3 -c1 -- 0.0.0.0
PING 0.0.0.0 (0.0.0.0) from 127.1.2.3 : 56(84) bytes of data.
--- 0.0.0.0 ping statistics ---
1 packets transmitted, 0 received, 100% packet loss, time 0ms
업데이트 1:
이것왜부분적으로 설명됨여기하지만 왜 이런 일이 발생하는지에 대한 자세한 내용을 기대하고 있습니다. 예를 들어 ( anyone
liberachat #kernel 채널에서 닉네임을 가진 사용자에게 감사드립니다):
$ ip route get 0.0.0.0
local 0.0.0.0 dev lo src 127.0.0.1 uid 1000
cache <local>
이는 어떻게든 localhost로 향하는 패킷이 0.0.0.0
localhost 인터페이스로 라우팅되어 lo
소스 IP를 얻고 127.0.0.1
(올바르게 해석한 경우) 해당 경로 때문에 이 목록에 표시되지 않음을 의미합니다.
$ ip route list table local
local 127.0.0.0/8 dev lo proto kernel scope host src 127.0.0.1
local 127.0.0.1 dev lo proto kernel scope host src 127.0.0.1
broadcast 127.255.255.255 dev lo proto kernel scope link src 127.0.0.1
local 169.254.6.5 dev em1 proto kernel scope host src 169.254.6.5
broadcast 169.254.6.255 dev em1 proto kernel scope link src 169.254.6.5
local 192.168.0.17 dev em1 proto kernel scope host src 192.168.0.17
broadcast 192.168.255.255 dev em1 proto kernel scope link src 192.168.0.17
이는 이것이 어떻게든 Linux 커널 내부에 존재해야 함을 의미합니다. 즉. 하드코딩된
아이디어를 제공하기 위해 인터넷에서 IP를 찾는 방법은 다음과 같습니다(예시 IP로 쿼드1을 사용했습니다).
$ ip route get 1.1.1.1
1.1.1.1 via 192.168.1.1 dev em1 src 192.168.0.17 uid 1000
cache
내 게이트웨이는 어디에 있습니까 192.168.1.1
?
$ ip route
default via 192.168.1.1 dev em1 metric 2
169.254.6.0/24 dev em1 proto kernel scope link src 169.254.6.5
192.168.0.0/16 dev em1 proto kernel scope link src 192.168.0.17
0.0.0.0으로 향하고 어떻게든 127.0.0.1로 라우팅되는 연결을 감지(따라서 차단/삭제)할 방법이 없으므로 iptables
차단할 방법을 찾는 것이 어려울 수 있습니다. 하지만 확실히 찾으려고 노력할 것입니다. 누군가가 이미 알고 있지 않는 한 한 가지 방법입니다.
@Stephen Kitt(의견에서)는 /etc/hosts에 있는 호스트 이름을 차단하는 방법을 제안했으므로 (127.0.0.1 이외의 이름)
0.0.0.0 someblockedhostname
사용할 수 있지만
127.1.2.3 someblockedhostname
127.1.2.3 someOTHERblockedhostname
원하지 않는 한 차단된 각 호스트 이름은 동일한 IP를 사용하는 것을 차단할 수 있습니다. 구별)
그런 다음 차단할 IP를 사용할 수 있습니다 iptables
.
그러나 DNS 확인자(예:다음 DNS, 또는1.1.1.30.0.0.0
) 가 차단된 호스트 이름( 대신 )을 반환 NXDOMAIN
하면 이 작업을 수행할 수 없습니다(물론 /etc/hosts에 각 호스트가 우선하기 때문에 수동으로 추가하려는 경우는 제외 - 에서 /etc/hosts
줄을 변경하지 않는다고 가정 ).hosts: files dns
/etc/nsswitch.conf
오래된:(편집하긴 했지만)
Linux(최신 Gentoo 및 Pop OS!를 사용해 보았습니다)에서 다음 줄이 있는 경우 /etc/hosts
:
0.0.0.0 somehosthere
그런 다음 루트로 실행하고(포트 443에서 수신하는 로컬 호스트 서버를 시뮬레이션하기 위해)
# nc -l -p 443 -s 127.0.0.1
브라우저로 이동하여(Firefox 및 Chrome/Chromium으로 테스트) 이를 주소 표시줄에 입력
https://somehosthere
합니다
0.0.0.0:443
.
https://0.0.0.0
그런 다음 시작한 터미널 nc
(일명 netcat)에 연결 시도가 표시됩니다( somehosthere
URL에 사용하는 경우 일반 텍스트를 포함한 일부 쓰레기 텍스트).
또는 브라우저 대신 다음을 시도해 볼 수 있습니다.
curl https://somehosthere
또는 일반 텍스트 요청을 보려면 다음을 수행하세요.
curl http://somehosthere:443
오랫동안 사용해 dnsmasq
도 완화되지 않는 것 같지만 DNS 확인자(예: NextDNS 또는0.0.0.0 somehosthere
/etc/hosts
dnsmasq
클라우드플레어 1.1.1.3) 는 ( 0.0.0.0
대신에 반환됩니다.NXDOMAIN
진짜이 글을 쓰는 시점에서) 해당 호스트 이름이 귀하의 호스트 이름 /etc/hosts
(및 귀하가 사용 dnsmasq
하도록 지시한 /etc/hosts
호스트 이름 )에 없으면 이를 완화할 수 있는 두 가지 방법이 있습니다(둘 중 하나 또는 둘 다 작동함).
dnsmasq
매개변수 사용--stop-dns-rebind
--stop-dns-rebind
Reject (and log) addresses from upstream nameservers which are in
the private ranges. This blocks an attack where a browser behind
a firewall is used to probe machines on the local network. For
IPv6, the private range covers the IPv4-mapped addresses in pri‐
vate space plus all link-local (LL) and site-local (ULA) ad‐
dresses.
- 이 줄을 사용하면 확인된 호스트 이름
bogus-nxdomain=0.0.0.0
이 무엇이든/etc/dnsmasq.conf
자동으로dnsmasq
반환됩니다 (해당 호스트 이름이 다시 /etc/hosts에 있는 경우(dnsmasq 우회) 및 그렇게 하는 경우 dnsmasq에 사용하도록 지시한 내용이 아닌 경우 ).NXDOMAIN
0.0.0.0
/etc/hosts
그래서 질문의 두 번째 부분은0.0.0.0에 대한 액세스가 127.0.0.1로 리디렉션되는 것을 방지하는 방법은 무엇입니까?NextDNS를 사용할 때(또는1.1.1.3 클라우드플레어) DNS 확인자로서 0.0.0.0
NXDOMAIN 대신 차단된 호스트 이름을 반환하므로 웹 페이지를 로드할 때 웹 페이지의 일부(차단된 호스트 이름에 있음)가 포트 443(있는 경우)에서 실행되는 로컬 호스트 서버에 액세스하려고 시도하고 로드됩니다. 단순히 차단되는 것이 아니라 페이지를 차단하는 것입니다.
이를 알고 있는 관련 브라우저별 공개 문제(0.0.0.0은 127.0.0.1에 매핑됨):
Chrome/Chromium:https://bugs.chromium.org/p/chromium/issues/detail?id=1300021
파이어폭스 브라우저:https://bugzilla.mozilla.org/show_bug.cgi?id=1672528#c17
답변1
왜 이런 일이 일어나는지에 대한 설명은 다음과 같습니다IP 0.0.0.0에 성공적으로 연결되었습니다. 어떻게? 왜?— 간단히 말해서, 대상 주소(0.0.0.0)가 없는 패킷은 소스 주소가 대상 주소로 복사되는 반면, 소스 또는 대상이 없는 패킷은 소스 및 대상 주소가 루프백 주소(INADDR_LOOPBACK
, 127.0.0.1) 생성된 데이터 패킷은 루프백 인터페이스를 통해 전송됩니다.
확인하신 바와 같이 이 동작은Linux 커널의 IPv4 네트워크 스택에 하드코딩됨, 이를 변경하는 유일한 방법은 커널을 패치하는 것입니다.
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 795cbe1de912..df15a685f04c 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -2740,14 +2740,8 @@ struct rtable *ip_route_output_key_hash_rcu(struct net *net, struct flowi4 *fl4,
}
if (!fl4->daddr) {
- fl4->daddr = fl4->saddr;
- if (!fl4->daddr)
- fl4->daddr = fl4->saddr = htonl(INADDR_LOOPBACK);
- dev_out = net->loopback_dev;
- fl4->flowi4_oif = LOOPBACK_IFINDEX;
- res->type = RTN_LOCAL;
- flags |= RTCF_LOCAL;
- goto make_route;
+ rth = ERR_PTR(-ENETUNREACH);
+ goto out;
}
err = fib_lookup(net, fl4, res, 0);
이 패치는 위의 "왜?" 부분을 설명하는 원래 구현을 보여줍니다. 패킷에 대상 주소가 없는 경우(즉0.0.0.0):
- 소스 주소가 대상 주소로 복사됩니다.
- 패킷의 경우아직목적지 주소가 없습니다.즉또한 소스 주소가 없으며 두 주소 모두 루프백 주소(127.0.0.1)로 설정됩니다.
- 모든 경우에 발신 장치는 루프백 장치로 설정되고 이에 따라 경로가 구성됩니다.
패치는 대신 "Network Unreachable" 오류를 반환하도록 이 동작을 변경합니다.
답변2
짧은 대답은 그렇지 않다는 것입니다. 그보다 훨씬 더 나쁩니다.
0.0.0.0에 매핑된 IP 주소어느시스템의 인터페이스. 따라서 열려 있는 netstat
경우 시스템은 루프백, 이더넷, Wi-Fi 및 기타 네트워크 인터페이스를 통해 들어오는 SSH 연결을 허용합니다. 단지 루프백이 포트를 수신하는 유일한 인터페이스이거나 인터페이스 중에서 우선순위를 갖는다는 것입니다.ip
0.0.0.0:22