DNS Lab.

IPTables, DNS 패킷 차단 설정 방법 모색 (1) 본문

보안

IPTables, DNS 패킷 차단 설정 방법 모색 (1)

승홍 2016. 12. 17. 13:33


DNS 질의 트래픽을 질의한 도메인이름, 질의타입을 기준으로 선별, 차단하는 방법은 없을까?


요즘 네임서버에 유입되는 DNS 질의 중에는 보안공격과 연관된 것으로 의심되는 각종 질의가 포함되어 있습니다. 

어떤 경우는 차단이 필요하다고 여겨지지만, 마땅한 방법이 없는 경우도 있습니다.


특정 IP 주소에서만 공격성 질의가 발생한다면,  해당 IP주소 기준으로 차단하는 것은 그리 어렵지 않습니다. 

라우터 ACL, 방화벽, 서버 IPTables의 단순한 설정을 사용할 수 있습니다.


그러나 불특정 IP주소에서 공격성 질의가 발생하는 경우는 대응이 달라져야 합니다.

IP주소 대신 질의된 도메인이름과 질의타입을 기준으로 선별 차단해야 한다면, DNS 질의 메시지 내용을 분석하여 차단해야 합니다. 

즉 어플리케이션 계층(L7)에서 선별하여 차단하는 기능이 필요합니다.


여기서는 리눅스 시스템의 IPTables/Netfilter를 사용하여 특정 질의도메인/질의타입 DNS 유입 패킷을 차단방법을 기본 원리 중심으로 검토해 봅니다.


IPTabbles를 사용하는 것만이 유일한 해법이라고 할 수는 없습니다. 

기능이 제한적이긴 하지만, 현재 일부 네임서버가 구현하고 있는 RPZ(Response Policy Zones) 기능을 활용해 보는 방법도 있습니다.


최근에는 인터넷 표준 측면에서 네임서버가 공격과 관련된 특정 DNS질의를 차단 할 수 있는 기능을 구현할 수 있도록 표준안 작업을 하고 있기도 합니다.



DNS 메시지 구조 


질의도메인과 질의타입을 기준으로 선별하여 차단하려면, 먼저 DNS 메시지 구조를 알아둘 필요가 있습니다.


DNS 메시지 패킷은 < IP헤더 | UDP헤더 | DNS 메시지 >로 구성됩니다. 


아래는 DNS 메시지 구조도입니다. UDP를 사용하는 DNS 메시지 경우로써, UDP 헤더 이후의 DNS 부분입니다.



DNS 메시지는 크게 DNS헤더 부분, 그리고 나머지 DNS 레코드가 채워지는 4개의 섹션으로 구분됩니다.


이 중에서 이번에 주목할 부분은 DNS헤더와 Question 섹션입니다. 


'DNS질의'에서 '질의도메인(QNAME)'과 '질의타입(QTYPE)'을 기준으로 선별하는 방법이 필요합니다.



'DNS질의' 메시지 판별 기준


'DNS질의' 메시지인지 여부는 위 그림 중 QR 필드값으로 판별할 수 있습니다. 


DNS 메시지 내에서 특정 필드 위치를 표시하는 방식으로 DNS[offset] 방식을 사용하기로 합니다.

DNS 메시지의 첫번째 바이트 위치(offset)를 0으로 정하면, DNS 메시지의 첫번째 바이트는 DNS[0]으로 표시합니다.


QR 필드가 속한 1개 바이트 위치는 DNS[2]입니다. 


DNS[2] & 0x80 == 0x00 이면 'DNS질의' 메시지라고 판단할 수 있습니다.


DNS[2]는 DNS[0], DNS[1]의 2개 바이트인 DNS ID 다음에 오는 1개 바이트를 의미합니다.


0x80은 16진수 표현으로써, DNS[2] 1개 바이트 8비트 값 중에서 첫번째 비트인 QR 플래그 비트만 세팅한 값입니다. 

