1P by GN⁺ | ★ favorite | 댓글 2개
  • Little Snitch 6.1에서 DNS 암호화가 일부 상황에서 실패할 수 있었으나, macOS 전반 문제가 아니라 해당 버전의 문제로 좁혀졌고 6.1.1에서 수정됨
  • 정상 동작하려면 macOS의 DNS 요청이 Little Snitch의 DNS 프록시로 전달되고, 프록시가 암호화된 조회를 수행해야 함
  • 조사 중 일부 저수준 레거시 API 요청이 프록시에 도달하지 않고 시스템 기본 네임서버로 암호화되지 않은 UDP 53 조회를 보내는 현상이 관찰됨
  • 재현은 Little Snitch에서 DNS 암호화를 켜고 Wireshark를 port 53 필터로 실행한 뒤 Xcode playground에서 getaddrinfo("dnsproxytest.com")를 호출하는 방식임
  • Safari와 Chrome 같은 고수준 API 기반 조회는 초기에는 영향이 없어 보였고 Firefox는 영향이 있는 것으로 보였지만, 최종 범위는 Little Snitch 6.1의 DNS 프록시로 정리됨

Little Snitch 6.1에서 발생한 DNS 암호화 실패

  • Little Snitch 6의 DNS 암호화 기능은 호스트명 조회를 Little Snitch로 라우팅해 암호화된 형태로 처리함
  • 이를 위해 Little Snitch는 DNS 프록시를 등록하고, macOS는 모든 DNS 요청을 해당 프록시로 보내야 함
  • 일부 DNS 요청, 특히 특정 저수준 레거시 API를 통한 요청은 프록시에 수신되지 않는 현상이 발견됨
  • 해당 요청은 시스템 기본 네임서버로 암호화되지 않은 형태로 전송될 수 있었고, Wireshark에서는 UDP 포트 53 트래픽으로 확인 가능했음
  • Little Snitch Network Monitor에는 해당 조회 트래픽이 표시되지 않았으며, 조회가 네트워크 필터를 완전히 우회했기 때문임

재현 절차와 업데이트 경과

  • 재현 절차

    • Little Snitch 설정에서 DNS encryption을 활성화함
    • Wiresharkport 53 캡처 필터로 실행함
    • Xcode playground에서 getaddrinfodnsproxytest.com 조회를 실행함
    • dnsproxytest.com 조회가 UDP 53에서 암호화되지 않은 형태로 보일 수 있음
  • 초기 영향 범위

    • 고수준 API를 통한 DNS 조회는 영향을 받지 않는 것으로 보였음
    • Safari와 Chrome의 웹 브라우징은 암호화된 조회의 이점을 유지하는 것으로 보였음
    • Firefox는 영향을 받는 것으로 보였음
  • 업데이트 내역

    • 2024-09-17 19:10: 이 문제가 macOS 14.5 Sonoma부터 존재했을 수 있음이 확인됐고, 더 오래된 14.x 시스템은 테스트할 수 없었음
    • 2024-09-18 12:05: macOS의 일반적인 DNS 프록시 문제가 아니라 Little Snitch 6.1의 DNS 프록시에만 영향을 주는 문제로 정리됨
    • 2024-09-18 15:52: 문제는 Little Snitch 6.1.1에서 수정됨

댓글과 토론

