在Python中实现DNS消息名称压缩算法
在DNS消息中,域名表示如下:在Python中实现DNS消息名称压缩算法,python,regex,search,dns,Python,Regex,Search,Dns,在DNS消息中,域名表示如下: Address Value ---------------------------------------------------------------- 0x00C 0x5 s t o r e 0x7 e x a m p l e 0x3 c o m 0x0 0x023 0x4 b l o g 0xC012 在地址0x00C我们有store.example.com,在地址0x023我们有blog.example.com0xC012表
Address Value
----------------------------------------------------------------
0x00C 0x5 s t o r e 0x7 e x a m p l e 0x3 c o m 0x0
0x023 0x4 b l o g 0xC012
在地址0x00C
我们有store.example.com
,在地址0x023
我们有blog.example.com
0xC012
表示指向0x012
的指针,其中example.com
从第一个域名开始,因此我们不必重复它
我使用以下代码成功地将域名转换为标签数组:
labels = []
for part in self.domain.split('.'):
label = part.encode('ascii')
length = len(label).to_bytes(1, 'big')
labels.append(length + label)
这为我提供了以下数组:
[b'\x04blog', b'\x07example', b'\x03com']
但是我很难构建一个正则表达式或一个高效函数来搜索已经为\x04blog\x07example\x03com\x00
或\x07example\x03com\x00
编写的消息部分。我想找到最长的比赛。我试着构建一个这样的正则表达式:
(((\x04blog)?\x07example)?\x03com)?\x00
但在这种情况下,正则表达式引擎似乎更喜欢只匹配\x00
。我该如何解决这个问题
还有另一个问题:我们可以从技术上添加
my.blog.example.com
,它需要包含0x2 m y 0xC023
,并且0xC023
指向blog.example.com
首先,对于我给你的错误提示,有更简单的事情要做。事实上,这里有比使用正则表达式简单得多的事情要做。正则表达式太强大了,无法做到这一点,您可以在不使用正则表达式的情况下实现相同的结果
DNS消息格式在中定义
第4.1.4节解释了名称压缩。
还请注意,您必须考虑不区分大小写的方面,如第2.3.3节所述
在下面的代码中应该是这样的情况,可以肯定
使用取自RFC的示例名称进行优化:
#/usr/bin/python3
名称=['F.ISI.ARPA','FOO.F.ISI.ARPA','ARPA']
缓存={}
pos=0
结果=[]
对于名称中的名称:
labels=name.split('.'))
而len(标签):
键=“.”。联接(标签)
如果缓存中有key.lower():
results.append((缓存[key.lower()]+2**15+2**14).to_字节(2,'big'))
pos+=2
打破
其他:
label=labels.pop(0).encode('ascii')
长度=len(标签)。到_字节(1,‘大’)
结果.追加(长度+标签)
缓存[key.lower()]=pos
位置+=透镜(标签)+1
其他:
results.append(b'0')
pos+=1
打印(结果)
产生:
[b'\x01F', b'\x03ISI', b'\x04ARPA', b'0', b'\x03FOO', b'\xc0\x00', b'\xc0\x06']
[b'\x05store', b'\x07example', b'\x03com', b'0', b'\x04blog', b'\xc0\x06', b'\x02my', b'\xc0\x13']
如果改为使用您的示例:
names=['store.example.com', 'blog.example.com', 'my.blog.example.com']
它产生:
[b'\x01F', b'\x03ISI', b'\x04ARPA', b'0', b'\x03FOO', b'\xc0\x00', b'\xc0\x06']
[b'\x05store', b'\x07example', b'\x03com', b'0', b'\x04blog', b'\xc0\x06', b'\x02my', b'\xc0\x13']
如果不是很明显,是的,我编程这纯粹是作为一种学习经验。提示:如果你从右到左解析东西,并将全名存储为键,将编码值存储为值,那么问题就会少一些。从
com
开始,将其编码为0x3 c o m 0x0
并保持cache['com']=position
,然后转到example
,对其进行编码并将example.com
放入缓存中,并在适当的位置进行压缩,在进行任何编码之前,请测试该值是否已存在于缓存中。这是一种不用正则表达式的方法。你也可以看看在当前的DNS库中是如何实现的,给你一些想法……我意识到我写的指针是一个字节而不是两个字节。我试着把它们修好,希望我没有弄错。我还写了超过三个十六进制数字的地址,考虑到一条消息可能会占用512字节(0x200)。是的,我在问了这个问题后不久得出结论,我可能需要一个缓存。哦,我明白了,你从左到右写名字,逐步地把它的条目添加到缓存中,一旦剩下一个在缓存中的余数,你就放一个指针。偏离航线!对于将来阅读本文的任何人来说,名称中的指针由两个1位组成,后跟消息顶部的偏移量(剩余的两个字节)。域可以写在消息的不同部分,域名之间总是有更多的数据。因此,从0开始并以那样的方式递增pos
并不是一件容易的事,但这段代码让人明白了一般的想法。@JacqueGoupil是的,职位会有“间隙”,这取决于你所处的位置,但这实际上取决于你所传达的信息;您只需要有一个通用函数,其中传递名称和当前位置,它将根据缓存的当前内容在给定位置对名称进行编码并递增。实际上,我使用了(0xC000+len(message))。到_字节(2,'大')
在执行message.append(长度+标签)
之前,在缓存中创建并存储指针。