DNS[2] 값에 0x80(QR bit)로 매스킹(&)한 결과 값이 0x80과 동일하면 DNS[2]의 QR 비트는 1로 세팅되어 있다는 의미입니다. 이 경우 'DNS응답' 메시지입니다. 그렇지 않고 이 값이 0이라면, QR 비트는 0으로 클리어된 상태이면, 이는 'DNS질의' 메시지임을 뜻합니다.


이에 더하여 DNS헤더의 Opcode 필드값도 함께 체크할 필요성이 있습니다. DNS Opcode는 DNS 메시지가 질의응답(Query) 메시지인지, 존 데이터의 변동을 알리는 Notify 메시지인지, DNS 동적업데이트 메시지(Update) 인지 여부를 표시합니다. Opcode 코드 값 전체 리스트는 IANA의 'DNS OpCodes' 페이지에 게재되어 있습니다.


DNS 질의응답 용 Opcode는 0 (0x00) 입니다.

따라서 Opcode까지 포함하여 DNS 질의메시지 여부를 판별하는 조건은 DNS[2] & 0xf8 == 0x00 이 됩니다. 0xf8 은 첫번째 비트(QR flag)와 이후 연속한 4개 비트(Opcode) 값를 매스킹하는 16진수 값입니다. 매스킹 처리한 결과이 0이 되면 QR flag가 0이고, Opcode 도 0인 경우입니다.


이 방법은 세밀하고 정확한 조건을 지정할 수 있는 장점을 지니지만, IPTables 룰셋으로 '간단하게' 표현하기에는 다소 어려움이 있습니다. IPTables의 U32 확장모듈과 같이 정밀한 필드값 검사기능을 사용하여 설정하는 것이 필요합니다.  U32 확장모듈을 사용한 설정은 후에 다루기로 합니다.


네임서버에 유입되는 DNS 질의응답 트래픽이 단순한 형태라면, 대신에 'UDP 착신포트가 53일때' 라는 '대략적인' 조건을 사용할 수 있습니다. 



'질의도메인' 식별 기준


'질의도메인'은 Question 섹션의 첫부분에 자리하고 있습니다. DNS헤더의 바로 다음입니다.


Question 섹션은 DNS[12]부터 시작합니다. DNS헤더가 항상 12바이트 길이를 가지므로, DNS 메시지 첫 바이트 이후의 12번째 바이트가 Question 섹션의 시작 바이트입니다.


Question 섹션의 '질의도메인' 길이는 미리 알 수 없습니다. 도메인이름은 IP 패킷의 DNS 메시지에서는 특별한 형태를 가진 가변 필드이기 때문입니다.

이 특성 때문에 각각의 DNS메시지를 '질의도메인' 기준으로 판별 차단하는 기능을 이용에 편리하도록 구현하는 것이 상당히 어렵습니다.


IP 패킷에서 도메인이름은  < len | label#1 | len | label#2 | ... | len | label#n | 0 > 이라는 구조화된 형식을 가집니다. len 에는 다음에 오는 레이블(label)의 문자개수(바이트수) 값을 설정합니다. label#1, label#2, ...은 도메인이름에서 '.'을 제외한 여러 개의 문자열(레이블)입니다.


구체적인 사례로써 'ripe.net'이라는 도메인이름 경우를 살펴봅니다.


도메인이름 'ripe.net'은 IP 패킷의 DNS 메시지에서는 < 4 | ripe | 3 | net | 0 >의 값으로 설정됩니다. 

'ripe', 'net'은 레이블(label) 입니다. 도메인이름은 레이블이 연속으로 이루어져 있습니다.

'ripe'는 4개 문자(바이트), 'net'은 3개 문자(바이트)를 가집니다. 여기에서 4, 3은 각 레이블 앞에 오는 len 필드 값이 됩니다.


