mDNS는 multicast DNS(Domain Name System)의 약어로 이 기술을 이용한 것으로는 애플사의 Bonjour서비스가 대표적이다. 일상생활에서는 가정 혹은 회사에서 네트워크에 연결된 프린터 혹은 다양한 멀티미디어 장치들이 자동으로 검색되는 것은 mDNS 기술을 이용했을 가능성이 크다.
IETF 규약
- RFC 6762 : Multicast DNS
- RFC 6763 : DNS Based Service Discovery
- RFC 1035 : Domain Names - Implementation & Specification
통신메시지 형식
+---------------------+
| Header |
+---------------------+
| Question | the question for the name server
+---------------------+
| Answer | RRs answering the question
+---------------------+
| Authority | RRs pointing toward an authority
+---------------------+
| Additional | RRs holding additional information
+---------------------+
Header 형식 (출처:RFC-1035)
1 1 1 1 1 1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ID |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|QR| Opcode |AA|TC|RD|RA| Z | RCODE |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| QDCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ANCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| NSCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ARCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
<< Header 항목 설명 >>
항 목 |
설명 및 정의 (DNS) |
mDNS |
ID |
조회문-응답문 짝을 맞추기 위한 구분값 |
0으로 설정한다. |
QR |
조회문이면 0, 응답문이면 1 |
|
OPCODE |
조회문의 종류를 구분하는 값 |
전송시 0으로 설정, 수신시 무시 |
AA |
응답문, 응답서버가 해당 도메인 담당서버 |
전송시 0으로 설정, 수신시 무시 |
TC |
추가 메시지 유무 |
전송시 0으로 설정, 수신시 무시 |
RD |
조회문, recursive query 옵션 |
전송시 0으로 설정, 수신시 무시 |
RA |
recursive query 지원 여부 |
전송시 0으로 설정, 수신시 무시 |
Z |
여분비트, RFC-2535에서 2개의 비트가 사용된다 |
전송시 0으로 설정, 수신시 무시 |
RCODE |
응답문, 응답코드 |
전송시 0으로 설정, 수신시 무시 |
QDCOUNT |
조회 갯수 |
|
ANCOUNT |
응답 갯수 |
|
NSCOUNT |
응답문, 응답코드 |
|
ARCOUNT |
응답문, 응답코드 |
|
<< 조회문(Query Message) 예 >>
항 목 | 바이트 스트림 | 의 미 |
Header | 00 00 00 00 |
|
QDCOUNT | 00 02 | 조회 2개 |
ANCOUNT | 00 00 | 0개 |
NSCOUNT | 00 00 | 0개 |
ARCOUNT | 00 00 | 0개 |
첫번째 Q:QNAME | 10 | 16바이트 NAME |
5F 69 70 73 63 61 6E 6E 65 72 62 65 61 63 6F 6E | _ipscannerbeacon | |
04 | 4바이트 NAME | |
5F 74 63 70 | _tcp | |
05 | 5바이트 NAME | |
6C 6F 63 61 6C | local | |
00 | QNAME 끝 | |
첫번째 Q:QTYPE | 00 0C | PTR |
첫번째 Q:QCLASS | 80 01 | 첫번째비트 ON:Unicast 선호 QCLASS: IN (Internet) |
두번째 Q:QNAME | 13 | 19바이트 NAME |
5F 69 70 73 5F 6D 61 63 | _ips_macsync_client | |
C0 | NAME 포인터 & QNAME 끝 | |
1D | NAME 포인터:주소:1D _tcp | |
두번째 Q:QTYPE | 00 0C | PTR |
두번째 Q:QCLASS | 80 01 | 첫번째비트 ON:Unicast 선호 QCLASS: IN (Internet) |
항 목 | 바이트 스트림 | 의 미 |
Header | 00 00 84 00 | QR-비트 ON |
QDCOUNT | 00 00 | 0개 |
ANCOUNT | 00 01 | 응답 1개 |
NSCOUNT | 00 00 | 0개 |
ARCOUNT | 00 01 | 추가정보 1개 |
응답:NAME | 0C | 12바이트 스트림 |
5F 73 6C 65 65 70 2D 70 72 6F 78 79 | _sleep-proxy | |
04 | 4바이트 스트림 | |
5F 75 64 70 | _udp | |
05 | 5바이트 스트림 | |
6C 6F 63 61 6C | local | |
00 | NAME 끝 | |
응답:TYPE | 00 0C | PTR |
응답:CLASS | 00 01 | IN (Internet) |
응답:TTL | 00 00 00 00 00 00 00 00 | 0초 = 정보 유지 안함 |
응답:데이터길이 | 00 19 | 25바이트 스트림 |
응답:데이터 | XX | |
XX XX 2D XX XX 2D XX XX 2D XX XX 2E 31 20 41 70 70 6C 65 20 54 56 | XX-XX-XX-XX.1 Apple TV | |
XX XX | ||
추가:NAME | 00 | NAME 끝 |
추가:TYPE | 00 29 | |
추가:CLASS | 05 A0 | |
추가:TTL | 00 00 11 94 | 4500초동안 정보 유지 |
추가:데이터길이 | 00 12 | 18바이트 스트림 |
추가:데이터 | 00 04 XX XX XX XX XX XX XX XX XX XX XX XX | MAC주소등 정보 |
자바 mDNS 테스트 코드
그동안 DNS모듈을 구현할 일이 없었는데, 이번에 관련 규약을 읽어보니 원래 DNS규약은 적은 양인듯 한데, 점점 많은 확장 규약들이 추가되서 상당히 방대한 양이었다. mDNS를 구현한 오픈소스 라이브러리를 구해서 사용해도 되지만 왠지 상당히 무겁지 않을까 생각된다. 만약 조회문에 대해 간단히 응답만하는 mDNS모듈을 구성한다면, 직접 구현하는 것도 모듈을 가볍게 하기에 도움이 된다고 본다. 혹시 도움이 될 지 모르지만 테스트 목적으로 작성한 Multicast 통신 샘플 코드를 추가한다.
mDNS는 224.0.0.251 : 5353 을 사용한다.
DatagramChannel mc = null;
try
{
InetAddress addr = InetAddress.getByName("127.0.0.1");
NetworkInterface ni = NetworkInterface.getByName("en1");
// Datagram 채널을 연다.
// "StandardProtocolFamily.INET"을 생략하면
// 예외가 발생함 ==> IPv6 socket cannot join IPv4 multicast group
mc = DatagramChannel.open(StandardProtocolFamily.INET);
// 몇가지 옵션을 설정
mc.setOption(StandardSocketOptions.SO_REUSEADDR, true);
mc.setOption(StandardSocketOptions.IP_MULTICAST_IF, ni);
// 포트를 5353에 맞춘다.
mc.bind(new InetSocketAddress(5353));
// 224.0.0.251 multicsting 그룹에 합류한다.
InetAddress group = InetAddress.getByName("224.0.0.251");
MembershipKey key = mc.join(group, ni);
ByteBuffer buf = ByteBuffer.allocate(512);
while (true)
{
if ( key.isValid() )
{
// read함수를 쓸 경우 connect를 요구한다
SocketAddress sender = mc.receive(buf);
buf.flip();
System.out.println("sender=" + sender + "\n" + ByteBufferUtils.serialize(buf));
buf.clear();
}
else
{
System.out.println("trying to connect");
try { Thread.sleep(1000); } catch(InterruptedException e) { }
}
}
}
catch(Exception e)
{
throw e;
}
finally
{
try { mc.close(); } catch(Exception e) { }
}
마치며
구글 클라우드 프린트 문서에 따르면, 크롬브라우저가 mDNS규약에 따라 로컬네트워크에 연결된 장치들을 검색한다. 약속된 장치이름으로 검색을 하는데, DNS-SD 서비스 이름은 _privet._tcp 이다. 장치는 두가지 PTR 정보를 제공할 수 있으면 된다.
- _privet._tcp.local
- _printer._sub._privet._tcp.local
'Maker Movement' 카테고리의 다른 글
자바유료화 대책 (0) | 2018.09.25 |
---|---|
구글 클라우드 프린트(4) - 프린터 등록 (0) | 2018.02.07 |
구글 클라우드 프린트(3) - 프린터인식 (0) | 2017.12.23 |
구글 클라우드 프린트(1) - 들어가기 (0) | 2017.11.19 |
라즈베리파이3 콘솔포트 연결 (0) | 2017.04.26 |