Hacker News 의견들
  • getaddrinfo() 가 “저수준 레거시 API”로 취급된다는 게 좀 이상하게 느껴짐
    macOS에서는 상황이 크게 다를 수 있지만, Linux와 아마 *BSD에서는 이름 해석에 쓰는 표준적인 방식임
    macOS 앱 대부분은 DNS 질의에 Foundation이나 NetworkKit류 프레임워크를 쓰겠지만, 그 내부가 결국 getaddrinfo() 같은 호출로 내려가 처리하지 않는다는 점도 의외임
    GAI가 블로킹이라서, 아마 다른 저수준 비동기 호출이 있는 듯함

    • 맞음. CFNetwork는 오픈소스라 구현을 확인할 수 있고, 예전에 봤을 때는 getaddrinfo_async 같은 변형을 썼던 것으로 기억함
      다만 Apple은 최종 사용자가 getaddrinfo나 CF가 노출하는 비동기 변형으로 IP를 직접 해석한 뒤 그 IP로 connect()하는 방식을 원하지 않음
      전반적으로 호스트명으로 연결하도록 유도돼 있고, 그래야 Apple이 내부적으로 해피 아이볼스(happy-eyeballs) 구현을 처리할 수 있음
      Apple이 getaddrinfo() 모델을 왜 선호하지 않는지는 https://www.ietf.org/proceedings/72/slides/plenaryw-6.pdf에서 볼 수 있음. 각 슬라이드 아래에 발표자 노트도 있음
    • getaddrinfo()가 레거시로 간주된다고 보지는 않음. 그 블로그 글이 이 부분은 잘못 쓴 것 같음
      “저수준”인지 여부는 관점에 따라 달라짐
    • getaddrinfo() 는 Linux와 관련된 게 아니라 그냥 glibc 함수
      사람들이 glibc가 Linux 사용자 공간의 표준 방식이라고 가정하지만 꼭 그래야 하는 건 아님
      예를 들어 systemd는 자체 resolved 메커니즘을 만들었고, glibc 쪽보다 훨씬 나은 것으로 드러났음
      나도 Linux를 대상으로 하는 독립 실행형 소프트웨어를 만들고 있어서 언젠가 직접 비슷한 걸 만들 가능성이 큼
    • OpenBSD에서는 적어도 getaddrinfo/gethostbyname 같은 전통적·표준 DNS 함수들이 모두 Eric Faurot가 작성한 OpenBSD libc asr 구현의 래퍼임
      https://man.openbsd.org/man3/asr_run.3
      https://github.com/openbsd/src/tree/master/lib/libc/asr
    • 이 경우가 정확히 그런지는 모르겠지만, 같은 이름의 시스템 함수라도 *Linux/BSD/macOS 사이에서 내부 구현이 크게 다를 수 있음
      *BSD들 사이에도 차이가 있음
      어떤 시스템에서는 한 함수 호출이 수년간 유지되어 “정석”이지만, 다른 시스템에서는 실제로 낡고 유용하지 않을 수 있음
  • 여기서 다룬 문제는 macOS 전반의 문제가 아니라 Little Snitch 6.1에만 해당하는 것으로 드러났고, 오늘 늦게 Little Snitch 업데이트로 수정될 예정임

    • 제목도 이 내용을 반영하도록 업데이트할 수 있으면 좋겠음
  • 추가 조사 결과, 이 버그는 적어도 macOS 14.5 Sonoma부터 이미 존재했음
    어쩌면 더 이전부터였을 수도 있지만, 현재 테스트할 더 오래된 14.x 시스템에 접근할 수 없다고 함

    • getaddrinfo에서 실제로 동작했는지 테스트한 적이 있는지 궁금함
      아니면 CFNetwork에서 한 번 동작하는 걸 보고 끝낸 뒤, 나중에 고장났다는 블로그 글을 올린 건지 모르겠음
    • 개발자들이 테스트를 위해 예전 OS 버전을 따로 보존해야 하는 상황은 아직도 말이 안 됨
      Apple이 다운그레이드를 허용하지 못할 기술적 이유는 0에 가까움
    • 제품을 판매 중이고 새 OS가 어제 나왔다는 점을 생각하면, 이것도 꽤 황당함
  • Sequoia는 macOS 방화벽이 켜져 있고 앱이 “들어오는 연결 차단”으로 등록돼 있으면, 해당 앱이 DNS를 쓰는 능력, 아마 UDP 기반 기능 전반도 깨뜨림
    https://waclaw.blog/macos-firewall-blocking-web-browsing-aft...

    • 재현이 안 됨. 일부는 ESET과 관련 있다고 말함: https://www.reddit.com/r/MacOS/comments/1fievr5/updating_mad...
    • Sequoia 이전에는 VPN에서 OpenDNS를 써도 VPN에 연결된 상태로 iMessage와 다른 앱들이 계속 동작했는데, Sequoia 이후에는 VPN 연결 중 iMessage 문자 등이 더 이상 동작하지 않음
      VPN을 끊으면 모두 통과함
      이것과 관련이 있는지 궁금함. macOS 방화벽은 켜져 있지만 모든 들어오는 연결 차단은 아님
    • Sequoia로 업그레이드한 뒤 Safari나 Mozilla로 탐색할 수 없었음
      Wi-Fi 연결의 DNS 설정에 들어가 Google DNS 서버인 8.8.8.88.8.4.4를 추가하니 해결됐고, 기존에 자동 입력되어 있던 DNS 서버를 대체했음
    • 솔직히 이런 동작은 괜찮다고 봄. 애플리케이션이 설정에 지정한 것 밖에서 자체적으로 DNS를 해석하면 안 됨
      앱들이 이렇게 하는 이유는 사용자가 원격 측정 같은 걸 차단하지 못하게 하려는 데 있음
      내 컴퓨터이니 무엇이 밖으로 나가는지에 대한 최종 결정권은 나에게 있어야 함
  • 제목은 이게 의도적이거나 Apple에 특권적으로 적용되는 것처럼 암시하지만, 실제로는 그냥 버그에 더 가까워 보임
    이런 내용을 신고했다고 할 때는 FB 번호와 신고 세부사항도 같이 올려주면 좋겠음

    • 악마의 대변인 입장에서는, 반발을 피하려고 일부러 이렇게 만들고 고치지 않는 버그처럼 보이게 할 수도 있음
      목표만 달성된다면 구현 방식은 얼마든지 유연함
    • 의도적이었다면 아마 하드코딩되고 암호화된 URL이었을 것임
      일부 기기는 광고 차단을 우회하려고 이미 그런 방식을 쓰기 시작했음
  • 착각일 수도 있지만, iOS나 Mac 새 릴리스 때마다 DNS 문제가 생겨 Little Snitch, Mullvad 같은 것들에 영향을 준다는 데자뷔가 있음
    사실이라면 Apple이 수개월간의 개발자·베타 테스트 동안 무엇을 하는지 정말 의문임

  • Little Snitch 언급이 헷갈렸는데, 더 읽어보니 특정 경우에만 동작하는 LS 버그처럼 보임
    이게 LS 블로그라면, 왜 macOS 버그처럼 묘사되는지가 유일한 의문임
    틀렸다는 뜻은 아니고, 그들의 영역이지 내 영역은 아니지만, 본문만으로는 정당화가 잘 안 돼 보임

    • OS가 DNS 프록시 등록을 허용해놓고 일부 호출이 그 프록시를 우회한다면, 그건 명백히 OS 버그임
  • Apple이 서드파티 개발자에게 특정 네트워크 API 사용을 폐기 처리했던 것으로 기억함
    하지만 Apple 자체 앱, 예를 들어 App Store는 같은 제한을 받지 않음
    그래서 새 API로 앱 방화벽을 통해 네트워크 트래픽을 필터링하려 하면, App Store가 레거시 API를 써서 실패했음
    예전에 고쳐진 줄 알았던 오래된 버그의 일부일 수도 있음

    • getaddrinfo()는 레거시 API가 아니라, DNS 조회를 위한 표준 크로스플랫폼 API
  • “새 OS 릴리스에서 버그 발견! 수정: 사실 꽤 오래전부터 있던 버그였음!” 같은 발표는 언제나 재미있음

  • 로컬 스텁 해석기로 routedns [0]를 써서 어떤 요청을 어디로 보내고 어떤 전송 방식을 쓸지 직접 고르고 있음
    차단 목록, 재작성, 캐시, 부하 분산, 대체 요청 처리도 가능해서 제어권이 많음
    로컬 요청에는 localhost:53의 스텁 리스너를 쓰고, 대부분의 요청은 캐시와 함께 UDP QUIC, 즉 TLS 0-RTT로 Cloudflare 1.1.1.1에 전달함
    빠르고 꽤 안전함
    [0] https://github.com/folbricht/routedns

중요한 정보 감사합니다.
일단 사파리, 크롬은 안심할 수 있다고 하니 다행입니다.