< len | label#1 | len | label#2 | ... | len | label#n | 0 > 에서 마지막 남은 < 0 > 값은 루트 도메인(.)을 의미합니다. 루트 도메인은 특수한 도메입니다. 루트 도메인 이름은 0개 문자로 된 레이블 갖습니다. 그래서 이를 IP 패킷에서 동일한 규칙에 따라 표현하면 < 0 > 이 됩니다. 이를 달리 표현하면, 루트 도메인 이름은 "이름이 없는 도메인이름"이라 할 수 있습니다.


< len | 문자열 >로 표현하는 방식은 문자열을 표현하는 데이터 구조 방식 중 하나입니다.


문자열은 여러 개의 문자로 이루어지고 그 길이를 미리 알 수 없는 가변길이 데이터입니다. 그래서 문자열을 다루려면 '길이' 정보가 필요합니다. 

< len | 문자열 > 의 표현방식은 문자열 데이터의 첫번째 바이트가 문자열 길이 값을 가지고, 이 길이 만큼의 나머지 데이터가 '문자열' 값을 가진다는 것을 의미합니다. 도메인이름은 이와 같은 문자열 표현 방식을 따르고 있습니다. 


< len | 문자열 > 표현방식은 표현할 수 있는 문자열 개수에 한계가 있습니다. len이 1개 바이트일 때, 1개 바이트가 표현할 수 있는 최대 길이는 0xff = 255입니다. 따라서 255개 문자를 초과하는 문자를 가진 문자열은 이 방식으로 표현할 수 없습니다.

이에 반하여 C 언어에서는 문자열을 < 문자열 | 0 >이라는 형식으로 표현 합니다. 맨 마지막에 특수한 null 문자(0x00)를 붙임으로써 문자열의 끝을 표시하는 것으로 정의하여 사용합니다. 문자열 길이는 문자열 첫부분부터 null문자 이전까지 문자(바이트) 개수를 별도로 세어 파악할 수 있습니다. 


C언어의 문자열 표현방식에서는 원칙적으로 문자열의 길이에 제한이 없습니다. 문자열 처음지점부터 0x00(null) 문자에 이르는 모든 데이터가 문자열이 됩니다. 그러나 문자열 데이터 끝의 0x00(null)의 설정처리가 제대로 되어 있지 않을 경우 심각한 시스템 에러를 유발하는 단점이 있습니다.



만일  'ripe.net'으로 질의하는 DNS 메시지를 검출하려면, Question 섹션 첫바이트 값은 4, 그 이후 4개 바이트는 'ripe', 그 다음 바이트 값은 3, 이후의 3개 바이트는 'net', 그리고 이 다음 마지막 바이트 값은 0 이어야 합니다.


Question 섹션의 첫바이트는 DNS[12]이므로 ( DNS[12] 부터 10개 바이트 영역 ) == <  4 | ripe | 3 | net | 0 > 이면 ripe.net을 질의하는 DNS 메시지라고 판단할 수 있습니다. 여기서 '10개 바이트 영역'은 <  4 | ripe | 3 | net | 0 >이 차지하는 바이트 영역을 의미합니다. 세어보면 10개 바이트를 차지하고 있습니다.



'질의타입' 식별 기준


'질의타입' 값은 '질의도메인' 바로 다음의 2바이트 필드에 설정됩니다. 


질의타입 A는 'A'라는 문자로 설정되는 것이 아니라, 숫자 코드값 1로 설정됩니다.

DNS 질의타입은 표준으로 정해집니다. 전체 질의타입 코드 리스트는 IANA의 "Resource Record Types" 페이지에 게재되어 있습니다.


여기서는 'ANY' 질의를 차단한다고 가정합니다. 


이전에 DNS증폭 DDoS 공격이 'ripe.net' 등에 대한 ANY 질의를 주로 사용하고 있었기에 이들 도메인에 대한 ANY 질의차단의 필요성이 있었습니다.

ANY 질의의 질의코드 값은 255입니다. 16진수 값으로는 0x00ff입니다. 질의필드는 2바이트이기에 ANY 질의코드는 2바이트 값 0x00ff로 표현됩니다.


