컴퓨터의 외부 IP 주소 (외부 인터넷 호스트가 내 컴퓨터를 볼 때 어떤 IP 주소로 인식하는지)를 얻어올 수 있는 라이브러리가 있으면 좋겠다는 생각에서 출발하여 만든 간단한 라이브러리 NuGet 패키지를 올려봅니다.
하고자 하는 일은 단순하지만 의외로 생각해볼 점이 많았던 흥미로운 구현 작업이었습니다.
시중에 ipify, ip6.me 등 무료로 IP 주소를 보여주는 서비스들이 많이 있습니다만, 수익 모델이 분명하지 않은 무료 서비스들이라 서비스 지속 가능성이 보장되지 않는다고 판단했습니다. 그래서 찾아보니 비슷한 서비스들이 시중에 이미 많이 나와있었고, 이런 서비스들을 동시에 쿼리하도록 라이브러리를 설계하는 것이 안정성에 도움이 되겠다고 생각했습니다.
HttpClient를 그냥 사용하면, 현재 컴퓨터가 듀얼 스택 네트워크 (IPv4와 IPv6를 동시에 쓰는 상태)에서는 외부에서 보여지는 IP 주소 버전을 명시적으로 선택할 수 없다는 문제가 있었습니다. 이를 해결하기 위해서 SocketsHttpHandler를 사용하면 되겠지만, 안타깝게도 이 API는 .NET Standard에 포함된 스펙이 아니었고, .NET Standard 환경에서 쓸 수 있는 범용 NuGet 패키지를 만들고 싶었기 때문에, HTTP 클라이언트 대신 과감하게 System.Net.Sockets.Socket 클래스를 사용하도록 바꾸었고, SSL 지원도 같이 고려할 수 있도록 만들었습니다.
듀얼 스택 네트워크를 테스트하기 위해, 개인적으로 보유하고 있는 Azure VM에 듀얼 스택 네트워크를 붙여 이 라이브러리가 IPv6 환경에서 잘 동작하는지 테스트해볼 수 있었습니다.
와일드카드 도메인 서비스는 IP 주소를 이용하여 퍼블릭 DNS 주소를 만들어주는 유용한 서비스입니다. 이 중에서도 sslip.io의 경우 기본 서비스 외에도 GitHub에 sslip DNS 서버 (Go로 만듦)를 오픈 소스로 공개하고 있어서, IP 주소를 와일드카드 도메인 주소로 변환해주는 도우미 메서드를 간단히 추가하면 유용하겠다는 생각이 들어 해당 구현을 추가했습니다.
이러한 배경 맥락에서 다음과 같이 프로젝트와 NuGet 패키지를 릴리즈해보았습니다.
코드 사용 방법은 대략 다음과 같습니다.
using ReflectionIPAddress;
...
var services = new PublicAddressReflectionServices()
.AddService<IpifyService>()
.AddService<SeeIPService>()
.AddService<IP6MeService>()
.AddService<CurlMyIPService>()
.AddService<ICanHazIPService>()
.AddService<IFConfigService>();
// Returns the IP address by checking for the fastest successful response among the specified services.
var ipv4Address = await services.ReflectIPv4Async();
var sslipDomain = ipv4Address.ToSSLIPDomain();
//var ipv6Address = await services.ReflectIPv6Async();
Console.Out.WriteLine($"IPv4 Address: {ipv4Address}, SSLIP Domain: {sslipDomain}");")
덧. TCP 소켓을 사용하기로 결정한 것은 제가 생각하기에 당분간은 문제가 없을 것으로 본 것이, HTTP 버전이 올라가더라도 Backward Compatibility를 보장해야 한다는 암묵적인 약속이 있는 것으로 보이고, 라이브러리에서 참조하는 서비스들 모두는 당장 HTTP/1.1 사양 지원을 곧바로 drop하지는 않을 것으로 보여 Socket으로 80이나 443 TCP 포트로 직접 연결하는 구현을 시도했습니다.
좀 더 범용적인 구현 방법 (HTTP 3.0의 QUIC/UDP까지 커버하는 구현 방법)을 쓰면서도 .NET Standard 범주 안에 속하도록 만들 방법은 개선 과제로 두어야 할 것 같습니다.