'질의타입' 값을 검사하려 할 때 '질의타입' 필드 위치는 '질의도메인'이 무엇인지에 따라 달라집니다. '질의도메인' 필드길이가 가변적이기에 그 다음에 오는 '질의타입' 필드의 위치 역시 가변적입니다.


그렇기에 '질의도메인'과 '질의타입' 값은 함께 검사하는 것이 필요합니다.


예로써, 'ripe.net'에 대해 'ANY'를 질의하는 DNS 질의메시지를 차단한다고 가정한다면, 다음과 같이 검사합니다.


( DNS[12] 부터 12개 바이트 영역 ) == <  4 | ripe | 3 | net | 0 | 0 | 255 >  이 일치한다면, 이 DNS질의 메시지는 'ripe.net'의 ANY 질의라고 판단합니다. 


도메인이름은 <  4 | ripe | 3 | net | 0 > 의 10 바이트 이고, ANY 질의타입 부분은 < 0 | 255 > 의  2바이트 입니다. 



IPTables 차단 룰셋 작성하기


그러면, 이것을 IPTable에 설정하는 구체적인 방법은 어떻게 될까요?


여러 가지 방법이 있을 수 있습니다. 그 중에서 되도록 단순한 방법을 사용하여 작성하는 사례를 보이도록 하겠습니다.


IPTables는 IP 패킷을 검사하는 다양한 방식을 여러 모듈로 제공하고 있습니다.


이 중에 STRING 모듈이 있습니다.


우선 STRING 모듈을 사용하여 유입되는 UDP DNS 메시지 중 ripe.net ANY 질의 메시지를 차단하는 룰셋을 아래와 같이 작성할 수 있습니다.


( DNS[12] 부터 12개 바이트 영역 ) == <  4 | ripe | 3 | net | 0 | 0 | 255 > 의 매칭 조건을 IPTables의 STRING 모듈이 요구하는 문법에 따라 작성하면 다음과 같습니다. 

-A INPUT -p udp --dport 53 -m string --algo bm --from 40 --to 52 --hex-string "|04|ripe|03|net|00 00 ff|" -j DROP



UDP를 사용하여 53 포트로 착신하는 ( -p udp --dport 53) 패킷에 대해서 STRING 모듈( -m string )을 적용한 매칭 조건에 일치하는 경우 패킷을 차단하는 룰셋을 작성하였습니다.


STRING 모듈의 매칭조건 인자설정 세부사항은 다음과 같습니다.


STRING 모듈이 제공하는 문자열 매칭 알고리듬 중에서 bm(Boyer-Moore) 알고리듬을 사용합니다 ( --algo bm ).


IP 헤더의 첫 바이트 기준으로 40 바이트 떨어진 지점부터 IP 헤더 첫 바이트에서 52번째 바이트 이전 범위 내에서 패턴 매칭을 시도합니다 ( --from 40 --to 52 ). 


40 바이트는 IP 헤더를 기준한 DNS 메시지의 Question Section 시작 지점으로써, 20 (IP헤더 기본 길이) + 8 (UDP헤더 고정 길이) + 12 (Question Section 시작지점) = 40 바이트로 계산됩니다. IP헤더 옵션이 달릴 경우 IP헤더 길이는 더 길어질 수 있지만, IP헤더 최소 길이 20바이트를 기준으로 계산합니다. UDP헤더는 항상 8 바이트 길이를 가집니다. DNS 메시지 내에서 12바이트 지점에서 Question Section이 시작되므로 12바이트를 더합니다. 


52바이트는 40바이트 지점에서 12바이트 떨어진 지점으로써, 40 +12 = 52 바이트로 계산됩니다. 


매칭검사 범위를 이와 같이 IP헤더 첫바이트에서 40 바이트 ~ 52바이트 사이 영역으로 한정시키는 경우, IP옵션이 달린 IP헤더가 사용되면 검출에 실패할 수 있습니다. 

IP헤더 옵션 길이만큼 DNS Question 섹션영역 범위가 밀려서 그 위치가 변동되기 때문입니다. 

그러나 IP헤더 옵션은 사용되는 경우가 거의 없어서 이러한 매칭검사 실패가 발생할 확률은 아주 적어서 별 문제가 되지는 않는다고 할 수는 있습니다.


IP헤더 옵션이 있는 경우까지 고려한는 경우, 검사대상 영역의 끝지점인 52바이트 값을 좀 더 늘려서 52 + 40 = 92 바이트 정도로 설정할 수도 있습니다. 

IP헤더 길이는 최소 20바이트 ~ 최대 60바이트까지 가능하므로 IP헤더 옵션이 40바이트 길이까지 부가되는 경우를 고려할 때 그렇게 설정할 수 있습니다. 


도메인이름 ripe.net과 ANY 질의타입(0x00ff)이 여기에 연이어 지정되어 있는지 검사합니다 ( --hex-string "|04|ripe|03|net|00 00 ff|"  ).


이 조건에 부합하는 경우, 패킷을 차단합니다 ( -j DROP )



여기에서 --hex-string 설정문에 대해서는 좀 자세히 살펴 볼 필요가 있습니다.


--hex-string 옵션은 바이너리 데이터에 대한 16진수 표현과 문자열 표현을 혼용하여 매칭 조건을 설정하는 용도의 옵션입니다.


"|04|ripe|03|net|00 00 ff|" 에서 16진수표현 부분은 '|' 구분자로 구분하여 일반 문자열 내용과 서로 혼동되지 않도록 설정합니다.

'|04|'은 다음 레이블 길이를 나타내는 숫자 4입니다. 16진수 표현으로 1개 바이트 값인 0x04입니다. '|04|'은 0x04을 구분자 '|'를 사용하여 표현한 것입니다.

이후의 '|03|' 은 동일하게 'net' 레이블 길이 값을 설정한 16진수입니다.


ripe, net 은 일반 문자열입니다. 이 부분은 문자열 그대로 설정합니다.

끝 부분의 '|00 00 ff|' 은 도메인 이름의 마지막 1바이트, 곧 루트 도메인이름인 1바이트 값 0x00 과 'A 질의타입' 2바이트 값인 0x00ff을 연이어 16진수로 표현한 것입니다. 


서버 시스템 적용 & 확인 


서버 시스템에 적용하고 원하는 대로 동작하는지 확인합니다.


아래와 같이 IPTables 룰셋 설정파일을 작성합니다.

$
$ cat ipt-drop-ripe.net-ANY.txt 
*filter
:INPUT ACCEPT 
:FORWARD ACCEPT 
:OUTPUT ACCEPT
-A INPUT -p udp --dport 53 -m string --algo bm --from 40 --to 52 --hex-string "|04|ripe|03|net|00 00 ff|" -j DROP
COMMIT
$ 

서버 시스템에 iptables로 적용합니다.

$ 
$ cat ipt-drop-ripe.net-ANY.txt | sudo iptables-restore 
$ 


iptables로 상태를 확인합니다.

룰셋 항목의 pkts와 bytes는 아직 0 인 상태입니다.

$ 
$ sudo iptables -nvL
Chain INPUT (policy ACCEPT 106 packets, 13066 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 DROP       udp  --  *      *       0.0.0.0/0            0.0.0.0/0            udp dpt:53 STRING match  "|0472697065036e65740000ff|" ALGO name bm FROM 40 TO 52

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain OUTPUT (policy ACCEPT 104 packets, 9434 bytes)
 pkts bytes target     prot opt in     out     source               destination         
$  


이 서버 시스템의 외부에서 ripe.net에 대한 ANY 질의를 합니다.

질의 결과, timeout 무응답 오류가 발생합니다.

$
$ dig @10.0.2.15 ripe.net ANY +multi

; <<>> DiG 9.11.0b1 <<>> @10.0.2.15 ripe.net ANY +multi
; (1 server found)
;; global options: +cmd
;; connection timed out; no servers could be reached
$


룰셋을 적용한 서버에서 iptables로 상태를 확인합니다.

룰셋항목의 pkts와 bytes 값이 각각 3, 231로 증가했습니다.

dig 유틸리티는 시도 후 무응답 오류가 발생하면 default로 3번 재시도합니다. 그래서 pkts 값이 0 --> 3으로 증가했습니다.

$
$ sudo iptables -nvL
Chain INPUT (policy ACCEPT 133 packets, 14298 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    3   231 DROP       udp  --  *      *       0.0.0.0/0            0.0.0.0/0            udp dpt:53 STRING match  "|0472697065036e65740000ff|" ALGO name bm FROM 40 TO 52

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain OUTPUT (policy ACCEPT 127 packets, 12038 bytes)
 pkts bytes target     prot opt in     out     source               destination         
$


지정된 조건의 DNS질의 패킷이 차단되기 직전에 로그파일에 로그를 남기면 좋을 것 같습니다.

동일한 조건에 일치할 때 로그를 남기도록 추가해 봅니다.

$ 
$ cat ipt-drop-ripe.net-ANY-LOG.txt
*filter
:INPUT ACCEPT 
:FORWARD ACCEPT 
:OUTPUT ACCEPT
-A INPUT -p udp --dport 53 -m string --algo bm --from 40 --to 52 --hex-string "|04|ripe|03|net|00 00 ff|" -j LOG --log-prefix "DROP RIPE.NET ANY :" --log-level info
-A INPUT -p udp --dport 53 -m string --algo bm --from 40 --to 52 --hex-string "|04|ripe|03|net|00 00 ff|" -j DROP
COMMIT
$ 


LOG는 로그를 기록처리하면서 해당 패킷 처리를 종료하지 않고 다음 순서의 룰셋 적용으로 절차를 넘겨줍니다.

따라서 이 패킷은 로그처리를 한 후 다음 순서의 룰셋에서 조건에 일치하여 DROP 처리됩니다.


사실 이러한 방식의 설정은 비효율적이라 할 수 있습니다. 동일한 매칭조건 검사를 2번 반복해야 합니다. 효율적인 매칭조건 검사를 위해 IPTables의 MARK 모듈을 사용할 수 있습니다.


서버 시스템에 적용한 후 로그를 체크한 결과입니다. dig을 사용하여 외부에서 서버로 ripe.net ANY를 질의했을 때 다음과 같이 로그가 남겨집니다.

$ 
$ tail -f /var/log/kern.log | grep 'RIPE.NET ANY'
Dec 11 13:27:14 SLab1 kernel: [ 1235.268966] DROP RIPE.NET ANY :IN=enp0s3 OUT= MAC=08:00:27:79:7a:18:52:54:00:12:35:02:08:00 SRC=10.0.2.2 DST=10.0.2.15 LEN=77 TOS=0x00 PREC=0x00 TTL=64 ID=3649 PROTO=UDP SPT=45379 DPT=53 LEN=57 
Dec 11 13:27:17 SLab1 kernel: [ 1238.068522] DROP RIPE.NET ANY :IN=enp0s3 OUT= MAC=08:00:27:79:7a:18:52:54:00:12:35:02:08:00 SRC=10.0.2.2 DST=10.0.2.15 LEN=77 TOS=0x00 PREC=0x00 TTL=64 ID=3652 PROTO=UDP SPT=45379 DPT=53 LEN=57 
Dec 11 13:27:20 SLab1 kernel: [ 1241.114650] DROP RIPE.NET ANY :IN=enp0s3 OUT= MAC=08:00:27:79:7a:18:52:54:00:12:35:02:08:00 SRC=10.0.2.2 DST=10.0.2.15 LEN=77 TOS=0x00 PREC=0x00 TTL=64 ID=3655 PROTO=UDP SPT=45379 DPT=53 LEN=57 
^C
$ 


dig에 의해 3번 시도된 패킷 3개가 모두 차단되었습니다. 


IPTables에 지정된 LOG 동작으로 남겨지는 로그는 kernel 로그 파일에 기록됩니다.


ripe.net ANY 질의는 차단되지만, ripe.net A 질의는 정상적으로 처리되어 응답됩니다.

$
$ dig @10.0.0.15 ripe.net A +multi

; <<>> DiG 9.11.0b1 <<>> @10.0.0.15 ripe.net A +multi
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 7011
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 7, ADDITIONAL: 15

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: 9e034752013b5bab3bad14c75843a2e9f0eb1504e94721ca (good)
;; QUESTION SECTION:
;ripe.net.IN A

;; ANSWER SECTION:
ripe.net.21547 IN A 193.0.6.139

;; AUTHORITY SECTION:
ripe.net.3547 INNS a2.verisigndns.com.
ripe.net.3547 INNS manus.authdns.ripe.net.
ripe.net.3547 INNS a1.verisigndns.com.
ripe.net.3547 INNS sns-pb.isc.org.
ripe.net.3547 INNS sec3.apnic.net.
ripe.net.3547 INNS tinnie.arin.net.
ripe.net.3547 INNS a3.verisigndns.com.

;; ADDITIONAL SECTION:
a1.verisigndns.com.3547 INA 209.112.113.33
a2.verisigndns.com.3547 INA 209.112.114.33
a3.verisigndns.com.3547 INA 69.36.145.33
sec3.apnic.net.172747 IN A 202.12.28.140
manus.authdns.ripe.net.3547 INA 193.0.9.7
sns-pb.isc.org.7147 INA 192.5.4.1
tinnie.arin.net.172747 IN A 199.212.0.53
a1.verisigndns.com.3547 INAAAA 2001:500:7967::2:33
a2.verisigndns.com.3547 INAAAA 2620:74:19::33
a3.verisigndns.com.3547 INAAAA 2001:502:cbe4::33
sec3.apnic.net.172747 IN AAAA 2001:dc0:1:0:4777::140
manus.authdns.ripe.net.3547 INAAAA 2001:67c:e0::7
sns-pb.isc.org.7147 INAAAA 2001:500:2e::1
tinnie.arin.net.172747 IN AAAA 2001:500:13::c7d4:35

;; Query time: 1 msec
;; SERVER: 10.0.0.15#53(10.0.0.15)
;; WHEN: Sun Dec 11 14:00:28 KST 2016
;; MSG SIZE  rcvd: 562

$ 



한계점


이로써 특정 질의도메인과 질의타입을 갖는 패킷을 골라 차단하는 설정을 보았습니다.


하지만 실제 적용할 때, 위에 제시된 방법만으로는 적용에 한계가 있습니다.


질의도메인 개수가 아주 많을 경우, 그 개수 만큼 일일이 IPTables 룰셋으로 작성해서 설정해야 하는 문제점이 있습니다.

IPTables의 룰셋 개수가 질의도메인 개수만큼 많아지고, 그러면 아무래도 DNS 패킷 검사에 소요되는 부하도 증가합니다.


특정 질의타입의 DNS 메시지 패킷을 질의된 도메인에 상관없이 모두 차단하려면?

예를 들어 ANY 질의하는 모든 DNS 패킷을 차단하려고 할 때, 질의하는 도메인의 길이를 미리 알 수 없으므로 '질의타입' 필드위치를 정할 수 없는 문제가 있습니다. 각각의 DNS질의 메시지에서 '질의타입' 필드의 위치는 질의된 도메인 길이에 따라 상시 달라지기 때문입니다.


IPTables 사용한 DNS 매칭조건 설정 방법을 더 확장해 볼 필요성이 있습니다.







Comments